Show active stories in profile top bar.

This commit is contained in:
John Preston 2023-06-20 19:31:40 +04:00
parent 738e20252e
commit d2dd63e90a
9 changed files with 143 additions and 8 deletions

View File

@ -505,6 +505,7 @@ DialogsStoriesList {
full: DialogsStories;
bg: color;
readOpacity: double;
fullClickable: int;
}
dialogsStories: DialogsStories {
@ -544,9 +545,11 @@ dialogsStoriesList: DialogsStoriesList {
full: dialogsStoriesFull;
bg: dialogsBg;
readOpacity: 0.6;
fullClickable: 0;
}
dialogsStoriesListInfo: DialogsStoriesList(dialogsStoriesList) {
bg: transparent;
fullClickable: 1;
}
dialogsStoriesListMine: DialogsStoriesList(dialogsStoriesListInfo) {
readOpacity: 1.;

View File

@ -846,7 +846,7 @@ void List::updateSelected() {
+ lastRightAdd)
? (infiniteIndex - 1) // Last small part should still be clickable.
: (startIndex + infiniteIndex >= endIndex)
? -1
? (_st.fullClickable ? (endIndex - 1) : -1)
: infiniteIndex;
const auto selected = (index < 0
|| startIndex + index >= layout.itemsCount)

View File

@ -273,6 +273,11 @@ void ContentWidget::setViewport(
}, _scroll->lifetime());
}
auto ContentWidget::titleStories()
-> rpl::producer<Dialogs::Stories::Content> {
return nullptr;
}
void ContentWidget::saveChanges(FnMut<void()> done) {
done();
}

View File

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h"
#include "info/info_wrap_widget.h"
namespace Dialogs::Stories {
struct Content;
} // namespace Dialogs::Stories
namespace Storage {
enum class SharedMediaType : signed char;
} // namespace Storage
@ -88,6 +92,8 @@ public:
}
[[nodiscard]] virtual rpl::producer<QString> title() = 0;
[[nodiscard]] virtual auto titleStories()
-> rpl::producer<Dialogs::Stories::Content>;
virtual void saveChanges(FnMut<void()> done);

View File

@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/never.h>
#include <rpl/merge.h>
#include "dialogs/ui/dialogs_stories_content.h"
#include "dialogs/ui/dialogs_stories_list.h"
#include "lang/lang_keys.h"
#include "lang/lang_numbers_animation.h"
#include "info/info_wrap_widget.h"
@ -30,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_channel.h"
#include "data/data_user.h"
#include "styles/style_dialogs.h"
#include "styles/style_info.h"
namespace Info {
@ -88,9 +91,11 @@ void TopBar::setTitle(rpl::producer<QString> &&title) {
object_ptr<Ui::FlatLabel>(this, std::move(title), _st.title),
st::infoTopBarScale);
_title->setDuration(st::infoTopBarDuration);
_title->toggle(!selectionMode(), anim::type::instant);
_title->toggle(
!selectionMode() && !storiesTitle(),
anim::type::instant);
registerToggleControlCallback(_title.data(), [=] {
return !selectionMode() && !searchMode();
return !selectionMode() && !storiesTitle() && !searchMode();
});
if (_back) {
@ -309,12 +314,15 @@ int TopBar::resizeGetHeight(int newWidth) {
void TopBar::updateControlsGeometry(int newWidth) {
updateDefaultControlsGeometry(newWidth);
updateSelectionControlsGeometry(newWidth);
updateStoriesGeometry(newWidth);
}
void TopBar::updateDefaultControlsGeometry(int newWidth) {
auto right = 0;
for (auto &button : _buttons) {
if (!button) continue;
if (!button) {
continue;
}
button->moveToRight(right, 0, newWidth);
right += button->width();
}
@ -362,6 +370,28 @@ void TopBar::updateSelectionControlsGeometry(int newWidth) {
newWidth);
}
void TopBar::updateStoriesGeometry(int newWidth) {
if (!_stories) {
return;
}
auto right = 0;
for (auto &button : _buttons) {
if (!button) {
continue;
}
button->moveToRight(right, 0, newWidth);
right += button->width();
}
const auto left = (_back ? _st.back.width : _st.titlePosition.x())
- st::dialogsStories.left - st::dialogsStories.photoLeft;
const auto top = st::dialogsStories.height
- st::dialogsStoriesFull.height
+ (_st.height - st::dialogsStories.height) / 2;
_stories->resizeToWidth(newWidth - left - right);
_stories->moveToLeft(left, top, newWidth);
}
void TopBar::paintEvent(QPaintEvent *e) {
auto p = QPainter(this);
@ -412,6 +442,60 @@ void TopBar::updateControlsVisibility(anim::type animated) {
}
}
void TopBar::setStories(rpl::producer<Dialogs::Stories::Content> content) {
_storiesLifetime.destroy();
if (content) {
using namespace Dialogs::Stories;
auto last = std::move(
content
) | rpl::start_spawning(_storiesLifetime);
delete _stories;
const auto stories = Ui::CreateChild<Ui::FadeWrap<List>>(
this,
object_ptr<List>(
this,
st::dialogsStoriesListInfo,
rpl::duplicate(
last
) | rpl::filter([](const Content &content) {
return !content.elements.empty();
}),
[] { return st::dialogsStories.height; }),
st::infoTopBarScale);
registerToggleControlCallback(
stories,
[this] { return _storiesCount > 0; });
stories->toggle(false, anim::type::instant);
stories->setDuration(st::infoTopBarDuration);
_stories = stories;
_stories->entity()->clicks(
) | rpl::start_to_stream(_storyClicks, _stories->lifetime());
if (_back) {
_back->raise();
}
rpl::duplicate(
last
) | rpl::start_with_next([=](const Content &content) {
const auto count = int(content.elements.size());
if (_storiesCount != count) {
const auto was = (_storiesCount > 0);
_storiesCount = count;
const auto now = (_storiesCount > 0);
if (was != now) {
updateControlsVisibility(anim::type::normal);
}
updateControlsGeometry(width());
}
}, _storiesLifetime);
} else {
_storiesCount = 0;
}
updateControlsVisibility(anim::type::instant);
}
void TopBar::setSelectedItems(SelectedItems &&items) {
auto wasSelectionMode = selectionMode();
_selectedItems = std::move(items);
@ -550,6 +634,10 @@ bool TopBar::selectionMode() const {
return !_selectedItems.list.empty();
}
bool TopBar::storiesTitle() const {
return _storiesCount > 0;
}
bool TopBar::searchMode() const {
return _searchModeAvailable && _searchModeEnabled;
}

View File

@ -18,6 +18,11 @@ namespace style {
struct InfoTopBar;
} // namespace style
namespace Dialogs::Stories {
class List;
struct Content;
} // namespace Dialogs::Stories
namespace Window {
class SessionNavigation;
} // namespace Window
@ -43,11 +48,15 @@ public:
const style::InfoTopBar &st,
SelectedItems &&items);
auto backRequest() const {
[[nodiscard]] auto backRequest() const {
return _backClicks.events();
}
[[nodiscard]] auto storyClicks() const {
return _storyClicks.events();
}
void setTitle(rpl::producer<QString> &&title);
void setStories(rpl::producer<Dialogs::Stories::Content> content);
void enableBackButton();
void highlight();
@ -95,6 +104,7 @@ private:
void updateControlsGeometry(int newWidth);
void updateDefaultControlsGeometry(int newWidth);
void updateSelectionControlsGeometry(int newWidth);
void updateStoriesGeometry(int newWidth);
Ui::FadeWrap<Ui::RpWidget> *pushButton(
base::unique_qptr<Ui::RpWidget> button);
void forceButtonVisibility(
@ -104,9 +114,10 @@ private:
void startHighlightAnimation();
void updateControlsVisibility(anim::type animated);
bool selectionMode() const;
bool searchMode() const;
Ui::StringWithNumbers generateSelectedText() const;
[[nodiscard]] bool selectionMode() const;
[[nodiscard]] bool storiesTitle() const;
[[nodiscard]] bool searchMode() const;
[[nodiscard]] Ui::StringWithNumbers generateSelectedText() const;
[[nodiscard]] bool computeCanDelete() const;
[[nodiscard]] bool computeCanForward() const;
void updateSelectionState();
@ -147,6 +158,7 @@ private:
QPointer<Ui::InputField> _searchField;
rpl::event_stream<> _backClicks;
rpl::event_stream<uint64> _storyClicks;
SelectedItems _selectedItems;
bool _canDelete = false;
@ -157,6 +169,10 @@ private:
QPointer<Ui::FadeWrap<Ui::IconButton>> _delete;
rpl::event_stream<SelectionAction> _selectionActionRequests;
QPointer<Ui::FadeWrap<Dialogs::Stories::List>> _stories;
rpl::lifetime _storiesLifetime;
int _storiesCount = 0;
using UpdateCallback = Fn<bool(anim::type)>;
std::map<QObject*, UpdateCallback> _updateControlCallbacks;

View File

@ -303,6 +303,11 @@ void WrapWidget::createTopBar() {
_controller->parentController()->closeThirdSection();
});
}
_topBar->storyClicks() | rpl::start_with_next([=] {
if (const auto peer = _controller->key().peer()) {
_controller->parentController()->openPeerStories(peer->id);
}
}, _topBar->lifetime());
if (wrapValue == Wrap::Layer) {
auto close = _topBar->addButton(
base::make_unique_q<Ui::IconButton>(
@ -579,6 +584,7 @@ void WrapWidget::finishShowContent() {
_content->setIsStackBottom(!hasStackHistory());
if (_topBar) {
_topBar->setTitle(_content->title());
_topBar->setStories(_content->titleStories());
}
_desiredHeights.fire(desiredHeightForContent());
_desiredShadowVisibilities.fire(_content->desiredShadowVisibility());

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "info/profile/info_profile_widget.h"
#include "dialogs/ui/dialogs_stories_content.h"
#include "info/profile/info_profile_inner_widget.h"
#include "info/profile/info_profile_members.h"
#include "ui/widgets/scroll_area.h"
@ -105,7 +106,16 @@ rpl::producer<QString> Widget::title() {
return tr::lng_info_group_title();
}
Unexpected("Bad peer type in Info::TitleValue()");
}
rpl::producer<Dialogs::Stories::Content> Widget::titleStories() {
const auto peer = controller()->key().peer();
if (const auto user = peer->asUser()) {
if (!user->isBot()) {
return Dialogs::Stories::LastForPeer(user);
}
}
return nullptr;
}
bool Widget::showInternal(not_null<ContentMemento*> memento) {

View File

@ -60,6 +60,7 @@ public:
void setInnerFocus() override;
rpl::producer<QString> title() override;
rpl::producer<Dialogs::Stories::Content> titleStories() override;
private:
void saveState(not_null<Memento*> memento);