mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show active stories in profile top bar.
This commit is contained in:
parent
738e20252e
commit
d2dd63e90a
9 changed files with 143 additions and 8 deletions
|
@ -505,6 +505,7 @@ DialogsStoriesList {
|
||||||
full: DialogsStories;
|
full: DialogsStories;
|
||||||
bg: color;
|
bg: color;
|
||||||
readOpacity: double;
|
readOpacity: double;
|
||||||
|
fullClickable: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogsStories: DialogsStories {
|
dialogsStories: DialogsStories {
|
||||||
|
@ -544,9 +545,11 @@ dialogsStoriesList: DialogsStoriesList {
|
||||||
full: dialogsStoriesFull;
|
full: dialogsStoriesFull;
|
||||||
bg: dialogsBg;
|
bg: dialogsBg;
|
||||||
readOpacity: 0.6;
|
readOpacity: 0.6;
|
||||||
|
fullClickable: 0;
|
||||||
}
|
}
|
||||||
dialogsStoriesListInfo: DialogsStoriesList(dialogsStoriesList) {
|
dialogsStoriesListInfo: DialogsStoriesList(dialogsStoriesList) {
|
||||||
bg: transparent;
|
bg: transparent;
|
||||||
|
fullClickable: 1;
|
||||||
}
|
}
|
||||||
dialogsStoriesListMine: DialogsStoriesList(dialogsStoriesListInfo) {
|
dialogsStoriesListMine: DialogsStoriesList(dialogsStoriesListInfo) {
|
||||||
readOpacity: 1.;
|
readOpacity: 1.;
|
||||||
|
|
|
@ -846,7 +846,7 @@ void List::updateSelected() {
|
||||||
+ lastRightAdd)
|
+ lastRightAdd)
|
||||||
? (infiniteIndex - 1) // Last small part should still be clickable.
|
? (infiniteIndex - 1) // Last small part should still be clickable.
|
||||||
: (startIndex + infiniteIndex >= endIndex)
|
: (startIndex + infiniteIndex >= endIndex)
|
||||||
? -1
|
? (_st.fullClickable ? (endIndex - 1) : -1)
|
||||||
: infiniteIndex;
|
: infiniteIndex;
|
||||||
const auto selected = (index < 0
|
const auto selected = (index < 0
|
||||||
|| startIndex + index >= layout.itemsCount)
|
|| startIndex + index >= layout.itemsCount)
|
||||||
|
|
|
@ -273,6 +273,11 @@ void ContentWidget::setViewport(
|
||||||
}, _scroll->lifetime());
|
}, _scroll->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ContentWidget::titleStories()
|
||||||
|
-> rpl::producer<Dialogs::Stories::Content> {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void ContentWidget::saveChanges(FnMut<void()> done) {
|
void ContentWidget::saveChanges(FnMut<void()> done) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
#include "info/info_wrap_widget.h"
|
#include "info/info_wrap_widget.h"
|
||||||
|
|
||||||
|
namespace Dialogs::Stories {
|
||||||
|
struct Content;
|
||||||
|
} // namespace Dialogs::Stories
|
||||||
|
|
||||||
namespace Storage {
|
namespace Storage {
|
||||||
enum class SharedMediaType : signed char;
|
enum class SharedMediaType : signed char;
|
||||||
} // namespace Storage
|
} // namespace Storage
|
||||||
|
@ -88,6 +92,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] virtual rpl::producer<QString> title() = 0;
|
[[nodiscard]] virtual rpl::producer<QString> title() = 0;
|
||||||
|
[[nodiscard]] virtual auto titleStories()
|
||||||
|
-> rpl::producer<Dialogs::Stories::Content>;
|
||||||
|
|
||||||
virtual void saveChanges(FnMut<void()> done);
|
virtual void saveChanges(FnMut<void()> done);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include <rpl/never.h>
|
#include <rpl/never.h>
|
||||||
#include <rpl/merge.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_keys.h"
|
||||||
#include "lang/lang_numbers_animation.h"
|
#include "lang/lang_numbers_animation.h"
|
||||||
#include "info/info_wrap_widget.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_session.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_info.h"
|
#include "styles/style_info.h"
|
||||||
|
|
||||||
namespace Info {
|
namespace Info {
|
||||||
|
@ -88,9 +91,11 @@ void TopBar::setTitle(rpl::producer<QString> &&title) {
|
||||||
object_ptr<Ui::FlatLabel>(this, std::move(title), _st.title),
|
object_ptr<Ui::FlatLabel>(this, std::move(title), _st.title),
|
||||||
st::infoTopBarScale);
|
st::infoTopBarScale);
|
||||||
_title->setDuration(st::infoTopBarDuration);
|
_title->setDuration(st::infoTopBarDuration);
|
||||||
_title->toggle(!selectionMode(), anim::type::instant);
|
_title->toggle(
|
||||||
|
!selectionMode() && !storiesTitle(),
|
||||||
|
anim::type::instant);
|
||||||
registerToggleControlCallback(_title.data(), [=] {
|
registerToggleControlCallback(_title.data(), [=] {
|
||||||
return !selectionMode() && !searchMode();
|
return !selectionMode() && !storiesTitle() && !searchMode();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (_back) {
|
if (_back) {
|
||||||
|
@ -309,12 +314,15 @@ int TopBar::resizeGetHeight(int newWidth) {
|
||||||
void TopBar::updateControlsGeometry(int newWidth) {
|
void TopBar::updateControlsGeometry(int newWidth) {
|
||||||
updateDefaultControlsGeometry(newWidth);
|
updateDefaultControlsGeometry(newWidth);
|
||||||
updateSelectionControlsGeometry(newWidth);
|
updateSelectionControlsGeometry(newWidth);
|
||||||
|
updateStoriesGeometry(newWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TopBar::updateDefaultControlsGeometry(int newWidth) {
|
void TopBar::updateDefaultControlsGeometry(int newWidth) {
|
||||||
auto right = 0;
|
auto right = 0;
|
||||||
for (auto &button : _buttons) {
|
for (auto &button : _buttons) {
|
||||||
if (!button) continue;
|
if (!button) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
button->moveToRight(right, 0, newWidth);
|
button->moveToRight(right, 0, newWidth);
|
||||||
right += button->width();
|
right += button->width();
|
||||||
}
|
}
|
||||||
|
@ -362,6 +370,28 @@ void TopBar::updateSelectionControlsGeometry(int newWidth) {
|
||||||
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) {
|
void TopBar::paintEvent(QPaintEvent *e) {
|
||||||
auto p = QPainter(this);
|
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) {
|
void TopBar::setSelectedItems(SelectedItems &&items) {
|
||||||
auto wasSelectionMode = selectionMode();
|
auto wasSelectionMode = selectionMode();
|
||||||
_selectedItems = std::move(items);
|
_selectedItems = std::move(items);
|
||||||
|
@ -550,6 +634,10 @@ bool TopBar::selectionMode() const {
|
||||||
return !_selectedItems.list.empty();
|
return !_selectedItems.list.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TopBar::storiesTitle() const {
|
||||||
|
return _storiesCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool TopBar::searchMode() const {
|
bool TopBar::searchMode() const {
|
||||||
return _searchModeAvailable && _searchModeEnabled;
|
return _searchModeAvailable && _searchModeEnabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,11 @@ namespace style {
|
||||||
struct InfoTopBar;
|
struct InfoTopBar;
|
||||||
} // namespace style
|
} // namespace style
|
||||||
|
|
||||||
|
namespace Dialogs::Stories {
|
||||||
|
class List;
|
||||||
|
struct Content;
|
||||||
|
} // namespace Dialogs::Stories
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
class SessionNavigation;
|
class SessionNavigation;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
@ -43,11 +48,15 @@ public:
|
||||||
const style::InfoTopBar &st,
|
const style::InfoTopBar &st,
|
||||||
SelectedItems &&items);
|
SelectedItems &&items);
|
||||||
|
|
||||||
auto backRequest() const {
|
[[nodiscard]] auto backRequest() const {
|
||||||
return _backClicks.events();
|
return _backClicks.events();
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] auto storyClicks() const {
|
||||||
|
return _storyClicks.events();
|
||||||
|
}
|
||||||
|
|
||||||
void setTitle(rpl::producer<QString> &&title);
|
void setTitle(rpl::producer<QString> &&title);
|
||||||
|
void setStories(rpl::producer<Dialogs::Stories::Content> content);
|
||||||
void enableBackButton();
|
void enableBackButton();
|
||||||
void highlight();
|
void highlight();
|
||||||
|
|
||||||
|
@ -95,6 +104,7 @@ private:
|
||||||
void updateControlsGeometry(int newWidth);
|
void updateControlsGeometry(int newWidth);
|
||||||
void updateDefaultControlsGeometry(int newWidth);
|
void updateDefaultControlsGeometry(int newWidth);
|
||||||
void updateSelectionControlsGeometry(int newWidth);
|
void updateSelectionControlsGeometry(int newWidth);
|
||||||
|
void updateStoriesGeometry(int newWidth);
|
||||||
Ui::FadeWrap<Ui::RpWidget> *pushButton(
|
Ui::FadeWrap<Ui::RpWidget> *pushButton(
|
||||||
base::unique_qptr<Ui::RpWidget> button);
|
base::unique_qptr<Ui::RpWidget> button);
|
||||||
void forceButtonVisibility(
|
void forceButtonVisibility(
|
||||||
|
@ -104,9 +114,10 @@ private:
|
||||||
void startHighlightAnimation();
|
void startHighlightAnimation();
|
||||||
void updateControlsVisibility(anim::type animated);
|
void updateControlsVisibility(anim::type animated);
|
||||||
|
|
||||||
bool selectionMode() const;
|
[[nodiscard]] bool selectionMode() const;
|
||||||
bool searchMode() const;
|
[[nodiscard]] bool storiesTitle() const;
|
||||||
Ui::StringWithNumbers generateSelectedText() const;
|
[[nodiscard]] bool searchMode() const;
|
||||||
|
[[nodiscard]] Ui::StringWithNumbers generateSelectedText() const;
|
||||||
[[nodiscard]] bool computeCanDelete() const;
|
[[nodiscard]] bool computeCanDelete() const;
|
||||||
[[nodiscard]] bool computeCanForward() const;
|
[[nodiscard]] bool computeCanForward() const;
|
||||||
void updateSelectionState();
|
void updateSelectionState();
|
||||||
|
@ -147,6 +158,7 @@ private:
|
||||||
QPointer<Ui::InputField> _searchField;
|
QPointer<Ui::InputField> _searchField;
|
||||||
|
|
||||||
rpl::event_stream<> _backClicks;
|
rpl::event_stream<> _backClicks;
|
||||||
|
rpl::event_stream<uint64> _storyClicks;
|
||||||
|
|
||||||
SelectedItems _selectedItems;
|
SelectedItems _selectedItems;
|
||||||
bool _canDelete = false;
|
bool _canDelete = false;
|
||||||
|
@ -157,6 +169,10 @@ private:
|
||||||
QPointer<Ui::FadeWrap<Ui::IconButton>> _delete;
|
QPointer<Ui::FadeWrap<Ui::IconButton>> _delete;
|
||||||
rpl::event_stream<SelectionAction> _selectionActionRequests;
|
rpl::event_stream<SelectionAction> _selectionActionRequests;
|
||||||
|
|
||||||
|
QPointer<Ui::FadeWrap<Dialogs::Stories::List>> _stories;
|
||||||
|
rpl::lifetime _storiesLifetime;
|
||||||
|
int _storiesCount = 0;
|
||||||
|
|
||||||
using UpdateCallback = Fn<bool(anim::type)>;
|
using UpdateCallback = Fn<bool(anim::type)>;
|
||||||
std::map<QObject*, UpdateCallback> _updateControlCallbacks;
|
std::map<QObject*, UpdateCallback> _updateControlCallbacks;
|
||||||
|
|
||||||
|
|
|
@ -303,6 +303,11 @@ void WrapWidget::createTopBar() {
|
||||||
_controller->parentController()->closeThirdSection();
|
_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) {
|
if (wrapValue == Wrap::Layer) {
|
||||||
auto close = _topBar->addButton(
|
auto close = _topBar->addButton(
|
||||||
base::make_unique_q<Ui::IconButton>(
|
base::make_unique_q<Ui::IconButton>(
|
||||||
|
@ -579,6 +584,7 @@ void WrapWidget::finishShowContent() {
|
||||||
_content->setIsStackBottom(!hasStackHistory());
|
_content->setIsStackBottom(!hasStackHistory());
|
||||||
if (_topBar) {
|
if (_topBar) {
|
||||||
_topBar->setTitle(_content->title());
|
_topBar->setTitle(_content->title());
|
||||||
|
_topBar->setStories(_content->titleStories());
|
||||||
}
|
}
|
||||||
_desiredHeights.fire(desiredHeightForContent());
|
_desiredHeights.fire(desiredHeightForContent());
|
||||||
_desiredShadowVisibilities.fire(_content->desiredShadowVisibility());
|
_desiredShadowVisibilities.fire(_content->desiredShadowVisibility());
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "info/profile/info_profile_widget.h"
|
#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_inner_widget.h"
|
||||||
#include "info/profile/info_profile_members.h"
|
#include "info/profile/info_profile_members.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
@ -105,7 +106,16 @@ rpl::producer<QString> Widget::title() {
|
||||||
return tr::lng_info_group_title();
|
return tr::lng_info_group_title();
|
||||||
}
|
}
|
||||||
Unexpected("Bad peer type in Info::TitleValue()");
|
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) {
|
bool Widget::showInternal(not_null<ContentMemento*> memento) {
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
void setInnerFocus() override;
|
void setInnerFocus() override;
|
||||||
|
|
||||||
rpl::producer<QString> title() override;
|
rpl::producer<QString> title() override;
|
||||||
|
rpl::producer<Dialogs::Stories::Content> titleStories() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void saveState(not_null<Memento*> memento);
|
void saveState(not_null<Memento*> memento);
|
||||||
|
|
Loading…
Add table
Reference in a new issue