wip redesign info top bar
| Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 189 B | 
| Before Width: | Height: | Size: 398 B After Width: | Height: | Size: 351 B | 
| Before Width: | Height: | Size: 204 B After Width: | Height: | Size: 213 B | 
| Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 390 B | 
|  | @ -21,12 +21,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | |||
| #include "info/info_top_bar.h" | ||||
| 
 | ||||
| #include <rpl/never.h> | ||||
| #include <rpl/merge.h> | ||||
| #include "styles/style_info.h" | ||||
| #include "lang/lang_keys.h" | ||||
| #include "info/info_wrap_widget.h" | ||||
| #include "info/info_controller.h" | ||||
| #include "info/profile/info_profile_values.h" | ||||
| #include "storage/storage_shared_media.h" | ||||
| #include "boxes/confirm_box.h" | ||||
| #include "boxes/peer_list_controllers.h" | ||||
| #include "mainwidget.h" | ||||
| #include "ui/widgets/buttons.h" | ||||
| #include "ui/widgets/labels.h" | ||||
| #include "ui/widgets/input_fields.h" | ||||
|  | @ -37,30 +41,48 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | |||
| 
 | ||||
| namespace Info { | ||||
| 
 | ||||
| TopBar::TopBar(QWidget *parent, const style::InfoTopBar &st) | ||||
| TopBar::TopBar( | ||||
| 	QWidget *parent, | ||||
| 	const style::InfoTopBar &st, | ||||
| 	SelectedItems &&selectedItems) | ||||
| : RpWidget(parent) | ||||
| , _st(st) { | ||||
| , _st(st) | ||||
| , _selectedItems(Section::MediaType::kCount) { | ||||
| 	setAttribute(Qt::WA_OpaquePaintEvent); | ||||
| 	setSelectedItems(std::move(selectedItems)); | ||||
| 	finishSelectionAnimations(); | ||||
| } | ||||
| 
 | ||||
| void TopBar::setTitle(rpl::producer<QString> &&title) { | ||||
| 	_title.create(this, std::move(title), _st.title); | ||||
| 	if (_title) { | ||||
| 		delete _title; | ||||
| 	} | ||||
| 	_title = Ui::CreateChild<Ui::FadeWrapScaled<Ui::FlatLabel>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::FlatLabel>(this, std::move(title), _st.title)); | ||||
| 	_title->toggle(!selectionMode(), anim::type::instant); | ||||
| 	_defaultControls.push_back(_title.data()); | ||||
| 
 | ||||
| 	if (_back) { | ||||
| 		_title->setAttribute(Qt::WA_TransparentForMouseEvents); | ||||
| 	} | ||||
| 	updateControlsGeometry(width()); | ||||
| } | ||||
| 
 | ||||
| void TopBar::enableBackButton(bool enable) { | ||||
| 	if (enable) { | ||||
| 		_back.create(this, _st.back); | ||||
| 		_back->clicks() | ||||
| 			| rpl::start_to_stream(_backClicks, _back->lifetime()); | ||||
| 	} else { | ||||
| 		_back.destroy(); | ||||
| void TopBar::enableBackButton() { | ||||
| 	if (_back) { | ||||
| 		return; | ||||
| 	} | ||||
| 	_back = Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::IconButton>(this, _st.back)); | ||||
| 	_back->toggle(!selectionMode(), anim::type::instant); | ||||
| 	_back->entity()->clicks() | ||||
| 		| rpl::start_to_stream(_backClicks, _back->lifetime()); | ||||
| 	_defaultControls.push_back(_back.data()); | ||||
| 
 | ||||
| 	if (_title) { | ||||
| 		_title->setAttribute(Qt::WA_TransparentForMouseEvents, enable); | ||||
| 		_title->setAttribute(Qt::WA_TransparentForMouseEvents); | ||||
| 	} | ||||
| 	updateControlsGeometry(width()); | ||||
| } | ||||
|  | @ -104,26 +126,30 @@ void TopBar::createSearchView( | |||
| 	field->setParent(wrap); | ||||
| 
 | ||||
| 	auto search = addButton( | ||||
| 		base::make_unique_q<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 		base::make_unique_q<Ui::FadeWrapScaled<Ui::FadeWrapScaled<Ui::IconButton>>>( | ||||
| 			this, | ||||
| 			object_ptr<Ui::IconButton>(this, _st.search))); | ||||
| 	auto cancel = Ui::CreateChild<Ui::CrossButton>( | ||||
| 			object_ptr<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 				this, | ||||
| 				object_ptr<Ui::IconButton>(this, _st.search)))); | ||||
| 	_defaultControls.push_back(search); | ||||
| 	auto cancel = Ui::CreateChild<Ui::FadeWrapScaled<Ui::CrossButton>>( | ||||
| 		wrap, | ||||
| 		_st.searchRow.fieldCancel); | ||||
| 		object_ptr<Ui::CrossButton>(wrap, _st.searchRow.fieldCancel)); | ||||
| 	_defaultControls.push_back(cancel); | ||||
| 
 | ||||
| 	auto toggleSearchMode = [=](bool enabled, anim::type animated) { | ||||
| 		if (!enabled) { | ||||
| 			setFocus(); | ||||
| 		} | ||||
| 		if (_title) { | ||||
| 			_title->setVisible(!enabled); | ||||
| 			_title->entity()->setVisible(!enabled); | ||||
| 		} | ||||
| 		field->setVisible(enabled); | ||||
| 		cancel->toggleAnimated(enabled); | ||||
| 		cancel->entity()->toggleAnimated(enabled); | ||||
| 		if (animated == anim::type::instant) { | ||||
| 			cancel->finishAnimations(); | ||||
| 			cancel->entity()->finishAnimations(); | ||||
| 		} | ||||
| 		search->toggle(!enabled, animated); | ||||
| 		search->wrapped()->toggle(!enabled, animated); | ||||
| 		if (enabled) { | ||||
| 			field->setFocus(); | ||||
| 		} | ||||
|  | @ -137,7 +163,7 @@ void TopBar::createSearchView( | |||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	cancel->addClickHandler(cancelSearch); | ||||
| 	cancel->entity()->addClickHandler(cancelSearch); | ||||
| 	field->connect(field, &Ui::InputField::cancelled, cancelSearch); | ||||
| 
 | ||||
| 	wrap->widthValue() | ||||
|  | @ -187,7 +213,7 @@ void TopBar::createSearchView( | |||
| 			} | ||||
| 			toggleSearchMode(false, anim::type::instant); | ||||
| 			wrap->setVisible(visible); | ||||
| 			search->toggle(visible, anim::type::instant); | ||||
| 			search->wrapped()->toggle(visible, anim::type::instant); | ||||
| 		}, wrap->lifetime()); | ||||
| } | ||||
| 
 | ||||
|  | @ -202,7 +228,23 @@ int TopBar::resizeGetHeight(int newWidth) { | |||
| 	return _st.height; | ||||
| } | ||||
| 
 | ||||
| void TopBar::finishSelectionAnimations() { | ||||
| 	ranges::for_each(ranges::view::concat( | ||||
| 		_defaultControls, | ||||
| 		_selectionControls | ||||
| 	), [](auto &&control) { | ||||
| 		if (auto pointer = control.data()) { | ||||
| 			pointer->finishAnimating(); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| void TopBar::updateControlsGeometry(int newWidth) { | ||||
| 	updateDefaultControlsGeometry(newWidth); | ||||
| 	updateSelectionControlsGeometry(newWidth); | ||||
| } | ||||
| 
 | ||||
| void TopBar::updateDefaultControlsGeometry(int newWidth) { | ||||
| 	auto right = 0; | ||||
| 	for (auto &button : _buttons) { | ||||
| 		if (!button) continue; | ||||
|  | @ -225,6 +267,32 @@ void TopBar::updateControlsGeometry(int newWidth) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| void TopBar::updateSelectionControlsGeometry(int newWidth) { | ||||
| 	if (!_selectionText) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	auto right = _st.mediaActionsSkip; | ||||
| 	if (_canDelete) { | ||||
| 		_delete->moveToRight(right, 0, newWidth); | ||||
| 		right += _delete->width(); | ||||
| 	} | ||||
| 	_forward->moveToRight(right, 0, newWidth); | ||||
| 	right += _forward->width(); | ||||
| 
 | ||||
| 	auto left = 0; | ||||
| 	_cancelSelection->moveToLeft(left, 0); | ||||
| 	left += _cancelSelection->width(); | ||||
| 
 | ||||
| 	const auto top = 0; | ||||
| 	const auto availableWidth = newWidth - left - right; | ||||
| 	_selectionText->resizeToWidth(availableWidth); | ||||
| 	_selectionText->moveToLeft( | ||||
| 		left, | ||||
| 		top, | ||||
| 		newWidth); | ||||
| } | ||||
| 
 | ||||
| void TopBar::paintEvent(QPaintEvent *e) { | ||||
| 	Painter p(this); | ||||
| 
 | ||||
|  | @ -251,6 +319,182 @@ void TopBar::startHighlightAnimation() { | |||
| 		_st.highlightDuration); | ||||
| } | ||||
| 
 | ||||
| void TopBar::setSelectedItems(SelectedItems &&items) { | ||||
| 	_selectedItems = std::move(items); | ||||
| 	if (selectionMode()) { | ||||
| 		if (_selectionText) { | ||||
| 			updateSelectionState(); | ||||
| 		} else { | ||||
| 			createSelectionControls(); | ||||
| 		} | ||||
| 	} | ||||
| 	toggleSelectionControls(); | ||||
| } | ||||
| 
 | ||||
| SelectedItems TopBar::takeSelectedItems() { | ||||
| 	_canDelete = false; | ||||
| 	return std::move(_selectedItems); | ||||
| } | ||||
| 
 | ||||
| rpl::producer<> TopBar::cancelSelectionRequests() const { | ||||
| 	return _cancelSelectionClicks.events(); | ||||
| } | ||||
| 
 | ||||
| void TopBar::updateSelectionState() { | ||||
| 	Expects(_selectionText && _delete); | ||||
| 
 | ||||
| 	_canDelete = computeCanDelete(); | ||||
| 	_selectionText->entity()->setValue(generateSelectedText()); | ||||
| 	_delete->entity()->setVisible(_canDelete); | ||||
| 
 | ||||
| 	updateSelectionControlsGeometry(width()); | ||||
| } | ||||
| 
 | ||||
| void TopBar::createSelectionControls() { | ||||
| 	auto wrap = [&](auto created) { | ||||
| 		_selectionControls.push_back(created); | ||||
| 		created->toggle(false, anim::type::instant); | ||||
| 		return created; | ||||
| 	}; | ||||
| 	_canDelete = computeCanDelete(); | ||||
| 	_cancelSelection = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::IconButton>(this, _st.mediaCancel))); | ||||
| 	_cancelSelection->entity()->clicks() | ||||
| 		| rpl::start_to_stream( | ||||
| 			_cancelSelectionClicks, | ||||
| 			_cancelSelection->lifetime()); | ||||
| 	_selectionText = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::LabelWithNumbers>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::LabelWithNumbers>( | ||||
| 			this, | ||||
| 			_st.title, | ||||
| 			_st.titlePosition.y(), | ||||
| 			generateSelectedText()))); | ||||
| 	_selectionText->entity()->resize(0, _st.height); | ||||
| 	_forward = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::IconButton>(this, _st.mediaForward))); | ||||
| 	_forward->entity()->addClickHandler([this] { performForward(); }); | ||||
| 	_delete = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::IconButton>(this, _st.mediaDelete))); | ||||
| 	_delete->entity()->addClickHandler([this] { performDelete(); }); | ||||
| 	_delete->entity()->setVisible(_canDelete); | ||||
| 
 | ||||
| 	updateControlsGeometry(width()); | ||||
| } | ||||
| 
 | ||||
| bool TopBar::computeCanDelete() const { | ||||
| 	return ranges::find_if( | ||||
| 		_selectedItems.list, | ||||
| 		[](const SelectedItem &item) { return !item.canDelete; } | ||||
| 	) == _selectedItems.list.end(); | ||||
| } | ||||
| 
 | ||||
| void TopBar::toggleSelectionControls() { | ||||
| 	auto toggle = [](bool shown) { | ||||
| 		return [=](auto &&control) { | ||||
| 			if (auto pointer = control.data()) { | ||||
| 				pointer->toggle(shown, anim::type::normal); | ||||
| 			} | ||||
| 		}; | ||||
| 	}; | ||||
| 	auto shown = selectionMode(); | ||||
| 	ranges::for_each(_defaultControls, toggle(!shown)); | ||||
| 	ranges::for_each(_selectionControls, toggle(shown)); | ||||
| 
 | ||||
| 	if (!shown) { | ||||
| 		clearSelectionControls(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| Ui::StringWithNumbers TopBar::generateSelectedText() const { | ||||
| 	using Data = Ui::StringWithNumbers; | ||||
| 	using Type = Storage::SharedMediaType; | ||||
| 	auto phrase = [&] { | ||||
| 		switch (_selectedItems.type) { | ||||
| 		case Type::Photo: return lng_media_selected_photo__generic<Data>; | ||||
| 		case Type::Video: return lng_media_selected_video__generic<Data>; | ||||
| 		case Type::File: return lng_media_selected_file__generic<Data>; | ||||
| 		case Type::MusicFile: return lng_media_selected_song__generic<Data>; | ||||
| 		case Type::Link: return lng_media_selected_link__generic<Data>; | ||||
| 		case Type::VoiceFile: return lng_media_selected_audio__generic<Data>; | ||||
| //		case Type::RoundFile: return lng_media_selected_round__generic<Data>;
 | ||||
| 		} | ||||
| 		Unexpected("Type in TopBarOverride::generateText()"); | ||||
| 	}(); | ||||
| 	return phrase(lt_count, _selectedItems.list.size()); | ||||
| } | ||||
| 
 | ||||
| bool TopBar::selectionMode() const { | ||||
| 	return !_selectedItems.list.empty(); | ||||
| } | ||||
| 
 | ||||
| void TopBar::clearSelectionControls() { | ||||
| 	for (auto &&control : _selectionControls) { | ||||
| 		if (auto pointer = control.data()) { | ||||
| 			pointer->shownValue() | ||||
| 				| rpl::filter([](bool shown) { return !shown; }) | ||||
| 				| rpl::start_with_next([control] { | ||||
| 					if (auto pointer = control.data()) { | ||||
| 						InvokeQueued(pointer, [pointer] { delete pointer; }); | ||||
| 					} | ||||
| 				}, pointer->lifetime()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	auto isStale = [](auto &&control) { return !control; }; | ||||
| 	_defaultControls |= ranges::action::remove_if(isStale); | ||||
| 	_selectionControls |= ranges::action::remove_if(isStale); | ||||
| 
 | ||||
| 	_cancelSelection = nullptr; | ||||
| 	_selectionText = nullptr; | ||||
| 	_forward = nullptr; | ||||
| 	_delete = nullptr; | ||||
| } | ||||
| 
 | ||||
| SelectedItemSet TopBar::collectItems() const { | ||||
| 	auto result = SelectedItemSet(); | ||||
| 	for (auto value : _selectedItems.list) { | ||||
| 		if (auto item = App::histItemById(value.msgId)) { | ||||
| 			result.insert(result.size(), item); | ||||
| 		} | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void TopBar::performForward() { | ||||
| 	auto items = collectItems(); | ||||
| 	if (items.empty()) { | ||||
| 		_cancelSelectionClicks.fire({}); | ||||
| 		return; | ||||
| 	} | ||||
| 	auto callback = [items = std::move(items), that = weak(this)]( | ||||
| 			not_null<PeerData*> peer) { | ||||
| 		App::main()->setForwardDraft(peer->id, items); | ||||
| 		if (that) { | ||||
| 			that->_cancelSelectionClicks.fire({}); | ||||
| 		} | ||||
| 	}; | ||||
| 	Ui::show(Box<PeerListBox>( | ||||
| 		std::make_unique<ChooseRecipientBoxController>(std::move(callback)), | ||||
| 		[](not_null<PeerListBox*> box) { | ||||
| 			box->addButton(langFactory(lng_cancel), [box] { | ||||
| 				box->closeBox(); | ||||
| 			}); | ||||
| 		})); | ||||
| } | ||||
| 
 | ||||
| void TopBar::performDelete() { | ||||
| 	auto items = collectItems(); | ||||
| 	if (items.empty()) { | ||||
| 		_cancelSelectionClicks.fire({}); | ||||
| 	} else { | ||||
| 		Ui::show(Box<DeleteMessagesBox>(items)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| rpl::producer<QString> TitleValue( | ||||
| 		const Section §ion, | ||||
| 		not_null<PeerData*> peer) { | ||||
|  |  | |||
|  | @ -21,6 +21,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | |||
| #pragma once | ||||
| 
 | ||||
| #include "ui/rp_widget.h" | ||||
| #include "ui/wrap/fade_wrap.h" | ||||
| #include "ui/effects/numbers_animation.h" | ||||
| #include "info/info_wrap_widget.h" | ||||
| 
 | ||||
| namespace style { | ||||
| struct InfoTopBar; | ||||
|  | @ -31,6 +34,7 @@ class IconButton; | |||
| class FlatLabel; | ||||
| class InputField; | ||||
| class SearchFieldController; | ||||
| class LabelWithNumbers; | ||||
| } // namespace Ui
 | ||||
| 
 | ||||
| namespace Info { | ||||
|  | @ -43,14 +47,17 @@ rpl::producer<QString> TitleValue( | |||
| 
 | ||||
| class TopBar : public Ui::RpWidget { | ||||
| public: | ||||
| 	TopBar(QWidget *parent, const style::InfoTopBar &st); | ||||
| 	TopBar( | ||||
| 		QWidget *parent, | ||||
| 		const style::InfoTopBar &st, | ||||
| 		SelectedItems &&items); | ||||
| 
 | ||||
| 	auto backRequest() const { | ||||
| 		return _backClicks.events(); | ||||
| 	} | ||||
| 
 | ||||
| 	void setTitle(rpl::producer<QString> &&title); | ||||
| 	void enableBackButton(bool enable); | ||||
| 	void enableBackButton(); | ||||
| 	void highlight(); | ||||
| 
 | ||||
| 	template <typename ButtonWidget> | ||||
|  | @ -64,16 +71,37 @@ public: | |||
| 		not_null<Ui::SearchFieldController*> controller, | ||||
| 		rpl::producer<bool> &&shown); | ||||
| 
 | ||||
| 	void setSelectedItems(SelectedItems &&items); | ||||
| 	SelectedItems takeSelectedItems(); | ||||
| 
 | ||||
| 	rpl::producer<> cancelSelectionRequests() const; | ||||
| 	void finishSelectionAnimations(); | ||||
| 
 | ||||
| protected: | ||||
| 	int resizeGetHeight(int newWidth) override; | ||||
| 	void paintEvent(QPaintEvent *e) override; | ||||
| 
 | ||||
| private: | ||||
| 	void updateControlsGeometry(int newWidth); | ||||
| 	void updateDefaultControlsGeometry(int newWidth); | ||||
| 	void updateSelectionControlsGeometry(int newWidth); | ||||
| 	void pushButton(base::unique_qptr<Ui::RpWidget> button); | ||||
| 	void removeButton(not_null<Ui::RpWidget*> button); | ||||
| 	void startHighlightAnimation(); | ||||
| 
 | ||||
| 	bool selectionMode() const; | ||||
| 	Ui::StringWithNumbers generateSelectedText() const; | ||||
| 	[[nodiscard]] bool computeCanDelete() const; | ||||
| 	[[nodiscard]] SelectedItemSet collectSelectedItems() const; | ||||
| 	void updateSelectionState(); | ||||
| 	void createSelectionControls(); | ||||
| 	void toggleSelectionControls(); | ||||
| 	void clearSelectionControls(); | ||||
| 
 | ||||
| 	SelectedItemSet collectItems() const; | ||||
| 	void performForward(); | ||||
| 	void performDelete(); | ||||
| 
 | ||||
| 	void setSearchField( | ||||
| 		base::unique_qptr<Ui::InputField> field, | ||||
| 		rpl::producer<bool> &&shown); | ||||
|  | @ -84,14 +112,26 @@ private: | |||
| 	const style::InfoTopBar &_st; | ||||
| 	Animation _a_highlight; | ||||
| 	bool _highlight = false; | ||||
| 	object_ptr<Ui::IconButton> _back = { nullptr }; | ||||
| 	QPointer<Ui::FadeWrap<Ui::IconButton>> _back; | ||||
| 	std::vector<base::unique_qptr<Ui::RpWidget>> _buttons; | ||||
| 	object_ptr<Ui::FlatLabel> _title = { nullptr }; | ||||
| 	QPointer<Ui::FadeWrap<Ui::FlatLabel>> _title; | ||||
| 
 | ||||
| 	base::unique_qptr<Ui::RpWidget> _searchView; | ||||
| 
 | ||||
| 	rpl::event_stream<> _backClicks; | ||||
| 
 | ||||
| 	SelectedItems _selectedItems; | ||||
| 	bool _canDelete = false; | ||||
| 	QPointer<Ui::FadeWrap<Ui::IconButton>> _cancelSelection; | ||||
| 	QPointer<Ui::FadeWrap<Ui::LabelWithNumbers>> _selectionText; | ||||
| 	QPointer<Ui::FadeWrap<Ui::IconButton>> _forward; | ||||
| 	QPointer<Ui::FadeWrap<Ui::IconButton>> _delete; | ||||
| 	rpl::event_stream<> _cancelSelectionClicks; | ||||
| 
 | ||||
| 	using FadingControl = QPointer<Ui::FadeWrap<RpWidget>>; | ||||
| 	std::vector<FadingControl> _defaultControls; | ||||
| 	std::vector<FadingControl> _selectionControls; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace Info
 | ||||
|  |  | |||
|  | @ -30,7 +30,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | |||
| #include "info/info_controller.h" | ||||
| #include "info/info_memento.h" | ||||
| #include "info/info_top_bar.h" | ||||
| #include "info/info_top_bar_override.h" | ||||
| #include "ui/widgets/discrete_sliders.h" | ||||
| #include "ui/widgets/buttons.h" | ||||
| #include "ui/widgets/shadow.h" | ||||
|  | @ -84,7 +83,7 @@ WrapWidget::WrapWidget( | |||
| 	selectedListValue() | ||||
| 		| rpl::start_with_next([this](SelectedItems &&items) { | ||||
| 			InvokeQueued(this, [this, items = std::move(items)]() mutable { | ||||
| 				refreshTopBarOverride(std::move(items)); | ||||
| 				if (_topBar) _topBar->setSelectedItems(std::move(items)); | ||||
| 			}); | ||||
| 		}, lifetime()); | ||||
| 	restoreHistoryStack(memento->takeStack()); | ||||
|  | @ -283,18 +282,24 @@ void WrapWidget::setupTop() { | |||
| 	//	createTopBar();
 | ||||
| 	//}
 | ||||
| 	createTopBar(); | ||||
| 	refreshTopBarOverride(); | ||||
| } | ||||
| 
 | ||||
| void WrapWidget::createTopBar() { | ||||
| 	auto wrapValue = wrap(); | ||||
| 	_topBar.create(this, TopBarStyle(wrapValue)); | ||||
| 	auto selectedItems = _topBar | ||||
| 		? _topBar->takeSelectedItems() | ||||
| 		: SelectedItems(Section::MediaType::kCount); | ||||
| 	_topBar.create(this, TopBarStyle(wrapValue), std::move(selectedItems)); | ||||
| 	_topBar->cancelSelectionRequests() | ||||
| 		| rpl::start_with_next([this](auto) { | ||||
| 			_content->cancelSelection(); | ||||
| 		}, _topBar->lifetime()); | ||||
| 
 | ||||
| 	_topBar->setTitle(TitleValue( | ||||
| 		_controller->section(), | ||||
| 		_controller->peer())); | ||||
| 	if (wrapValue == Wrap::Narrow || hasStackHistory()) { | ||||
| 		_topBar->enableBackButton(true); | ||||
| 		_topBar->enableBackButton(); | ||||
| 		_topBar->backRequest() | ||||
| 			| rpl::start_with_next([this] { | ||||
| 				showBackFromStack(); | ||||
|  | @ -418,81 +423,6 @@ void WrapWidget::showProfileMenu() { | |||
| 	_topBarMenu->showAnimated(Ui::PanelAnimation::Origin::TopRight); | ||||
| } | ||||
| 
 | ||||
| void WrapWidget::refreshTopBarOverride(SelectedItems &&items) { | ||||
| 	auto empty = items.list.empty(); | ||||
| 	if (!empty) { | ||||
| 		if (_topBarOverride) { | ||||
| 			_topBarOverride->setItems(std::move(items)); | ||||
| 		} else { | ||||
| 			createTopBarOverride(std::move(items)); | ||||
| 		} | ||||
| 	} | ||||
| 	toggleTopBarOverride(!empty); | ||||
| } | ||||
| 
 | ||||
| void WrapWidget::refreshTopBarOverride() { | ||||
| 	if (_topBarOverride) { | ||||
| 		auto items = _topBarOverride->takeItems(); | ||||
| 		createTopBarOverride(std::move(items)); | ||||
| 		topBarOverrideStep(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void WrapWidget::toggleTopBarOverride(bool shown) { | ||||
| 	if (_topBarOverrideShown == shown) { | ||||
| 		return; | ||||
| 	} | ||||
| 	_topBarOverrideShown = shown; | ||||
| 	_topBar->show(); | ||||
| 	_topBarOverrideAnimation.start( | ||||
| 		[this] { topBarOverrideStep(); }, | ||||
| 		_topBarOverrideShown ? 0. : 1., | ||||
| 		_topBarOverrideShown ? 1. : 0., | ||||
| 		st::slideWrapDuration, | ||||
| 		anim::easeOutCirc); | ||||
| } | ||||
| 
 | ||||
| void WrapWidget::topBarOverrideStep() { | ||||
| 	auto shown = _topBarOverrideAnimation.current( | ||||
| 		_topBarOverrideShown ? 1. : 0.); | ||||
| 	auto topBarTop = anim::interpolate(0, _topBar->height(), shown); | ||||
| 	auto overrideTop = anim::interpolate(-_topBar->height(), 0, shown); | ||||
| 	_topBar->moveToLeft(0, topBarTop); | ||||
| 	if (_topBarOverride) { | ||||
| 		_topBarOverride->moveToLeft(0, overrideTop); | ||||
| 	} | ||||
| 	if (!_topBarOverrideAnimation.animating()) { | ||||
| 		if (_topBarOverrideShown) { | ||||
| 			_topBar->hide(); | ||||
| 		} else { | ||||
| 			_topBarOverride = nullptr; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void WrapWidget::createTopBarOverride(SelectedItems &&items) { | ||||
| 	_topBarOverride.create( | ||||
| 		this, | ||||
| 		TopBarStyle(wrap()), | ||||
| 		std::move(items)); | ||||
| 
 | ||||
| 	// This was done for tabs support.
 | ||||
| 	//
 | ||||
| 	//if (_topTabs) {
 | ||||
| 	//	_topTabs->hide();
 | ||||
| 	//}
 | ||||
| 
 | ||||
| 	if (_topBar) { | ||||
| 		_topBar->hide(); | ||||
| 	} | ||||
| 	_topBarOverride->cancelRequests() | ||||
| 		| rpl::start_with_next([this](auto) { | ||||
| 			_content->cancelSelection(); | ||||
| 		}, _topBarOverride->lifetime()); | ||||
| 	_topBarOverride->resizeToWidth(width()); | ||||
| 	_topBarOverride->show(); | ||||
| } | ||||
| 
 | ||||
| bool WrapWidget::requireTopBarSearch() const { | ||||
| 	if (!_controller->searchFieldController()) { | ||||
| 		return false; | ||||
|  | @ -832,10 +762,6 @@ void WrapWidget::showNewContent( | |||
| 		showNewContent(memento); | ||||
| 	} | ||||
| 	if (animationParams) { | ||||
| 		refreshTopBarOverride(SelectedItems(Section::MediaType::kCount)); | ||||
| 		_topBarOverrideAnimation.finish(); | ||||
| 		topBarOverrideStep(); | ||||
| 
 | ||||
| 		showAnimated( | ||||
| 			saveToStack | ||||
| 				? SlideDirection::FromRight | ||||
|  | @ -876,9 +802,6 @@ void WrapWidget::resizeEvent(QResizeEvent *e) { | |||
| 	if (_topBar) { | ||||
| 		_topBar->resizeToWidth(width()); | ||||
| 	} | ||||
| 	if (_topBarOverride) { | ||||
| 		_topBarOverride->resizeToWidth(width()); | ||||
| 	} | ||||
| 	updateContentGeometry(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -52,7 +52,6 @@ class MoveMemento; | |||
| class ContentMemento; | ||||
| class ContentWidget; | ||||
| class TopBar; | ||||
| class TopBarOverride; | ||||
| 
 | ||||
| enum class Wrap { | ||||
| 	Layer, | ||||
|  | @ -190,11 +189,6 @@ private: | |||
| 	//void convertProfileFromStackToTab();
 | ||||
| 
 | ||||
| 	rpl::producer<SelectedItems> selectedListValue() const; | ||||
| 	void refreshTopBarOverride(); | ||||
| 	void refreshTopBarOverride(SelectedItems &&items); | ||||
| 	void createTopBarOverride(SelectedItems &&items); | ||||
| 	void toggleTopBarOverride(bool shown); | ||||
| 	void topBarOverrideStep(); | ||||
| 	bool requireTopBarSearch() const; | ||||
| 
 | ||||
| 	void addProfileMenuButton(); | ||||
|  | @ -209,7 +203,6 @@ private: | |||
| 	//object_ptr<Ui::SettingsSlider> _topTabs = { nullptr };
 | ||||
| 	object_ptr<TopBar> _topBar = { nullptr }; | ||||
| 	object_ptr<Ui::RpWidget> _topBarSurrogate = { nullptr }; | ||||
| 	object_ptr<TopBarOverride> _topBarOverride = { nullptr }; | ||||
| 	Animation _topBarOverrideAnimation; | ||||
| 	bool _topBarOverrideShown = false; | ||||
| 	object_ptr<Ui::FadeShadow> _topShadow; | ||||
|  |  | |||
|  | @ -794,6 +794,10 @@ void ListWidget::refreshViewer() { | |||
| 		_idsLimit) | ||||
| 		| rpl::start_with_next([=]( | ||||
| 				SparseIdsMergedSlice &&slice) { | ||||
| 			if (!slice.fullCount()) { | ||||
| 				// Don't display anything while full count is unknown.
 | ||||
| 				return; | ||||
| 			} | ||||
| 			_slice = std::move(slice); | ||||
| 			if (auto nearest = _slice.nearest(idForViewer)) { | ||||
| 				_universalAroundId = GetUniversalId(*nearest); | ||||
|  | @ -906,9 +910,11 @@ void ListWidget::refreshRows() { | |||
| 		_sections.push_back(std::move(section)); | ||||
| 	} | ||||
| 
 | ||||
| 	if (_layouts.size() > kMediaCountForSearch) { | ||||
| 	if (auto count = _slice.fullCount()) { | ||||
| 		if (*count > kMediaCountForSearch) { | ||||
| 			_controller->setSearchEnabledByContent(true); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	clearStaleLayouts(); | ||||
| 
 | ||||
|  |  | |||