Add shared media empty placeholders.

This commit is contained in:
John Preston 2017-11-14 21:22:44 +04:00
parent fafcd02e7c
commit 8dfccf55d1
29 changed files with 257 additions and 18 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -590,8 +590,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_files_header" = "Files"; "lng_profile_files_header" = "Files";
"lng_profile_audios#one" = "{count} voice message"; "lng_profile_audios#one" = "{count} voice message";
"lng_profile_audios#other" = "{count} voice messages"; "lng_profile_audios#other" = "{count} voice messages";
"lng_profile_rounds#one" = "{count} video message"; //"lng_profile_rounds#one" = "{count} video message";
"lng_profile_rounds#other" = "{count} video messages"; //"lng_profile_rounds#other" = "{count} video messages";
"lng_profile_audios_header" = "Voice messages"; "lng_profile_audios_header" = "Voice messages";
"lng_profile_shared_links#one" = "{count} shared link"; "lng_profile_shared_links#one" = "{count} shared link";
"lng_profile_shared_links#other" = "{count} shared links"; "lng_profile_shared_links#other" = "{count} shared links";
@ -645,10 +645,19 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_media_selected_file#other" = "{count} Files"; "lng_media_selected_file#other" = "{count} Files";
"lng_media_selected_audio#one" = "{count} Voice message"; "lng_media_selected_audio#one" = "{count} Voice message";
"lng_media_selected_audio#other" = "{count} Voice messages"; "lng_media_selected_audio#other" = "{count} Voice messages";
"lng_media_selected_round#one" = "{count} Video message"; //"lng_media_selected_round#one" = "{count} Video message";
"lng_media_selected_round#other" = "{count} video messages"; //"lng_media_selected_round#other" = "{count} Video messages";
"lng_media_selected_link#one" = "{count} Shared link"; "lng_media_selected_link#one" = "{count} Shared link";
"lng_media_selected_link#other" = "{count} Shared links"; "lng_media_selected_link#other" = "{count} Shared links";
"lng_media_photo_empty" = "No photos here yet";
"lng_media_video_empty" = "No videos here yet";
"lng_media_song_empty" = "No music files here yet";
"lng_media_file_empty" = "No files here yet";
"lng_media_audio_empty" = "No voice messages here yet";
"lng_media_link_empty" = "No shared links here yet";
"lng_media_song_empty_search" = "No music files found";
"lng_media_file_empty_search" = "No files found";
"lng_media_link_empty_search" = "No shared links found";
"lng_manage_group_title" = "Manage Group"; "lng_manage_group_title" = "Manage Group";
"lng_manage_channel_title" = "Manage Channel"; "lng_manage_channel_title" = "Manage Channel";

View File

@ -390,7 +390,7 @@ void DelayedSearchController::setQuery(
void DelayedSearchController::setQueryFast(const Query &query) { void DelayedSearchController::setQueryFast(const Query &query) {
_controller.setQuery(query); _controller.setQuery(query);
_sourceChanges.fire({}); _currentQueryChanges.fire_copy(query.query);
} }
} // namespace Api } // namespace Api

View File

@ -162,8 +162,9 @@ public:
limitAfter); limitAfter);
} }
rpl::producer<> sourceChanged() const { rpl::producer<QString> currentQueryValue() const {
return _sourceChanges.events(); return _currentQueryChanges.events_starting_with(
currentQuery().query);
} }
SavedState saveState() { SavedState saveState() {
@ -178,7 +179,7 @@ private:
SearchController _controller; SearchController _controller;
Query _nextQuery; Query _nextQuery;
base::Timer _timer; base::Timer _timer;
rpl::event_stream<> _sourceChanges; rpl::event_stream<QString> _currentQueryChanges;
}; };

View File

@ -548,6 +548,21 @@ managePeerButtonLabel: FlatLabel(defaultFlatLabel) {
} }
managePeerButtonLabelPosition: point(25px, 10px); managePeerButtonLabelPosition: point(25px, 10px);
infoEmptyFg: windowSubTextFg;
infoEmptyPhoto: icon {{ "info_media_photo_empty", infoEmptyFg }};
infoEmptyVideo: icon {{ "info_media_video_empty", infoEmptyFg }};
infoEmptyAudio: icon {{ "info_media_audio_empty", infoEmptyFg }};
infoEmptyFile: icon {{ "info_media_file_empty", infoEmptyFg }};
infoEmptyVoice: icon {{ "info_media_voice_empty", infoEmptyFg }};
infoEmptyLink: icon {{ "info_media_link_empty", infoEmptyFg }};
infoEmptyIconTop: 120px;
infoEmptyLabelTop: 40px;
infoEmptyLabelSkip: 20px;
infoEmptyLabel: FlatLabel(defaultFlatLabel) {
minWidth: 220px;
textFg: windowSubTextFg;
}
editPeerDeleteButtonMargins: margins(23px, 16px, 23px, 16px); editPeerDeleteButtonMargins: margins(23px, 16px, 23px, 16px);
editPeerDeleteButton: sessionTerminateAllButton; editPeerDeleteButton: sessionTerminateAllButton;
editPeerPhotoMargins: margins(23px, 16px, 23px, 8px); editPeerPhotoMargins: margins(23px, 16px, 23px, 8px);

View File

@ -150,6 +150,10 @@ rpl::producer<Section> ContentWidget::sectionRequest() const {
return rpl::never<Section>(); return rpl::never<Section>();
} }
rpl::producer<int> ContentWidget::scrollHeightValue() const {
return _scroll->heightValue();
}
rpl::producer<int> ContentWidget::desiredHeightValue() const { rpl::producer<int> ContentWidget::desiredHeightValue() const {
using namespace rpl::mappers; using namespace rpl::mappers;
return rpl::combine( return rpl::combine(

View File

@ -52,6 +52,7 @@ public:
virtual void setIsStackBottom(bool isStackBottom) { virtual void setIsStackBottom(bool isStackBottom) {
} }
rpl::producer<int> scrollHeightValue() const;
rpl::producer<int> desiredHeightValue() const override; rpl::producer<int> desiredHeightValue() const override;
rpl::producer<bool> desiredShadowVisibility() const; rpl::producer<bool> desiredShadowVisibility() const;
bool hasTopBarShadow() const; bool hasTopBarShadow() const;

View File

@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#include "info/info_controller.h" #include "info/info_controller.h"
#include <rpl/range.h>
#include <rpl/then.h>
#include "ui/search_field_controller.h" #include "ui/search_field_controller.h"
#include "data/data_shared_media.h" #include "data/data_shared_media.h"
#include "info/info_content_widget.h" #include "info/info_content_widget.h"

View File

@ -116,8 +116,8 @@ public:
SparseIdsMergedSlice::UniversalMsgId aroundId, SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore, int limitBefore,
int limitAfter) const; int limitAfter) const;
rpl::producer<> mediaSourceChanged() const { rpl::producer<QString> mediaSourceQueryValue() const {
return _searchController->sourceChanged(); return _searchController->currentQueryValue();
} }
void saveSearchState(not_null<ContentMemento*> memento); void saveSearchState(not_null<ContentMemento*> memento);

View File

@ -65,7 +65,7 @@ QString TopBarOverride::generateText() const {
case Type::MusicFile: return lng_media_selected_song; case Type::MusicFile: return lng_media_selected_song;
case Type::Link: return lng_media_selected_link; case Type::Link: return lng_media_selected_link;
case Type::VoiceFile: return lng_media_selected_audio; case Type::VoiceFile: return lng_media_selected_audio;
case Type::RoundFile: return lng_media_selected_round; // case Type::RoundFile: return lng_media_selected_round;
} }
Unexpected("Type in TopBarOverride::generateText()"); Unexpected("Type in TopBarOverride::generateText()");
}(); }();

View File

@ -46,7 +46,7 @@ inline auto MediaTextPhrase(Type type) {
case Type::MusicFile: return lng_profile_songs; case Type::MusicFile: return lng_profile_songs;
case Type::Link: return lng_profile_shared_links; case Type::Link: return lng_profile_shared_links;
case Type::VoiceFile: return lng_profile_audios; case Type::VoiceFile: return lng_profile_audios;
case Type::RoundFile: return lng_profile_rounds; // case Type::RoundFile: return lng_profile_rounds;
} }
Unexpected("Type in MediaTextPhrase()"); Unexpected("Type in MediaTextPhrase()");
}; };

View File

@ -0,0 +1,117 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#include "info/media/info_media_empty_widget.h"
#include "ui/widgets/labels.h"
#include "styles/style_info.h"
#include "lang/lang_keys.h"
namespace Info {
namespace Media {
EmptyWidget::EmptyWidget(QWidget *parent)
: RpWidget(parent)
, _text(this, st::infoEmptyLabel) {
}
void EmptyWidget::setFullHeight(rpl::producer<int> fullHeightValue) {
std::move(fullHeightValue)
| rpl::start_with_next([this](int fullHeight) {
// Make icon center be on 1/3 height.
auto iconCenter = fullHeight / 3;
auto iconHeight = st::infoEmptyFile.height();
auto iconTop = iconCenter - iconHeight / 2;
_height = iconTop + st::infoEmptyIconTop;
resizeToWidth(width());
}, lifetime());
}
void EmptyWidget::setType(Type type) {
_type = type;
using Data = std::pair<const style::icon*, LangKey>;
_icon = [&] {
switch (_type) {
case Type::Photo: return &st::infoEmptyPhoto;
case Type::Video: return &st::infoEmptyVideo;
case Type::MusicFile: return &st::infoEmptyAudio;
case Type::File: return &st::infoEmptyFile;
case Type::Link: return &st::infoEmptyLink;
case Type::VoiceFile: return &st::infoEmptyVoice;
}
Unexpected("Bad type in EmptyWidget::setType()");
}();
update();
}
void EmptyWidget::setSearchQuery(const QString &query) {
auto key = [&] {
switch (_type) {
case Type::Photo:
return lng_media_photo_empty;
case Type::Video:
return lng_media_video_empty;
case Type::MusicFile:
return query.isEmpty()
? lng_media_song_empty
: lng_media_song_empty_search;
case Type::File:
return query.isEmpty()
? lng_media_file_empty
: lng_media_file_empty_search;
case Type::Link:
return query.isEmpty()
? lng_media_link_empty
: lng_media_link_empty_search;
case Type::VoiceFile:
return lng_media_audio_empty;
}
Unexpected("Bad type in EmptyWidget::setSearchQuery()");
}();
_text->setText(lang(key));
resizeToWidth(width());
}
void EmptyWidget::paintEvent(QPaintEvent *e) {
if (!_icon) {
return;
}
Painter p(this);
auto iconLeft = (width() - _icon->width()) / 2;
auto iconTop = height() - st::infoEmptyIconTop;
_icon->paint(p, iconLeft, iconTop, width());
}
int EmptyWidget::resizeGetHeight(int newWidth) {
auto labelTop = _height - st::infoEmptyLabelTop;
auto labelWidth = newWidth - 2 * st::infoEmptyLabelSkip;
_text->resizeToNaturalWidth(labelWidth);
auto labelLeft = (newWidth - _text->width()) / 2;
_text->moveToLeft(labelLeft, labelTop, newWidth);
update();
return _height;
}
} // namespace Media
} // namespace Info

View File

@ -0,0 +1,55 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "ui/rp_widget.h"
#include "info/media/info_media_widget.h"
namespace Ui {
class FlatLabel;
} // namespace Ui
namespace Info {
namespace Media {
class EmptyWidget : public Ui::RpWidget {
public:
EmptyWidget(QWidget *parent);
void setFullHeight(rpl::producer<int> fullHeightValue);
void setType(Type type);
void setSearchQuery(const QString &query);
protected:
void paintEvent(QPaintEvent *e) override;
int resizeGetHeight(int newWidth) override;
private:
object_ptr<Ui::FlatLabel> _text;
Type _type = Type::kCount;
const style::icon *_icon = nullptr;
int _height = 0;
};
} // namespace Media
} // namespace Info

View File

@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "boxes/abstract_box.h" #include "boxes/abstract_box.h"
#include "info/media/info_media_list_widget.h" #include "info/media/info_media_list_widget.h"
#include "info/media/info_media_buttons.h" #include "info/media/info_media_buttons.h"
#include "info/media/info_media_empty_widget.h"
#include "info/profile/info_profile_button.h" #include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_icon.h"
#include "info/info_controller.h" #include "info/info_controller.h"
@ -41,7 +42,8 @@ InnerWidget::InnerWidget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller) not_null<Controller*> controller)
: RpWidget(parent) : RpWidget(parent)
, _controller(controller) { , _controller(controller)
, _empty(this) {
_list = setupList(); _list = setupList();
setupOtherTypes(); setupOtherTypes();
} }
@ -253,6 +255,12 @@ object_ptr<ListWidget> InnerWidget::setupList() {
_scrollToRequests, _scrollToRequests,
result->lifetime()); result->lifetime());
_selectedLists.fire(result->selectedListValue()); _selectedLists.fire(result->selectedListValue());
_listTops.fire(result->topValue());
_empty->setType(_controller->section().mediaType());
_controller->mediaSourceQueryValue()
| rpl::start_with_next([this](const QString &query) {
_empty->setSearchQuery(query);
}, result->lifetime());
return result; return result;
} }
@ -287,6 +295,7 @@ int InnerWidget::resizeGetHeight(int newWidth) {
_searchField->resizeToWidth(newWidth); _searchField->resizeToWidth(newWidth);
} }
_list->resizeToWidth(newWidth); _list->resizeToWidth(newWidth);
_empty->resizeToWidth(newWidth);
return recountHeight(); return recountHeight();
} }
@ -308,12 +317,30 @@ int InnerWidget::recountHeight() {
_searchField->moveToLeft(0, top); _searchField->moveToLeft(0, top);
top += _searchField->heightNoMargins() - st::lineWidth; top += _searchField->heightNoMargins() - st::lineWidth;
} }
auto listHeight = 0;
if (_list) { if (_list) {
_list->moveToLeft(0, top); _list->moveToLeft(0, top);
top += _list->heightNoMargins(); listHeight = _list->heightNoMargins();
top += listHeight;
}
if (listHeight > 0) {
_empty->hide();
} else {
_empty->show();
_empty->moveToLeft(0, top);
top += _empty->heightNoMargins();
} }
return top; return top;
} }
void InnerWidget::setScrollHeightValue(rpl::producer<int> value) {
using namespace rpl::mappers;
_empty->setFullHeight(rpl::combine(
std::move(value),
_listTops.events_starting_with(_list->topValue())
| rpl::flatten_latest(),
$1 - $2));
}
} // namespace Media } // namespace Media
} // namespace Info } // namespace Info

View File

@ -40,6 +40,7 @@ namespace Media {
class Memento; class Memento;
class ListWidget; class ListWidget;
class EmptyWidget;
class InnerWidget final : public Ui::RpWidget { class InnerWidget final : public Ui::RpWidget {
public: public:
@ -52,6 +53,8 @@ public:
void saveState(not_null<Memento*> memento); void saveState(not_null<Memento*> memento);
void restoreState(not_null<Memento*> memento); void restoreState(not_null<Memento*> memento);
void setScrollHeightValue(rpl::producer<int> value);
rpl::producer<Ui::ScrollToRequest> scrollToRequests() const { rpl::producer<Ui::ScrollToRequest> scrollToRequests() const {
return _scrollToRequests.events(); return _scrollToRequests.events();
} }
@ -88,12 +91,14 @@ private:
object_ptr<Ui::PlainShadow> _otherTabsShadow = { nullptr }; object_ptr<Ui::PlainShadow> _otherTabsShadow = { nullptr };
base::unique_qptr<Ui::RpWidget> _searchField = nullptr; base::unique_qptr<Ui::RpWidget> _searchField = nullptr;
object_ptr<ListWidget> _list = { nullptr }; object_ptr<ListWidget> _list = { nullptr };
object_ptr<EmptyWidget> _empty;
bool _searchEnabled = false; bool _searchEnabled = false;
bool _inResize = false; bool _inResize = false;
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests; rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
rpl::event_stream<rpl::producer<SelectedItems>> _selectedLists; rpl::event_stream<rpl::producer<SelectedItems>> _selectedLists;
rpl::event_stream<rpl::producer<int>> _listTops;
}; };

View File

@ -549,7 +549,6 @@ ListWidget::ListWidget(
, _slice(sliceKey(_universalAroundId)) { , _slice(sliceKey(_universalAroundId)) {
setAttribute(Qt::WA_MouseTracking); setAttribute(Qt::WA_MouseTracking);
start(); start();
refreshViewer();
} }
void ListWidget::start() { void ListWidget::start() {
@ -574,7 +573,7 @@ void ListWidget::start() {
| rpl::start_with_next([this](auto item) { | rpl::start_with_next([this](auto item) {
repaintItem(item); repaintItem(item);
}, lifetime()); }, lifetime());
_controller->mediaSourceChanged() _controller->mediaSourceQueryValue()
| rpl::start_with_next([this]{ | rpl::start_with_next([this]{
restart(); restart();
}, lifetime()); }, lifetime());
@ -2014,8 +2013,9 @@ int ListWidget::recountHeight() {
section.setTop(result); section.setTop(result);
result += section.height(); result += section.height();
} }
return result return (result > cachedPadding.top())
+ cachedPadding.bottom(); ? (result + cachedPadding.bottom())
: 0;
} }
void ListWidget::mouseActionUpdate() { void ListWidget::mouseActionUpdate() {

View File

@ -87,6 +87,7 @@ Widget::Widget(
_inner = setInnerWidget(object_ptr<InnerWidget>( _inner = setInnerWidget(object_ptr<InnerWidget>(
this, this,
controller)); controller));
_inner->setScrollHeightValue(scrollHeightValue());
_inner->scrollToRequests() _inner->scrollToRequests()
| rpl::start_with_next([this](Ui::ScrollToRequest request) { | rpl::start_with_next([this](Ui::ScrollToRequest request) {
scrollTo(request); scrollTo(request);

View File

@ -240,6 +240,8 @@
<(src_loc)/info/common_groups/info_common_groups_widget.cpp <(src_loc)/info/common_groups/info_common_groups_widget.cpp
<(src_loc)/info/common_groups/info_common_groups_widget.h <(src_loc)/info/common_groups/info_common_groups_widget.h
<(src_loc)/info/media/info_media_buttons.h <(src_loc)/info/media/info_media_buttons.h
<(src_loc)/info/media/info_media_empty_widget.cpp
<(src_loc)/info/media/info_media_empty_widget.h
<(src_loc)/info/media/info_media_inner_widget.cpp <(src_loc)/info/media/info_media_inner_widget.cpp
<(src_loc)/info/media/info_media_inner_widget.h <(src_loc)/info/media/info_media_inner_widget.h
<(src_loc)/info/media/info_media_list_widget.cpp <(src_loc)/info/media/info_media_list_widget.cpp