Profile fixed bar actions done, adaptive layout for profile buttons.

This commit is contained in:
John Preston 2016-05-27 16:56:35 +03:00
parent 3570a1cf91
commit 2c5c25962c
18 changed files with 246 additions and 33 deletions

View File

@ -58,6 +58,7 @@ adaptiveWideWidth: 1366px;
windowBg: #fff; // fallback for background: white
windowTextFg: #000; // fallback for text color: black
windowSubTextFg: #8a8a8a; // fallback for subtext color: gray
windowShadowFg: #000; // fallback for shadow color
wndMinHeight: 480px;
wndDefWidth: 800px;

View File

@ -308,6 +308,8 @@ BoxButton {
textTop: pixels;
icon: icon;
font: font;
duration: int;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

View File

@ -460,6 +460,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_profile_drop_area_title" = "Drop your image here";
"lng_profile_drop_area_subtitle" = "to set it as a group photo";
"lng_profile_drop_area_subtitle_channel" = "to set it as a channel photo";
"lng_profile_top_bar_share_contact" = "Share";
"lng_channel_add_admins" = "New administrator";
"lng_channel_add_members" = "Add members";

View File

@ -289,7 +289,7 @@ QString Generator::valueAssignmentCode(structure::Value value) const {
} break;
case Tag::Icon: {
auto v(value.Icon());
if (v.parts.empty()) return QString();
if (v.parts.empty()) return QString("{}");
QStringList parts;
for (const auto &part : v.parts) {

View File

@ -134,6 +134,7 @@ private:
{ "align" , { structure::TypeTag::Align } },
{ "margins" , { structure::TypeTag::Margins } },
{ "font" , { structure::TypeTag::Font } },
{ "icon" , { structure::TypeTag::Icon } },
};
};

View File

@ -6867,7 +6867,8 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh
}
} else {
}
if (toY > _scroll.scrollTopMax()) toY = _scroll.scrollTopMax();
auto scrollMax = _scroll.scrollTopMax();
accumulate_min(toY, scrollMax);
if (_scroll.scrollTop() == toY) {
visibleAreaUpdated();
} else {

View File

@ -32,6 +32,8 @@ profileTopBarBackIconPosition: point(15px, 19px);
profileTopBarBackFont: font(14px);
profileTopBarBackFg: #1485c2;
profileTopBarBackPosition: point(32px, 17px);
profileFixedBarButton: flatButton(topBarButton) {
}
profileMarginTop: 13px;
profilePhotoSize: 112px;
@ -76,6 +78,13 @@ profileSecondaryButton: BoxButton(profilePrimaryButton) {
textBg: #ffffff;
textBgOver: #f2f7fa;
}
profileAddMemberIcon: icon {
{ "profile_add_member", #3fb0e4, point(20px, 10px) },
};
profileAddMemberButton: BoxButton(profileSecondaryButton) {
width: 62px;
icon: profileAddMemberIcon;
}
profileDropAreaBg: profileBg;
profileDropAreaFg: #3fb0e4;
@ -88,7 +97,7 @@ profileDropAreaBorderFg: profileDropAreaFg;
profileDropAreaBorderWidth: 3px;
profileDropAreaDuration: 200;
profileDividerFg: black;
profileDividerFg: windowShadowFg;
profileDividerLeft: icon {
{ "profile_divider_left", profileDividerFg },
};

View File

@ -119,17 +119,13 @@ void CoverWidget::resizeToWidth(int newWidth) {
int nameLeft = infoLeft + st::profileNameLeft - st::profileNameLabel.margin.left();
int nameTop = _userpicButton->y() + st::profileNameTop - st::profileNameLabel.margin.top();
_name.moveToLeft(nameLeft, nameTop);
int nameWidth = width() - infoLeft - st::profileNameLeft - st::profileButtonSkip;
int nameWidth = newWidth - infoLeft - st::profileNameLeft - st::profileButtonSkip;
nameWidth += st::profileNameLabel.margin.left() + st::profileNameLabel.margin.right();
_name.resizeToWidth(nameWidth);
_statusPosition = QPoint(infoLeft + st::profileStatusLeft, _userpicButton->y() + st::profileStatusTop);
int buttonLeft = st::profilePhotoLeft + _userpicButton->width() + st::profileButtonLeft;
for_const (auto button, _buttons) {
button->moveToLeft(buttonLeft, st::profileButtonTop);
buttonLeft += button->width() + st::profileButtonSkip;
}
moveAndToggleButtons(newWidth);
newHeight += st::profilePhotoSize;
newHeight += st::profileMarginBottom;
@ -144,10 +140,41 @@ void CoverWidget::resizeToWidth(int newWidth) {
update();
}
// A more generic solution would be allowing an optional icon button
// for each text button. But currently we use only one, so it is done easily:
// There can be primary + secondary + icon buttons. If primary + secondary fit,
// then icon is hidden, otherwise secondary is hidden and icon is shown.
void CoverWidget::moveAndToggleButtons(int newWiddth) {
bool showNextButton = true;
int buttonLeft = st::profilePhotoLeft + _userpicButton->width() + st::profileButtonLeft;
int buttonsRight = newWiddth - st::profileButtonSkip;
for (int i = 0, count = _buttons.size(); i < count; ++i) {
auto button = _buttons.at(i);
button->moveToLeft(buttonLeft, st::profileButtonTop);
if (i == 1) {
// If second button is not fitting.
if (buttonLeft + button->width() > buttonsRight) {
button->hide();
} else {
button->show();
buttonLeft += button->width() + st::profileButtonSkip;
showNextButton = false;
}
} else {
button->setVisible(showNextButton);
buttonLeft += button->width() + st::profileButtonSkip;
}
}
}
void CoverWidget::showFinished() {
_userpicButton->showFinished();
}
bool CoverWidget::shareContactButtonShown() const {
return _peerUser && (_buttons.size() > 1) && !(_buttons.at(1)->isHidden());
}
void CoverWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
@ -368,6 +395,7 @@ void CoverWidget::setChatButtons() {
if (_peerChat->canEdit()) {
addButton(lang(lng_profile_set_group_photo), SLOT(onSetPhoto()));
addButton(lang(lng_profile_add_participant), SLOT(onAddMember()));
addButton(st::profileAddMemberButton, SLOT(onAddMember()));
}
}
@ -377,6 +405,7 @@ void CoverWidget::setMegagroupButtons() {
}
if (_peerMegagroup->canAddParticipants()) {
addButton(lang(lng_profile_add_participant), SLOT(onAddMember()));
addButton(st::profileAddMemberButton, SLOT(onAddMember()));
}
}
@ -398,12 +427,16 @@ void CoverWidget::clearButtons() {
}
void CoverWidget::addButton(const QString &text, const char *slot) {
if (!text.isEmpty()) {
auto &buttonStyle = _buttons.isEmpty() ? st::profilePrimaryButton : st::profileSecondaryButton;
_buttons.push_back(new Ui::RoundButton(this, text, buttonStyle));
connect(_buttons.back(), SIGNAL(clicked()), this, slot);
_buttons.back()->show();
}
auto &buttonStyle = _buttons.isEmpty() ? st::profilePrimaryButton : st::profileSecondaryButton;
_buttons.push_back(new Ui::RoundButton(this, text, buttonStyle));
connect(_buttons.back(), SIGNAL(clicked()), this, slot);
_buttons.back()->show();
}
void CoverWidget::addButton(const style::BoxButton &buttonStyle, const char *slot) {
_buttons.push_back(new Ui::RoundButton(this, QString(), buttonStyle));
connect(_buttons.back(), SIGNAL(clicked()), this, slot);
_buttons.back()->hide();
}
void CoverWidget::onSendMessage() {

View File

@ -49,6 +49,11 @@ public:
void showFinished();
// Profile fixed top bar should use this flag to decide
// if it shows "Share contact" button or not.
// It should show it only if it is hidden in the cover.
bool shareContactButtonShown() const;
private slots:
void onPhotoShow();
@ -70,6 +75,7 @@ private:
void notifyPeerUpdated(const Notify::PeerUpdate &update);
void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update);
void moveAndToggleButtons(int newWiddth);
void refreshNameText();
void refreshStatusText();
bool isUsingMegagroupOnlineCount() const;
@ -82,6 +88,7 @@ private:
void clearButtons();
void addButton(const QString &text, const char *slot);
void addButton(const style::BoxButton &buttonStyle, const char *slot);
void paintDivider(Painter &p);

View File

@ -24,6 +24,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_profile.h"
#include "lang.h"
#include "mainwidget.h"
#include "boxes/addcontactbox.h"
#include "boxes/confirmbox.h"
namespace Profile {
@ -67,6 +69,74 @@ FixedBar::FixedBar(QWidget *parent, PeerData *peer) : TWidget(parent)
, _backButton(this) {
_backButton->moveToLeft(0, 0);
connect(_backButton, SIGNAL(clicked()), this, SLOT(onBack()));
refreshRightActions();
}
void FixedBar::refreshRightActions() {
_currentAction = 0;
if (_peerUser) {
setUserActions();
} else if (_peerChat) {
setChatActions();
} else if (_peerMegagroup) {
setMegagroupActions();
} else if (_peerChannel) {
setChannelActions();
}
while (_rightActions.size() > _currentAction) {
delete _rightActions.back().button;
_rightActions.pop_back();
}
resizeToWidth(width());
}
void FixedBar::setUserActions() {
if (_peerUser->contact > 0) {
addRightAction(RightActionType::EditContact, lang(lng_profile_edit_contact), SLOT(onEditContact()));
addRightAction(RightActionType::DeleteContact, lang(lng_profile_delete_contact), SLOT(onDeleteContact()));
addRightAction(RightActionType::ShareContact, lang(lng_profile_top_bar_share_contact), SLOT(onShareContact()));
} else if (_peerUser->contact == 0 || !App::phoneFromSharedContact(peerToUser(_peer->id)).isEmpty()) {
addRightAction(RightActionType::AddContact, lang(lng_profile_add_contact), SLOT(onAddContact()));
addRightAction(RightActionType::ShareContact, lang(lng_profile_top_bar_share_contact), SLOT(onShareContact()));
}
}
void FixedBar::setChatActions() {
if (_peerChat->canEdit()) {
addRightAction(RightActionType::EditGroup, lang(lng_profile_edit_contact), SLOT(onEditGroup()));
}
addRightAction(RightActionType::LeaveGroup, lang(lng_profile_delete_and_exit), SLOT(onLeaveGroup()));
}
void FixedBar::setMegagroupActions() {
if (_peerMegagroup->amCreator() || _peerMegagroup->amEditor()) {
addRightAction(RightActionType::EditChannel, lang(lng_profile_edit_contact), SLOT(onEditChannel()));
}
}
void FixedBar::setChannelActions() {
if (_peerChannel->amCreator()) {
addRightAction(RightActionType::EditChannel, lang(lng_profile_edit_contact), SLOT(onEditChannel()));
}
}
void FixedBar::addRightAction(RightActionType type, const QString &text, const char *slot) {
if (_rightActions.size() > _currentAction) {
if (_rightActions.at(_currentAction).type == type) {
++_currentAction;
return;
}
} else {
t_assert(_rightActions.size() == _currentAction);
_rightActions.push_back({});
}
_rightActions[_currentAction].type = type;
_rightActions[_currentAction].button = new FlatButton(this, text, st::profileFixedBarButton);
connect(_rightActions[_currentAction].button, SIGNAL(clicked()), this, slot);
bool showButton = !_animatingMode && (type != RightActionType::ShareContact || !_hideShareContactButton);
_rightActions[_currentAction].button->setVisible(showButton);
++_currentAction;
}
void FixedBar::onBack() {
@ -74,32 +144,63 @@ void FixedBar::onBack() {
}
void FixedBar::onEditChannel() {
Ui::showLayer(new EditChannelBox(_peerMegagroup ? _peerMegagroup : _peerChannel));
}
void FixedBar::onEditGroup() {
}
void FixedBar::onLeaveGroup() {
Ui::showLayer(new EditNameTitleBox(_peerChat));
}
void FixedBar::onAddContact() {
auto firstName = _peerUser->firstName;
auto lastName = _peerUser->lastName;
auto phone = _peerUser->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(_peer->id)) : _peerUser->phone;
Ui::showLayer(new AddContactBox(firstName, lastName, phone));
}
void FixedBar::onEditContact() {
Ui::showLayer(new AddContactBox(_peerUser));
}
void FixedBar::onShareContact() {
App::main()->shareContactLayer(_peerUser);
}
void FixedBar::onDeleteContact() {
ConfirmBox *box = new ConfirmBox(lng_sure_delete_contact(lt_contact, App::peerName(_peerUser)), lang(lng_box_delete));
connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteContactSure()));
Ui::showLayer(box);
}
void FixedBar::onDeleteContactSure() {
Ui::showChatsList();
Ui::hideLayer();
MTP::send(MTPcontacts_DeleteContact(_peerUser->inputUser), App::main()->rpcDone(&MainWidget::deletedContact, _peerUser));
}
void FixedBar::onLeaveGroup() {
ConfirmBox *box = new ConfirmBox(lng_sure_delete_and_exit(lt_group, App::peerName(_peerChat)), lang(lng_box_leave), st::attentionBoxButton);
connect(box, SIGNAL(confirmed()), this, SLOT(onLeaveGroupSure()));
Ui::showLayer(box);
}
void FixedBar::onLeaveGroupSure() {
Ui::showChatsList();
Ui::hideLayer();
MTP::send(MTPmessages_DeleteChatUser(_peerChat->inputChat, App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistoryAfterLeave, _peer), App::main()->rpcFail(&MainWidget::leaveChatFailed, _peer));
}
void FixedBar::resizeToWidth(int newWidth) {
int newHeight = 0;
int buttonLeft = newWidth;
for (auto i = _rightActions.cend(), b = _rightActions.cbegin(); i != b;) {
--i;
buttonLeft -= i->button->width();
i->button->moveToLeft(buttonLeft, 0);
}
_backButton->moveToLeft(0, 0);
_backButton->resizeToWidth(newWidth);
newHeight += _backButton->height();
@ -116,11 +217,29 @@ void FixedBar::setAnimatingMode(bool enabled) {
} else {
setAttribute(Qt::WA_OpaquePaintEvent);
showChildren();
if (_hideShareContactButton) {
applyHideShareContactButton();
}
}
show();
}
}
void FixedBar::setHideShareContactButton(bool hideButton) {
_hideShareContactButton = hideButton;
if (!_animatingMode) {
applyHideShareContactButton();
}
}
void FixedBar::applyHideShareContactButton() {
for_const (auto &action, _rightActions) {
if (action.type == RightActionType::ShareContact) {
action.button->setVisible(_hideShareContactButton);
}
}
}
void FixedBar::mousePressEvent(QMouseEvent *e) {
if (e->button() == Qt::LeftButton) {
onBack();

View File

@ -36,6 +36,9 @@ public:
// whole fixed bar acts like a back button.
void setAnimatingMode(bool enabled);
// The "Share contact" button should be hidden if it is shown in the profile cover.
void setHideShareContactButton(bool hideButton);
protected:
void mousePressEvent(QMouseEvent *e) override;
@ -45,22 +48,34 @@ public slots:
private slots:
void onEditChannel();
void onEditGroup();
void onLeaveGroup();
void onAddContact();
void onEditContact();
void onShareContact();
void onDeleteContact();
void onDeleteContactSure();
void onLeaveGroup();
void onLeaveGroupSure();
private:
void refreshRightActions();
void setUserActions();
void setChatActions();
void setMegagroupActions();
void setChannelActions();
enum class RightActionType {
EditChannel,
EditGroup,
LeaveGroup,
AddContact,
EditContact,
DeleteContact
DeleteContact,
ShareContact,
};
void addRightAction(RightActionType type, const QString &text, const char *slot);
void applyHideShareContactButton();
PeerData *_peer;
UserData *_peerUser;
ChatData *_peerChat;
@ -68,10 +83,16 @@ private:
ChannelData *_peerMegagroup;
ChildWidget<BackButton> _backButton;
QList<FlatButton*> _rightActions;
QList<RightActionType> _rightActionTypes;
int _currentAction = 0;
struct RightAction {
RightActionType type;
FlatButton *button;
};
QList<RightAction> _rightActions;
bool _animatingMode = false;
bool _hideShareContactButton = false;
};

View File

@ -45,7 +45,7 @@ void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
int notDisplayedAtBottom = height() - _visibleBottom;
if (notDisplayedAtBottom > 0) {
decreaseAdditionalHeight(notDisplayedAtBottom);
// decreaseAdditionalHeight(notDisplayedAtBottom); // testing
}
//loadProfilePhotos(_visibleTop);
@ -56,6 +56,10 @@ void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
}
}
bool InnerWidget::shareContactButtonShown() const {
return _cover->shareContactButtonShown();
}
void InnerWidget::showFinished() {
_cover->showFinished();
}

View File

@ -41,6 +41,11 @@ public:
// Updates the area that is visible inside the scroll container.
void setVisibleTopBottom(int visibleTop, int visibleBottom);
// Profile fixed top bar should use this flag to decide
// if it shows "Share contact" button or not.
// It should show it only if it is hidden in the cover.
bool shareContactButtonShown() const;
void showFinished();
signals:

View File

@ -106,8 +106,11 @@ void Widget::resizeEvent(QResizeEvent *e) {
QSize scrollSize(width(), height() - _fixedBar->height());
if (_scroll->size() != scrollSize) {
_scroll->resize(scrollSize);
_inner->resizeToWidth(scrollSize.width(), _scroll->height() * 2);
// _inner->resizeToWidth(scrollSize.width(), _scroll->height());
_inner->resizeToWidth(scrollSize.width(), _scroll->height() * 2); // testing
}
_fixedBar->setHideShareContactButton(!_inner->shareContactButtonShown());
if (!_scroll->isHidden()) {
if (topDelta()) {
_scroll->scrollToY(newScrollTop);

View File

@ -65,12 +65,17 @@ void RoundButton::paintEvent(QPaintEvent *e) {
p.setOpacity(o);
App::roundRect(p, rect(), _st.textBgOver);
p.setOpacity(1);
p.setPen(a_textFg.current());
} else {
p.setPen(_st.textFg);
}
p.setFont(_st.font);
p.drawText((width() - _textWidth) / 2, _st.textTop + _st.font->ascent, _text);
if (!_text.isEmpty()) {
if (o > 0) {
p.setPen(a_textFg.current());
} else {
p.setPen(_st.textFg);
}
p.setFont(_st.font);
p.drawText((width() - _textWidth) / 2, _st.textTop + _st.font->ascent, _text);
}
_st.icon.paint(p, QPoint(0, 0), width());
}
void RoundButton::step_over(float64 ms, bool timer) {

View File

@ -677,6 +677,7 @@ void ScrollArea::leaveEvent(QEvent *e) {
void ScrollArea::scrollToY(int toTop, int toBottom) {
myEnsureResized(widget());
myEnsureResized(this);
int toMin = 0, toMax = scrollTopMax();
if (toTop < toMin) {