Allow to resize chats list. One more mode added (narrow chats list).

This commit is contained in:
John Preston 2017-01-14 21:50:16 +03:00
parent 983db3a682
commit 4424dbf64a
33 changed files with 558 additions and 140 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

View file

@ -771,7 +771,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_record_cancel" = "Release outside this field to cancel"; "lng_record_cancel" = "Release outside this field to cancel";
"lng_will_be_notified" = "Members will be notified when you post"; "lng_will_be_notified" = "Members will be notified when you post";
"lng_wont_be_notified" = "Members will not be notified when you post"; "lng_wont_be_notified" = "Members will not be notified when you post";
"lng_empty_history" = "";
"lng_willbe_history" = "Please select a chat to start messaging"; "lng_willbe_history" = "Please select a chat to start messaging";
"lng_from_you" = "You"; "lng_from_you" = "You";
"lng_from_draft" = "Draft"; "lng_from_draft" = "Draft";

View file

@ -31,12 +31,9 @@ void RegisterPendingObservable(ObservableCallHandlers *handlers);
void UnregisterActiveObservable(ObservableCallHandlers *handlers); void UnregisterActiveObservable(ObservableCallHandlers *handlers);
void UnregisterObservable(ObservableCallHandlers *handlers); void UnregisterObservable(ObservableCallHandlers *handlers);
template <typename EventType>
using EventParamType = typename base::type_traits<EventType>::parameter_type;
template <typename EventType> template <typename EventType>
struct SubscriptionHandlerHelper { struct SubscriptionHandlerHelper {
using type = base::lambda<void(EventParamType<EventType>)>; using type = base::lambda<void(parameter_type<EventType>)>;
}; };
template <> template <>
@ -355,6 +352,52 @@ public:
template <typename EventType, typename Handler = internal::SubscriptionHandler<EventType>> template <typename EventType, typename Handler = internal::SubscriptionHandler<EventType>>
class Observable : public internal::BaseObservable<EventType, Handler, base::type_traits<EventType>::is_fast_copy_type::value> { class Observable : public internal::BaseObservable<EventType, Handler, base::type_traits<EventType>::is_fast_copy_type::value> {
public:
Observable() = default;
Observable(const Observable &other) = delete;
Observable(Observable &&other) = default;
Observable &operator=(const Observable &other) = delete;
Observable &operator=(Observable &&other) = default;
};
template <typename Type>
class Variable {
public:
Variable(parameter_type<Type> startValue = Type()) : _value(startValue) {
}
Variable(Variable &&other) = default;
Variable &operator=(Variable &&other) = default;
parameter_type<Type> value() const {
return _value;
}
void setForced(parameter_type<Type> newValue, bool sync = false) {
_value = newValue;
_observable.notify(_value, sync);
}
void set(parameter_type<Type> newValue, bool sync = false) {
if (_value != newValue) {
setForced(newValue, sync);
}
}
template <typename Callback>
void process(Callback callback, bool sync = false) {
callback(_value);
_observable.notify(_value, sync);
}
Observable<Type> &observable() {
return _observable;
}
private:
Type _value;
Observable<Type> _observable;
}; };
class Subscriber { class Subscriber {
@ -370,6 +413,16 @@ protected:
return subscribe(*observable, std_::forward<Lambda>(handler)); return subscribe(*observable, std_::forward<Lambda>(handler));
} }
template <typename Type, typename Lambda>
int subscribe(base::Variable<Type> &variable, Lambda &&handler) {
return subscribe(variable.observable(), std_::forward<Lambda>(handler));
}
template <typename Type, typename Lambda>
int subscribe(base::Variable<Type> *variable, Lambda &&handler) {
return subscribe(variable->observable(), std_::forward<Lambda>(handler));
}
void unsubscribe(int index) { void unsubscribe(int index) {
if (!index) return; if (!index) return;
t_assert(index > 0 && index <= _subscriptions.size()); t_assert(index > 0 && index <= _subscriptions.size());

View file

@ -126,4 +126,7 @@ struct type_traits {
using pointed_type = internal::remove_pointer_t<T>; using pointed_type = internal::remove_pointer_t<T>;
}; };
template <typename T>
using parameter_type = typename type_traits<T>::parameter_type;
} // namespace base } // namespace base

View file

@ -53,6 +53,7 @@ dialogsSkip: 8px;
dialogsWidthMin: 260px; dialogsWidthMin: 260px;
dialogsWidthMax: 540px; dialogsWidthMax: 540px;
dialogsWidthDuration: 120;
dialogsTextWidthMin: 150px; dialogsTextWidthMin: 150px;
dialogsScroll: ScrollArea(defaultScrollArea) { dialogsScroll: ScrollArea(defaultScrollArea) {
topsh: 0px; topsh: 0px;
@ -191,6 +192,9 @@ dialogsUpdateButton: FlatButton {
} }
} }
dialogsInstallUpdate: icon {{ "install_update", activeButtonFg }};
dialogsInstallUpdateOver: icon {{ "install_update", activeButtonFgOver }};
dialogsForwardHeight: 32px; dialogsForwardHeight: 32px;
dialogsForwardTextLeft: 35px; dialogsForwardTextLeft: 35px;
dialogsForwardTextTop: 6px; dialogsForwardTextTop: 6px;

View file

@ -58,8 +58,8 @@ void paintRowDate(Painter &p, const QDateTime &date, QRect &rectForName, bool ac
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt); p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt);
} }
template <typename PaintItemCallback> template <typename PaintItemCallback, typename PaintCounterCallback>
void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *item, Data::Draft *draft, QDateTime date, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms, PaintItemCallback paintItemCallback) { void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *item, Data::Draft *draft, QDateTime date, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms, PaintItemCallback paintItemCallback, PaintCounterCallback paintCounterCallback) {
QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight); QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
row->paintRipple(p, 0, 0, fullWidth, ms, &(active ? st::dialogsRippleBgActive : st::dialogsRippleBg)->c); row->paintRipple(p, 0, 0, fullWidth, ms, &(active ? st::dialogsRippleBgActive : st::dialogsRippleBg)->c);
@ -69,6 +69,13 @@ void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *i
userpicPeer->paintUserpicLeft(p, st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth, st::dialogsPhotoSize); userpicPeer->paintUserpicLeft(p, st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth, st::dialogsPhotoSize);
auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding; auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding;
if (fullWidth <= nameleft) {
if (!draft && item && !item->isEmpty()) {
paintCounterCallback();
}
return;
}
auto namewidth = fullWidth - nameleft - st::dialogsPadding.x(); auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height); QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height);
@ -105,8 +112,7 @@ void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *i
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService); auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
p.setFont(st::dialogsTextFont); p.setFont(st::dialogsTextFont);
if (!history->paintSendAction(p, nameleft, texttop, namewidth, fullWidth, color, ms)) { if (!history->paintSendAction(p, nameleft, texttop, namewidth, fullWidth, color, ms)) {
p.setPen(color); // Empty history
p.drawText(nameleft, texttop + st::msgNameFont->ascent, lang(lng_empty_history));
} }
} else if (!item->isEmpty()) { } else if (!item->isEmpty()) {
paintRowDate(p, date, rectForName, active, selected); paintRowDate(p, date, rectForName, active, selected);
@ -299,6 +305,22 @@ void RowPainter::paint(Painter &p, const Row *row, int fullWidth, bool active, b
if (!history->paintSendAction(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) { if (!history->paintSendAction(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) {
item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache); item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache);
} }
}, [&p, fullWidth, active, selected, ms, history, unreadCount] {
if (unreadCount) {
auto counter = QString::number(unreadCount);
if (counter.size() > 4) {
counter = qsl("..") + counter.mid(counter.size() - 3);
}
auto mutedCounter = history->mute();
auto unreadRight = st::dialogsPadding.x() + st::dialogsPhotoSize;
auto unreadTop = st::dialogsPadding.y() + st::dialogsPhotoSize - st::dialogsUnreadHeight;
auto unreadWidth = 0;
UnreadBadgeStyle st;
st.active = active;
st.muted = history->mute();
paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
}
}); });
} }
@ -308,6 +330,7 @@ void RowPainter::paint(Painter &p, const FakeRow *row, int fullWidth, bool activ
paintRow(p, row, history, item, nullptr, item->date, fullWidth, active, selected, onlyBackground, ms, [&p, row, active, selected](int nameleft, int namewidth, HistoryItem *item) { paintRow(p, row, history, item, nullptr, item->date, fullWidth, active, selected, onlyBackground, ms, [&p, row, active, selected](int nameleft, int namewidth, HistoryItem *item) {
int lastWidth = namewidth, texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; int lastWidth = namewidth, texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height), active, selected, row->_cacheFor, row->_cache); item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height), active, selected, row->_cacheFor, row->_cache);
}, [] {
}); });
} }

View file

@ -608,7 +608,8 @@ void DialogsInner::setSearchedPressed(int pressed) {
void DialogsInner::resizeEvent(QResizeEvent *e) { void DialogsInner::resizeEvent(QResizeEvent *e) {
_addContactLnk->move((width() - _addContactLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2); _addContactLnk->move((width() - _addContactLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2);
_cancelSearchInPeer->moveToRight(st::dialogsFilterSkip + st::dialogsFilterPadding.x() - otherWidth(), (st::dialogsRowHeight - st::dialogsCancelSearchInPeer.height) / 2); auto widthForCancelButton = qMax(width() + otherWidth(), st::dialogsWidthMin);
_cancelSearchInPeer->moveToLeft(widthForCancelButton - st::dialogsFilterSkip - st::dialogsFilterPadding.x() - _cancelSearchInPeer->width(), (st::dialogsRowHeight - st::dialogsCancelSearchInPeer.height) / 2);
} }
void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) { void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) {
@ -1349,6 +1350,7 @@ void DialogsInner::refresh(bool toTop) {
emit mustScrollTo(0, 0); emit mustScrollTo(0, 0);
loadPeerPhotos(0); loadPeerPhotos(0);
} }
Global::RefDialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true);
update(); update();
} }
@ -1396,6 +1398,7 @@ void DialogsInner::searchInPeer(PeerData *peer) {
} else { } else {
_cancelSearchInPeer->hide(); _cancelSearchInPeer->hide();
} }
Global::RefDialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true);
} }
void DialogsInner::clearFilter() { void DialogsInner::clearFilter() {
@ -1889,6 +1892,52 @@ MsgId DialogsInner::lastSearchMigratedId() const {
return _lastSearchMigratedId; return _lastSearchMigratedId;
} }
class DialogsWidget::UpdateButton : public Ui::RippleButton {
public:
UpdateButton(QWidget *parent);
protected:
void paintEvent(QPaintEvent *e) override;
void onStateChanged(State was, StateChangeSource source) override;
private:
QString _text;
const style::FlatButton &_st;
};
DialogsWidget::UpdateButton::UpdateButton(QWidget *parent) : RippleButton(parent, st::dialogsUpdateButton.ripple)
, _text(lang(lng_update_telegram).toUpper())
, _st(st::dialogsUpdateButton) {
resize(st::dialogsWidthMin, _st.height);
}
void DialogsWidget::UpdateButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(was, source);
update();
}
void DialogsWidget::UpdateButton::paintEvent(QPaintEvent *e) {
QPainter p(this);
QRect r(0, height() - _st.height, width(), _st.height);
p.fillRect(r, isOver() ? _st.overBgColor : _st.bgColor);
paintRipple(p, 0, 0, getms());
p.setFont(isOver() ? _st.overFont : _st.font);
p.setRenderHint(QPainter::TextAntialiasing);
p.setPen(isOver() ? _st.overColor : _st.color);
if (width() >= st::dialogsWidthMin) {
r.setTop(_st.textTop);
p.drawText(r, _text, style::al_top);
} else {
(isOver() ? st::dialogsInstallUpdateOver : st::dialogsInstallUpdate).paintInCenter(p, r);
}
}
DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent) DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent)
, _mainMenuToggle(this, st::dialogsMenuToggle) , _mainMenuToggle(this, st::dialogsMenuToggle)
, _filter(this, st::dialogsFilter, lang(lng_dlg_filter)) , _filter(this, st::dialogsFilter, lang(lng_dlg_filter))
@ -1952,7 +2001,7 @@ DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent)
void DialogsWidget::onCheckUpdateStatus() { void DialogsWidget::onCheckUpdateStatus() {
if (Sandbox::updatingState() == Application::UpdatingReady) { if (Sandbox::updatingState() == Application::UpdatingReady) {
if (_updateTelegram) return; if (_updateTelegram) return;
_updateTelegram.create(this, lang(lng_update_telegram).toUpper(), st::dialogsUpdateButton); _updateTelegram.create(this);
_updateTelegram->show(); _updateTelegram->show();
_updateTelegram->setClickedCallback([] { _updateTelegram->setClickedCallback([] {
checkReadyUpdate(); checkReadyUpdate();
@ -1997,6 +2046,30 @@ void DialogsWidget::dialogsToUp() {
} }
} }
void DialogsWidget::startWidthAnimation() {
if (!_widthAnimationCache.isNull()) {
return;
}
auto scrollGeometry = _scroll->geometry();
auto grabGeometry = QRect(scrollGeometry.x(), scrollGeometry.y(), st::dialogsWidthMin, scrollGeometry.height());
_scroll->setGeometry(grabGeometry);
myEnsureResized(_scroll);
_widthAnimationCache = QPixmap(grabGeometry.size() * cIntRetinaFactor());
_widthAnimationCache.setDevicePixelRatio(cRetinaFactor());
_widthAnimationCache.fill(Qt::transparent);
_scroll->render(&_widthAnimationCache, QPoint(0, 0), QRect(QPoint(0, 0), grabGeometry.size()), QWidget::DrawChildren | QWidget::IgnoreMask);
_scroll->setGeometry(scrollGeometry);
_scroll->hide();
}
void DialogsWidget::stopWidthAnimation() {
_widthAnimationCache = QPixmap();
if (!_a_show.animating()) {
_scroll->show();
}
update();
}
void DialogsWidget::showFast() { void DialogsWidget::showFast() {
show(); show();
updateForwardBar(); updateForwardBar();
@ -2621,12 +2694,12 @@ void DialogsWidget::updateControlsGeometry() {
} }
auto filterLeft = st::dialogsFilterPadding.x() + _mainMenuToggle->width() + st::dialogsFilterPadding.x(); auto filterLeft = st::dialogsFilterPadding.x() + _mainMenuToggle->width() + st::dialogsFilterPadding.x();
auto filterRight = (Global::LocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x(); auto filterRight = (Global::LocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x();
auto filterWidth = width() - filterLeft - filterRight; auto filterWidth = qMax(width(), st::dialogsWidthMin) - filterLeft - filterRight;
auto filterAreaHeight = st::dialogsFilterPadding.y() + _mainMenuToggle->height() + st::dialogsFilterPadding.y(); auto filterAreaHeight = st::dialogsFilterPadding.y() + _mainMenuToggle->height() + st::dialogsFilterPadding.y();
auto filterTop = filterAreaTop + (filterAreaHeight - _filter->height()) / 2; auto filterTop = filterAreaTop + (filterAreaHeight - _filter->height()) / 2;
_filter->setGeometryToLeft(filterLeft, filterTop, filterWidth, _filter->height()); _filter->setGeometryToLeft(filterLeft, filterTop, filterWidth, _filter->height());
_mainMenuToggle->moveToLeft(st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y()); _mainMenuToggle->moveToLeft(st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y());
_lockUnlock->moveToRight(st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y()); _lockUnlock->moveToLeft(filterLeft + filterWidth + st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y());
_cancelSearch->moveToLeft(filterLeft + filterWidth - _cancelSearch->width(), _filter->y()); _cancelSearch->moveToLeft(filterLeft + filterWidth - _cancelSearch->width(), _filter->y());
auto scrollTop = filterAreaTop + filterAreaHeight; auto scrollTop = filterAreaTop + filterAreaHeight;
@ -2728,11 +2801,18 @@ void DialogsWidget::paintEvent(QPaintEvent *e) {
p.drawTextLeft(st::dialogsForwardTextLeft, st::dialogsForwardTextTop, width(), lang(lng_forward_choose)); p.drawTextLeft(st::dialogsForwardTextLeft, st::dialogsForwardTextTop, width(), lang(lng_forward_choose));
aboveTop += st::dialogsForwardHeight; aboveTop += st::dialogsForwardHeight;
} }
auto above = QRect(0, aboveTop, width(), _scroll->y()); auto above = QRect(0, aboveTop, width(), _scroll->y() - aboveTop);
if (above.intersects(r)) { if (above.intersects(r)) {
p.fillRect(above.intersected(r), st::dialogsBg); p.fillRect(above.intersected(r), st::dialogsBg);
} }
auto below = QRect(0, _scroll->y() + qMin(_scroll->height(), _inner->height()), width(), height());
auto belowTop = _scroll->y() + qMin(_scroll->height(), _inner->height());
if (!_widthAnimationCache.isNull()) {
p.drawPixmapLeft(0, _scroll->y(), width(), _widthAnimationCache);
belowTop = _scroll->y() + (_widthAnimationCache.height() / cIntRetinaFactor());
}
auto below = QRect(0, belowTop, width(), height() - belowTop);
if (below.intersects(r)) { if (below.intersects(r)) {
p.fillRect(below.intersected(r), st::dialogsBg); p.fillRect(below.intersected(r), st::dialogsBg);
} }

View file

@ -287,6 +287,9 @@ public:
void dialogsToUp(); void dialogsToUp();
void startWidthAnimation();
void stopWidthAnimation();
bool hasTopBarShadow() const { bool hasTopBarShadow() const {
return true; return true;
} }
@ -389,7 +392,8 @@ private:
object_ptr<Ui::IconButton> _lockUnlock; object_ptr<Ui::IconButton> _lockUnlock;
object_ptr<Ui::ScrollArea> _scroll; object_ptr<Ui::ScrollArea> _scroll;
QPointer<DialogsInner> _inner; QPointer<DialogsInner> _inner;
object_ptr<Ui::FlatButton> _updateTelegram = { nullptr }; class UpdateButton;
object_ptr<UpdateButton> _updateTelegram = { nullptr };
Animation _a_show; Animation _a_show;
Window::SlideDirection _showDirection; Window::SlideDirection _showDirection;
@ -421,4 +425,6 @@ private:
using PeerSearchQueries = QMap<mtpRequestId, QString>; using PeerSearchQueries = QMap<mtpRequestId, QString>;
PeerSearchQueries _peerSearchQueries; PeerSearchQueries _peerSearchQueries;
QPixmap _widthAnimationCache;
}; };

View file

@ -620,7 +620,8 @@ struct Data {
SingleDelayedCall HandleDelayedPeerUpdates = { App::app(), "call_handleDelayedPeerUpdates" }; SingleDelayedCall HandleDelayedPeerUpdates = { App::app(), "call_handleDelayedPeerUpdates" };
SingleDelayedCall HandleObservables = { App::app(), "call_handleObservables" }; SingleDelayedCall HandleObservables = { App::app(), "call_handleObservables" };
Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout; Adaptive::WindowLayout AdaptiveWindowLayout = Adaptive::WindowLayout::Normal;
Adaptive::ChatLayout AdaptiveChatLayout = Adaptive::ChatLayout::Normal;
bool AdaptiveForWide = true; bool AdaptiveForWide = true;
base::Observable<void> AdaptiveChanged; base::Observable<void> AdaptiveChanged;
@ -708,6 +709,10 @@ struct Data {
base::Observable<void> UnreadCounterUpdate; base::Observable<void> UnreadCounterUpdate;
base::Observable<void> PeerChooseCancel; base::Observable<void> PeerChooseCancel;
float64 DialogsWidthRatio = 5. / 14;
base::Variable<bool> DialogsListFocused = { false };
base::Variable<bool> DialogsListDisplayForced = { false };
}; };
} // namespace internal } // namespace internal
@ -739,7 +744,8 @@ DefineRefVar(Global, SingleDelayedCall, HandleFileDialogQueue);
DefineRefVar(Global, SingleDelayedCall, HandleDelayedPeerUpdates); DefineRefVar(Global, SingleDelayedCall, HandleDelayedPeerUpdates);
DefineRefVar(Global, SingleDelayedCall, HandleObservables); DefineRefVar(Global, SingleDelayedCall, HandleObservables);
DefineVar(Global, Adaptive::Layout, AdaptiveLayout); DefineVar(Global, Adaptive::WindowLayout, AdaptiveWindowLayout);
DefineVar(Global, Adaptive::ChatLayout, AdaptiveChatLayout);
DefineVar(Global, bool, AdaptiveForWide); DefineVar(Global, bool, AdaptiveForWide);
DefineRefVar(Global, base::Observable<void>, AdaptiveChanged); DefineRefVar(Global, base::Observable<void>, AdaptiveChanged);
@ -827,4 +833,8 @@ DefineRefVar(Global, base::Observable<HistoryItem*>, ItemRemoved);
DefineRefVar(Global, base::Observable<void>, UnreadCounterUpdate); DefineRefVar(Global, base::Observable<void>, UnreadCounterUpdate);
DefineRefVar(Global, base::Observable<void>, PeerChooseCancel); DefineRefVar(Global, base::Observable<void>, PeerChooseCancel);
DefineVar(Global, float64, DialogsWidthRatio);
DefineRefVar(Global, base::Variable<bool>, DialogsListFocused);
DefineRefVar(Global, base::Variable<bool>, DialogsListDisplayForced);
} // namespace Global } // namespace Global

View file

@ -241,11 +241,18 @@ DeclareVar(ProxyData, PreLaunchProxy);
} // namespace Sandbox } // namespace Sandbox
namespace Adaptive { namespace Adaptive {
enum Layout {
OneColumnLayout, enum class WindowLayout {
NormalLayout, OneColumn,
WideLayout, SmallColumn,
Normal,
}; };
enum class ChatLayout {
Normal,
Wide,
};
} // namespace Adaptive } // namespace Adaptive
namespace DebugLogging { namespace DebugLogging {
@ -306,7 +313,8 @@ DeclareRefVar(SingleDelayedCall, HandleFileDialogQueue);
DeclareRefVar(SingleDelayedCall, HandleDelayedPeerUpdates); DeclareRefVar(SingleDelayedCall, HandleDelayedPeerUpdates);
DeclareRefVar(SingleDelayedCall, HandleObservables); DeclareRefVar(SingleDelayedCall, HandleObservables);
DeclareVar(Adaptive::Layout, AdaptiveLayout); DeclareVar(Adaptive::WindowLayout, AdaptiveWindowLayout);
DeclareVar(Adaptive::ChatLayout, AdaptiveChatLayout);
DeclareVar(bool, AdaptiveForWide); DeclareVar(bool, AdaptiveForWide);
DeclareRefVar(base::Observable<void>, AdaptiveChanged); DeclareRefVar(base::Observable<void>, AdaptiveChanged);
@ -399,6 +407,10 @@ DeclareRefVar(base::Observable<HistoryItem*>, ItemRemoved);
DeclareRefVar(base::Observable<void>, UnreadCounterUpdate); DeclareRefVar(base::Observable<void>, UnreadCounterUpdate);
DeclareRefVar(base::Observable<void>, PeerChooseCancel); DeclareRefVar(base::Observable<void>, PeerChooseCancel);
DeclareVar(float64, DialogsWidthRatio);
DeclareRefVar(base::Variable<bool>, DialogsListFocused);
DeclareRefVar(base::Variable<bool>, DialogsListDisplayForced);
} // namespace Global } // namespace Global
namespace Adaptive { namespace Adaptive {
@ -408,13 +420,23 @@ inline base::Observable<void> &Changed() {
} }
inline bool OneColumn() { inline bool OneColumn() {
return Global::AdaptiveLayout() == OneColumnLayout; return Global::AdaptiveWindowLayout() == WindowLayout::OneColumn;
} }
inline bool SmallColumn() {
return Global::AdaptiveWindowLayout() == WindowLayout::SmallColumn;
}
inline bool Normal() { inline bool Normal() {
return Global::AdaptiveLayout() == NormalLayout; return Global::AdaptiveWindowLayout() == WindowLayout::Normal;
} }
inline bool Wide() {
return Global::AdaptiveForWide() && (Global::AdaptiveLayout() == WideLayout); inline bool ChatNormal() {
return !Global::AdaptiveForWide() || (Global::AdaptiveChatLayout() == ChatLayout::Normal);
}
inline bool ChatWide() {
return !ChatNormal();
} }
} // namespace Adaptive } // namespace Adaptive

View file

@ -92,7 +92,7 @@ void History::clearLastKeyboard() {
} }
bool History::canHaveFromPhotos() const { bool History::canHaveFromPhotos() const {
if (peer->isUser() && !Adaptive::Wide()) { if (peer->isUser() && !Adaptive::ChatWide()) {
return false; return false;
} else if (isChannel() && !peer->isMegagroup()) { } else if (isChannel() && !peer->isMegagroup()) {
return false; return false;

View file

@ -39,6 +39,8 @@ historyScroll: ScrollArea(defaultScrollArea) {
bottomsh: -1px; bottomsh: -1px;
} }
historyResizeWidth: 6px;
historyPaddingBottom: 8px; historyPaddingBottom: 8px;
historyToDownPosition: point(12px, 10px); historyToDownPosition: point(12px, 10px);

View file

@ -517,7 +517,7 @@ void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const {
int left = st::msgServiceMargin.left(); int left = st::msgServiceMargin.left();
int maxwidth = w; int maxwidth = w;
if (Adaptive::Wide()) { if (Adaptive::ChatWide()) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
} }
w = maxwidth; w = maxwidth;

View file

@ -814,7 +814,7 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
maxwidth = qMax(_media->currentWidth(), qMin(maxwidth, plainMaxWidth())); maxwidth = qMax(_media->currentWidth(), qMin(maxwidth, plainMaxWidth()));
} }
left = (!isPost() && out() && !Adaptive::Wide()) ? st::msgMargin.right() : st::msgMargin.left(); left = (!isPost() && out() && !Adaptive::ChatWide()) ? st::msgMargin.right() : st::msgMargin.left();
if (hasFromPhoto()) { if (hasFromPhoto()) {
left += st::msgPhotoSkip; left += st::msgPhotoSkip;
// } else if (!Adaptive::Wide() && !out() && !fromChannel() && st::msgPhotoSkip - (hmaxwidth - hwidth) > 0) { // } else if (!Adaptive::Wide() && !out() && !fromChannel() && st::msgPhotoSkip - (hmaxwidth - hwidth) > 0) {
@ -823,7 +823,7 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
width = hwidth - st::msgMargin.left() - st::msgMargin.right(); width = hwidth - st::msgMargin.left() - st::msgMargin.right();
if (width > maxwidth) { if (width > maxwidth) {
if (!isPost() && out() && !Adaptive::Wide()) { if (!isPost() && out() && !Adaptive::ChatWide()) {
left += width - maxwidth; left += width - maxwidth;
} }
width = maxwidth; width = maxwidth;
@ -1291,7 +1291,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, T
auto r = QRect(left, top, width, height - top - marginBottom()); auto r = QRect(left, top, width, height - top - marginBottom());
auto skipTail = isAttachedToNext() || (_media && _media->skipBubbleTail()); auto skipTail = isAttachedToNext() || (_media && _media->skipBubbleTail());
auto displayTail = skipTail ? HistoryLayout::BubbleTail::None : (outbg && !Adaptive::Wide()) ? HistoryLayout::BubbleTail::Right : HistoryLayout::BubbleTail::Left; auto displayTail = skipTail ? HistoryLayout::BubbleTail::None : (outbg && !Adaptive::ChatWide()) ? HistoryLayout::BubbleTail::Right : HistoryLayout::BubbleTail::Left;
HistoryLayout::paintBubble(p, r, _history->width, selected, outbg, displayTail); HistoryLayout::paintBubble(p, r, _history->width, selected, outbg, displayTail);
QRect trect(r.marginsAdded(-st::msgPadding)); QRect trect(r.marginsAdded(-st::msgPadding));
@ -1739,7 +1739,7 @@ bool HistoryMessage::displayFromPhoto() const {
} }
bool HistoryMessage::hasFromPhoto() const { bool HistoryMessage::hasFromPhoto() const {
return (Adaptive::Wide() || (!out() && !history()->peer->isUser())) && !isPost() && !isEmpty(); return (Adaptive::ChatWide() || (!out() && !history()->peer->isUser())) && !isPost() && !isEmpty();
} }
HistoryMessage::~HistoryMessage() { HistoryMessage::~HistoryMessage() {
@ -2089,7 +2089,7 @@ bool HistoryService::updateDependencyItem() {
void HistoryService::countPositionAndSize(int32 &left, int32 &width) const { void HistoryService::countPositionAndSize(int32 &left, int32 &width) const {
left = st::msgServiceMargin.left(); left = st::msgServiceMargin.left();
int32 maxwidth = _history->width; int32 maxwidth = _history->width;
if (Adaptive::Wide()) { if (Adaptive::ChatWide()) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
} }
width = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left(); width = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left();
@ -2161,7 +2161,7 @@ int32 HistoryService::resizeGetHeight_(int32 width) {
_textHeight = 0; _textHeight = 0;
} else { } else {
int32 maxwidth = _history->width; int32 maxwidth = _history->width;
if (Adaptive::Wide()) { if (Adaptive::ChatWide()) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
} }
if (width > maxwidth) width = maxwidth; if (width > maxwidth) width = maxwidth;

View file

@ -167,7 +167,7 @@ void paintBubblePart(Painter &p, int x, int y, int width, int height, SideStyle
void paintPreparedDate(Painter &p, const QString &dateText, int dateTextWidth, int y, int w) { void paintPreparedDate(Painter &p, const QString &dateText, int dateTextWidth, int y, int w) {
int left = st::msgServiceMargin.left(); int left = st::msgServiceMargin.left();
int maxwidth = w; int maxwidth = w;
if (Adaptive::Wide()) { if (Adaptive::ChatWide()) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
} }
w = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left(); w = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left();

View file

@ -1630,7 +1630,7 @@ void HistoryInner::recountHeight() {
int32 descH = st::msgMargin.top() + st::msgPadding.top() + st::msgNameFont->height + st::botDescSkip + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom(); int32 descH = st::msgMargin.top() + st::msgPadding.top() + st::msgNameFont->height + st::botDescSkip + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom();
int32 descMaxWidth = _scroll->width(); int32 descMaxWidth = _scroll->width();
if (Adaptive::Wide()) { if (Adaptive::ChatWide()) {
descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
} }
int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left(); int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left();
@ -1796,7 +1796,7 @@ void HistoryInner::updateSize() {
if (_botAbout && _botAbout->height > 0) { if (_botAbout && _botAbout->height > 0) {
int32 descH = st::msgMargin.top() + st::msgPadding.top() + st::msgNameFont->height + st::botDescSkip + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom(); int32 descH = st::msgMargin.top() + st::msgPadding.top() + st::msgNameFont->height + st::botDescSkip + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom();
int32 descMaxWidth = _scroll->width(); int32 descMaxWidth = _scroll->width();
if (Adaptive::Wide()) { if (Adaptive::ChatWide()) {
descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
} }
int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left(); int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left();
@ -7071,6 +7071,11 @@ void HistoryWidget::notify_handlePendingHistoryUpdate() {
} }
void HistoryWidget::resizeEvent(QResizeEvent *e) { void HistoryWidget::resizeEvent(QResizeEvent *e) {
auto layout = (width() < st::adaptiveChatWideWidth) ? Adaptive::ChatLayout::Normal : Adaptive::ChatLayout::Wide;
if (layout != Global::AdaptiveChatLayout()) {
Global::SetAdaptiveChatLayout(layout);
Adaptive::Changed().notify(true);
}
updateControlsGeometry(); updateControlsGeometry();
} }

View file

@ -119,6 +119,7 @@ void Widget::changeLanguage(int32 languageId) {
} }
void Widget::setInnerFocus() { void Widget::setInnerFocus() {
Global::RefDialogsListFocused().set(false, true);
if (getStep()->animating()) { if (getStep()->animating()) {
setFocus(); setFocus();
} else { } else {

View file

@ -558,6 +558,7 @@ enum {
dbiNotificationsCount = 0x45, dbiNotificationsCount = 0x45,
dbiNotificationsCorner = 0x46, dbiNotificationsCorner = 0x46,
dbiTheme = 0x47, dbiTheme = 0x47,
dbiDialogsWidthRatio = 0x48,
dbiEncryptedWithSalt = 333, dbiEncryptedWithSalt = 333,
dbiEncrypted = 444, dbiEncrypted = 444,
@ -1032,6 +1033,14 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
Global::SetNotificationsCorner(static_cast<Notify::ScreenCorner>((v >= 0 && v < 4) ? v : 2)); Global::SetNotificationsCorner(static_cast<Notify::ScreenCorner>((v >= 0 && v < 4) ? v : 2));
} break; } break;
case dbiDialogsWidthRatio: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
Global::SetDialogsWidthRatio(v / 1000000.);
} break;
case dbiWorkMode: { case dbiWorkMode: {
qint32 v; qint32 v;
stream >> v; stream >> v;
@ -1608,7 +1617,7 @@ void _writeUserSettings() {
_writeMap(WriteMapFast); _writeMap(WriteMapFast);
} }
uint32 size = 20 * (sizeof(quint32) + sizeof(qint32)); uint32 size = 21 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark()); size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort)); size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64)); size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
@ -1644,6 +1653,7 @@ void _writeUserSettings() {
data.stream << quint32(dbiDialogsMode) << qint32(Global::DialogsModeEnabled() ? 1 : 0) << static_cast<qint32>(Global::DialogsMode()); data.stream << quint32(dbiDialogsMode) << qint32(Global::DialogsModeEnabled() ? 1 : 0) << static_cast<qint32>(Global::DialogsMode());
data.stream << quint32(dbiModerateMode) << qint32(Global::ModerateModeEnabled() ? 1 : 0); data.stream << quint32(dbiModerateMode) << qint32(Global::ModerateModeEnabled() ? 1 : 0);
data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0); data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0);
data.stream << quint32(dbiDialogsWidthRatio) << qint32(snap(qRound(Global::DialogsWidthRatio() * 1000000), 0, 1000000));
{ {
RecentEmojisPreload v(cRecentEmojisPreload()); RecentEmojisPreload v(cRecentEmojisPreload());

View file

@ -71,6 +71,7 @@ StackItemSection::~StackItemSection() {
MainWidget::MainWidget(QWidget *parent) : TWidget(parent) MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
, _dialogsWidth(st::dialogsWidthMin) , _dialogsWidth(st::dialogsWidthMin)
, _sideShadow(this, st::shadowFg) , _sideShadow(this, st::shadowFg)
, _sideResizeArea(this)
, _dialogs(this) , _dialogs(this)
, _history(this) , _history(this)
, _topBar(this) , _topBar(this)
@ -107,12 +108,23 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
}); });
} }
subscribe(Global::RefDialogsListFocused(), [this](bool) {
updateDialogsWidthAnimated();
});
subscribe(Global::RefDialogsListDisplayForced(), [this](bool) {
updateDialogsWidthAnimated();
});
Sandbox::installEventFilter(this);
connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted())); connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted()));
connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement())); connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement()));
_webPageOrGameUpdater.setSingleShot(true); _webPageOrGameUpdater.setSingleShot(true);
connect(&_webPageOrGameUpdater, SIGNAL(timeout()), this, SLOT(webPagesOrGamesUpdate())); connect(&_webPageOrGameUpdater, SIGNAL(timeout()), this, SLOT(webPagesOrGamesUpdate()));
_sideResizeArea->setCursor(style::cur_sizehor);
using Update = Window::Theme::BackgroundUpdate; using Update = Window::Theme::BackgroundUpdate;
subscribe(Window::Theme::Background(), [this](const Update &update) { subscribe(Window::Theme::Background(), [this](const Update &update) {
if (update.type == Update::Type::New || update.type == Update::Type::Changed) { if (update.type == Update::Type::New || update.type == Update::Type::Changed) {
@ -146,7 +158,7 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
}); });
} }
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); }); subscribe(Adaptive::Changed(), [this]() { handleAdaptiveLayoutUpdate(); });
auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged; auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
@ -168,9 +180,7 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
_mediaType->hide(); _mediaType->hide();
_mediaType->setOrigin(Ui::PanelAnimation::Origin::TopRight); _mediaType->setOrigin(Ui::PanelAnimation::Origin::TopRight);
_topBar->mediaTypeButton()->installEventFilter(_mediaType); _topBar->mediaTypeButton()->installEventFilter(_mediaType);
_sideResizeArea->installEventFilter(this);
show();
setFocus();
_api->init(); _api->init();
@ -601,14 +611,14 @@ void MainWidget::noHider(HistoryHider *destroyed) {
} }
onHistoryShown(_history->history(), _history->msgId()); onHistoryShown(_history->history(), _history->msgId());
if (_wideSection || _overview || (_history->peer() && _history->peer()->id)) { if (_wideSection || _overview || (_history->peer() && _history->peer()->id)) {
Window::SectionSlideParams animationParams; auto animationParams = ([this] {
if (_overview) { if (_overview) {
animationParams = prepareOverviewAnimation(); return prepareOverviewAnimation();
} else if (_wideSection) { } else if (_wideSection) {
animationParams = prepareWideSectionAnimation(_wideSection); return prepareWideSectionAnimation(_wideSection);
} else { }
animationParams = prepareHistoryAnimation(_history->peer() ? _history->peer()->id : 0); return prepareHistoryAnimation(_history->peer() ? _history->peer()->id : 0);
} })();
_dialogs->hide(); _dialogs->hide();
if (_overview) { if (_overview) {
_overview->showAnimated(Window::SlideDirection::FromRight, animationParams); _overview->showAnimated(Window::SlideDirection::FromRight, animationParams);
@ -2176,7 +2186,7 @@ void MainWidget::ctrlEnterSubmitUpdated() {
} }
void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::ShowWay way) { void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::ShowWay way) {
if (PeerData *peer = App::peerLoaded(peerId)) { if (auto peer = App::peerLoaded(peerId)) {
if (peer->migrateTo()) { if (peer->migrateTo()) {
peer = peer->migrateTo(); peer = peer->migrateTo();
peerId = peer->id; peerId = peer->id;
@ -2190,6 +2200,9 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
} }
} }
Global::RefDialogsListFocused().set(false, true);
_a_dialogsWidth.finish();
bool back = (way == Ui::ShowWay::Backward || !peerId); bool back = (way == Ui::ShowWay::Backward || !peerId);
bool foundInStack = !peerId; bool foundInStack = !peerId;
if (foundInStack || (way == Ui::ShowWay::ClearStack)) { if (foundInStack || (way == Ui::ShowWay::ClearStack)) {
@ -2228,7 +2241,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
} }
dlgUpdated(); dlgUpdated();
PeerData *wasActivePeer = activePeer(); auto wasActivePeer = activePeer();
Ui::hideSettingsAndLayer(); Ui::hideSettingsAndLayer();
if (_hider) { if (_hider) {
@ -2236,16 +2249,34 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
_hider = nullptr; _hider = nullptr;
} }
Window::SectionSlideParams animationParams; auto animatedShow = [this, peerId, back, way] {
if (!_a_show.animating() && !App::passcoded() && ((_history->isHidden() && (_wideSection || _overview)) || (Adaptive::OneColumn() && (_history->isHidden() || !peerId)) || back || (way == Ui::ShowWay::Forward))) { if (_a_show.animating() || App::passcoded()) {
animationParams = prepareHistoryAnimation(peerId); return false;
} }
if (!peerId) {
if (Adaptive::OneColumn()) {
return true;
} else {
return false;
}
}
if (back || way == Ui::ShowWay::Forward) {
return true;
}
if (_history->isHidden() && (_wideSection || _overview || Adaptive::OneColumn())) {
return true;
}
return false;
};
auto animationParams = animatedShow() ? prepareHistoryAnimation(peerId) : Window::SectionSlideParams();
if (_history->peer() && _history->peer()->id != peerId && way != Ui::ShowWay::Forward) { if (_history->peer() && _history->peer()->id != peerId && way != Ui::ShowWay::Forward) {
clearBotStartToken(_history->peer()); clearBotStartToken(_history->peer());
} }
_history->showHistory(peerId, showAtMsgId); _history->showHistory(peerId, showAtMsgId);
bool noPeer = (!_history->peer() || !_history->peer()->id), onlyDialogs = noPeer && Adaptive::OneColumn(); auto noPeer = !_history->peer();
auto onlyDialogs = noPeer && Adaptive::OneColumn();
if (_wideSection || _overview) { if (_wideSection || _overview) {
if (_wideSection) { if (_wideSection) {
_wideSection->hide(); _wideSection->hide();
@ -2264,8 +2295,9 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
_topBar->hide(); _topBar->hide();
_history->hide(); _history->hide();
if (!_a_show.animating()) { if (!_a_show.animating()) {
if (!animationParams.oldContentCache.isNull()) { if (animationParams) {
_dialogs->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams); auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight;
_dialogs->showAnimated(direction, animationParams);
} else { } else {
_dialogs->showFast(); _dialogs->showFast();
} }
@ -2385,10 +2417,19 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
return; return;
} }
Window::SectionSlideParams animationParams; Global::RefDialogsListFocused().set(false, true);
if (!_a_show.animating() && (Adaptive::OneColumn() || _wideSection || _overview || _history->peer())) { _a_dialogsWidth.finish();
animationParams = prepareOverviewAnimation();
} auto animatedShow = [this] {
if (_a_show.animating() || App::passcoded()) {
return false;
}
if (Adaptive::OneColumn() || isSectionShown()) {
return true;
}
return false;
};
auto animationParams = animatedShow() ? prepareOverviewAnimation() : Window::SectionSlideParams();
if (!back) { if (!back) {
saveSectionInStack(); saveSectionInStack();
} }
@ -2436,7 +2477,7 @@ void MainWidget::showWideSection(const Window::SectionMemento &memento) {
if (_wideSection && _wideSection->showInternal(&memento)) { if (_wideSection && _wideSection->showInternal(&memento)) {
return; return;
} }
showWideSectionAnimated(&memento, false, true); showNewWideSection(&memento, false, true);
} }
Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarShadow) { Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarShadow) {
@ -2523,12 +2564,24 @@ Window::SectionSlideParams MainWidget::prepareDialogsAnimation() {
return prepareShowAnimation(false); return prepareShowAnimation(false);
} }
void MainWidget::showWideSectionAnimated(const Window::SectionMemento *memento, bool back, bool saveInStack) { void MainWidget::showNewWideSection(const Window::SectionMemento *memento, bool back, bool saveInStack) {
QPixmap animCache; QPixmap animCache;
Global::RefDialogsListFocused().set(false, true);
_a_dialogsWidth.finish();
auto newWideGeometry = QRect(_history->x(), _playerHeight, _history->width(), height() - _playerHeight); auto newWideGeometry = QRect(_history->x(), _playerHeight, _history->width(), height() - _playerHeight);
auto newWideSection = memento->createWidget(this, newWideGeometry); auto newWideSection = memento->createWidget(this, newWideGeometry);
Window::SectionSlideParams animationParams = prepareWideSectionAnimation(newWideSection); auto animatedShow = [this] {
if (_a_show.animating() || App::passcoded()) {
return false;
}
if (Adaptive::OneColumn() || isSectionShown()) {
return true;
}
return false;
};
auto animationParams = animatedShow() ? prepareWideSectionAnimation(newWideSection) : Window::SectionSlideParams();
if (saveInStack) { if (saveInStack) {
saveSectionInStack(); saveSectionInStack();
@ -2553,12 +2606,20 @@ void MainWidget::showWideSectionAnimated(const Window::SectionMemento *memento,
_history->hide(); _history->hide();
if (Adaptive::OneColumn()) _dialogs->hide(); if (Adaptive::OneColumn()) _dialogs->hide();
auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight; if (animationParams) {
_wideSection->showAnimated(direction, animationParams); auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight;
_wideSection->showAnimated(direction, animationParams);
} else {
_wideSection->showFast();
}
orderWidgets(); orderWidgets();
} }
bool MainWidget::isSectionShown() const {
return _wideSection || _overview || _history->peer();
}
bool MainWidget::stackIsEmpty() const { bool MainWidget::stackIsEmpty() const {
return _stack.isEmpty(); return _stack.isEmpty();
} }
@ -2579,23 +2640,24 @@ void MainWidget::showBackFromStack() {
dlgUpdated(); dlgUpdated();
_peerInStack = nullptr; _peerInStack = nullptr;
_msgIdInStack = 0; _msgIdInStack = 0;
for (int32 i = _stack.size(); i > 0;) { for (auto i = _stack.size(); i > 0;) {
if (_stack.at(--i)->type() == HistoryStackItem) { if (_stack[--i]->type() == HistoryStackItem) {
_peerInStack = static_cast<StackItemHistory*>(_stack.at(i).get())->peer; auto historyItem = static_cast<StackItemHistory*>(_stack[i].get());
_msgIdInStack = static_cast<StackItemHistory*>(_stack.at(i).get())->msgId; _peerInStack = historyItem->peer;
_msgIdInStack = historyItem->msgId;
dlgUpdated(); dlgUpdated();
break; break;
} }
} }
StackItemHistory *histItem = static_cast<StackItemHistory*>(item.get()); auto historyItem = static_cast<StackItemHistory*>(item.get());
Ui::showPeerHistory(histItem->peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Backward); Ui::showPeerHistory(historyItem->peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Backward);
_history->setReplyReturns(histItem->peer->id, histItem->replyReturns); _history->setReplyReturns(historyItem->peer->id, historyItem->replyReturns);
} else if (item->type() == SectionStackItem) { } else if (item->type() == SectionStackItem) {
StackItemSection *sectionItem = static_cast<StackItemSection*>(item.get()); auto sectionItem = static_cast<StackItemSection*>(item.get());
showWideSectionAnimated(sectionItem->memento(), true, false); showNewWideSection(sectionItem->memento(), true, false);
} else if (item->type() == OverviewStackItem) { } else if (item->type() == OverviewStackItem) {
StackItemOverview *overItem = static_cast<StackItemOverview*>(item.get()); auto overviewItem = static_cast<StackItemOverview*>(item.get());
showMediaOverview(overItem->peer, overItem->mediaType, true, overItem->lastScrollTop); showMediaOverview(overviewItem->peer, overviewItem->mediaType, true, overviewItem->lastScrollTop);
} }
} }
@ -2610,6 +2672,7 @@ void MainWidget::orderWidgets() {
} }
_mediaType->raise(); _mediaType->raise();
_sideShadow->raise(); _sideShadow->raise();
_sideResizeArea->raise();
_playerPlaylist->raise(); _playerPlaylist->raise();
_playerPanel->raise(); _playerPanel->raise();
if (_hider) _hider->raise(); if (_hider) _hider->raise();
@ -2837,7 +2900,7 @@ void MainWidget::showAll() {
if (_wideSection) { if (_wideSection) {
_topBar->hide(); _topBar->hide();
_dialogs->hide(); _dialogs->hide();
} else if (_overview || _history->peer()) { } else if (isSectionShown()) {
_topBar->show(); _topBar->show();
_dialogs->hide(); _dialogs->hide();
} }
@ -2865,7 +2928,7 @@ void MainWidget::showAll() {
} }
if (_wideSection) { if (_wideSection) {
_topBar->hide(); _topBar->hide();
} else if (_overview || _history->peer()) { } else if (isSectionShown()) {
_topBar->show(); _topBar->show();
} }
} }
@ -2878,46 +2941,56 @@ void MainWidget::showAll() {
App::wnd()->checkHistoryActivation(); App::wnd()->checkHistoryActivation();
} }
namespace {
inline int chatsListWidth(int windowWidth) {
return snap<int>((windowWidth * 5) / 14, st::dialogsWidthMin, st::dialogsWidthMax);
}
} // namespace
void MainWidget::resizeEvent(QResizeEvent *e) { void MainWidget::resizeEvent(QResizeEvent *e) {
updateControlsGeometry(); updateControlsGeometry();
} }
void MainWidget::updateControlsGeometry() { void MainWidget::updateControlsGeometry() {
auto tbh = _topBar->isHidden() ? 0 : st::topBarHeight; updateWindowAdaptiveLayout();
auto topBarHeight = _topBar->isHidden() ? 0 : st::topBarHeight;
if (!Adaptive::SmallColumn()) {
_a_dialogsWidth.finish();
}
if (!_a_dialogsWidth.animating()) {
_dialogs->stopWidthAnimation();
}
auto dialogsWidth = qRound(_a_dialogsWidth.current(_dialogsWidth));
if (Adaptive::OneColumn()) { if (Adaptive::OneColumn()) {
_dialogsWidth = width();
if (_player) { if (_player) {
_player->resizeToWidth(_dialogsWidth); _player->resizeToWidth(dialogsWidth);
_player->moveToLeft(0, 0); _player->moveToLeft(0, 0);
} }
_dialogs->setGeometry(0, _playerHeight, _dialogsWidth, height() - _playerHeight); _dialogs->setGeometry(0, _playerHeight, dialogsWidth, height() - _playerHeight);
_topBar->setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight); _topBar->setGeometry(0, _playerHeight, dialogsWidth, st::topBarHeight);
_history->setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh); _history->setGeometry(0, _playerHeight + topBarHeight, dialogsWidth, height() - _playerHeight - topBarHeight);
if (_hider) _hider->setGeometry(0, 0, _dialogsWidth, height()); if (_hider) _hider->setGeometry(0, 0, dialogsWidth, height());
} else { } else {
_dialogsWidth = chatsListWidth(width()); accumulate_min(dialogsWidth, width() - st::windowMinWidth);
auto sectionWidth = width() - _dialogsWidth; auto sectionWidth = width() - dialogsWidth;
_dialogs->setGeometryToLeft(0, 0, _dialogsWidth, height()); _dialogs->setGeometryToLeft(0, 0, dialogsWidth, height());
_sideShadow->setGeometryToLeft(_dialogsWidth, 0, st::lineWidth, height()); _sideShadow->setGeometryToLeft(dialogsWidth, 0, st::lineWidth, height());
if (_player) { if (_player) {
_player->resizeToWidth(sectionWidth); _player->resizeToWidth(sectionWidth);
_player->moveToLeft(_dialogsWidth, 0); _player->moveToLeft(dialogsWidth, 0);
} }
_topBar->setGeometryToLeft(_dialogsWidth, _playerHeight, sectionWidth, st::topBarHeight); _topBar->setGeometryToLeft(dialogsWidth, _playerHeight, sectionWidth, st::topBarHeight);
_history->setGeometryToLeft(_dialogsWidth, _playerHeight + tbh, sectionWidth, height() - _playerHeight - tbh); _history->setGeometryToLeft(dialogsWidth, _playerHeight + topBarHeight, sectionWidth, height() - _playerHeight - topBarHeight);
if (_hider) { if (_hider) {
_hider->setGeometryToLeft(_dialogsWidth, 0, sectionWidth, height()); _hider->setGeometryToLeft(dialogsWidth, 0, sectionWidth, height());
} }
} }
_sideResizeArea->setGeometryToLeft(_history->x(), 0, st::historyResizeWidth, height());
auto isSideResizeAreaVisible = [this] {
if (width() < st::windowMinWidth + st::dialogsWidthMin) {
return false;
}
if (Adaptive::OneColumn() && !isSectionShown()) {
return false;
}
return true;
};
_sideResizeArea->setVisible(isSideResizeAreaVisible());
_mediaType->moveToLeft(width() - _mediaType->width(), _playerHeight + st::topBarHeight); _mediaType->moveToLeft(width() - _mediaType->width(), _playerHeight + st::topBarHeight);
if (_wideSection) { if (_wideSection) {
QRect wideSectionGeometry(_history->x(), _playerHeight, _history->width(), height() - _playerHeight); QRect wideSectionGeometry(_history->x(), _playerHeight, _history->width(), height() - _playerHeight);
@ -2929,6 +3002,19 @@ void MainWidget::updateControlsGeometry() {
_contentScrollAddToY = 0; _contentScrollAddToY = 0;
} }
void MainWidget::updateDialogsWidthAnimated() {
if (!Adaptive::SmallColumn()) {
return;
}
auto dialogsWidth = _dialogsWidth;
updateWindowAdaptiveLayout();
if (Adaptive::SmallColumn() && (_dialogsWidth != dialogsWidth || _a_dialogsWidth.animating())) {
_dialogs->startWidthAnimation();
_a_dialogsWidth.start([this] { updateControlsGeometry(); }, dialogsWidth, _dialogsWidth, st::dialogsWidthDuration, anim::easeOutCirc);
updateControlsGeometry();
}
}
void MainWidget::updateMediaPlayerPosition() { void MainWidget::updateMediaPlayerPosition() {
_playerPanel->moveToRight(0, 0); _playerPanel->moveToRight(0, 0);
if (_player && _playerVolume) { if (_player && _playerVolume) {
@ -2960,7 +3046,40 @@ int MainWidget::contentScrollAddToY() const {
void MainWidget::keyPressEvent(QKeyEvent *e) { void MainWidget::keyPressEvent(QKeyEvent *e) {
} }
void MainWidget::updateAdaptiveLayout() { bool MainWidget::eventFilter(QObject *o, QEvent *e) {
if (o == _sideResizeArea) {
auto mouseLeft = [this, e] {
return mapFromGlobal(static_cast<QMouseEvent*>(e)->globalPos()).x();
};
if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton) {
_resizingSide = true;
_resizingSideShift = mouseLeft() - (Adaptive::OneColumn() ? 0 : _dialogsWidth);
} else if (e->type() == QEvent::MouseButtonRelease) {
_resizingSide = false;
if (!Adaptive::OneColumn()) {
Global::SetDialogsWidthRatio(float64(_dialogsWidth) / width());
}
Local::writeUserSettings();
} else if (e->type() == QEvent::MouseMove && _resizingSide) {
auto newWidth = mouseLeft() - _resizingSideShift;
Global::SetDialogsWidthRatio(float64(newWidth) / width());
updateControlsGeometry();
}
} else if (e->type() == QEvent::FocusIn) {
if (auto widget = qobject_cast<QWidget*>(o)) {
if (_history == widget || _history->isAncestorOf(widget)
|| (_overview && (_overview == widget || _overview->isAncestorOf(widget)))
|| (_wideSection && (_wideSection == widget || _wideSection->isAncestorOf(widget)))) {
Global::RefDialogsListFocused().set(false, false);
} else if (_dialogs == widget || _dialogs->isAncestorOf(widget)) {
Global::RefDialogsListFocused().set(true, false);
}
}
}
return TWidget::eventFilter(o, e);
}
void MainWidget::handleAdaptiveLayoutUpdate() {
showAll(); showAll();
_sideShadow->setVisible(!Adaptive::OneColumn()); _sideShadow->setVisible(!Adaptive::OneColumn());
if (_player) { if (_player) {
@ -2968,8 +3087,61 @@ void MainWidget::updateAdaptiveLayout() {
} }
} }
void MainWidget::updateWindowAdaptiveLayout() {
auto layout = Adaptive::WindowLayout::OneColumn;
auto dialogsWidth = qRound(width() * Global::DialogsWidthRatio());
auto historyWidth = width() - dialogsWidth;
accumulate_max(historyWidth, st::windowMinWidth);
dialogsWidth = width() - historyWidth;
auto useOneColumnLayout = [this, dialogsWidth] {
auto someSectionShown = !selectingPeer() && isSectionShown();
if (dialogsWidth < st::dialogsPadding.x() && (Adaptive::OneColumn() || someSectionShown)) {
return true;
}
if (width() < st::windowMinWidth + st::dialogsWidthMin) {
return true;
}
return false;
};
auto useSmallColumnLayout = [this, dialogsWidth] {
// used if useOneColumnLayout() == false.
if (dialogsWidth < st::dialogsWidthMin / 2) {
return true;
}
return false;
};
if (useOneColumnLayout()) {
dialogsWidth = width();
} else if (useSmallColumnLayout()) {
layout = Adaptive::WindowLayout::SmallColumn;
auto forceWideDialogs = [this] {
if (Global::DialogsListDisplayForced().value()) {
return true;
} else if (Global::DialogsListFocused().value()) {
return true;
}
return !isSectionShown();
};
if (forceWideDialogs()) {
dialogsWidth = st::dialogsWidthMin;
} else {
dialogsWidth = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPadding.x();
}
} else {
layout = Adaptive::WindowLayout::Normal;
accumulate_max(dialogsWidth, st::dialogsWidthMin);
}
_dialogsWidth = dialogsWidth;
if (layout != Global::AdaptiveWindowLayout()) {
Global::SetAdaptiveWindowLayout(layout);
Adaptive::Changed().notify(true);
}
}
bool MainWidget::needBackButton() { bool MainWidget::needBackButton() {
return _overview || _wideSection || _history->peer(); return isSectionShown();
} }
bool MainWidget::paintTopBar(Painter &p, int decreaseWidth, TimeMs ms) { bool MainWidget::paintTopBar(Painter &p, int decreaseWidth, TimeMs ms) {

View file

@ -477,14 +477,17 @@ protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override; void keyPressEvent(QKeyEvent *e) override;
bool eventFilter(QObject *o, QEvent *e) override;
private: private:
void animationCallback(); void animationCallback();
void updateAdaptiveLayout(); void handleAdaptiveLayoutUpdate();
void updateWindowAdaptiveLayout();
void handleAudioUpdate(const AudioMsgId &audioId); void handleAudioUpdate(const AudioMsgId &audioId);
void updateMediaPlayerPosition(); void updateMediaPlayerPosition();
void updateMediaPlaylistPosition(int x); void updateMediaPlaylistPosition(int x);
void updateControlsGeometry(); void updateControlsGeometry();
void updateDialogsWidthAnimated();
void updateForwardingTexts(); void updateForwardingTexts();
void updateForwardingItemRemovedSubscription(); void updateForwardingItemRemovedSubscription();
@ -506,7 +509,8 @@ private:
void mediaOverviewUpdated(const Notify::PeerUpdate &update); void mediaOverviewUpdated(const Notify::PeerUpdate &update);
Window::SectionSlideParams prepareShowAnimation(bool willHaveTopBarShadow); Window::SectionSlideParams prepareShowAnimation(bool willHaveTopBarShadow);
void showWideSectionAnimated(const Window::SectionMemento *memento, bool back, bool saveInStack); void showNewWideSection(const Window::SectionMemento *memento, bool back, bool saveInStack);
bool isSectionShown() const;
// All this methods use the prepareShowAnimation(). // All this methods use the prepareShowAnimation().
Window::SectionSlideParams prepareWideSectionAnimation(Window::SectionWidget *section); Window::SectionSlideParams prepareWideSectionAnimation(Window::SectionWidget *section);
@ -586,8 +590,10 @@ private:
QPixmap _cacheUnder, _cacheOver; QPixmap _cacheUnder, _cacheOver;
int _dialogsWidth; int _dialogsWidth;
Animation _a_dialogsWidth;
object_ptr<Ui::PlainShadow> _sideShadow; object_ptr<Ui::PlainShadow> _sideShadow;
object_ptr<TWidget> _sideResizeArea;
object_ptr<DialogsWidget> _dialogs; object_ptr<DialogsWidget> _dialogs;
object_ptr<HistoryWidget> _history; object_ptr<HistoryWidget> _history;
object_ptr<Window::SectionWidget> _wideSection = { nullptr }; object_ptr<Window::SectionWidget> _wideSection = { nullptr };
@ -691,4 +697,7 @@ private:
std_::unique_ptr<ApiWrap> _api; std_::unique_ptr<ApiWrap> _api;
bool _resizingSide = false;
int _resizingSideShift = 0;
}; };

View file

@ -359,6 +359,7 @@ void MainWindow::setupMain(const MTPUser *self) {
clearWidgets(); clearWidgets();
_main.create(bodyWidget()); _main.create(bodyWidget());
_main->show();
updateControlsGeometry(); updateControlsGeometry();
if (animated) { if (animated) {
@ -835,18 +836,6 @@ void MainWindow::closeEvent(QCloseEvent *e) {
void MainWindow::resizeEvent(QResizeEvent *e) { void MainWindow::resizeEvent(QResizeEvent *e) {
Platform::MainWindow::resizeEvent(e); Platform::MainWindow::resizeEvent(e);
Adaptive::Layout layout = Adaptive::OneColumnLayout;
if (width() > st::adaptiveWideWidth) {
layout = Adaptive::WideLayout;
} else if (width() >= st::adaptiveNormalWidth) {
layout = Adaptive::NormalLayout;
}
if (layout != Global::AdaptiveLayout()) {
Global::SetAdaptiveLayout(layout);
Adaptive::Changed().notify(true);
}
updateControlsGeometry(); updateControlsGeometry();
} }

View file

@ -187,5 +187,6 @@ void PasscodeWidget::resizeEvent(QResizeEvent *e) {
} }
void PasscodeWidget::setInnerFocus() { void PasscodeWidget::setInnerFocus() {
Global::RefDialogsListFocused().set(false, true);
_passcode->setFocusFast(); _passcode->setFocusFast();
} }

View file

@ -369,7 +369,7 @@ QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams &params) {
return result; return result;
} }
void Widget::setInnerFocus() { void Widget::doSetInnerFocus() {
_inner->setFocus(); _inner->setFocus();
} }

View file

@ -184,8 +184,6 @@ public:
QPixmap grabForShowAnimation(const Window::SectionSlideParams &params) override; QPixmap grabForShowAnimation(const Window::SectionSlideParams &params) override;
void setInnerFocus() override;
bool showInternal(const Window::SectionMemento *memento) override; bool showInternal(const Window::SectionMemento *memento) override;
std_::unique_ptr<Window::SectionMemento> createMemento() const override; std_::unique_ptr<Window::SectionMemento> createMemento() const override;
@ -196,8 +194,9 @@ protected:
void showAnimatedHook() override; void showAnimatedHook() override;
void showFinishedHook() override; void showFinishedHook() override;
void doSetInnerFocus() override;
private slots: private slots:
void onScroll(); void onScroll();
private: private:

View file

@ -73,7 +73,7 @@ QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams &params) {
return result; return result;
} }
void Widget::setInnerFocus() { void Widget::doSetInnerFocus() {
_inner->setFocus(); _inner->setFocus();
} }

View file

@ -49,8 +49,6 @@ public:
QPixmap grabForShowAnimation(const Window::SectionSlideParams &params) override; QPixmap grabForShowAnimation(const Window::SectionSlideParams &params) override;
void setInnerFocus() override;
bool showInternal(const Window::SectionMemento *memento) override; bool showInternal(const Window::SectionMemento *memento) override;
std_::unique_ptr<Window::SectionMemento> createMemento() const override; std_::unique_ptr<Window::SectionMemento> createMemento() const override;
@ -61,6 +59,7 @@ protected:
void showAnimatedHook() override; void showAnimatedHook() override;
void showFinishedHook() override; void showFinishedHook() override;
void doSetInnerFocus() override;
private slots: private slots:
void onScroll(); void onScroll();

View file

@ -205,7 +205,7 @@ BackgroundWidget::BackgroundWidget(QWidget *parent, UserData *self) : BlockWidge
} }
}); });
subscribe(Adaptive::Changed(), [this]() { subscribe(Adaptive::Changed(), [this]() {
if (Global::AdaptiveLayout() == Adaptive::WideLayout) { if (Global::AdaptiveChatLayout() == Adaptive::ChatLayout::Wide) {
_adaptive->slideDown(); _adaptive->slideDown();
} else { } else {
_adaptive->slideUp(); _adaptive->slideUp();
@ -224,7 +224,7 @@ void BackgroundWidget::createControls() {
addChildRow(_tile, margin, lang(lng_settings_bg_tile), SLOT(onTile()), Window::Theme::Background()->tile()); addChildRow(_tile, margin, lang(lng_settings_bg_tile), SLOT(onTile()), Window::Theme::Background()->tile());
addChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), SLOT(onAdaptive()), Global::AdaptiveForWide()); addChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), SLOT(onAdaptive()), Global::AdaptiveForWide());
if (Global::AdaptiveLayout() != Adaptive::WideLayout) { if (Global::AdaptiveChatLayout() != Adaptive::ChatLayout::Wide) {
_adaptive->hideFast(); _adaptive->hideFast();
} }
} }

View file

@ -339,7 +339,7 @@ void FlatTextarea::paintEvent(QPaintEvent *e) {
p.save(); p.save();
p.setClipRect(r); p.setClipRect(r);
p.setFont(_st.font); p.setFont(_st.font);
p.setPen(anim::pen(_st.phColor, _st.phFocusColor, _a_placeholderFocused.current(ms, hasFocus() ? 1. : 0.))); p.setPen(anim::pen(_st.phColor, _st.phFocusColor, _a_placeholderFocused.current(ms, _focused ? 1. : 0.)));
if (_st.phAlign == style::al_topleft && _phAfter > 0) { if (_st.phAlign == style::al_topleft && _phAfter > 0) {
int skipWidth = placeholderSkipWidth(); int skipWidth = placeholderSkipWidth();
p.drawText(_st.textMrg.left() - _fakeMargin + placeholderLeft + skipWidth, _st.textMrg.top() - _fakeMargin - st::lineWidth + _st.font->ascent, _ph); p.drawText(_st.textMrg.left() - _fakeMargin + placeholderLeft + skipWidth, _st.textMrg.top() - _fakeMargin - st::lineWidth + _st.font->ascent, _ph);
@ -366,12 +366,20 @@ int FlatTextarea::placeholderSkipWidth() const {
} }
void FlatTextarea::focusInEvent(QFocusEvent *e) { void FlatTextarea::focusInEvent(QFocusEvent *e) {
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration); if (!_focused) {
_focused = true;
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration);
update();
}
QTextEdit::focusInEvent(e); QTextEdit::focusInEvent(e);
} }
void FlatTextarea::focusOutEvent(QFocusEvent *e) { void FlatTextarea::focusOutEvent(QFocusEvent *e) {
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration); if (_focused) {
_focused = false;
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration);
update();
}
QTextEdit::focusOutEvent(e); QTextEdit::focusOutEvent(e);
} }
@ -1559,7 +1567,7 @@ void FlatInput::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto ms = getms(); auto ms = getms();
auto placeholderFocused = _a_placeholderFocused.current(ms, hasFocus() ? 1. : 0.); auto placeholderFocused = _a_placeholderFocused.current(ms, _focused ? 1. : 0.);
auto pen = anim::pen(_st.borderColor, _st.borderActive, placeholderFocused); auto pen = anim::pen(_st.borderColor, _st.borderActive, placeholderFocused);
pen.setWidth(_st.borderWidth); pen.setWidth(_st.borderWidth);
@ -1592,13 +1600,21 @@ void FlatInput::paintEvent(QPaintEvent *e) {
} }
void FlatInput::focusInEvent(QFocusEvent *e) { void FlatInput::focusInEvent(QFocusEvent *e) {
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration); if (!_focused) {
_focused = true;
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration);
update();
}
QLineEdit::focusInEvent(e); QLineEdit::focusInEvent(e);
emit focused(); emit focused();
} }
void FlatInput::focusOutEvent(QFocusEvent *e) { void FlatInput::focusOutEvent(QFocusEvent *e) {
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration); if (_focused) {
_focused = false;
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration);
update();
}
QLineEdit::focusOutEvent(e); QLineEdit::focusOutEvent(e);
emit blurred(); emit blurred();
} }

View file

@ -191,6 +191,7 @@ private:
QString _ph, _phelided; QString _ph, _phelided;
int _phAfter = 0; int _phAfter = 0;
bool _focused = false;
bool _placeholderVisible = true; bool _placeholderVisible = true;
Animation _a_placeholderFocused; Animation _a_placeholderFocused;
Animation _a_placeholderVisible; Animation _a_placeholderVisible;
@ -313,6 +314,7 @@ private:
bool _customUpDown = false; bool _customUpDown = false;
bool _focused = false;
bool _placeholderVisible = true; bool _placeholderVisible = true;
Animation _a_placeholderFocused; Animation _a_placeholderFocused;
Animation _a_placeholderVisible; Animation _a_placeholderVisible;

View file

@ -59,6 +59,11 @@ void SectionWidget::showAnimated(SlideDirection direction, const SectionSlidePar
show(); show();
} }
void SectionWidget::showFast() {
show();
showFinished();
}
void SectionWidget::paintEvent(QPaintEvent *e) { void SectionWidget::paintEvent(QPaintEvent *e) {
if (Ui::skipPaintEvent(this, e)) return; if (Ui::skipPaintEvent(this, e)) return;

View file

@ -30,6 +30,10 @@ class SectionMemento;
struct SectionSlideParams { struct SectionSlideParams {
QPixmap oldContentCache; QPixmap oldContentCache;
bool withTopBarShadow = false; bool withTopBarShadow = false;
explicit operator bool() const {
return !oldContentCache.isNull();
}
}; };
class SectionWidget : public TWidget, protected base::Subscriber { class SectionWidget : public TWidget, protected base::Subscriber {
@ -52,6 +56,7 @@ public:
return false; return false;
} }
void showAnimated(SlideDirection direction, const SectionSlideParams &params); void showAnimated(SlideDirection direction, const SectionSlideParams &params);
void showFast();
// This can be used to grab with or without top bar shadow. // This can be used to grab with or without top bar shadow.
// This will be protected when animation preparation will be done inside. // This will be protected when animation preparation will be done inside.
@ -67,8 +72,8 @@ public:
// Create a memento of that section to store it in the history stack. // Create a memento of that section to store it in the history stack.
virtual std_::unique_ptr<SectionMemento> createMemento() const = 0; virtual std_::unique_ptr<SectionMemento> createMemento() const = 0;
virtual void setInnerFocus() { void setInnerFocus() {
setFocus(); doSetInnerFocus();
} }
protected: protected:
@ -88,6 +93,10 @@ protected:
virtual void showFinishedHook() { virtual void showFinishedHook() {
} }
virtual void doSetInnerFocus() {
setFocus();
}
private: private:
void showFinished(); void showFinished();

View file

@ -30,8 +30,7 @@ windowDefaultHeight: 600px;
windowShadow: icon {{ "window_shadow", windowShadowFg }}; windowShadow: icon {{ "window_shadow", windowShadowFg }};
windowShadowShift: 1px; windowShadowShift: 1px;
adaptiveNormalWidth: 640px; adaptiveChatWideWidth: 860px;
adaptiveWideWidth: 1366px;
notifyBorder: windowShadowFgFallback; notifyBorder: windowShadowFgFallback;
notifyBorderWidth: 1px; notifyBorderWidth: 1px;