Working stories in overscroll.
This commit is contained in:
parent
e0c10e7cc2
commit
85795aa376
|
@ -246,7 +246,7 @@ dialogsSearchForNarrowFilters: IconButton(dialogsMenuToggle) {
|
||||||
dialogsFilter: InputField(defaultInputField) {
|
dialogsFilter: InputField(defaultInputField) {
|
||||||
textBg: filterInputInactiveBg;
|
textBg: filterInputInactiveBg;
|
||||||
textBgActive: filterInputActiveBg;
|
textBgActive: filterInputActiveBg;
|
||||||
textMargins: margins(12px, 7px, 30px, 3px);
|
textMargins: margins(12px, 8px, 30px, 5px);
|
||||||
|
|
||||||
placeholderFg: placeholderFg;
|
placeholderFg: placeholderFg;
|
||||||
placeholderFgActive: placeholderFgActive;
|
placeholderFgActive: placeholderFgActive;
|
||||||
|
@ -257,16 +257,16 @@ dialogsFilter: InputField(defaultInputField) {
|
||||||
placeholderFont: normalFont;
|
placeholderFont: normalFont;
|
||||||
|
|
||||||
borderFg: filterInputInactiveBg;
|
borderFg: filterInputInactiveBg;
|
||||||
borderFgActive: filterInputBorderFg;
|
borderFgActive: windowBgRipple;
|
||||||
borderFgError: activeLineFgError;
|
borderFgError: activeLineFgError;
|
||||||
|
|
||||||
border: 2px;
|
border: 2px;
|
||||||
borderActive: 2px;
|
borderActive: 2px;
|
||||||
borderRadius: roundRadiusSmall;
|
borderRadius: 18px;
|
||||||
|
|
||||||
font: normalFont;
|
font: normalFont;
|
||||||
|
|
||||||
heightMin: 32px;
|
heightMin: 35px;
|
||||||
}
|
}
|
||||||
dialogsCancelSearchInPeer: IconButton(dialogsMenuToggle) {
|
dialogsCancelSearchInPeer: IconButton(dialogsMenuToggle) {
|
||||||
icon: icon {{ "dialogs/dialogs_cancel_search", dialogsMenuIconFg }};
|
icon: icon {{ "dialogs/dialogs_cancel_search", dialogsMenuIconFg }};
|
||||||
|
@ -511,8 +511,9 @@ DialogsStoriesList {
|
||||||
dialogsStories: DialogsStories {
|
dialogsStories: DialogsStories {
|
||||||
left: 4px;
|
left: 4px;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
photo: 24px;
|
photo: 21px;
|
||||||
photoLeft: 10px;
|
photoTop: 4px;
|
||||||
|
photoLeft: 4px;
|
||||||
shift: 16px;
|
shift: 16px;
|
||||||
lineTwice: 3px;
|
lineTwice: 3px;
|
||||||
lineReadTwice: 0px;
|
lineReadTwice: 0px;
|
||||||
|
|
|
@ -141,13 +141,6 @@ InnerWidget::InnerWidget(
|
||||||
rpl::producer<ChildListShown> childListShown)
|
rpl::producer<ChildListShown> childListShown)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _stories(std::make_unique<Stories::List>(
|
|
||||||
this,
|
|
||||||
st::dialogsStoriesList,
|
|
||||||
Stories::ContentForSession(
|
|
||||||
&controller->session(),
|
|
||||||
Data::StorySourcesList::NotHidden),
|
|
||||||
[=] { return _stories->height() - _visibleTop; }))
|
|
||||||
, _shownList(controller->session().data().chatsList()->indexed())
|
, _shownList(controller->session().data().chatsList()->indexed())
|
||||||
, _st(&st::defaultDialogRow)
|
, _st(&st::defaultDialogRow)
|
||||||
, _pinnedShiftAnimation([=](crl::time now) {
|
, _pinnedShiftAnimation([=](crl::time now) {
|
||||||
|
@ -328,37 +321,6 @@ InnerWidget::InnerWidget(
|
||||||
switchToFilter(filterId);
|
switchToFilter(filterId);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_stories->heightValue(
|
|
||||||
) | rpl::filter([=] {
|
|
||||||
return (_viewportHeight > 0) && (defaultScrollTop() > _visibleTop);
|
|
||||||
}) | rpl::start_with_next([=] {
|
|
||||||
refreshForDefaultScroll();
|
|
||||||
jumpToTop();
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
_stories->entered(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
clearSelection();
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
_stories->clicks(
|
|
||||||
) | rpl::start_with_next([=](uint64 id) {
|
|
||||||
_controller->openPeerStories(
|
|
||||||
PeerId(int64(id)),
|
|
||||||
Data::StorySourcesList::NotHidden);
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
_stories->showMenuRequests(
|
|
||||||
) | rpl::start_with_next([=](const Stories::ShowMenuRequest &request) {
|
|
||||||
FillSourceMenu(_controller, request);
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
_stories->loadMoreRequests(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
session().data().stories().loadMore(
|
|
||||||
Data::StorySourcesList::NotHidden);
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
session().data().stories().incrementPreloadingMainSources();
|
session().data().stories().incrementPreloadingMainSources();
|
||||||
|
|
||||||
handleChatListEntryRefreshes();
|
handleChatListEntryRefreshes();
|
||||||
|
@ -450,14 +412,8 @@ int InnerWidget::skipTopHeight() const {
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InnerWidget::storiesShown() const {
|
|
||||||
return (_state == WidgetState::Default)
|
|
||||||
&& !_openedFolder
|
|
||||||
&& !_openedForum;
|
|
||||||
}
|
|
||||||
|
|
||||||
int InnerWidget::collapsedRowsOffset() const {
|
int InnerWidget::collapsedRowsOffset() const {
|
||||||
return storiesShown() ? _stories->height() : 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int InnerWidget::dialogsOffset() const {
|
int InnerWidget::dialogsOffset() const {
|
||||||
|
@ -466,22 +422,6 @@ int InnerWidget::dialogsOffset() const {
|
||||||
- skipTopHeight();
|
- skipTopHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<bool> InnerWidget::storiesExpandedRequests() const {
|
|
||||||
return rpl::merge(
|
|
||||||
_stories->toggleExpandedRequests(),
|
|
||||||
_storiesExpandedRequests.events());
|
|
||||||
}
|
|
||||||
|
|
||||||
void InnerWidget::setTouchScrollActive(bool active) {
|
|
||||||
_stories->setTouchScrollActive(active);
|
|
||||||
}
|
|
||||||
|
|
||||||
int InnerWidget::defaultScrollTop() const {
|
|
||||||
return storiesShown()
|
|
||||||
? std::max(_stories->height() - st::dialogsStories.height, 0)
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int InnerWidget::fixedOnTopCount() const {
|
int InnerWidget::fixedOnTopCount() const {
|
||||||
auto result = 0;
|
auto result = 0;
|
||||||
for (const auto &row : *_shownList) {
|
for (const auto &row : *_shownList) {
|
||||||
|
@ -564,7 +504,6 @@ void InnerWidget::changeOpenedFolder(Data::Folder *folder) {
|
||||||
stopReorderPinned();
|
stopReorderPinned();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
_openedFolder = folder;
|
_openedFolder = folder;
|
||||||
_stories->setVisible(storiesShown());
|
|
||||||
refreshShownList();
|
refreshShownList();
|
||||||
refreshWithCollapsedRows(true);
|
refreshWithCollapsedRows(true);
|
||||||
if (_loadMoreCallback) {
|
if (_loadMoreCallback) {
|
||||||
|
@ -591,7 +530,6 @@ void InnerWidget::changeOpenedForum(Data::Forum *forum) {
|
||||||
}
|
}
|
||||||
_openedForum = forum;
|
_openedForum = forum;
|
||||||
_st = forum ? &st::forumTopicRow : &st::defaultDialogRow;
|
_st = forum ? &st::forumTopicRow : &st::defaultDialogRow;
|
||||||
_stories->setVisible(storiesShown());
|
|
||||||
refreshShownList();
|
refreshShownList();
|
||||||
|
|
||||||
_openedForumLifetime.destroy();
|
_openedForumLifetime.destroy();
|
||||||
|
@ -642,7 +580,6 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
.paused = videoPaused,
|
.paused = videoPaused,
|
||||||
.narrow = (fullWidth < st::columnMinimalWidthLeft / 2),
|
.narrow = (fullWidth < st::columnMinimalWidthLeft / 2),
|
||||||
};
|
};
|
||||||
_stories->setBgOverride(context.currentBg);
|
|
||||||
const auto fillGuard = gsl::finally([&] {
|
const auto fillGuard = gsl::finally([&] {
|
||||||
// We translate painter down, but it'll be cropped below rect.
|
// We translate painter down, but it'll be cropped below rect.
|
||||||
p.fillRect(rect(), context.currentBg);
|
p.fillRect(rect(), context.currentBg);
|
||||||
|
@ -1759,13 +1696,6 @@ void InnerWidget::mousePressReleased(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::setViewportHeight(int viewportHeight) {
|
|
||||||
if (_viewportHeight != viewportHeight) {
|
|
||||||
_viewportHeight = viewportHeight;
|
|
||||||
refreshForDefaultScroll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InnerWidget::setCollapsedPressed(int pressed) {
|
void InnerWidget::setCollapsedPressed(int pressed) {
|
||||||
if (_collapsedPressed != pressed) {
|
if (_collapsedPressed != pressed) {
|
||||||
if (_collapsedPressed >= 0) {
|
if (_collapsedPressed >= 0) {
|
||||||
|
@ -1836,7 +1766,6 @@ void InnerWidget::setSearchedPressed(int pressed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::resizeEvent(QResizeEvent *e) {
|
void InnerWidget::resizeEvent(QResizeEvent *e) {
|
||||||
_stories->resizeToWidth(width());
|
|
||||||
resizeEmptyLabel();
|
resizeEmptyLabel();
|
||||||
moveCancelSearchButtons();
|
moveCancelSearchButtons();
|
||||||
}
|
}
|
||||||
|
@ -2597,7 +2526,6 @@ void InnerWidget::visibleTopBottomUpdated(
|
||||||
int visibleBottom) {
|
int visibleBottom) {
|
||||||
_visibleTop = visibleTop;
|
_visibleTop = visibleTop;
|
||||||
_visibleBottom = visibleBottom;
|
_visibleBottom = visibleBottom;
|
||||||
_stories->update();
|
|
||||||
preloadRowsData();
|
preloadRowsData();
|
||||||
const auto loadTill = _visibleTop
|
const auto loadTill = _visibleTop
|
||||||
+ PreloadHeightsCount * (_visibleBottom - _visibleTop);
|
+ PreloadHeightsCount * (_visibleBottom - _visibleTop);
|
||||||
|
@ -2793,12 +2721,6 @@ void InnerWidget::editOpenedFilter() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::refreshForDefaultScroll() {
|
|
||||||
if (height() < defaultScrollTop() + _viewportHeight) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InnerWidget::refresh(bool toTop) {
|
void InnerWidget::refresh(bool toTop) {
|
||||||
if (!_geometryInited) {
|
if (!_geometryInited) {
|
||||||
return;
|
return;
|
||||||
|
@ -2820,9 +2742,6 @@ void InnerWidget::refresh(bool toTop) {
|
||||||
h = searchedOffset() + (_searchResults.size() * _st->height);
|
h = searchedOffset() + (_searchResults.size() * _st->height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (const auto storiesSkip = defaultScrollTop()) {
|
|
||||||
accumulate_max(h, storiesSkip + _viewportHeight);
|
|
||||||
}
|
|
||||||
resize(width(), h);
|
resize(width(), h);
|
||||||
if (toTop) {
|
if (toTop) {
|
||||||
stopReorderPinned();
|
stopReorderPinned();
|
||||||
|
@ -3033,10 +2952,7 @@ void InnerWidget::clearFilter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::setState(WidgetState state) {
|
void InnerWidget::setState(WidgetState state) {
|
||||||
if (_state != state) {
|
_state = state;
|
||||||
_state = state;
|
|
||||||
_stories->setVisible(storiesShown());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::selectSkip(int32 direction) {
|
void InnerWidget::selectSkip(int32 direction) {
|
||||||
|
@ -3331,8 +3247,7 @@ void InnerWidget::switchToFilter(FilterId filterId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::jumpToTop() {
|
void InnerWidget::jumpToTop() {
|
||||||
const auto to = defaultScrollTop();
|
_mustScrollTo.fire({ 0, -1 });
|
||||||
_mustScrollTo.fire({ to, -1 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::saveChatsFilterScrollState(FilterId filterId) {
|
void InnerWidget::saveChatsFilterScrollState(FilterId filterId) {
|
||||||
|
@ -3342,8 +3257,7 @@ void InnerWidget::saveChatsFilterScrollState(FilterId filterId) {
|
||||||
void InnerWidget::restoreChatsFilterScrollState(FilterId filterId) {
|
void InnerWidget::restoreChatsFilterScrollState(FilterId filterId) {
|
||||||
const auto it = _chatsFilterScrollStates.find(filterId);
|
const auto it = _chatsFilterScrollStates.find(filterId);
|
||||||
if (it != end(_chatsFilterScrollStates)) {
|
if (it != end(_chatsFilterScrollStates)) {
|
||||||
const auto top = std::max(it->second, defaultScrollTop());
|
_mustScrollTo.fire({ std::max(it->second, 0), -1 });
|
||||||
_mustScrollTo.fire({ top, -1 });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3412,7 +3326,6 @@ ChosenRow InnerWidget::computeChosenRow() const {
|
||||||
bool InnerWidget::chooseRow(
|
bool InnerWidget::chooseRow(
|
||||||
Qt::KeyboardModifiers modifiers,
|
Qt::KeyboardModifiers modifiers,
|
||||||
MsgId pressedTopicRootId) {
|
MsgId pressedTopicRootId) {
|
||||||
_storiesExpandedRequests.fire(false);
|
|
||||||
if (chooseCollapsedRow()) {
|
if (chooseCollapsedRow()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (chooseHashtag()) {
|
} else if (chooseHashtag()) {
|
||||||
|
|
|
@ -52,10 +52,6 @@ struct PaintContext;
|
||||||
struct TopicJumpCache;
|
struct TopicJumpCache;
|
||||||
} // namespace Dialogs::Ui
|
} // namespace Dialogs::Ui
|
||||||
|
|
||||||
namespace Dialogs::Stories {
|
|
||||||
class List;
|
|
||||||
} // namespace Dialogs::Stories
|
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
|
||||||
class Row;
|
class Row;
|
||||||
|
@ -105,11 +101,6 @@ public:
|
||||||
const QVector<MTPPeer> &my,
|
const QVector<MTPPeer> &my,
|
||||||
const QVector<MTPPeer> &result);
|
const QVector<MTPPeer> &result);
|
||||||
|
|
||||||
void setTouchScrollActive(bool active);
|
|
||||||
[[nodiscard]] rpl::producer<bool> storiesExpandedRequests() const;
|
|
||||||
[[nodiscard]] int defaultScrollTop() const;
|
|
||||||
void setViewportHeight(int viewportHeight);
|
|
||||||
|
|
||||||
[[nodiscard]] FilterId filterId() const;
|
[[nodiscard]] FilterId filterId() const;
|
||||||
|
|
||||||
void clearSelection();
|
void clearSelection();
|
||||||
|
@ -124,7 +115,6 @@ public:
|
||||||
|
|
||||||
void clearFilter();
|
void clearFilter();
|
||||||
void refresh(bool toTop = false);
|
void refresh(bool toTop = false);
|
||||||
void refreshForDefaultScroll();
|
|
||||||
void refreshEmptyLabel();
|
void refreshEmptyLabel();
|
||||||
void resizeEmptyLabel();
|
void resizeEmptyLabel();
|
||||||
|
|
||||||
|
@ -322,7 +312,6 @@ private:
|
||||||
void fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu);
|
void fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu);
|
||||||
|
|
||||||
void refreshShownList();
|
void refreshShownList();
|
||||||
[[nodiscard]] bool storiesShown() const;
|
|
||||||
[[nodiscard]] int skipTopHeight() const;
|
[[nodiscard]] int skipTopHeight() const;
|
||||||
[[nodiscard]] int collapsedRowsOffset() const;
|
[[nodiscard]] int collapsedRowsOffset() const;
|
||||||
[[nodiscard]] int dialogsOffset() const;
|
[[nodiscard]] int dialogsOffset() const;
|
||||||
|
@ -409,10 +398,6 @@ private:
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
|
|
||||||
const std::unique_ptr<Stories::List> _stories;
|
|
||||||
rpl::event_stream<bool> _storiesExpandedRequests;
|
|
||||||
int _viewportHeight = 0;
|
|
||||||
|
|
||||||
not_null<IndexedList*> _shownList;
|
not_null<IndexedList*> _shownList;
|
||||||
FilterId _filterId = 0;
|
FilterId _filterId = 0;
|
||||||
bool _mouseSelection = false;
|
bool _mouseSelection = false;
|
||||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "dialogs/dialogs_widget.h"
|
#include "dialogs/dialogs_widget.h"
|
||||||
|
|
||||||
|
#include "dialogs/ui/dialogs_stories_content.h"
|
||||||
|
#include "dialogs/ui/dialogs_stories_list.h"
|
||||||
#include "dialogs/dialogs_inner_widget.h"
|
#include "dialogs/dialogs_inner_widget.h"
|
||||||
#include "dialogs/dialogs_search_from_controllers.h"
|
#include "dialogs/dialogs_search_from_controllers.h"
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
|
@ -64,6 +66,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_download_manager.h"
|
#include "data/data_download_manager.h"
|
||||||
#include "data/data_chat_filters.h"
|
#include "data/data_chat_filters.h"
|
||||||
|
#include "data/data_stories.h"
|
||||||
#include "info/downloads/info_downloads_widget.h"
|
#include "info/downloads/info_downloads_widget.h"
|
||||||
#include "info/info_memento.h"
|
#include "info/info_memento.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
@ -211,15 +214,21 @@ Widget::Widget(
|
||||||
, _cancelSearch(_searchControls, st::dialogsCancelSearch)
|
, _cancelSearch(_searchControls, st::dialogsCancelSearch)
|
||||||
, _lockUnlock(_searchControls, st::dialogsLock)
|
, _lockUnlock(_searchControls, st::dialogsLock)
|
||||||
, _scroll(this)
|
, _scroll(this)
|
||||||
, _allowStoriesExpandTimer([=] {
|
|
||||||
//_scroll->verticalScrollBar()->setMinimum(0);
|
|
||||||
})
|
|
||||||
, _scrollToTop(_scroll, st::dialogsToUp)
|
, _scrollToTop(_scroll, st::dialogsToUp)
|
||||||
|
, _stories(std::make_unique<Stories::List>(
|
||||||
|
this,
|
||||||
|
st::dialogsStoriesList,
|
||||||
|
Stories::ContentForSession(
|
||||||
|
&controller->session(),
|
||||||
|
Data::StorySourcesList::NotHidden)))
|
||||||
, _searchTimer([=] { searchMessages(); })
|
, _searchTimer([=] { searchMessages(); })
|
||||||
, _singleMessageSearch(&controller->session()) {
|
, _singleMessageSearch(&controller->session()) {
|
||||||
const auto makeChildListShown = [](PeerId peerId, float64 shown) {
|
const auto makeChildListShown = [](PeerId peerId, float64 shown) {
|
||||||
return InnerWidget::ChildListShown{ peerId, shown };
|
return InnerWidget::ChildListShown{ peerId, shown };
|
||||||
};
|
};
|
||||||
|
_scroll->setOverscrollTypes(
|
||||||
|
Ui::ElasticScroll::OverscrollType::Virtual,
|
||||||
|
Ui::ElasticScroll::OverscrollType::Real);
|
||||||
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(
|
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(
|
||||||
this,
|
this,
|
||||||
controller,
|
controller,
|
||||||
|
@ -228,6 +237,22 @@ Widget::Widget(
|
||||||
_childListShown.value(),
|
_childListShown.value(),
|
||||||
makeChildListShown)));
|
makeChildListShown)));
|
||||||
_scrollToTop->raise();
|
_scrollToTop->raise();
|
||||||
|
rpl::combine(
|
||||||
|
_scroll->positionValue(),
|
||||||
|
_scroll->movementValue()
|
||||||
|
) | rpl::start_with_next([=](
|
||||||
|
Ui::ElasticScrollPosition position,
|
||||||
|
Ui::ElasticScrollMovement movement) {
|
||||||
|
const auto overscrollTop = std::max(-position.overscroll, 0);
|
||||||
|
if (_overscrollTop != overscrollTop) {
|
||||||
|
_overscrollTop = overscrollTop;
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
using Phase = Ui::ElasticScrollMovement;
|
||||||
|
_stories->setExpandedHeight(
|
||||||
|
_overscrollTop,
|
||||||
|
(movement == Phase::Momentum || movement == Phase::Returning));
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_inner->updated(
|
_inner->updated(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
|
@ -268,15 +293,6 @@ Widget::Widget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_inner->storiesExpandedRequests(
|
|
||||||
) | rpl::start_with_next([=](bool expanded) {
|
|
||||||
if (expanded || _scroll->scrollTop() < _inner->defaultScrollTop()) {
|
|
||||||
if (_scroll->scrollTop() > 0) {
|
|
||||||
scrollToDefaultChecked(expanded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
_inner->mustScrollTo(
|
_inner->mustScrollTo(
|
||||||
) | rpl::start_with_next([=](const Ui::ScrollToRequest &data) {
|
) | rpl::start_with_next([=](const Ui::ScrollToRequest &data) {
|
||||||
if (_scroll) {
|
if (_scroll) {
|
||||||
|
@ -328,12 +344,6 @@ Widget::Widget(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
listScrollUpdated();
|
listScrollUpdated();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
_scroll->setCustomWheelProcess([=](not_null<QWheelEvent*> e) {
|
|
||||||
return customWheelProcess(e);
|
|
||||||
});
|
|
||||||
_scroll->setCustomTouchProcess([=](not_null<QTouchEvent*> e) {
|
|
||||||
return customTouchProcess(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
session().data().chatsListChanges(
|
session().data().chatsListChanges(
|
||||||
) | rpl::filter([=](Data::Folder *folder) {
|
) | rpl::filter([=](Data::Folder *folder) {
|
||||||
|
@ -383,6 +393,7 @@ Widget::Widget(
|
||||||
|
|
||||||
setupMainMenuToggle();
|
setupMainMenuToggle();
|
||||||
setupShortcuts();
|
setupShortcuts();
|
||||||
|
setupStories();
|
||||||
|
|
||||||
_searchForNarrowFilters->setClickedCallback([=] {
|
_searchForNarrowFilters->setClickedCallback([=] {
|
||||||
_filter->setFocusFast();
|
_filter->setFocusFast();
|
||||||
|
@ -589,7 +600,7 @@ void Widget::setupMoreChatsBar() {
|
||||||
}
|
}
|
||||||
controller()->activeChatsFilter(
|
controller()->activeChatsFilter(
|
||||||
) | rpl::start_with_next([=](FilterId id) {
|
) | rpl::start_with_next([=](FilterId id) {
|
||||||
if (!id) {
|
if (!id && false) { // #TODO stories testing
|
||||||
_moreChatsBar = nullptr;
|
_moreChatsBar = nullptr;
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
return;
|
return;
|
||||||
|
@ -770,6 +781,38 @@ void Widget::setupMainMenuToggle() {
|
||||||
}, _mainMenu.toggle->lifetime());
|
}, _mainMenu.toggle->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::setupStories() {
|
||||||
|
_stories->clicks(
|
||||||
|
) | rpl::start_with_next([=](uint64 id) {
|
||||||
|
controller()->openPeerStories(
|
||||||
|
PeerId(int64(id)),
|
||||||
|
Data::StorySourcesList::NotHidden);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_stories->showMenuRequests(
|
||||||
|
) | rpl::start_with_next([=](const Stories::ShowMenuRequest &request) {
|
||||||
|
FillSourceMenu(controller(), request);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_stories->loadMoreRequests(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
session().data().stories().loadMore(
|
||||||
|
Data::StorySourcesList::NotHidden);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_stories->toggleExpandedRequests(
|
||||||
|
) | rpl::start_with_next([=](bool expanded) {
|
||||||
|
if (expanded) {
|
||||||
|
if (!_scrollToAnimation.animating() || _scrollAnimationTo) {
|
||||||
|
scrollToDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_scroll->setOverscrollDefaults(
|
||||||
|
expanded ? -st::dialogsStoriesFull.height : 0,
|
||||||
|
0);
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::setupShortcuts() {
|
void Widget::setupShortcuts() {
|
||||||
Shortcuts::Requests(
|
Shortcuts::Requests(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
|
@ -1128,7 +1171,7 @@ void Widget::jumpToTop(bool belowPinned) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((currentSearchQuery().trimmed().isEmpty() && !_searchInChat)) {
|
if ((currentSearchQuery().trimmed().isEmpty() && !_searchInChat)) {
|
||||||
auto to = _inner->defaultScrollTop();
|
auto to = 0;
|
||||||
if (belowPinned) {
|
if (belowPinned) {
|
||||||
const auto list = _openedForum
|
const auto list = _openedForum
|
||||||
? _openedForum->topicsList()
|
? _openedForum->topicsList()
|
||||||
|
@ -1156,7 +1199,7 @@ void Widget::scrollToDefault(bool verytop) {
|
||||||
}
|
}
|
||||||
_scrollToAnimation.stop();
|
_scrollToAnimation.stop();
|
||||||
auto scrollTop = _scroll->scrollTop();
|
auto scrollTop = _scroll->scrollTop();
|
||||||
const auto scrollTo = verytop ? 0 : _inner->defaultScrollTop();
|
const auto scrollTo = 0;
|
||||||
if (scrollTop == scrollTo) {
|
if (scrollTop == scrollTo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1172,7 +1215,7 @@ void Widget::scrollToDefault(bool verytop) {
|
||||||
const auto animated = qRound(_scrollToAnimation.value(scrollTo));
|
const auto animated = qRound(_scrollToAnimation.value(scrollTo));
|
||||||
const auto animatedDelta = animated - scrollTo;
|
const auto animatedDelta = animated - scrollTo;
|
||||||
const auto realDelta = _scroll->scrollTop() - scrollTo;
|
const auto realDelta = _scroll->scrollTop() - scrollTo;
|
||||||
if (realDelta * animatedDelta < 0) {
|
if (base::OppositeSigns(realDelta, animatedDelta)) {
|
||||||
// We scrolled manually to the other side of target 'scrollTo'.
|
// We scrolled manually to the other side of target 'scrollTo'.
|
||||||
_scrollToAnimation.stop();
|
_scrollToAnimation.stop();
|
||||||
} else if (std::abs(realDelta) > std::abs(animatedDelta)) {
|
} else if (std::abs(realDelta) > std::abs(animatedDelta)) {
|
||||||
|
@ -1181,6 +1224,7 @@ void Widget::scrollToDefault(bool verytop) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_scrollAnimationTo = scrollTo;
|
||||||
_scrollToAnimation.start(
|
_scrollToAnimation.start(
|
||||||
scroll,
|
scroll,
|
||||||
scrollTop,
|
scrollTop,
|
||||||
|
@ -2398,55 +2442,6 @@ void Widget::completeHashtag(QString tag) {
|
||||||
applyFilterUpdate(true);
|
applyFilterUpdate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Widget::customWheelProcess(not_null<QWheelEvent*> e) {
|
|
||||||
customScrollProcess(e->phase());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::customScrollProcess(Qt::ScrollPhase phase) {
|
|
||||||
const auto now = _scroll->scrollTop();
|
|
||||||
const auto def = _inner->defaultScrollTop();
|
|
||||||
//const auto bar = _scroll->verticalScrollBar();
|
|
||||||
if (phase == Qt::ScrollBegin || phase == Qt::ScrollUpdate) {
|
|
||||||
_allowStoriesExpandTimer.cancel();
|
|
||||||
_inner->setTouchScrollActive(true);
|
|
||||||
//bar->setMinimum(0);
|
|
||||||
} else if (phase == Qt::ScrollEnd || phase == Qt::ScrollMomentum) {
|
|
||||||
_allowStoriesExpandTimer.cancel();
|
|
||||||
_inner->setTouchScrollActive(false);
|
|
||||||
if (def > 0 && now >= def) {
|
|
||||||
//bar->setMinimum(def);
|
|
||||||
} else {
|
|
||||||
//bar->setMinimum(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const auto allow = (def <= 0)
|
|
||||||
|| (now < def)
|
|
||||||
|| (now == def && !_allowStoriesExpandTimer.isActive());
|
|
||||||
if (allow) {
|
|
||||||
//_scroll->verticalScrollBar()->setMinimum(0);
|
|
||||||
_allowStoriesExpandTimer.cancel();
|
|
||||||
} else {
|
|
||||||
//bar->setMinimum(def);
|
|
||||||
_allowStoriesExpandTimer.callOnce(kWaitTillAllowStoriesExpand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Widget::customTouchProcess(not_null<QTouchEvent*> e) {
|
|
||||||
const auto type = e->type();
|
|
||||||
customScrollProcess([&] {
|
|
||||||
switch (e->type()) {
|
|
||||||
case QEvent::TouchBegin: return Qt::ScrollBegin;
|
|
||||||
case QEvent::TouchUpdate: return Qt::ScrollUpdate;
|
|
||||||
case QEvent::TouchEnd:
|
|
||||||
case QEvent::TouchCancel: return Qt::ScrollEnd;
|
|
||||||
}
|
|
||||||
Unexpected("Touch event type in Widdget::customTouchProcess.");
|
|
||||||
}());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::resizeEvent(QResizeEvent *e) {
|
void Widget::resizeEvent(QResizeEvent *e) {
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}
|
}
|
||||||
|
@ -2526,11 +2521,9 @@ void Widget::updateControlsGeometry() {
|
||||||
? st::dialogsFilterSkip
|
? st::dialogsFilterSkip
|
||||||
: (st::dialogsFilterPadding.x() + _mainMenu.toggle->width()))
|
: (st::dialogsFilterPadding.x() + _mainMenu.toggle->width()))
|
||||||
+ st::dialogsFilterPadding.x();
|
+ st::dialogsFilterPadding.x();
|
||||||
auto filterRight = (session().domain().local().hasLocalPasscode()
|
const auto filterRight = st::dialogsFilterSkip + st::dialogsFilterPadding.x();
|
||||||
? (st::dialogsFilterPadding.x() + _lockUnlock->width())
|
const auto filterWidth = qMax(ratiow, smallw) - filterLeft - filterRight;
|
||||||
: st::dialogsFilterSkip) + st::dialogsFilterPadding.x();
|
const auto filterAreaHeight = st::topBarHeight;
|
||||||
auto filterWidth = qMax(ratiow, smallw) - filterLeft - filterRight;
|
|
||||||
auto filterAreaHeight = st::topBarHeight;
|
|
||||||
_searchControls->setGeometry(0, filterAreaTop, ratiow, filterAreaHeight);
|
_searchControls->setGeometry(0, filterAreaTop, ratiow, filterAreaHeight);
|
||||||
if (_subsectionTopBar) {
|
if (_subsectionTopBar) {
|
||||||
_subsectionTopBar->setGeometryWithNarrowRatio(
|
_subsectionTopBar->setGeometryWithNarrowRatio(
|
||||||
|
@ -2542,6 +2535,7 @@ void Widget::updateControlsGeometry() {
|
||||||
auto filterTop = (filterAreaHeight - _filter->height()) / 2;
|
auto filterTop = (filterAreaHeight - _filter->height()) / 2;
|
||||||
filterLeft = anim::interpolate(filterLeft, _narrowWidth, narrowRatio);
|
filterLeft = anim::interpolate(filterLeft, _narrowWidth, narrowRatio);
|
||||||
_filter->setGeometryToLeft(filterLeft, filterTop, filterWidth, _filter->height());
|
_filter->setGeometryToLeft(filterLeft, filterTop, filterWidth, _filter->height());
|
||||||
|
|
||||||
auto mainMenuLeft = anim::interpolate(
|
auto mainMenuLeft = anim::interpolate(
|
||||||
st::dialogsFilterPadding.x(),
|
st::dialogsFilterPadding.x(),
|
||||||
(_narrowWidth - _mainMenu.toggle->width()) / 2,
|
(_narrowWidth - _mainMenu.toggle->width()) / 2,
|
||||||
|
@ -2567,14 +2561,21 @@ void Widget::updateControlsGeometry() {
|
||||||
right -= _chooseFromUser->width(); _chooseFromUser->moveToLeft(right, _filter->y());
|
right -= _chooseFromUser->width(); _chooseFromUser->moveToLeft(right, _filter->y());
|
||||||
|
|
||||||
const auto barw = width();
|
const auto barw = width();
|
||||||
|
const auto expandedStoriesTop = filterAreaTop + filterAreaHeight;
|
||||||
|
const auto storiesHeight = 2 * st::dialogsStories.photoTop
|
||||||
|
+ st::dialogsStories.photo;
|
||||||
|
const auto added = (st::dialogsFilter.heightMin - storiesHeight) / 2;
|
||||||
|
_stories->setLayoutConstraints(
|
||||||
|
{ filterLeft + filterWidth, filterTop + added },
|
||||||
|
{ 0, expandedStoriesTop, barw, st::dialogsStoriesFull.height });
|
||||||
if (_forumTopShadow) {
|
if (_forumTopShadow) {
|
||||||
_forumTopShadow->setGeometry(
|
_forumTopShadow->setGeometry(
|
||||||
0,
|
0,
|
||||||
filterAreaTop + filterAreaHeight,
|
expandedStoriesTop,
|
||||||
barw,
|
barw,
|
||||||
st::lineWidth);
|
st::lineWidth);
|
||||||
}
|
}
|
||||||
const auto moreChatsBarTop = filterAreaTop + filterAreaHeight;
|
const auto moreChatsBarTop = expandedStoriesTop + _overscrollTop;
|
||||||
if (_moreChatsBar) {
|
if (_moreChatsBar) {
|
||||||
_moreChatsBar->move(0, moreChatsBarTop);
|
_moreChatsBar->move(0, moreChatsBarTop);
|
||||||
_moreChatsBar->resizeToWidth(barw);
|
_moreChatsBar->resizeToWidth(barw);
|
||||||
|
@ -2599,8 +2600,7 @@ void Widget::updateControlsGeometry() {
|
||||||
auto scrollTop = forumReportTop
|
auto scrollTop = forumReportTop
|
||||||
+ (_forumReportBar ? _forumReportBar->bar().height() : 0);
|
+ (_forumReportBar ? _forumReportBar->bar().height() : 0);
|
||||||
const auto wasScrollTop = _scroll->scrollTop();
|
const auto wasScrollTop = _scroll->scrollTop();
|
||||||
const auto newScrollTop = (_topDelta < 0
|
const auto newScrollTop = (_topDelta < 0 && wasScrollTop <= 0)
|
||||||
&& wasScrollTop <= _inner->defaultScrollTop())
|
|
||||||
? wasScrollTop
|
? wasScrollTop
|
||||||
: (wasScrollTop + _topDelta);
|
: (wasScrollTop + _topDelta);
|
||||||
auto scrollHeight = height() - scrollTop;
|
auto scrollHeight = height() - scrollTop;
|
||||||
|
@ -2626,19 +2626,13 @@ void Widget::updateControlsGeometry() {
|
||||||
|
|
||||||
const auto scrollw = _childList ? _narrowWidth : barw;
|
const auto scrollw = _childList ? _narrowWidth : barw;
|
||||||
const auto wasScrollHeight = _scroll->height();
|
const auto wasScrollHeight = _scroll->height();
|
||||||
if (scrollHeight >= wasScrollHeight) {
|
|
||||||
_inner->setViewportHeight(scrollHeight);
|
|
||||||
}
|
|
||||||
_scroll->setGeometry(0, scrollTop, scrollw, scrollHeight);
|
_scroll->setGeometry(0, scrollTop, scrollw, scrollHeight);
|
||||||
if (scrollHeight < wasScrollHeight) {
|
|
||||||
_inner->setViewportHeight(scrollHeight);
|
|
||||||
}
|
|
||||||
_inner->resize(scrollw, _inner->height());
|
_inner->resize(scrollw, _inner->height());
|
||||||
_inner->setNarrowRatio(narrowRatio);
|
_inner->setNarrowRatio(narrowRatio);
|
||||||
if (scrollHeight != wasScrollHeight) {
|
if (scrollHeight != wasScrollHeight) {
|
||||||
controller()->floatPlayerAreaUpdated();
|
controller()->floatPlayerAreaUpdated();
|
||||||
}
|
}
|
||||||
const auto startWithTop = _inner->defaultScrollTop();
|
const auto startWithTop = 0;
|
||||||
if (wasScrollHeight < startWithTop && scrollHeight >= startWithTop) {
|
if (wasScrollHeight < startWithTop && scrollHeight >= startWithTop) {
|
||||||
_scroll->scrollToY(startWithTop);
|
_scroll->scrollToY(startWithTop);
|
||||||
} else if (newScrollTop != wasScrollTop) {
|
} else if (newScrollTop != wasScrollTop) {
|
||||||
|
@ -2718,7 +2712,7 @@ void Widget::paintEvent(QPaintEvent *e) {
|
||||||
p.fillRect(above.intersected(r), bg);
|
p.fillRect(above.intersected(r), bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto belowTop = _scroll->y() + qMin(_scroll->height(), _inner->height());
|
auto belowTop = _scroll->y() + _scroll->height();
|
||||||
if (!_widthAnimationCache.isNull()) {
|
if (!_widthAnimationCache.isNull()) {
|
||||||
p.drawPixmapLeft(0, _scroll->y(), width(), _widthAnimationCache);
|
p.drawPixmapLeft(0, _scroll->y(), width(), _widthAnimationCache);
|
||||||
belowTop = _scroll->y() + (_widthAnimationCache.height() / cIntRetinaFactor());
|
belowTop = _scroll->y() + (_widthAnimationCache.height() / cIntRetinaFactor());
|
||||||
|
|
|
@ -56,6 +56,10 @@ class ConnectionState;
|
||||||
struct SectionShow;
|
struct SectionShow;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Dialogs::Stories {
|
||||||
|
class List;
|
||||||
|
} // namespace Dialogs::Stories
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
|
||||||
struct RowDescriptor;
|
struct RowDescriptor;
|
||||||
|
@ -136,9 +140,6 @@ private:
|
||||||
void cancelSearchInChat();
|
void cancelSearchInChat();
|
||||||
void filterCursorMoved();
|
void filterCursorMoved();
|
||||||
void completeHashtag(QString tag);
|
void completeHashtag(QString tag);
|
||||||
bool customWheelProcess(not_null<QWheelEvent*> e);
|
|
||||||
bool customTouchProcess(not_null<QTouchEvent*> e);
|
|
||||||
void customScrollProcess(Qt::ScrollPhase phase);
|
|
||||||
|
|
||||||
[[nodiscard]] QString currentSearchQuery() const;
|
[[nodiscard]] QString currentSearchQuery() const;
|
||||||
void clearSearchField();
|
void clearSearchField();
|
||||||
|
@ -165,6 +166,7 @@ private:
|
||||||
void setupMoreChatsBar();
|
void setupMoreChatsBar();
|
||||||
void setupDownloadBar();
|
void setupDownloadBar();
|
||||||
void setupShortcuts();
|
void setupShortcuts();
|
||||||
|
void setupStories();
|
||||||
[[nodiscard]] bool searchForPeersRequired(const QString &query) const;
|
[[nodiscard]] bool searchForPeersRequired(const QString &query) const;
|
||||||
[[nodiscard]] bool searchForTopicsRequired(const QString &query) const;
|
[[nodiscard]] bool searchForTopicsRequired(const QString &query) const;
|
||||||
bool setSearchInChat(Key chat, PeerData *from = nullptr);
|
bool setSearchInChat(Key chat, PeerData *from = nullptr);
|
||||||
|
@ -248,7 +250,6 @@ private:
|
||||||
std::unique_ptr<HistoryView::ContactStatus> _forumReportBar;
|
std::unique_ptr<HistoryView::ContactStatus> _forumReportBar;
|
||||||
|
|
||||||
object_ptr<Ui::ElasticScroll> _scroll;
|
object_ptr<Ui::ElasticScroll> _scroll;
|
||||||
base::Timer _allowStoriesExpandTimer;
|
|
||||||
QPointer<InnerWidget> _inner;
|
QPointer<InnerWidget> _inner;
|
||||||
class BottomButton;
|
class BottomButton;
|
||||||
object_ptr<BottomButton> _updateTelegram = { nullptr };
|
object_ptr<BottomButton> _updateTelegram = { nullptr };
|
||||||
|
@ -257,6 +258,7 @@ private:
|
||||||
std::unique_ptr<Window::ConnectionState> _connecting;
|
std::unique_ptr<Window::ConnectionState> _connecting;
|
||||||
|
|
||||||
Ui::Animations::Simple _scrollToAnimation;
|
Ui::Animations::Simple _scrollToAnimation;
|
||||||
|
int _scrollAnimationTo = 0;
|
||||||
std::unique_ptr<Window::SlideAnimation> _showAnimation;
|
std::unique_ptr<Window::SlideAnimation> _showAnimation;
|
||||||
rpl::variable<float64> _shownProgressValue;
|
rpl::variable<float64> _shownProgressValue;
|
||||||
|
|
||||||
|
@ -265,6 +267,9 @@ private:
|
||||||
bool _scrollToTopIsShown = false;
|
bool _scrollToTopIsShown = false;
|
||||||
bool _forumSearchRequested = false;
|
bool _forumSearchRequested = false;
|
||||||
|
|
||||||
|
int _overscrollTop = 0;
|
||||||
|
std::unique_ptr<Stories::List> _stories;
|
||||||
|
|
||||||
Data::Folder *_openedFolder = nullptr;
|
Data::Folder *_openedFolder = nullptr;
|
||||||
Data::Forum *_openedForum = nullptr;
|
Data::Forum *_openedForum = nullptr;
|
||||||
Dialogs::Key _searchInChat;
|
Dialogs::Key _searchInChat;
|
||||||
|
|
|
@ -24,7 +24,7 @@ constexpr auto kPreloadPages = 2;
|
||||||
constexpr auto kExpandAfterRatio = 0.85;
|
constexpr auto kExpandAfterRatio = 0.85;
|
||||||
constexpr auto kCollapseAfterRatio = 0.72;
|
constexpr auto kCollapseAfterRatio = 0.72;
|
||||||
constexpr auto kFrictionRatio = 0.15;
|
constexpr auto kFrictionRatio = 0.15;
|
||||||
constexpr auto kSnapExpandedTimeout = crl::time(200);
|
constexpr auto kExpandCatchUpDuration = crl::time(200);
|
||||||
|
|
||||||
[[nodiscard]] int AvailableNameWidth(const style::DialogsStoriesList &st) {
|
[[nodiscard]] int AvailableNameWidth(const style::DialogsStoriesList &st) {
|
||||||
const auto &full = st.full;
|
const auto &full = st.full;
|
||||||
|
@ -37,7 +37,6 @@ constexpr auto kSnapExpandedTimeout = crl::time(200);
|
||||||
|
|
||||||
struct List::Layout {
|
struct List::Layout {
|
||||||
int itemsCount = 0;
|
int itemsCount = 0;
|
||||||
int shownHeight = 0;
|
|
||||||
float64 expandedRatio = 0.;
|
float64 expandedRatio = 0.;
|
||||||
float64 ratio = 0.;
|
float64 ratio = 0.;
|
||||||
float64 thumbnailLeft = 0.;
|
float64 thumbnailLeft = 0.;
|
||||||
|
@ -58,12 +57,9 @@ struct List::Layout {
|
||||||
List::List(
|
List::List(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
const style::DialogsStoriesList &st,
|
const style::DialogsStoriesList &st,
|
||||||
rpl::producer<Content> content,
|
rpl::producer<Content> content)
|
||||||
Fn<int()> shownHeight)
|
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _st(st)
|
, _st(st) {
|
||||||
, _shownHeight(shownHeight)
|
|
||||||
, _snapExpandedTimer([=] { requestExpanded(_expanded); }) {
|
|
||||||
setCursor(style::cur_default);
|
setCursor(style::cur_default);
|
||||||
|
|
||||||
std::move(content) | rpl::start_with_next([=](Content &&content) {
|
std::move(content) | rpl::start_with_next([=](Content &&content) {
|
||||||
|
@ -87,6 +83,7 @@ void List::showContent(Content &&content) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto hidden = _content.elements.empty();
|
const auto hidden = _content.elements.empty();
|
||||||
|
const auto wasCount = int((hidden ? _hidingData : _data).items.size());
|
||||||
_content = std::move(content);
|
_content = std::move(content);
|
||||||
auto items = base::take(
|
auto items = base::take(
|
||||||
_data.items.empty() ? _hidingData.items : _data.items);
|
_data.items.empty() ? _hidingData.items : _data.items);
|
||||||
|
@ -114,6 +111,9 @@ void List::showContent(Content &&content) {
|
||||||
_data.items.emplace_back(Item{ .element = element });
|
_data.items.emplace_back(Item{ .element = element });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (int(_data.items.size()) != wasCount) {
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
updateScrollMax();
|
updateScrollMax();
|
||||||
updateSummary(_data);
|
updateSummary(_data);
|
||||||
update();
|
update();
|
||||||
|
@ -253,7 +253,6 @@ rpl::producer<> List::loadMoreRequests() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::requestExpanded(bool expanded) {
|
void List::requestExpanded(bool expanded) {
|
||||||
_snapExpandedTimer.cancel();
|
|
||||||
if (_expanded != expanded) {
|
if (_expanded != expanded) {
|
||||||
_expanded = expanded;
|
_expanded = expanded;
|
||||||
_expandedAnimation.start(
|
_expandedAnimation.start(
|
||||||
|
@ -274,12 +273,12 @@ void List::resizeEvent(QResizeEvent *e) {
|
||||||
updateScrollMax();
|
updateScrollMax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::updateExpanding(int minHeight, int shownHeight, int fullHeight) {
|
void List::updateExpanding(int expandingHeight, int expandedHeight) {
|
||||||
Expects(shownHeight == minHeight || fullHeight > minHeight);
|
Expects(!expandingHeight || expandedHeight > 0);
|
||||||
|
|
||||||
const auto ratio = (shownHeight == minHeight)
|
const auto ratio = !expandingHeight
|
||||||
? 0.
|
? 0.
|
||||||
: (float64(shownHeight - minHeight) / (fullHeight - minHeight));
|
: (float64(expandingHeight) / expandedHeight);
|
||||||
if (_lastRatio == ratio) {
|
if (_lastRatio == ratio) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -296,20 +295,12 @@ void List::updateExpanding(int minHeight, int shownHeight, int fullHeight) {
|
||||||
List::Layout List::computeLayout() {
|
List::Layout List::computeLayout() {
|
||||||
const auto &st = _st.small;
|
const auto &st = _st.small;
|
||||||
const auto &full = _st.full;
|
const auto &full = _st.full;
|
||||||
const auto shownHeight = std::max(_shownHeight(), st.height);
|
const auto use = _lastExpandedHeight
|
||||||
if (_lastHeight != shownHeight) {
|
* _expandCatchUpAnimation.value(1.);
|
||||||
_lastHeight = shownHeight;
|
updateExpanding(use, full.height);
|
||||||
if (_lastHeight == st.height || _lastHeight == full.height) {
|
|
||||||
_snapExpandedTimer.cancel();
|
|
||||||
} else if (!_touchScrollActive) {
|
|
||||||
_snapExpandedTimer.callOnce(kSnapExpandedTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateExpanding(st.height, shownHeight, full.height);
|
|
||||||
|
|
||||||
const auto expanded = _expandedAnimation.value(_expanded ? 1. : 0.);
|
const auto expanded = _expandedAnimation.value(_expanded ? 1. : 0.);
|
||||||
const auto expandedRatio = float64(shownHeight - st.height)
|
const auto expandedRatio = _lastRatio;
|
||||||
/ (full.height - st.height);
|
|
||||||
const auto collapsedRatio = expandedRatio * kFrictionRatio;
|
const auto collapsedRatio = expandedRatio * kFrictionRatio;
|
||||||
const auto ratio = expandedRatio * expanded
|
const auto ratio = expandedRatio * expanded
|
||||||
+ collapsedRatio * (1. - expanded);
|
+ collapsedRatio * (1. - expanded);
|
||||||
|
@ -323,7 +314,7 @@ List::Layout List::computeLayout() {
|
||||||
const auto narrowWidth = st::defaultDialogRow.padding.left()
|
const auto narrowWidth = st::defaultDialogRow.padding.left()
|
||||||
+ st::defaultDialogRow.photoSize
|
+ st::defaultDialogRow.photoSize
|
||||||
+ st::defaultDialogRow.padding.left();
|
+ st::defaultDialogRow.padding.left();
|
||||||
const auto narrow = (width() <= narrowWidth);
|
const auto narrow = false;// (width() <= narrowWidth);
|
||||||
const auto smallSkip = (itemsCount > 1
|
const auto smallSkip = (itemsCount > 1
|
||||||
&& rendering.items[0].element.skipSmall)
|
&& rendering.items[0].element.skipSmall)
|
||||||
? 1
|
? 1
|
||||||
|
@ -352,7 +343,6 @@ List::Layout List::computeLayout() {
|
||||||
const auto photoLeft = lerp(st.photoLeft, full.photoLeft);
|
const auto photoLeft = lerp(st.photoLeft, full.photoLeft);
|
||||||
return Layout{
|
return Layout{
|
||||||
.itemsCount = itemsCount,
|
.itemsCount = itemsCount,
|
||||||
.shownHeight = shownHeight,
|
|
||||||
.expandedRatio = expandedRatio,
|
.expandedRatio = expandedRatio,
|
||||||
.ratio = ratio,
|
.ratio = ratio,
|
||||||
.thumbnailLeft = thumbnailLeft,
|
.thumbnailLeft = thumbnailLeft,
|
||||||
|
@ -391,14 +381,14 @@ void List::paintEvent(QPaintEvent *e) {
|
||||||
auto &rendering = _data.empty() ? _hidingData : _data;
|
auto &rendering = _data.empty() ? _hidingData : _data;
|
||||||
const auto line = elerp(st.lineTwice, full.lineTwice) / 2.;
|
const auto line = elerp(st.lineTwice, full.lineTwice) / 2.;
|
||||||
const auto lineRead = elerp(st.lineReadTwice, full.lineReadTwice) / 2.;
|
const auto lineRead = elerp(st.lineReadTwice, full.lineReadTwice) / 2.;
|
||||||
const auto photoTopSmall = (st.height - st.photo) / 2.;
|
const auto photoTopSmall = st.photoTop;
|
||||||
const auto photoTop = photoTopSmall
|
const auto photoTop = photoTopSmall
|
||||||
+ (full.photoTop - photoTopSmall) * layout.expandedRatio;
|
+ (full.photoTop - photoTopSmall) * layout.expandedRatio;
|
||||||
const auto photo = lerp(st.photo, full.photo);
|
const auto photo = lerp(st.photo, full.photo);
|
||||||
const auto summaryTop = st.nameTop
|
const auto summaryTop = st.nameTop
|
||||||
- (st.photoTop + (st.photo / 2.))
|
- (st.photoTop + (st.photo / 2.))
|
||||||
+ (photoTop + (photo / 2.));
|
+ (photoTop + (photo / 2.));
|
||||||
const auto nameScale = layout.shownHeight / float64(full.height);
|
const auto nameScale = _lastRatio;
|
||||||
const auto nameTop = nameScale * full.nameTop;
|
const auto nameTop = nameScale * full.nameTop;
|
||||||
const auto nameWidth = nameScale * AvailableNameWidth(_st);
|
const auto nameWidth = nameScale * AvailableNameWidth(_st);
|
||||||
const auto nameHeight = nameScale * full.nameStyle.font->height;
|
const auto nameHeight = nameScale * full.nameStyle.font->height;
|
||||||
|
@ -407,8 +397,18 @@ void List::paintEvent(QPaintEvent *e) {
|
||||||
const auto readUserpicAppearingOpacity = elerp(_st.readOpacity, 0.);
|
const auto readUserpicAppearingOpacity = elerp(_st.readOpacity, 0.);
|
||||||
|
|
||||||
auto p = QPainter(this);
|
auto p = QPainter(this);
|
||||||
p.fillRect(e->rect(), _bgOverride.value_or(_st.bg));
|
|
||||||
p.translate(0, height() - layout.shownHeight);
|
if (_state == State::Changing) {
|
||||||
|
const auto left = anim::interpolate(
|
||||||
|
_changingGeometryFrom.x(),
|
||||||
|
_geometryFull.x(),
|
||||||
|
layout.expandedRatio);
|
||||||
|
const auto top = anim::interpolate(
|
||||||
|
_changingGeometryFrom.y(),
|
||||||
|
_geometryFull.y(),
|
||||||
|
layout.expandedRatio);
|
||||||
|
p.translate(QPoint(left, top) - pos());
|
||||||
|
}
|
||||||
|
|
||||||
const auto drawSmall = (expandRatio < 1.);
|
const auto drawSmall = (expandRatio < 1.);
|
||||||
const auto drawFull = (expandRatio > 0.);
|
const auto drawFull = (expandRatio > 0.);
|
||||||
|
@ -691,6 +691,7 @@ void List::paintSummary(
|
||||||
Data &data,
|
Data &data,
|
||||||
float64 summaryTop,
|
float64 summaryTop,
|
||||||
float64 hidden) {
|
float64 hidden) {
|
||||||
|
#if 0 // #TODO stories to-remove
|
||||||
const auto total = int(data.items.size());
|
const auto total = int(data.items.size());
|
||||||
auto &summary = ChooseSummary(
|
auto &summary = ChooseSummary(
|
||||||
_st.small,
|
_st.small,
|
||||||
|
@ -723,6 +724,7 @@ void List::paintSummary(
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QRectF(left, summaryTop, summaryWidth, summaryHeight),
|
QRectF(left, summaryTop, summaryWidth, summaryHeight),
|
||||||
summary.cache);
|
summary.cache);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::wheelEvent(QWheelEvent *e) {
|
void List::wheelEvent(QWheelEvent *e) {
|
||||||
|
@ -767,12 +769,9 @@ void List::mouseMoveEvent(QMouseEvent *e) {
|
||||||
_lastMousePosition = e->globalPos();
|
_lastMousePosition = e->globalPos();
|
||||||
updateSelected();
|
updateSelected();
|
||||||
|
|
||||||
if (!_dragging && _mouseDownPosition) {
|
if (!_dragging && _mouseDownPosition && _state == State::Full) {
|
||||||
if ((_lastMousePosition - *_mouseDownPosition).manhattanLength()
|
if ((_lastMousePosition - *_mouseDownPosition).manhattanLength()
|
||||||
>= QApplication::startDragDistance()) {
|
>= QApplication::startDragDistance()) {
|
||||||
if (_shownHeight() < _st.full.height) {
|
|
||||||
requestExpanded(true);
|
|
||||||
}
|
|
||||||
_dragging = true;
|
_dragging = true;
|
||||||
_startDraggingLeft = _scrollLeft;
|
_startDraggingLeft = _scrollLeft;
|
||||||
}
|
}
|
||||||
|
@ -822,19 +821,82 @@ void List::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::setBgOverride(QBrush brush) {
|
void List::setExpandedHeight(int height, bool momentum) {
|
||||||
_bgOverride = std::move(brush);
|
height = std::clamp(height, 0, _st.full.height);
|
||||||
|
if (_lastExpandedHeight == height) {
|
||||||
|
return;
|
||||||
|
} else if (momentum && _expandIgnored) {
|
||||||
|
return;
|
||||||
|
} else if (momentum && height > 0 && !_lastExpandedHeight) {
|
||||||
|
_expandIgnored = true;
|
||||||
|
return;
|
||||||
|
} else if (!momentum && _expandIgnored && height > 0) {
|
||||||
|
_expandIgnored = false;
|
||||||
|
_expandCatchUpAnimation.start([=] {
|
||||||
|
update();
|
||||||
|
if (!_expandCatchUpAnimation.animating()
|
||||||
|
&& _lastExpandedHeight == _st.full.height) {
|
||||||
|
setState(State::Full);
|
||||||
|
}
|
||||||
|
}, 0., 1., kExpandCatchUpDuration);
|
||||||
|
} else if (!height && _expandCatchUpAnimation.animating()) {
|
||||||
|
_expandCatchUpAnimation.stop();
|
||||||
|
}
|
||||||
|
_lastExpandedHeight = height;
|
||||||
|
setState(!height
|
||||||
|
? State::Small
|
||||||
|
: (height < _st.full.height
|
||||||
|
|| _expandCatchUpAnimation.animating()
|
||||||
|
|| _expandedAnimation.animating())
|
||||||
|
? State::Changing
|
||||||
|
: State::Full);
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::setTouchScrollActive(bool active) {
|
void List::setLayoutConstraints(QPoint topRightSmall, QRect geometryFull) {
|
||||||
if (_touchScrollActive != active) {
|
_topRightSmall = topRightSmall;
|
||||||
_touchScrollActive = active;
|
_geometryFull = geometryFull;
|
||||||
if (active) {
|
updateGeometry();
|
||||||
_snapExpandedTimer.cancel();
|
update();
|
||||||
} else {
|
}
|
||||||
requestExpanded(_expanded);
|
|
||||||
}
|
void List::updateGeometry() {
|
||||||
|
switch (_state) {
|
||||||
|
case State::Small: setGeometry(countSmallGeometry()); break;
|
||||||
|
case State::Changing: {
|
||||||
|
_changingGeometryFrom = countSmallGeometry();
|
||||||
|
setGeometry(_geometryFull.united(_changingGeometryFrom));
|
||||||
|
} break;
|
||||||
|
case State::Full: setGeometry(_geometryFull);
|
||||||
}
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect List::countSmallGeometry() const {
|
||||||
|
const auto &st = _st.small;
|
||||||
|
const auto layout = const_cast<List*>(this)->computeLayout();
|
||||||
|
const auto count = layout.endIndexSmall - layout.startIndexSmall;
|
||||||
|
const auto width = st.left
|
||||||
|
+ st.photoLeft
|
||||||
|
+ st.photo + (count - 1) * st.shift
|
||||||
|
+ st.photoLeft
|
||||||
|
+ st.left;
|
||||||
|
return QRect(
|
||||||
|
_topRightSmall.x() - width,
|
||||||
|
_topRightSmall.y(),
|
||||||
|
width,
|
||||||
|
st.photoTop + st.photo + st.photoTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::setState(State state) {
|
||||||
|
if (_state == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_state = state;
|
||||||
|
setAttribute(
|
||||||
|
Qt::WA_TransparentForMouseEvents,
|
||||||
|
state == State::Changing);
|
||||||
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::contextMenuEvent(QContextMenuEvent *e) {
|
void List::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
|
|
|
@ -63,11 +63,10 @@ public:
|
||||||
List(
|
List(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
const style::DialogsStoriesList &st,
|
const style::DialogsStoriesList &st,
|
||||||
rpl::producer<Content> content,
|
rpl::producer<Content> content);
|
||||||
Fn<int()> shownHeight);
|
|
||||||
|
|
||||||
void setBgOverride(QBrush brush);
|
void setExpandedHeight(int height, bool momentum = false);
|
||||||
void setTouchScrollActive(bool active);
|
void setLayoutConstraints(QPoint topRightSmall, QRect geometryFull);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<uint64> clicks() const;
|
[[nodiscard]] rpl::producer<uint64> clicks() const;
|
||||||
[[nodiscard]] rpl::producer<ShowMenuRequest> showMenuRequests() const;
|
[[nodiscard]] rpl::producer<ShowMenuRequest> showMenuRequests() const;
|
||||||
|
@ -77,6 +76,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Layout;
|
struct Layout;
|
||||||
|
enum class State {
|
||||||
|
Small,
|
||||||
|
Changing,
|
||||||
|
Full,
|
||||||
|
};
|
||||||
struct Item {
|
struct Item {
|
||||||
Element element;
|
Element element;
|
||||||
QImage nameCache;
|
QImage nameCache;
|
||||||
|
@ -149,7 +153,10 @@ private:
|
||||||
void checkLoadMore();
|
void checkLoadMore();
|
||||||
void requestExpanded(bool expanded);
|
void requestExpanded(bool expanded);
|
||||||
|
|
||||||
void updateExpanding(int minHeight, int shownHeight, int fullHeight);
|
void setState(State state);
|
||||||
|
void updateGeometry();
|
||||||
|
[[nodiscard]] QRect countSmallGeometry() const;
|
||||||
|
void updateExpanding(int expandingHeight, int expandedHeight);
|
||||||
void updateHeight();
|
void updateHeight();
|
||||||
void toggleAnimated(bool shown);
|
void toggleAnimated(bool shown);
|
||||||
void paintSummary(
|
void paintSummary(
|
||||||
|
@ -164,14 +171,17 @@ private:
|
||||||
Content _content;
|
Content _content;
|
||||||
Data _data;
|
Data _data;
|
||||||
Data _hidingData;
|
Data _hidingData;
|
||||||
Fn<int()> _shownHeight = 0;
|
|
||||||
rpl::event_stream<uint64> _clicks;
|
rpl::event_stream<uint64> _clicks;
|
||||||
rpl::event_stream<ShowMenuRequest> _showMenuRequests;
|
rpl::event_stream<ShowMenuRequest> _showMenuRequests;
|
||||||
rpl::event_stream<bool> _toggleExpandedRequests;
|
rpl::event_stream<bool> _toggleExpandedRequests;
|
||||||
rpl::event_stream<> _entered;
|
rpl::event_stream<> _entered;
|
||||||
rpl::event_stream<> _loadMoreRequests;
|
rpl::event_stream<> _loadMoreRequests;
|
||||||
|
|
||||||
std::optional<QBrush> _bgOverride;
|
QPoint _topRightSmall;
|
||||||
|
QRect _geometryFull;
|
||||||
|
QRect _changingGeometryFrom;
|
||||||
|
State _state = State::Small;
|
||||||
|
|
||||||
Ui::Animations::Simple _shownAnimation;
|
Ui::Animations::Simple _shownAnimation;
|
||||||
|
|
||||||
QPoint _lastMousePosition;
|
QPoint _lastMousePosition;
|
||||||
|
@ -182,11 +192,11 @@ private:
|
||||||
bool _dragging = false;
|
bool _dragging = false;
|
||||||
|
|
||||||
Ui::Animations::Simple _expandedAnimation;
|
Ui::Animations::Simple _expandedAnimation;
|
||||||
base::Timer _snapExpandedTimer;
|
Ui::Animations::Simple _expandCatchUpAnimation;
|
||||||
float64 _lastRatio = 0.;
|
float64 _lastRatio = 0.;
|
||||||
int _lastHeight = 0;
|
int _lastExpandedHeight = 0;
|
||||||
bool _expanded = false;
|
bool _expandIgnored : 1 = false;
|
||||||
bool _touchScrollActive = false;
|
bool _expanded : 1 = false;
|
||||||
|
|
||||||
int _selected = -1;
|
int _selected = -1;
|
||||||
int _pressed = -1;
|
int _pressed = -1;
|
||||||
|
|
|
@ -465,8 +465,7 @@ void TopBar::setStories(rpl::producer<Dialogs::Stories::Content> content) {
|
||||||
last
|
last
|
||||||
) | rpl::filter([](const Content &content) {
|
) | rpl::filter([](const Content &content) {
|
||||||
return !content.elements.empty();
|
return !content.elements.empty();
|
||||||
}),
|
})),
|
||||||
[] { return st::dialogsStories.height; }),
|
|
||||||
st::infoTopBarScale);
|
st::infoTopBarScale);
|
||||||
registerToggleControlCallback(
|
registerToggleControlCallback(
|
||||||
stories,
|
stories,
|
||||||
|
|
|
@ -170,8 +170,7 @@ void InnerWidget::createButtons() {
|
||||||
st::dialogsStoriesListMine,
|
st::dialogsStoriesListMine,
|
||||||
rpl::duplicate(last) | rpl::filter([](const Content &content) {
|
rpl::duplicate(last) | rpl::filter([](const Content &content) {
|
||||||
return !content.elements.empty();
|
return !content.elements.empty();
|
||||||
}),
|
}));
|
||||||
[] { return st::dialogsStories.height; });
|
|
||||||
thumbs->show();
|
thumbs->show();
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
recent->sizeValue(),
|
recent->sizeValue(),
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7135f3ed87ee1a6d89cebe6510a2250ffedfb1a9
|
Subproject commit 80308cea4f57fd13e73abec121325f174ba21883
|
Loading…
Reference in New Issue
Block a user