mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Scrollable boxes reorganized: _scroll always owns _inner.
Also some boxes moved to separate modules: MembersBox, StickersBox.
This commit is contained in:
parent
2bd561821a
commit
e5a5273b3a
34 changed files with 3676 additions and 3566 deletions
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Binary file not shown.
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 83 KiB |
|
@ -343,48 +343,6 @@ boxScroll: flatScroll(solidScroll) {
|
|||
boxScrollSkip: 6px;
|
||||
boxScrollShadowBg: #00000012;
|
||||
|
||||
boxSearchField: InputField(defaultInputField) {
|
||||
textMargins: margins(41px, 16px, 41px, 0px);
|
||||
|
||||
placeholderFg: #999;
|
||||
placeholderFgActive: #aaa;
|
||||
placeholderMargins: margins(4px, 0px, 4px, 0px);
|
||||
|
||||
border: 0px;
|
||||
borderActive: 0px;
|
||||
borderError: 0px;
|
||||
|
||||
height: 48px;
|
||||
|
||||
iconSprite: sprite(227px, 21px, 24px, 24px);
|
||||
iconPosition: point(15px, 14px);
|
||||
|
||||
font: normalFont;
|
||||
}
|
||||
boxSearchCancel: iconedButton {
|
||||
color: white;
|
||||
bgColor: white;
|
||||
overBgColor: white;
|
||||
font: font(fsize);
|
||||
|
||||
opacity: 0.3;
|
||||
overOpacity: 0.4;
|
||||
|
||||
textPos: point(0px, 0px);
|
||||
downTextPos: point(0px, 0px);
|
||||
|
||||
duration: 150;
|
||||
cursor: cursor(pointer);
|
||||
|
||||
icon: sprite(133px, 108px, 12px, 12px);
|
||||
iconPos: point(8px, 18px);
|
||||
downIcon: sprite(133px, 108px, 12px, 12px);
|
||||
downIconPos: point(8px, 18px);
|
||||
|
||||
width: 41px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
titleBg: #6389a8;
|
||||
titleHeight: 39px;
|
||||
titleIconPos: point(7px, 7px);
|
||||
|
|
BIN
Telegram/Resources/icons/box_search_cancel.png
Normal file
BIN
Telegram/Resources/icons/box_search_cancel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 187 B |
BIN
Telegram/Resources/icons/box_search_cancel@2x.png
Normal file
BIN
Telegram/Resources/icons/box_search_cancel@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 296 B |
|
@ -205,15 +205,7 @@ void ScrollableBox::resizeEvent(QResizeEvent *e) {
|
|||
AbstractBox::resizeEvent(e);
|
||||
}
|
||||
|
||||
void ScrollableBox::init(QWidget *inner, int bottomSkip, int topSkip) {
|
||||
_bottomSkip = bottomSkip;
|
||||
_topSkip = topSkip;
|
||||
_scroll->setWidget(inner);
|
||||
_scroll->setFocusPolicy(Qt::NoFocus);
|
||||
ScrollableBox::resizeEvent(nullptr);
|
||||
}
|
||||
|
||||
void ScrollableBox::initOwned(QWidget *inner, int bottomSkip, int topSkip) {
|
||||
void ScrollableBox::init(ScrolledWidget *inner, int bottomSkip, int topSkip) {
|
||||
_bottomSkip = bottomSkip;
|
||||
_topSkip = topSkip;
|
||||
_scroll->setOwnedWidget(inner);
|
||||
|
|
|
@ -105,8 +105,7 @@ public:
|
|||
ScrollableBox(const style::flatScroll &scroll, int w = st::boxWideWidth);
|
||||
|
||||
protected:
|
||||
void init(QWidget *inner, int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
||||
void initOwned(QWidget *inner, int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
||||
void init(ScrolledWidget *inner, int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
|
|
|
@ -27,11 +27,41 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "window/chat_background.h"
|
||||
#include "styles/style_overview.h"
|
||||
|
||||
BackgroundInner::BackgroundInner() :
|
||||
_bgCount(0), _rows(0), _over(-1), _overDown(-1) {
|
||||
BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll)
|
||||
, _inner(this) {
|
||||
init(_inner);
|
||||
|
||||
connect(_inner, SIGNAL(backgroundChosen(int)), this, SLOT(onBackgroundChosen(int)));
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
void BackgroundBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
paintTitle(p, lang(lng_backgrounds_header));
|
||||
}
|
||||
|
||||
void BackgroundBox::onBackgroundChosen(int index) {
|
||||
if (index >= 0 && index < App::cServerBackgrounds().size()) {
|
||||
const App::WallPaper &paper(App::cServerBackgrounds().at(index));
|
||||
if (App::main()) App::main()->setChatBackground(paper);
|
||||
|
||||
using Update = Window::ChatBackgroundUpdate;
|
||||
Window::chatBackground()->notify(Update(Update::Type::Start, !paper.id));
|
||||
}
|
||||
onClose();
|
||||
}
|
||||
|
||||
BackgroundBox::Inner::Inner(QWidget *parent) : ScrolledWidget(parent)
|
||||
, _bgCount(0)
|
||||
, _rows(0)
|
||||
, _over(-1)
|
||||
, _overDown(-1) {
|
||||
if (App::cServerBackgrounds().isEmpty()) {
|
||||
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
MTP::send(MTPaccount_GetWallPapers(), rpcDone(&BackgroundInner::gotWallpapers));
|
||||
MTP::send(MTPaccount_GetWallPapers(), rpcDone(&Inner::gotWallpapers));
|
||||
} else {
|
||||
updateWallpapers();
|
||||
}
|
||||
|
@ -40,7 +70,7 @@ _bgCount(0), _rows(0), _over(-1), _overDown(-1) {
|
|||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void BackgroundInner::gotWallpapers(const MTPVector<MTPWallPaper> &result) {
|
||||
void BackgroundBox::Inner::gotWallpapers(const MTPVector<MTPWallPaper> &result) {
|
||||
App::WallPapers wallpapers;
|
||||
|
||||
wallpapers.push_back(App::WallPaper(0, ImagePtr(st::msgBG0), ImagePtr(st::msgBG0)));
|
||||
|
@ -98,7 +128,7 @@ void BackgroundInner::gotWallpapers(const MTPVector<MTPWallPaper> &result) {
|
|||
updateWallpapers();
|
||||
}
|
||||
|
||||
void BackgroundInner::updateWallpapers() {
|
||||
void BackgroundBox::Inner::updateWallpapers() {
|
||||
_bgCount = App::cServerBackgrounds().size();
|
||||
_rows = _bgCount / BackgroundsInRow;
|
||||
if (_bgCount % BackgroundsInRow) ++_rows;
|
||||
|
@ -111,7 +141,7 @@ void BackgroundInner::updateWallpapers() {
|
|||
}
|
||||
}
|
||||
|
||||
void BackgroundInner::paintEvent(QPaintEvent *e) {
|
||||
void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
|
@ -145,7 +175,7 @@ void BackgroundInner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void BackgroundInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
int x = e->pos().x(), y = e->pos().y();
|
||||
int row = int((y - st::backgroundPadding) / (st::backgroundSize.height() + st::backgroundPadding));
|
||||
if (y - row * (st::backgroundSize.height() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.height()) row = _rows + 1;
|
||||
|
@ -161,11 +191,11 @@ void BackgroundInner::mouseMoveEvent(QMouseEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void BackgroundInner::mousePressEvent(QMouseEvent *e) {
|
||||
void BackgroundBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
_overDown = _over;
|
||||
}
|
||||
|
||||
void BackgroundInner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (_overDown == _over && _over >= 0) {
|
||||
emit backgroundChosen(_over);
|
||||
} else if (_over < 0) {
|
||||
|
@ -173,33 +203,5 @@ void BackgroundInner::mouseReleaseEvent(QMouseEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void BackgroundInner::resizeEvent(QResizeEvent *e) {
|
||||
}
|
||||
|
||||
BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll)
|
||||
, _inner() {
|
||||
|
||||
init(&_inner);
|
||||
|
||||
connect(&_inner, SIGNAL(backgroundChosen(int)), this, SLOT(onBackgroundChosen(int)));
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
void BackgroundBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
paintTitle(p, lang(lng_backgrounds_header));
|
||||
}
|
||||
|
||||
void BackgroundBox::onBackgroundChosen(int index) {
|
||||
if (index >= 0 && index < App::cServerBackgrounds().size()) {
|
||||
const App::WallPaper &paper(App::cServerBackgrounds().at(index));
|
||||
if (App::main()) App::main()->setChatBackground(paper);
|
||||
|
||||
using Update = Window::ChatBackgroundUpdate;
|
||||
Window::chatBackground()->notify(Update(Update::Type::Start, !paper.id));
|
||||
}
|
||||
onClose();
|
||||
void BackgroundBox::Inner::resizeEvent(QResizeEvent *e) {
|
||||
}
|
||||
|
|
|
@ -23,11 +23,30 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "abstractbox.h"
|
||||
#include "core/lambda_wrap.h"
|
||||
|
||||
class BackgroundInner : public TWidget, public RPCSender, private base::Subscriber {
|
||||
class BackgroundBox : public ItemListBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BackgroundInner();
|
||||
BackgroundBox();
|
||||
|
||||
public slots:
|
||||
void onBackgroundChosen(int index);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
|
||||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class BackgroundBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Inner(QWidget *parent);
|
||||
|
||||
signals:
|
||||
void backgroundChosen(int index);
|
||||
|
@ -47,20 +66,3 @@ private:
|
|||
int32 _over, _overDown;
|
||||
|
||||
};
|
||||
|
||||
class BackgroundBox : public ItemListBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BackgroundBox();
|
||||
|
||||
public slots:
|
||||
void onBackgroundChosen(int index);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
BackgroundInner _inner;
|
||||
|
||||
};
|
||||
|
|
|
@ -68,6 +68,38 @@ aboutRevokePublicLabel: flatLabel(labelDefFlat) {
|
|||
textFg: windowTextFg;
|
||||
}
|
||||
|
||||
boxSearchField: InputField(defaultInputField) {
|
||||
textMargins: margins(41px, 16px, 41px, 0px);
|
||||
|
||||
placeholderFg: #999;
|
||||
placeholderFgActive: #aaa;
|
||||
placeholderMargins: margins(4px, 0px, 4px, 0px);
|
||||
|
||||
border: 0px;
|
||||
borderActive: 0px;
|
||||
borderError: 0px;
|
||||
|
||||
height: 48px;
|
||||
|
||||
iconSprite: sprite(227px, 21px, 24px, 24px);
|
||||
iconPosition: point(15px, 14px);
|
||||
|
||||
font: normalFont;
|
||||
}
|
||||
boxSearchCancel: IconButton {
|
||||
width: 41px;
|
||||
height: 48px;
|
||||
|
||||
opacity: 0.3;
|
||||
overOpacity: 0.4;
|
||||
|
||||
icon: icon {{ "box_search_cancel", #000000 }};
|
||||
iconPosition: point(8px, 18px);
|
||||
downIconPosition: point(8px, 18px);
|
||||
|
||||
duration: 150;
|
||||
}
|
||||
|
||||
contactsPhotoCheckbox: RoundImageCheckbox {
|
||||
imageRadius: 21px;
|
||||
imageSmallRadius: 18px;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,186 +23,24 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "abstractbox.h"
|
||||
#include "core/single_timer.h"
|
||||
#include "ui/effects/round_image_checkbox.h"
|
||||
#include "boxes/members_box.h"
|
||||
|
||||
namespace Dialogs {
|
||||
class Row;
|
||||
class IndexedList;
|
||||
} // namespace Dialogs
|
||||
|
||||
enum MembersFilter {
|
||||
MembersFilterRecent,
|
||||
MembersFilterAdmins,
|
||||
};
|
||||
using MembersAlreadyIn = OrderedSet<UserData*>;
|
||||
namespace Ui {
|
||||
class IconButton;
|
||||
} // namespace Ui
|
||||
|
||||
QString cantInviteError();
|
||||
|
||||
class ConfirmBox;
|
||||
class ContactsInner : public TWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
struct ContactData;
|
||||
|
||||
public:
|
||||
ContactsInner(CreatingGroupType creating = CreatingGroupNone);
|
||||
ContactsInner(ChannelData *channel, MembersFilter membersFilter, const MembersAlreadyIn &already);
|
||||
ContactsInner(ChatData *chat, MembersFilter membersFilter);
|
||||
ContactsInner(UserData *bot);
|
||||
void init();
|
||||
void initList();
|
||||
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
void selectSkip(int32 dir);
|
||||
void selectSkipPage(int32 h, int32 dir);
|
||||
|
||||
QVector<UserData*> selected();
|
||||
QVector<MTPInputUser> selectedInputs();
|
||||
bool allAdmins() const {
|
||||
return _allAdmins.checked();
|
||||
}
|
||||
|
||||
void loadProfilePhotos(int32 yFrom);
|
||||
void chooseParticipant();
|
||||
void changeCheckState(Dialogs::Row *row);
|
||||
void changeCheckState(ContactData *data, PeerData *peer);
|
||||
|
||||
void peopleReceived(const QString &query, const QVector<MTPPeer> &people);
|
||||
|
||||
void refresh();
|
||||
|
||||
ChatData *chat() const;
|
||||
ChannelData *channel() const;
|
||||
MembersFilter membersFilter() const;
|
||||
UserData *bot() const;
|
||||
CreatingGroupType creating() const;
|
||||
|
||||
bool sharingBotGame() const;
|
||||
|
||||
int32 selectedCount() const;
|
||||
bool hasAlreadyMembersInChannel() const {
|
||||
return !_already.isEmpty();
|
||||
}
|
||||
|
||||
void saving(bool flag);
|
||||
|
||||
~ContactsInner();
|
||||
|
||||
signals:
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
void selectAllQuery();
|
||||
void searchByUsername();
|
||||
void chosenChanged();
|
||||
void adminAdded();
|
||||
void addRequested();
|
||||
|
||||
public slots:
|
||||
void onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow);
|
||||
|
||||
void updateSel();
|
||||
void peerUpdated(PeerData *peer);
|
||||
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
||||
|
||||
void onAddBot();
|
||||
void onAddAdmin();
|
||||
void onNoAddAdminBox(QObject *obj);
|
||||
|
||||
void onAllAdminsChanged();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void enterEvent(QEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
void updateRowWithTop(int rowTop);
|
||||
int getSelectedRowTop() const;
|
||||
void updateSelectedRow();
|
||||
int getRowTopWithPeer(PeerData *peer) const;
|
||||
void updateRowWithPeer(PeerData *peer);
|
||||
void addAdminDone(const MTPUpdates &result, mtpRequestId req);
|
||||
bool addAdminFail(const RPCError &error, mtpRequestId req);
|
||||
|
||||
void paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel);
|
||||
void paintDisabledCheckUserpic(Painter &p, PeerData *peer, int x, int y, int outerWidth) const;
|
||||
|
||||
template <typename FilterCallback>
|
||||
void addDialogsToList(FilterCallback callback);
|
||||
|
||||
bool usingMultiSelect() const {
|
||||
return (_chat != nullptr) || (_creating != CreatingGroupNone && (!_channel || _membersFilter != MembersFilterAdmins));
|
||||
}
|
||||
|
||||
int32 _rowHeight;
|
||||
int _newItemHeight = 0;
|
||||
bool _newItemSel = false;
|
||||
|
||||
ChatData *_chat = nullptr;
|
||||
ChannelData *_channel = nullptr;
|
||||
MembersFilter _membersFilter = MembersFilterRecent;
|
||||
UserData *_bot = nullptr;
|
||||
CreatingGroupType _creating = CreatingGroupNone;
|
||||
MembersAlreadyIn _already;
|
||||
|
||||
Checkbox _allAdmins;
|
||||
int32 _aboutWidth;
|
||||
Text _aboutAllAdmins, _aboutAdmins;
|
||||
|
||||
PeerData *_addToPeer = nullptr;
|
||||
UserData *_addAdmin = nullptr;
|
||||
mtpRequestId _addAdminRequestId = 0;
|
||||
ConfirmBox *_addAdminBox = nullptr;
|
||||
|
||||
int32 _time;
|
||||
|
||||
std_::unique_ptr<Dialogs::IndexedList> _customList;
|
||||
Dialogs::IndexedList *_contacts = nullptr;
|
||||
Dialogs::Row *_sel = nullptr;
|
||||
QString _filter;
|
||||
typedef QVector<Dialogs::Row*> FilteredDialogs;
|
||||
FilteredDialogs _filtered;
|
||||
int _filteredSel = -1;
|
||||
bool _mouseSel = false;
|
||||
|
||||
int _selCount = 0;
|
||||
|
||||
struct ContactData {
|
||||
ContactData();
|
||||
ContactData(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback);
|
||||
|
||||
std_::unique_ptr<Ui::RoundImageCheckbox> checkbox;
|
||||
Text name;
|
||||
QString statusText;
|
||||
bool statusHasOnlineColor = false;
|
||||
bool disabledChecked = false;
|
||||
inline Ui::RoundImageCheckbox::PaintRoundImage PaintUserpicCallback(PeerData *peer) {
|
||||
return [peer](Painter &p, int x, int y, int outerWidth, int size) {
|
||||
peer->paintUserpicLeft(p, size, x, y, outerWidth);
|
||||
};
|
||||
typedef QMap<PeerData*, ContactData*> ContactsData;
|
||||
ContactsData _contactsData;
|
||||
typedef QMap<PeerData*, bool> CheckedContacts;
|
||||
CheckedContacts _checkedContacts;
|
||||
|
||||
ContactData *contactData(Dialogs::Row *row);
|
||||
|
||||
bool _searching = false;
|
||||
QString _lastQuery;
|
||||
typedef QVector<PeerData*> ByUsernameRows;
|
||||
typedef QVector<ContactData*> ByUsernameDatas;
|
||||
ByUsernameRows _byUsername, _byUsernameFiltered;
|
||||
ByUsernameDatas d_byUsername, d_byUsernameFiltered; // filtered is partly subset of d_byUsername, partly subset of _byUsernameDatas
|
||||
ByUsernameDatas _byUsernameDatas;
|
||||
int _byUsernameSel = -1;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
LinkButton _addContactLnk;
|
||||
|
||||
bool _saving = false;
|
||||
bool _allAdminsChecked = false;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class ContactsBox : public ItemListBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
@ -245,9 +83,10 @@ protected:
|
|||
private:
|
||||
void init();
|
||||
|
||||
ContactsInner _inner;
|
||||
InputField _filter;
|
||||
IconedButton _filterCancel;
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ChildWidget<InputField> _filter;
|
||||
ChildWidget<Ui::IconButton> _filterCancel;
|
||||
|
||||
BoxButton _next, _cancel;
|
||||
MembersFilter _membersFilter;
|
||||
|
@ -289,50 +128,74 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class MembersInner : public TWidget, public RPCSender, private base::Subscriber {
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class ContactsBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
struct MemberData;
|
||||
|
||||
public:
|
||||
MembersInner(ChannelData *channel, MembersFilter filter);
|
||||
Inner(QWidget *parent, CreatingGroupType creating = CreatingGroupNone);
|
||||
Inner(QWidget *parent, ChannelData *channel, MembersFilter membersFilter, const MembersAlreadyIn &already);
|
||||
Inner(QWidget *parent, ChatData *chat, MembersFilter membersFilter);
|
||||
Inner(QWidget *parent, UserData *bot);
|
||||
|
||||
void paintDialog(Painter &p, PeerData *peer, MemberData *data, bool sel, bool kickSel, bool kickDown);
|
||||
void init();
|
||||
void initList();
|
||||
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
void selectSkip(int32 dir);
|
||||
void selectSkipPage(int32 h, int32 dir);
|
||||
|
||||
QVector<UserData*> selected();
|
||||
QVector<MTPInputUser> selectedInputs();
|
||||
bool allAdmins() const {
|
||||
return _allAdmins.checked();
|
||||
}
|
||||
|
||||
void loadProfilePhotos(int32 yFrom);
|
||||
void chooseParticipant();
|
||||
|
||||
void peopleReceived(const QString &query, const QVector<MTPPeer> &people);
|
||||
|
||||
void refresh();
|
||||
|
||||
ChatData *chat() const;
|
||||
ChannelData *channel() const;
|
||||
MembersFilter filter() const;
|
||||
MembersFilter membersFilter() const;
|
||||
UserData *bot() const;
|
||||
CreatingGroupType creating() const;
|
||||
|
||||
bool isLoaded() const {
|
||||
return !_loading;
|
||||
bool sharingBotGame() const;
|
||||
|
||||
int32 selectedCount() const;
|
||||
bool hasAlreadyMembersInChannel() const {
|
||||
return !_already.isEmpty();
|
||||
}
|
||||
void clearSel();
|
||||
|
||||
MembersAlreadyIn already() const;
|
||||
void saving(bool flag);
|
||||
|
||||
~MembersInner();
|
||||
~Inner();
|
||||
|
||||
signals:
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
void selectAllQuery();
|
||||
void searchByUsername();
|
||||
void chosenChanged();
|
||||
void adminAdded();
|
||||
void addRequested();
|
||||
void loaded();
|
||||
|
||||
public slots:
|
||||
void load();
|
||||
void onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow);
|
||||
|
||||
void updateSel();
|
||||
void peerUpdated(PeerData *peer);
|
||||
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
||||
void onKickConfirm();
|
||||
void onKickBoxDestroyed(QObject *obj);
|
||||
|
||||
void onAddBot();
|
||||
void onAddAdmin();
|
||||
void onNoAddAdminBox(QObject *obj);
|
||||
|
||||
void onAllAdminsChanged();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
@ -340,102 +203,94 @@ protected:
|
|||
void leaveEvent(QEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
void updateSelectedRow();
|
||||
MemberData *data(int32 index);
|
||||
|
||||
void membersReceived(const MTPchannels_ChannelParticipants &result, mtpRequestId req);
|
||||
bool membersFailed(const RPCError &error, mtpRequestId req);
|
||||
|
||||
void kickDone(const MTPUpdates &result, mtpRequestId req);
|
||||
void kickAdminDone(const MTPUpdates &result, mtpRequestId req);
|
||||
bool kickFail(const RPCError &error, mtpRequestId req);
|
||||
void removeKicked();
|
||||
|
||||
void clear();
|
||||
|
||||
int32 _rowHeight, _newItemHeight;
|
||||
bool _newItemSel;
|
||||
|
||||
ChannelData *_channel;
|
||||
MembersFilter _filter;
|
||||
|
||||
QString _kickText;
|
||||
int32 _time, _kickWidth;
|
||||
|
||||
int32 _sel, _kickSel, _kickDown;
|
||||
bool _mouseSel;
|
||||
|
||||
UserData *_kickConfirm;
|
||||
mtpRequestId _kickRequestId;
|
||||
|
||||
ConfirmBox *_kickBox;
|
||||
|
||||
enum MemberRole {
|
||||
MemberRoleNone,
|
||||
MemberRoleSelf,
|
||||
MemberRoleCreator,
|
||||
MemberRoleEditor,
|
||||
MemberRoleModerator,
|
||||
MemberRoleKicked
|
||||
};
|
||||
|
||||
struct MemberData {
|
||||
Text name;
|
||||
QString online;
|
||||
bool onlineColor;
|
||||
bool canKick;
|
||||
};
|
||||
|
||||
bool _loading;
|
||||
mtpRequestId _loadingRequestId;
|
||||
typedef QVector<UserData*> MemberRows;
|
||||
typedef QVector<QDateTime> MemberDates;
|
||||
typedef QVector<MemberRole> MemberRoles;
|
||||
typedef QVector<MemberData*> MemberDatas;
|
||||
MemberRows _rows;
|
||||
MemberDates _dates;
|
||||
MemberRoles _roles;
|
||||
MemberDatas _datas;
|
||||
|
||||
int32 _aboutWidth;
|
||||
Text _about;
|
||||
int32 _aboutHeight;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
};
|
||||
|
||||
class MembersBox : public ItemListBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MembersBox(ChannelData *channel, MembersFilter filter);
|
||||
|
||||
public slots:
|
||||
void onScroll();
|
||||
|
||||
void onAdd();
|
||||
void onAdminAdded();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
MembersInner _inner;
|
||||
struct ContactData {
|
||||
ContactData();
|
||||
ContactData(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback);
|
||||
|
||||
ContactsBox *_addBox;
|
||||
std_::unique_ptr<Ui::RoundImageCheckbox> checkbox;
|
||||
Text name;
|
||||
QString statusText;
|
||||
bool statusHasOnlineColor = false;
|
||||
bool disabledChecked = false;
|
||||
};
|
||||
|
||||
SingleTimer _loadTimer;
|
||||
void updateRowWithTop(int rowTop);
|
||||
int getSelectedRowTop() const;
|
||||
void updateSelectedRow();
|
||||
int getRowTopWithPeer(PeerData *peer) const;
|
||||
void updateRowWithPeer(PeerData *peer);
|
||||
void addAdminDone(const MTPUpdates &result, mtpRequestId req);
|
||||
bool addAdminFail(const RPCError &error, mtpRequestId req);
|
||||
|
||||
void paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel);
|
||||
void paintDisabledCheckUserpic(Painter &p, PeerData *peer, int x, int y, int outerWidth) const;
|
||||
|
||||
void changeCheckState(Dialogs::Row *row);
|
||||
void changeCheckState(ContactData *data, PeerData *peer);
|
||||
|
||||
template <typename FilterCallback>
|
||||
void addDialogsToList(FilterCallback callback);
|
||||
|
||||
bool usingMultiSelect() const {
|
||||
return (_chat != nullptr) || (_creating != CreatingGroupNone && (!_channel || _membersFilter != MembersFilter::Admins));
|
||||
}
|
||||
|
||||
int32 _rowHeight;
|
||||
int _newItemHeight = 0;
|
||||
bool _newItemSel = false;
|
||||
|
||||
ChatData *_chat = nullptr;
|
||||
ChannelData *_channel = nullptr;
|
||||
MembersFilter _membersFilter = MembersFilter::Recent;
|
||||
UserData *_bot = nullptr;
|
||||
CreatingGroupType _creating = CreatingGroupNone;
|
||||
MembersAlreadyIn _already;
|
||||
|
||||
Checkbox _allAdmins;
|
||||
int32 _aboutWidth;
|
||||
Text _aboutAllAdmins, _aboutAdmins;
|
||||
|
||||
PeerData *_addToPeer = nullptr;
|
||||
UserData *_addAdmin = nullptr;
|
||||
mtpRequestId _addAdminRequestId = 0;
|
||||
ConfirmBox *_addAdminBox = nullptr;
|
||||
|
||||
int32 _time;
|
||||
|
||||
std_::unique_ptr<Dialogs::IndexedList> _customList;
|
||||
Dialogs::IndexedList *_contacts = nullptr;
|
||||
Dialogs::Row *_sel = nullptr;
|
||||
QString _filter;
|
||||
typedef QVector<Dialogs::Row*> FilteredDialogs;
|
||||
FilteredDialogs _filtered;
|
||||
int _filteredSel = -1;
|
||||
bool _mouseSel = false;
|
||||
|
||||
int _selCount = 0;
|
||||
|
||||
typedef QMap<PeerData*, ContactData*> ContactsData;
|
||||
ContactsData _contactsData;
|
||||
typedef QMap<PeerData*, bool> CheckedContacts;
|
||||
CheckedContacts _checkedContacts;
|
||||
|
||||
ContactData *contactData(Dialogs::Row *row);
|
||||
|
||||
bool _searching = false;
|
||||
QString _lastQuery;
|
||||
typedef QVector<PeerData*> ByUsernameRows;
|
||||
typedef QVector<ContactData*> ByUsernameDatas;
|
||||
ByUsernameRows _byUsername, _byUsernameFiltered;
|
||||
ByUsernameDatas d_byUsername, d_byUsernameFiltered; // filtered is partly subset of d_byUsername, partly subset of _byUsernameDatas
|
||||
ByUsernameDatas _byUsernameDatas;
|
||||
int _byUsernameSel = -1;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
LinkButton _addContactLnk;
|
||||
|
||||
bool _saving = false;
|
||||
bool _allAdminsChecked = false;
|
||||
|
||||
};
|
||||
|
||||
inline Ui::RoundImageCheckbox::PaintRoundImage PaintUserpicCallback(PeerData *peer) {
|
||||
return [peer](Painter &p, int x, int y, int outerWidth, int size) {
|
||||
peer->paintUserpicLeft(p, size, x, y, outerWidth);
|
||||
};
|
||||
}
|
||||
|
|
607
Telegram/SourceFiles/boxes/members_box.cpp
Normal file
607
Telegram/SourceFiles/boxes/members_box.cpp
Normal file
|
@ -0,0 +1,607 @@
|
|||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "boxes/members_box.h"
|
||||
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "lang.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "boxes/contactsbox.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "observer_peer.h"
|
||||
|
||||
MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox(st::boxScroll)
|
||||
, _inner(this, channel, filter) {
|
||||
ItemListBox::init(_inner);
|
||||
|
||||
connect(_inner, SIGNAL(addRequested()), this, SLOT(onAdd()));
|
||||
|
||||
connect(scrollArea(), SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
||||
|
||||
connect(&_loadTimer, SIGNAL(timeout()), _inner, SLOT(load()));
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
void MembersBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Down) {
|
||||
_inner->selectSkip(1);
|
||||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner->selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner->selectSkipPage(scrollArea()->height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner->selectSkipPage(scrollArea()->height(), -1);
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
QString title(lang(_inner->filter() == MembersFilter::Recent ? lng_channel_members : lng_channel_admins));
|
||||
paintTitle(p, title);
|
||||
}
|
||||
|
||||
void MembersBox::resizeEvent(QResizeEvent *e) {
|
||||
ItemListBox::resizeEvent(e);
|
||||
_inner->resize(width(), _inner->height());
|
||||
}
|
||||
|
||||
void MembersBox::onScroll() {
|
||||
_inner->loadProfilePhotos(scrollArea()->scrollTop());
|
||||
}
|
||||
|
||||
void MembersBox::onAdd() {
|
||||
if (_inner->filter() == MembersFilter::Recent && _inner->channel()->membersCount() >= (_inner->channel()->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
|
||||
Ui::showLayer(new MaxInviteBox(_inner->channel()->inviteLink()), KeepOtherLayers);
|
||||
return;
|
||||
}
|
||||
ContactsBox *box = new ContactsBox(_inner->channel(), _inner->filter(), _inner->already());
|
||||
if (_inner->filter() == MembersFilter::Recent) {
|
||||
Ui::showLayer(box);
|
||||
} else {
|
||||
_addBox = box;
|
||||
connect(_addBox, SIGNAL(adminAdded()), this, SLOT(onAdminAdded()));
|
||||
Ui::showLayer(_addBox, KeepOtherLayers);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::onAdminAdded() {
|
||||
if (!_addBox) return;
|
||||
_addBox->onClose();
|
||||
_addBox = 0;
|
||||
_loadTimer.start(ReloadChannelMembersTimeout);
|
||||
}
|
||||
|
||||
MembersBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter filter) : ScrolledWidget(parent)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _newItemHeight((channel->amCreator() && (channel->membersCount() < (channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilter::Admins)) ? st::contactsNewItemHeight : 0)
|
||||
, _newItemSel(false)
|
||||
, _channel(channel)
|
||||
, _filter(filter)
|
||||
, _kickText(lang(lng_profile_kick))
|
||||
, _time(0)
|
||||
, _kickWidth(st::normalFont->width(_kickText))
|
||||
, _sel(-1)
|
||||
, _kickSel(-1)
|
||||
, _kickDown(-1)
|
||||
, _mouseSel(false)
|
||||
, _kickConfirm(0)
|
||||
, _kickRequestId(0)
|
||||
, _kickBox(0)
|
||||
, _loading(true)
|
||||
, _loadingRequestId(0)
|
||||
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right())
|
||||
, _about(_aboutWidth)
|
||||
, _aboutHeight(0) {
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
|
||||
connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)));
|
||||
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*)));
|
||||
|
||||
refresh();
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
void MembersBox::Inner::load() {
|
||||
if (!_loadingRequestId) {
|
||||
_loadingRequestId = MTP::send(MTPchannels_GetParticipants(_channel->inputChannel, (_filter == MembersFilter::Recent) ? MTP_channelParticipantsRecent() : MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(Global::ChatSizeMax())), rpcDone(&Inner::membersReceived), rpcFail(&Inner::membersFailed));
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
_time = unixtime();
|
||||
p.fillRect(r, st::white->b);
|
||||
|
||||
int32 yFrom = r.y() - st::membersPadding.top(), yTo = r.y() + r.height() - st::membersPadding.top();
|
||||
p.translate(0, st::membersPadding.top());
|
||||
if (_rows.isEmpty()) {
|
||||
p.setFont(st::noContactsFont->f);
|
||||
p.setPen(st::noContactsColor->p);
|
||||
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
|
||||
} else {
|
||||
if (_newItemHeight) {
|
||||
p.fillRect(0, 0, width(), _newItemHeight, (_newItemSel ? st::contactsBgOver : st::white)->b);
|
||||
p.drawSpriteLeft(st::contactsNewItemIconPosition.x(), st::contactsNewItemIconPosition.y(), width(), st::contactsNewItemIcon);
|
||||
p.setFont(st::contactsNameFont);
|
||||
p.setPen(st::contactsNewItemFg);
|
||||
p.drawTextLeft(st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(), st::contactsNewItemTop, width(), lang(_filter == MembersFilter::Admins ? lng_channel_add_admins : lng_channel_add_members));
|
||||
|
||||
yFrom -= _newItemHeight;
|
||||
yTo -= _newItemHeight;
|
||||
p.translate(0, _newItemHeight);
|
||||
}
|
||||
int32 from = floorclamp(yFrom, _rowHeight, 0, _rows.size());
|
||||
int32 to = ceilclamp(yTo, _rowHeight, 0, _rows.size());
|
||||
p.translate(0, from * _rowHeight);
|
||||
for (; from < to; ++from) {
|
||||
bool sel = (from == _sel);
|
||||
bool kickSel = (from == _kickSel && (_kickDown < 0 || from == _kickDown));
|
||||
bool kickDown = kickSel && (from == _kickDown);
|
||||
paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown);
|
||||
p.translate(0, _rowHeight);
|
||||
}
|
||||
if (to == _rows.size() && _filter == MembersFilter::Recent && (_rows.size() < _channel->membersCount() || _rows.size() >= Global::ChatSizeMax())) {
|
||||
p.setPen(st::stickersReorderFg);
|
||||
_about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void MembersBox::Inner::leaveEvent(QEvent *e) {
|
||||
_mouseSel = false;
|
||||
setMouseTracking(false);
|
||||
if (_sel >= 0) {
|
||||
clearSel();
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void MembersBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
if (e->button() == Qt::LeftButton && _kickSel < 0) {
|
||||
chooseParticipant();
|
||||
}
|
||||
_kickDown = _kickSel;
|
||||
update();
|
||||
}
|
||||
|
||||
void MembersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
if (_kickDown >= 0 && _kickDown == _kickSel && !_kickRequestId) {
|
||||
_kickConfirm = _rows.at(_kickSel);
|
||||
if (_kickBox) _kickBox->deleteLater();
|
||||
_kickBox = new ConfirmBox((_filter == MembersFilter::Recent ? (_channel->isMegagroup() ? lng_profile_sure_kick : lng_profile_sure_kick_channel) : lng_profile_sure_kick_admin)(lt_user, _kickConfirm->firstName));
|
||||
connect(_kickBox, SIGNAL(confirmed()), this, SLOT(onKickConfirm()));
|
||||
connect(_kickBox, SIGNAL(destroyed(QObject*)), this, SLOT(onKickBoxDestroyed(QObject*)));
|
||||
Ui::showLayer(_kickBox, KeepOtherLayers);
|
||||
}
|
||||
_kickDown = -1;
|
||||
}
|
||||
|
||||
void MembersBox::Inner::onKickBoxDestroyed(QObject *obj) {
|
||||
if (_kickBox == obj) {
|
||||
_kickBox = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::onKickConfirm() {
|
||||
if (_filter == MembersFilter::Recent) {
|
||||
_kickRequestId = MTP::send(MTPchannels_KickFromChannel(_channel->inputChannel, _kickConfirm->inputUser, MTP_bool(true)), rpcDone(&Inner::kickDone), rpcFail(&Inner::kickFail));
|
||||
} else {
|
||||
_kickRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _kickConfirm->inputUser, MTP_channelRoleEmpty()), rpcDone(&Inner::kickAdminDone), rpcFail(&Inner::kickFail));
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::paintDialog(Painter &p, PeerData *peer, MemberData *data, bool sel, bool kickSel, bool kickDown) {
|
||||
UserData *user = peer->asUser();
|
||||
|
||||
p.fillRect(0, 0, width(), _rowHeight, (sel ? st::contactsBgOver : st::white)->b);
|
||||
peer->paintUserpicLeft(p, st::contactsPhotoSize, st::contactsPadding.left(), st::contactsPadding.top(), width());
|
||||
|
||||
p.setPen(st::black);
|
||||
|
||||
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
|
||||
int32 namew = width() - namex - st::contactsPadding.right() - (data->canKick ? (_kickWidth + st::contactsCheckPosition.x() * 2) : 0);
|
||||
if (peer->isVerified()) {
|
||||
auto icon = &st::dialogsVerifiedIcon;
|
||||
namew -= icon->width();
|
||||
icon->paint(p, namex + qMin(data->name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, width());
|
||||
}
|
||||
data->name.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew, width());
|
||||
|
||||
if (data->canKick) {
|
||||
p.setFont((kickSel ? st::linkOverFont : st::linkFont)->f);
|
||||
if (kickDown) {
|
||||
p.setPen(st::btnDefLink.downColor->p);
|
||||
} else {
|
||||
p.setPen(st::btnDefLink.color->p);
|
||||
}
|
||||
p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), _kickText, _kickWidth);
|
||||
}
|
||||
|
||||
p.setFont(st::contactsStatusFont->f);
|
||||
p.setPen(data->onlineColor ? st::contactsStatusFgOnline : (sel ? st::contactsStatusFgOver : st::contactsStatusFg));
|
||||
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->online);
|
||||
}
|
||||
|
||||
void MembersBox::Inner::selectSkip(int32 dir) {
|
||||
_time = unixtime();
|
||||
_mouseSel = false;
|
||||
|
||||
int cur = -1;
|
||||
if (_newItemHeight && _newItemSel) {
|
||||
cur = 0;
|
||||
} else if (_sel >= 0) {
|
||||
cur = _sel + (_newItemHeight ? 1 : 0);
|
||||
}
|
||||
cur += dir;
|
||||
if (cur <= 0) {
|
||||
_newItemSel = _newItemHeight ? true : false;
|
||||
_sel = (_newItemSel || _rows.isEmpty()) ? -1 : 0;
|
||||
} else if (cur >= _rows.size() + (_newItemHeight ? 1 : 0)) {
|
||||
_sel = -1;
|
||||
} else {
|
||||
_sel = cur - (_newItemHeight ? 1 : 0);
|
||||
}
|
||||
if (dir > 0) {
|
||||
if (_sel < 0 || _sel >= _rows.size()) {
|
||||
_sel = -1;
|
||||
}
|
||||
} else {
|
||||
if (!_rows.isEmpty()) {
|
||||
if (_sel < 0 && !_newItemSel) _sel = _rows.size() - 1;
|
||||
}
|
||||
}
|
||||
if (_newItemSel) {
|
||||
emit mustScrollTo(0, _newItemHeight);
|
||||
} else if (_sel >= 0) {
|
||||
emit mustScrollTo(_newItemHeight + _sel * _rowHeight, _newItemHeight + (_sel + 1) * _rowHeight);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void MembersBox::Inner::selectSkipPage(int32 h, int32 dir) {
|
||||
int32 points = h / _rowHeight;
|
||||
if (!points) return;
|
||||
selectSkip(points * dir);
|
||||
}
|
||||
|
||||
void MembersBox::Inner::loadProfilePhotos(int32 yFrom) {
|
||||
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
|
||||
MTP::clearLoaderPriorities();
|
||||
|
||||
if (yTo < 0) return;
|
||||
if (yFrom < 0) yFrom = 0;
|
||||
|
||||
if (!_rows.isEmpty()) {
|
||||
int32 from = (yFrom - _newItemHeight) / _rowHeight;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _rows.size()) {
|
||||
int32 to = ((yTo - _newItemHeight) / _rowHeight) + 1;
|
||||
if (to > _rows.size()) to = _rows.size();
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_rows[from]->loadUserpic();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::chooseParticipant() {
|
||||
if (_newItemSel) {
|
||||
emit addRequested();
|
||||
return;
|
||||
}
|
||||
if (_sel < 0 || _sel >= _rows.size()) return;
|
||||
if (PeerData *peer = _rows[_sel]) {
|
||||
Ui::hideLayer();
|
||||
Ui::showPeerProfile(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::refresh() {
|
||||
if (_rows.isEmpty()) {
|
||||
resize(width(), st::membersPadding.top() + st::noContactsHeight + st::membersPadding.bottom());
|
||||
_aboutHeight = 0;
|
||||
} else {
|
||||
_about.setText(st::boxTextFont, lng_channel_only_last_shown(lt_count, _rows.size()));
|
||||
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
|
||||
if (_filter != MembersFilter::Recent || (_rows.size() >= _channel->membersCount() && _rows.size() < Global::ChatSizeMax())) {
|
||||
_aboutHeight = 0;
|
||||
}
|
||||
resize(width(), st::membersPadding.top() + _newItemHeight + _rows.size() * _rowHeight + st::membersPadding.bottom() + _aboutHeight);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
ChannelData *MembersBox::Inner::channel() const {
|
||||
return _channel;
|
||||
}
|
||||
|
||||
MembersFilter MembersBox::Inner::filter() const {
|
||||
return _filter;
|
||||
}
|
||||
|
||||
MembersAlreadyIn MembersBox::Inner::already() const {
|
||||
MembersAlreadyIn result;
|
||||
for_const (auto peer, _rows) {
|
||||
if (peer->isUser()) {
|
||||
result.insert(peer->asUser());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MembersBox::Inner::clearSel() {
|
||||
updateSelectedRow();
|
||||
_newItemSel = false;
|
||||
_sel = _kickSel = _kickDown = -1;
|
||||
_lastMousePos = QCursor::pos();
|
||||
updateSel();
|
||||
}
|
||||
|
||||
MembersBox::Inner::MemberData *MembersBox::Inner::data(int32 index) {
|
||||
if (MemberData *result = _datas.at(index)) {
|
||||
return result;
|
||||
}
|
||||
MemberData *result = _datas[index] = new MemberData();
|
||||
result->name.setText(st::contactsNameFont, _rows[index]->name, _textNameOptions);
|
||||
int32 t = unixtime();
|
||||
result->online = App::onlineText(_rows[index], t);// lng_mediaview_date_time(lt_date, _dates[index].date().toString(qsl("dd.MM.yy")), lt_time, _dates[index].time().toString(cTimeFormat()));
|
||||
result->onlineColor = App::onlineColorUse(_rows[index], t);
|
||||
if (_filter == MembersFilter::Recent) {
|
||||
result->canKick = (_channel->amCreator() || _channel->amEditor() || _channel->amModerator()) ? (_roles[index] == MemberRole::None) : false;
|
||||
} else if (_filter == MembersFilter::Admins) {
|
||||
result->canKick = _channel->amCreator() ? (_roles[index] == MemberRole::Editor || _roles[index] == MemberRole::Moderator) : false;
|
||||
} else {
|
||||
result->canKick = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MembersBox::Inner::clear() {
|
||||
for (int32 i = 0, l = _datas.size(); i < l; ++i) {
|
||||
delete _datas.at(i);
|
||||
}
|
||||
_datas.clear();
|
||||
_rows.clear();
|
||||
_dates.clear();
|
||||
_roles.clear();
|
||||
if (_kickBox) _kickBox->deleteLater();
|
||||
clearSel();
|
||||
}
|
||||
|
||||
MembersBox::Inner::~Inner() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void MembersBox::Inner::updateSel() {
|
||||
if (!_mouseSel) return;
|
||||
|
||||
QPoint p(mapFromGlobal(_lastMousePos));
|
||||
p.setY(p.y() - st::membersPadding.top());
|
||||
bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos));
|
||||
bool newItemSel = (in && p.y() >= 0 && p.y() < _newItemHeight);
|
||||
int32 newSel = (in && !newItemSel && p.y() >= _newItemHeight && p.y() < _newItemHeight + _rows.size() * _rowHeight) ? ((p.y() - _newItemHeight) / _rowHeight) : -1;
|
||||
int32 newKickSel = newSel;
|
||||
if (newSel >= 0 && (!data(newSel)->canKick || !QRect(width() - _kickWidth - st::contactsPadding.right() - st::contactsCheckPosition.x(), _newItemHeight + newSel * _rowHeight + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, _kickWidth, st::normalFont->height).contains(p))) {
|
||||
newKickSel = -1;
|
||||
}
|
||||
if (newSel != _sel || newKickSel != _kickSel || newItemSel != _newItemSel) {
|
||||
updateSelectedRow();
|
||||
_newItemSel = newItemSel;
|
||||
_sel = newSel;
|
||||
_kickSel = newKickSel;
|
||||
updateSelectedRow();
|
||||
setCursor(_kickSel >= 0 ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::peerUpdated(PeerData *peer) {
|
||||
update();
|
||||
}
|
||||
|
||||
void MembersBox::Inner::updateSelectedRow() {
|
||||
if (_newItemSel) {
|
||||
update(0, st::membersPadding.top(), width(), _newItemHeight);
|
||||
}
|
||||
if (_sel >= 0) {
|
||||
update(0, st::membersPadding.top() + _newItemHeight + _sel * _rowHeight, width(), _rowHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
||||
for (int32 i = 0, l = _rows.size(); i < l; ++i) {
|
||||
if (_rows.at(i) == peer) {
|
||||
if (_datas.at(i)) {
|
||||
_datas.at(i)->name.setText(st::contactsNameFont, peer->name, _textNameOptions);
|
||||
update(0, st::membersPadding.top() + i * _rowHeight, width(), _rowHeight);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &result, mtpRequestId req) {
|
||||
clear();
|
||||
_loadingRequestId = 0;
|
||||
|
||||
if (result.type() == mtpc_channels_channelParticipants) {
|
||||
const auto &d(result.c_channels_channelParticipants());
|
||||
const auto &v(d.vparticipants.c_vector().v);
|
||||
_rows.reserve(v.size());
|
||||
_datas.reserve(v.size());
|
||||
_dates.reserve(v.size());
|
||||
_roles.reserve(v.size());
|
||||
|
||||
if (_filter == MembersFilter::Recent && _channel->membersCount() < d.vcount.v) {
|
||||
_channel->setMembersCount(d.vcount.v);
|
||||
if (App::main()) emit App::main()->peerUpdated(_channel);
|
||||
} else if (_filter == MembersFilter::Admins && _channel->adminsCount() < d.vcount.v) {
|
||||
_channel->setAdminsCount(d.vcount.v);
|
||||
if (App::main()) emit App::main()->peerUpdated(_channel);
|
||||
}
|
||||
App::feedUsers(d.vusers);
|
||||
|
||||
for (QVector<MTPChannelParticipant>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
|
||||
int32 userId = 0, addedTime = 0;
|
||||
MemberRole role = MemberRole::None;
|
||||
switch (i->type()) {
|
||||
case mtpc_channelParticipant:
|
||||
userId = i->c_channelParticipant().vuser_id.v;
|
||||
addedTime = i->c_channelParticipant().vdate.v;
|
||||
break;
|
||||
case mtpc_channelParticipantSelf:
|
||||
role = MemberRole::Self;
|
||||
userId = i->c_channelParticipantSelf().vuser_id.v;
|
||||
addedTime = i->c_channelParticipantSelf().vdate.v;
|
||||
break;
|
||||
case mtpc_channelParticipantModerator:
|
||||
role = MemberRole::Moderator;
|
||||
userId = i->c_channelParticipantModerator().vuser_id.v;
|
||||
addedTime = i->c_channelParticipantModerator().vdate.v;
|
||||
break;
|
||||
case mtpc_channelParticipantEditor:
|
||||
role = MemberRole::Editor;
|
||||
userId = i->c_channelParticipantEditor().vuser_id.v;
|
||||
addedTime = i->c_channelParticipantEditor().vdate.v;
|
||||
break;
|
||||
case mtpc_channelParticipantKicked:
|
||||
userId = i->c_channelParticipantKicked().vuser_id.v;
|
||||
addedTime = i->c_channelParticipantKicked().vdate.v;
|
||||
role = MemberRole::Kicked;
|
||||
break;
|
||||
case mtpc_channelParticipantCreator:
|
||||
userId = i->c_channelParticipantCreator().vuser_id.v;
|
||||
addedTime = _channel->date;
|
||||
role = MemberRole::Creator;
|
||||
break;
|
||||
}
|
||||
if (UserData *user = App::userLoaded(userId)) {
|
||||
_rows.push_back(user);
|
||||
_dates.push_back(date(addedTime));
|
||||
_roles.push_back(role);
|
||||
_datas.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
// update admins if we got all of them
|
||||
if (_filter == MembersFilter::Admins && _channel->isMegagroup() && _rows.size() < Global::ChatSizeMax()) {
|
||||
_channel->mgInfo->lastAdmins.clear();
|
||||
for (int32 i = 0, l = _rows.size(); i != l; ++i) {
|
||||
if (_roles.at(i) == MemberRole::Creator || _roles.at(i) == MemberRole::Editor) {
|
||||
_channel->mgInfo->lastAdmins.insert(_rows.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
Notify::peerUpdatedDelayed(_channel, Notify::PeerUpdate::Flag::AdminsChanged);
|
||||
}
|
||||
}
|
||||
if (_rows.isEmpty()) {
|
||||
_rows.push_back(App::self());
|
||||
_dates.push_back(date(MTP_int(_channel->date)));
|
||||
_roles.push_back(MemberRole::Self);
|
||||
_datas.push_back(0);
|
||||
}
|
||||
|
||||
clearSel();
|
||||
_loading = false;
|
||||
refresh();
|
||||
|
||||
emit loaded();
|
||||
}
|
||||
|
||||
bool MembersBox::Inner::membersFailed(const RPCError &error, mtpRequestId req) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
Ui::hideLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MembersBox::Inner::kickDone(const MTPUpdates &result, mtpRequestId req) {
|
||||
App::main()->sentUpdatesReceived(result);
|
||||
|
||||
if (_kickRequestId != req) return;
|
||||
removeKicked();
|
||||
if (_kickBox) _kickBox->onClose();
|
||||
}
|
||||
|
||||
void MembersBox::Inner::kickAdminDone(const MTPUpdates &result, mtpRequestId req) {
|
||||
if (_kickRequestId != req) return;
|
||||
if (App::main()) App::main()->sentUpdatesReceived(result);
|
||||
removeKicked();
|
||||
if (_kickBox) _kickBox->onClose();
|
||||
}
|
||||
|
||||
bool MembersBox::Inner::kickFail(const RPCError &error, mtpRequestId req) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
if (_kickBox) _kickBox->onClose();
|
||||
load();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MembersBox::Inner::removeKicked() {
|
||||
_kickRequestId = 0;
|
||||
int32 index = _rows.indexOf(_kickConfirm);
|
||||
if (index >= 0) {
|
||||
_rows.removeAt(index);
|
||||
delete _datas.at(index);
|
||||
_datas.removeAt(index);
|
||||
_dates.removeAt(index);
|
||||
_roles.removeAt(index);
|
||||
clearSel();
|
||||
if (_filter == MembersFilter::Recent && _channel->membersCount() > 1) {
|
||||
_channel->setMembersCount(_channel->membersCount() - 1);
|
||||
if (App::main()) emit App::main()->peerUpdated(_channel);
|
||||
} else if (_filter == MembersFilter::Admins && _channel->adminsCount() > 1) {
|
||||
_channel->setAdminsCount(_channel->adminsCount() - 1);
|
||||
if (App::main()) emit App::main()->peerUpdated(_channel);
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
_kickConfirm = 0;
|
||||
}
|
178
Telegram/SourceFiles/boxes/members_box.h
Normal file
178
Telegram/SourceFiles/boxes/members_box.h
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "core/single_timer.h"
|
||||
#include "ui/effects/round_image_checkbox.h"
|
||||
|
||||
class ContactsBox;
|
||||
class ConfirmBox;
|
||||
|
||||
enum class MembersFilter {
|
||||
Recent,
|
||||
Admins,
|
||||
};
|
||||
using MembersAlreadyIn = OrderedSet<UserData*>;
|
||||
|
||||
class MembersBox : public ItemListBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MembersBox(ChannelData *channel, MembersFilter filter);
|
||||
|
||||
public slots:
|
||||
void onScroll();
|
||||
|
||||
void onAdd();
|
||||
void onAdminAdded();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
|
||||
ContactsBox *_addBox = nullptr;
|
||||
|
||||
SingleTimer _loadTimer;
|
||||
|
||||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class MembersBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Inner(QWidget *parent, ChannelData *channel, MembersFilter filter);
|
||||
|
||||
void selectSkip(int32 dir);
|
||||
void selectSkipPage(int32 h, int32 dir);
|
||||
|
||||
void loadProfilePhotos(int32 yFrom);
|
||||
void chooseParticipant();
|
||||
|
||||
void refresh();
|
||||
|
||||
ChannelData *channel() const;
|
||||
MembersFilter filter() const;
|
||||
|
||||
bool isLoaded() const {
|
||||
return !_loading;
|
||||
}
|
||||
void clearSel();
|
||||
|
||||
MembersAlreadyIn already() const;
|
||||
|
||||
~Inner();
|
||||
|
||||
signals:
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
void addRequested();
|
||||
void loaded();
|
||||
|
||||
public slots:
|
||||
void load();
|
||||
|
||||
void updateSel();
|
||||
void peerUpdated(PeerData *peer);
|
||||
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
||||
void onKickConfirm();
|
||||
void onKickBoxDestroyed(QObject *obj);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void enterEvent(QEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
struct MemberData {
|
||||
Text name;
|
||||
QString online;
|
||||
bool onlineColor;
|
||||
bool canKick;
|
||||
};
|
||||
|
||||
void updateSelectedRow();
|
||||
MemberData *data(int32 index);
|
||||
|
||||
void paintDialog(Painter &p, PeerData *peer, MemberData *data, bool sel, bool kickSel, bool kickDown);
|
||||
|
||||
void membersReceived(const MTPchannels_ChannelParticipants &result, mtpRequestId req);
|
||||
bool membersFailed(const RPCError &error, mtpRequestId req);
|
||||
|
||||
void kickDone(const MTPUpdates &result, mtpRequestId req);
|
||||
void kickAdminDone(const MTPUpdates &result, mtpRequestId req);
|
||||
bool kickFail(const RPCError &error, mtpRequestId req);
|
||||
void removeKicked();
|
||||
|
||||
void clear();
|
||||
|
||||
int32 _rowHeight, _newItemHeight;
|
||||
bool _newItemSel;
|
||||
|
||||
ChannelData *_channel;
|
||||
MembersFilter _filter;
|
||||
|
||||
QString _kickText;
|
||||
int32 _time, _kickWidth;
|
||||
|
||||
int32 _sel, _kickSel, _kickDown;
|
||||
bool _mouseSel;
|
||||
|
||||
UserData *_kickConfirm;
|
||||
mtpRequestId _kickRequestId;
|
||||
|
||||
ConfirmBox *_kickBox;
|
||||
|
||||
enum class MemberRole {
|
||||
None,
|
||||
Self,
|
||||
Creator,
|
||||
Editor,
|
||||
Moderator,
|
||||
Kicked
|
||||
};
|
||||
|
||||
bool _loading;
|
||||
mtpRequestId _loadingRequestId;
|
||||
typedef QVector<UserData*> MemberRows;
|
||||
typedef QVector<QDateTime> MemberDates;
|
||||
typedef QVector<MemberRole> MemberRoles;
|
||||
typedef QVector<MemberData*> MemberDatas;
|
||||
MemberRows _rows;
|
||||
MemberDates _dates;
|
||||
MemberRoles _roles;
|
||||
MemberDatas _datas;
|
||||
|
||||
int32 _aboutWidth;
|
||||
Text _about;
|
||||
int32 _aboutHeight;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
};
|
|
@ -30,213 +30,23 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "countries.h"
|
||||
#include "confirmbox.h"
|
||||
|
||||
SessionsInner::SessionsInner(SessionsList *list, SessionData *current) : TWidget()
|
||||
, _list(list)
|
||||
, _current(current)
|
||||
, _terminating(0)
|
||||
, _terminateAll(this, lang(lng_sessions_terminate_all), st::redBoxLinkButton)
|
||||
, _terminateBox(0) {
|
||||
connect(&_terminateAll, SIGNAL(clicked()), this, SLOT(onTerminateAll()));
|
||||
_terminateAll.hide();
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
}
|
||||
|
||||
void SessionsInner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
p.fillRect(r, st::white->b);
|
||||
int32 x = st::sessionPadding.left(), xact = st::sessionTerminateSkip + st::sessionTerminate.iconPos.x();// st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip;
|
||||
int32 w = width();
|
||||
|
||||
if (_current->active.isEmpty() && _list->isEmpty()) {
|
||||
p.setFont(st::noContactsFont->f);
|
||||
p.setPen(st::noContactsColor->p);
|
||||
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r.y() <= st::sessionCurrentHeight) {
|
||||
p.translate(0, st::sessionCurrentPadding.top());
|
||||
p.setFont(st::sessionNameFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top(), w, _current->name, _current->nameWidth);
|
||||
|
||||
p.setFont(st::sessionActiveFont->f);
|
||||
p.setPen(st::sessionActiveColor->p);
|
||||
p.drawTextRight(x, st::sessionPadding.top(), w, _current->active, _current->activeWidth);
|
||||
|
||||
p.setFont(st::sessionInfoFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, _current->info, _current->infoWidth);
|
||||
p.setPen(st::sessionInfoColor->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, _current->ip, _current->ipWidth);
|
||||
}
|
||||
p.translate(0, st::sessionCurrentHeight - st::sessionCurrentPadding.top());
|
||||
if (_list->isEmpty()) {
|
||||
p.setFont(st::sessionInfoFont->f);
|
||||
p.setPen(st::sessionInfoColor->p);
|
||||
p.drawText(QRect(st::sessionPadding.left(), 0, width() - st::sessionPadding.left() - st::sessionPadding.right(), st::noContactsHeight), lang(lng_sessions_other_desc), style::al_topleft);
|
||||
return;
|
||||
}
|
||||
|
||||
p.setFont(st::linkFont->f);
|
||||
int32 count = _list->size();
|
||||
int32 from = floorclamp(r.y() - st::sessionCurrentHeight, st::sessionHeight, 0, count);
|
||||
int32 to = ceilclamp(r.y() + r.height() - st::sessionCurrentHeight, st::sessionHeight, 0, count);
|
||||
p.translate(0, from * st::sessionHeight);
|
||||
for (int32 i = from; i < to; ++i) {
|
||||
const SessionData &auth(_list->at(i));
|
||||
|
||||
p.setFont(st::sessionNameFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top(), w, auth.name, auth.nameWidth);
|
||||
|
||||
p.setFont(st::sessionActiveFont->f);
|
||||
p.setPen(st::sessionActiveColor->p);
|
||||
p.drawTextRight(xact, st::sessionPadding.top(), w, auth.active, auth.activeWidth);
|
||||
|
||||
p.setFont(st::sessionInfoFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, auth.info, auth.infoWidth);
|
||||
p.setPen(st::sessionInfoColor->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, auth.ip, auth.ipWidth);
|
||||
|
||||
p.translate(0, st::sessionHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsInner::onTerminate() {
|
||||
for (TerminateButtons::iterator i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) {
|
||||
if (i.value()->getState() & Button::StateOver) {
|
||||
_terminating = i.key();
|
||||
|
||||
if (_terminateBox) _terminateBox->deleteLater();
|
||||
_terminateBox = new ConfirmBox(lang(lng_settings_reset_one_sure), lang(lng_settings_reset_button), st::attentionBoxButton);
|
||||
connect(_terminateBox, SIGNAL(confirmed()), this, SLOT(onTerminateSure()));
|
||||
connect(_terminateBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoTerminateBox(QObject*)));
|
||||
Ui::showLayer(_terminateBox, KeepOtherLayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsInner::onTerminateSure() {
|
||||
if (_terminateBox) {
|
||||
_terminateBox->onClose();
|
||||
_terminateBox = 0;
|
||||
}
|
||||
MTP::send(MTPaccount_ResetAuthorization(MTP_long(_terminating)), rpcDone(&SessionsInner::terminateDone, _terminating), rpcFail(&SessionsInner::terminateFail, _terminating));
|
||||
TerminateButtons::iterator i = _terminateButtons.find(_terminating);
|
||||
if (i != _terminateButtons.cend()) {
|
||||
i.value()->clearState();
|
||||
i.value()->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsInner::onTerminateAll() {
|
||||
if (_terminateBox) _terminateBox->deleteLater();
|
||||
_terminateBox = new ConfirmBox(lang(lng_settings_reset_sure), lang(lng_settings_reset_button), st::attentionBoxButton);
|
||||
connect(_terminateBox, SIGNAL(confirmed()), this, SLOT(onTerminateAllSure()));
|
||||
connect(_terminateBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoTerminateBox(QObject*)));
|
||||
Ui::showLayer(_terminateBox, KeepOtherLayers);
|
||||
}
|
||||
|
||||
void SessionsInner::onTerminateAllSure() {
|
||||
if (_terminateBox) {
|
||||
_terminateBox->onClose();
|
||||
_terminateBox = 0;
|
||||
}
|
||||
MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&SessionsInner::terminateAllDone), rpcFail(&SessionsInner::terminateAllFail));
|
||||
emit terminateAll();
|
||||
}
|
||||
|
||||
void SessionsInner::onNoTerminateBox(QObject *obj) {
|
||||
if (obj == _terminateBox) _terminateBox = 0;
|
||||
}
|
||||
|
||||
void SessionsInner::terminateDone(uint64 hash, const MTPBool &result) {
|
||||
for (int32 i = 0, l = _list->size(); i < l; ++i) {
|
||||
if (_list->at(i).hash == hash) {
|
||||
_list->removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
listUpdated();
|
||||
emit oneTerminated();
|
||||
}
|
||||
|
||||
bool SessionsInner::terminateFail(uint64 hash, const RPCError &error) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
TerminateButtons::iterator i = _terminateButtons.find(hash);
|
||||
if (i != _terminateButtons.end()) {
|
||||
i.value()->show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SessionsInner::terminateAllDone(const MTPBool &result) {
|
||||
emit allTerminated();
|
||||
}
|
||||
|
||||
bool SessionsInner::terminateAllFail(const RPCError &error) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
emit allTerminated();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionsInner::resizeEvent(QResizeEvent *e) {
|
||||
_terminateAll.moveToLeft(st::sessionPadding.left(), st::sessionCurrentPadding.top() + st::sessionHeight + st::sessionCurrentPadding.bottom());
|
||||
}
|
||||
|
||||
void SessionsInner::listUpdated() {
|
||||
if (_list->isEmpty()) {
|
||||
_terminateAll.hide();
|
||||
} else {
|
||||
_terminateAll.show();
|
||||
}
|
||||
for (TerminateButtons::iterator i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) {
|
||||
i.value()->move(0, -1);
|
||||
}
|
||||
for (int32 i = 0, l = _list->size(); i < l; ++i) {
|
||||
TerminateButtons::iterator j = _terminateButtons.find(_list->at(i).hash);
|
||||
if (j == _terminateButtons.cend()) {
|
||||
j = _terminateButtons.insert(_list->at(i).hash, new IconedButton(this, st::sessionTerminate));
|
||||
connect(j.value(), SIGNAL(clicked()), this, SLOT(onTerminate()));
|
||||
}
|
||||
j.value()->moveToRight(st::sessionTerminateSkip, st::sessionCurrentHeight + i * st::sessionHeight + st::sessionTerminateTop, width());
|
||||
j.value()->show();
|
||||
}
|
||||
for (TerminateButtons::iterator i = _terminateButtons.begin(); i != _terminateButtons.cend();) {
|
||||
if (i.value()->y() >= 0) {
|
||||
++i;
|
||||
} else {
|
||||
delete i.value();
|
||||
i = _terminateButtons.erase(i);
|
||||
}
|
||||
}
|
||||
resize(width(), _list->isEmpty() ? (st::sessionCurrentHeight + st::noContactsHeight) : (st::sessionCurrentHeight + _list->size() * st::sessionHeight));
|
||||
update();
|
||||
}
|
||||
|
||||
SessionsBox::SessionsBox() : ScrollableBox(st::sessionsScroll)
|
||||
, _loading(true)
|
||||
, _inner(&_list, &_current)
|
||||
, _inner(this, &_list, &_current)
|
||||
, _shadow(this)
|
||||
, _done(this, lang(lng_about_done), st::defaultBoxButton)
|
||||
, _shortPollRequest(0) {
|
||||
setMaxHeight(st::sessionsHeight);
|
||||
|
||||
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
connect(&_inner, SIGNAL(oneTerminated()), this, SLOT(onOneTerminated()));
|
||||
connect(&_inner, SIGNAL(allTerminated()), this, SLOT(onAllTerminated()));
|
||||
connect(&_inner, SIGNAL(terminateAll()), this, SLOT(onTerminateAll()));
|
||||
connect(_inner, SIGNAL(oneTerminated()), this, SLOT(onOneTerminated()));
|
||||
connect(_inner, SIGNAL(allTerminated()), this, SLOT(onAllTerminated()));
|
||||
connect(_inner, SIGNAL(terminateAll()), this, SLOT(onTerminateAll()));
|
||||
connect(App::wnd(), SIGNAL(newAuthorization()), this, SLOT(onNewAuthorization()));
|
||||
connect(&_shortPollTimer, SIGNAL(timeout()), this, SLOT(onShortPollAuthorizations()));
|
||||
|
||||
init(&_inner, st::boxButtonPadding.bottom() + _done.height() + st::boxButtonPadding.top(), st::boxTitleHeight);
|
||||
_inner.resize(width(), st::noContactsHeight);
|
||||
init(_inner, st::boxButtonPadding.bottom() + _done.height() + st::boxButtonPadding.top(), st::boxTitleHeight);
|
||||
_inner->resize(width(), st::noContactsHeight);
|
||||
|
||||
prepare();
|
||||
|
||||
|
@ -291,7 +101,7 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) {
|
|||
|
||||
for (int32 i = 0; i < l; ++i) {
|
||||
const auto &d(v.at(i).c_authorization());
|
||||
SessionData data;
|
||||
Data data;
|
||||
data.hash = d.vhash.v;
|
||||
|
||||
QString appName, appVer = qs(d.vapp_version), systemVer = qs(d.vsystem_version), deviceModel = qs(d.vdevice_model);
|
||||
|
@ -383,7 +193,7 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) {
|
|||
}
|
||||
}
|
||||
}
|
||||
_inner.listUpdated();
|
||||
_inner->listUpdated();
|
||||
if (!_done.isHidden()) {
|
||||
showAll();
|
||||
update();
|
||||
|
@ -430,4 +240,194 @@ void SessionsBox::onTerminateAll() {
|
|||
showAll();
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SessionsBox::Inner::Inner(QWidget *parent, SessionsBox::List *list, SessionsBox::Data *current) : ScrolledWidget(parent)
|
||||
, _list(list)
|
||||
, _current(current)
|
||||
, _terminating(0)
|
||||
, _terminateAll(this, lang(lng_sessions_terminate_all), st::redBoxLinkButton)
|
||||
, _terminateBox(0) {
|
||||
connect(&_terminateAll, SIGNAL(clicked()), this, SLOT(onTerminateAll()));
|
||||
_terminateAll.hide();
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
p.fillRect(r, st::white->b);
|
||||
int32 x = st::sessionPadding.left(), xact = st::sessionTerminateSkip + st::sessionTerminate.iconPos.x();// st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip;
|
||||
int32 w = width();
|
||||
|
||||
if (_current->active.isEmpty() && _list->isEmpty()) {
|
||||
p.setFont(st::noContactsFont->f);
|
||||
p.setPen(st::noContactsColor->p);
|
||||
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r.y() <= st::sessionCurrentHeight) {
|
||||
p.translate(0, st::sessionCurrentPadding.top());
|
||||
p.setFont(st::sessionNameFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top(), w, _current->name, _current->nameWidth);
|
||||
|
||||
p.setFont(st::sessionActiveFont->f);
|
||||
p.setPen(st::sessionActiveColor->p);
|
||||
p.drawTextRight(x, st::sessionPadding.top(), w, _current->active, _current->activeWidth);
|
||||
|
||||
p.setFont(st::sessionInfoFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, _current->info, _current->infoWidth);
|
||||
p.setPen(st::sessionInfoColor->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, _current->ip, _current->ipWidth);
|
||||
}
|
||||
p.translate(0, st::sessionCurrentHeight - st::sessionCurrentPadding.top());
|
||||
if (_list->isEmpty()) {
|
||||
p.setFont(st::sessionInfoFont->f);
|
||||
p.setPen(st::sessionInfoColor->p);
|
||||
p.drawText(QRect(st::sessionPadding.left(), 0, width() - st::sessionPadding.left() - st::sessionPadding.right(), st::noContactsHeight), lang(lng_sessions_other_desc), style::al_topleft);
|
||||
return;
|
||||
}
|
||||
|
||||
p.setFont(st::linkFont->f);
|
||||
int32 count = _list->size();
|
||||
int32 from = floorclamp(r.y() - st::sessionCurrentHeight, st::sessionHeight, 0, count);
|
||||
int32 to = ceilclamp(r.y() + r.height() - st::sessionCurrentHeight, st::sessionHeight, 0, count);
|
||||
p.translate(0, from * st::sessionHeight);
|
||||
for (int32 i = from; i < to; ++i) {
|
||||
const SessionsBox::Data &auth(_list->at(i));
|
||||
|
||||
p.setFont(st::sessionNameFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top(), w, auth.name, auth.nameWidth);
|
||||
|
||||
p.setFont(st::sessionActiveFont->f);
|
||||
p.setPen(st::sessionActiveColor->p);
|
||||
p.drawTextRight(xact, st::sessionPadding.top(), w, auth.active, auth.activeWidth);
|
||||
|
||||
p.setFont(st::sessionInfoFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, auth.info, auth.infoWidth);
|
||||
p.setPen(st::sessionInfoColor->p);
|
||||
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, auth.ip, auth.ipWidth);
|
||||
|
||||
p.translate(0, st::sessionHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::onTerminate() {
|
||||
for (TerminateButtons::iterator i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) {
|
||||
if (i.value()->getState() & Button::StateOver) {
|
||||
_terminating = i.key();
|
||||
|
||||
if (_terminateBox) _terminateBox->deleteLater();
|
||||
_terminateBox = new ConfirmBox(lang(lng_settings_reset_one_sure), lang(lng_settings_reset_button), st::attentionBoxButton);
|
||||
connect(_terminateBox, SIGNAL(confirmed()), this, SLOT(onTerminateSure()));
|
||||
connect(_terminateBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoTerminateBox(QObject*)));
|
||||
Ui::showLayer(_terminateBox, KeepOtherLayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::onTerminateSure() {
|
||||
if (_terminateBox) {
|
||||
_terminateBox->onClose();
|
||||
_terminateBox = 0;
|
||||
}
|
||||
MTP::send(MTPaccount_ResetAuthorization(MTP_long(_terminating)), rpcDone(&Inner::terminateDone, _terminating), rpcFail(&Inner::terminateFail, _terminating));
|
||||
TerminateButtons::iterator i = _terminateButtons.find(_terminating);
|
||||
if (i != _terminateButtons.cend()) {
|
||||
i.value()->clearState();
|
||||
i.value()->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::onTerminateAll() {
|
||||
if (_terminateBox) _terminateBox->deleteLater();
|
||||
_terminateBox = new ConfirmBox(lang(lng_settings_reset_sure), lang(lng_settings_reset_button), st::attentionBoxButton);
|
||||
connect(_terminateBox, SIGNAL(confirmed()), this, SLOT(onTerminateAllSure()));
|
||||
connect(_terminateBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoTerminateBox(QObject*)));
|
||||
Ui::showLayer(_terminateBox, KeepOtherLayers);
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::onTerminateAllSure() {
|
||||
if (_terminateBox) {
|
||||
_terminateBox->onClose();
|
||||
_terminateBox = 0;
|
||||
}
|
||||
MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&Inner::terminateAllDone), rpcFail(&Inner::terminateAllFail));
|
||||
emit terminateAll();
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::onNoTerminateBox(QObject *obj) {
|
||||
if (obj == _terminateBox) _terminateBox = 0;
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::terminateDone(uint64 hash, const MTPBool &result) {
|
||||
for (int32 i = 0, l = _list->size(); i < l; ++i) {
|
||||
if (_list->at(i).hash == hash) {
|
||||
_list->removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
listUpdated();
|
||||
emit oneTerminated();
|
||||
}
|
||||
|
||||
bool SessionsBox::Inner::terminateFail(uint64 hash, const RPCError &error) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
TerminateButtons::iterator i = _terminateButtons.find(hash);
|
||||
if (i != _terminateButtons.end()) {
|
||||
i.value()->show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::terminateAllDone(const MTPBool &result) {
|
||||
emit allTerminated();
|
||||
}
|
||||
|
||||
bool SessionsBox::Inner::terminateAllFail(const RPCError &error) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
emit allTerminated();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::resizeEvent(QResizeEvent *e) {
|
||||
_terminateAll.moveToLeft(st::sessionPadding.left(), st::sessionCurrentPadding.top() + st::sessionHeight + st::sessionCurrentPadding.bottom());
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::listUpdated() {
|
||||
if (_list->isEmpty()) {
|
||||
_terminateAll.hide();
|
||||
} else {
|
||||
_terminateAll.show();
|
||||
}
|
||||
for (TerminateButtons::iterator i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) {
|
||||
i.value()->move(0, -1);
|
||||
}
|
||||
for (int32 i = 0, l = _list->size(); i < l; ++i) {
|
||||
TerminateButtons::iterator j = _terminateButtons.find(_list->at(i).hash);
|
||||
if (j == _terminateButtons.cend()) {
|
||||
j = _terminateButtons.insert(_list->at(i).hash, new IconedButton(this, st::sessionTerminate));
|
||||
connect(j.value(), SIGNAL(clicked()), this, SLOT(onTerminate()));
|
||||
}
|
||||
j.value()->moveToRight(st::sessionTerminateSkip, st::sessionCurrentHeight + i * st::sessionHeight + st::sessionTerminateTop, width());
|
||||
j.value()->show();
|
||||
}
|
||||
for (TerminateButtons::iterator i = _terminateButtons.begin(); i != _terminateButtons.cend();) {
|
||||
if (i.value()->y() >= 0) {
|
||||
++i;
|
||||
} else {
|
||||
delete i.value();
|
||||
i = _terminateButtons.erase(i);
|
||||
}
|
||||
}
|
||||
resize(width(), _list->isEmpty() ? (st::sessionCurrentHeight + st::noContactsHeight) : (st::sessionCurrentHeight + _list->size() * st::sessionHeight));
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -25,20 +25,58 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
class ConfirmBox;
|
||||
|
||||
struct SessionData {
|
||||
uint64 hash;
|
||||
|
||||
int32 activeTime;
|
||||
int32 nameWidth, activeWidth, infoWidth, ipWidth;
|
||||
QString name, active, info, ip;
|
||||
};
|
||||
typedef QList<SessionData> SessionsList;
|
||||
|
||||
class SessionsInner : public TWidget, public RPCSender {
|
||||
class SessionsBox : public ScrollableBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SessionsInner(SessionsList *list, SessionData *current);
|
||||
SessionsBox();
|
||||
|
||||
public slots:
|
||||
void onOneTerminated();
|
||||
void onAllTerminated();
|
||||
void onTerminateAll();
|
||||
void onShortPollAuthorizations();
|
||||
void onNewAuthorization();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
struct Data {
|
||||
uint64 hash;
|
||||
|
||||
int32 activeTime;
|
||||
int32 nameWidth, activeWidth, infoWidth, ipWidth;
|
||||
QString name, active, info, ip;
|
||||
};
|
||||
using List = QList<Data>;
|
||||
|
||||
void gotAuthorizations(const MTPaccount_Authorizations &result);
|
||||
|
||||
bool _loading;
|
||||
|
||||
Data _current;
|
||||
List _list;
|
||||
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ScrollableBoxShadow _shadow;
|
||||
BoxButton _done;
|
||||
|
||||
SingleTimer _shortPollTimer;
|
||||
mtpRequestId _shortPollRequest;
|
||||
|
||||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class SessionsBox::Inner : public ScrolledWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Inner(QWidget *parent, SessionsBox::List *list, SessionsBox::Data *current);
|
||||
|
||||
void listUpdated();
|
||||
|
||||
|
@ -65,8 +103,8 @@ private:
|
|||
void terminateAllDone(const MTPBool &res);
|
||||
bool terminateAllFail(const RPCError &error);
|
||||
|
||||
SessionsList *_list;
|
||||
SessionData *_current;
|
||||
SessionsBox::List *_list;
|
||||
SessionsBox::Data *_current;
|
||||
|
||||
typedef QMap<uint64, IconedButton*> TerminateButtons;
|
||||
TerminateButtons _terminateButtons;
|
||||
|
@ -76,39 +114,3 @@ private:
|
|||
ConfirmBox *_terminateBox;
|
||||
|
||||
};
|
||||
|
||||
class SessionsBox : public ScrollableBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SessionsBox();
|
||||
|
||||
public slots:
|
||||
void onOneTerminated();
|
||||
void onAllTerminated();
|
||||
void onTerminateAll();
|
||||
void onShortPollAuthorizations();
|
||||
void onNewAuthorization();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
void gotAuthorizations(const MTPaccount_Authorizations &result);
|
||||
|
||||
bool _loading;
|
||||
|
||||
SessionData _current;
|
||||
SessionsList _list;
|
||||
|
||||
SessionsInner _inner;
|
||||
ScrollableBoxShadow _shadow;
|
||||
BoxButton _done;
|
||||
|
||||
SingleTimer _shortPollTimer;
|
||||
mtpRequestId _shortPollRequest;
|
||||
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "boxes/confirmbox.h"
|
||||
#include "apiwrap.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/buttons/icon_button.h"
|
||||
#include "history/history_media_types.h"
|
||||
#include "boxes/contactsbox.h"
|
||||
|
||||
|
@ -241,9 +242,7 @@ void ShareBox::onScroll() {
|
|||
_inner->setVisibleTopBottom(scrollTop, scrollTop + scroll->height());
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
ShareInner::ShareInner(QWidget *parent, ShareBox::FilterCallback &&filterCallback) : ScrolledWidget(parent)
|
||||
ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallback) : ScrolledWidget(parent)
|
||||
, _filterCallback(std_::move(filterCallback))
|
||||
, _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) {
|
||||
_rowsTop = st::shareRowsTop;
|
||||
|
@ -269,19 +268,19 @@ ShareInner::ShareInner(QWidget *parent, ShareBox::FilterCallback &&filterCallbac
|
|||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
}
|
||||
|
||||
void ShareInner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
void ShareBox::Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
loadProfilePhotos(visibleTop);
|
||||
}
|
||||
|
||||
void ShareInner::activateSkipRow(int direction) {
|
||||
void ShareBox::Inner::activateSkipRow(int direction) {
|
||||
activateSkipColumn(direction * _columnCount);
|
||||
}
|
||||
|
||||
int ShareInner::displayedChatsCount() const {
|
||||
int ShareBox::Inner::displayedChatsCount() const {
|
||||
return _filter.isEmpty() ? _chatsIndexed->size() : (_filtered.size() + d_byUsernameFiltered.size());
|
||||
}
|
||||
|
||||
void ShareInner::activateSkipColumn(int direction) {
|
||||
void ShareBox::Inner::activateSkipColumn(int direction) {
|
||||
if (_active < 0) {
|
||||
if (direction > 0) {
|
||||
setActive(0);
|
||||
|
@ -299,11 +298,11 @@ void ShareInner::activateSkipColumn(int direction) {
|
|||
setActive(active);
|
||||
}
|
||||
|
||||
void ShareInner::activateSkipPage(int pageHeight, int direction) {
|
||||
void ShareBox::Inner::activateSkipPage(int pageHeight, int direction) {
|
||||
activateSkipRow(direction * (pageHeight / _rowHeight));
|
||||
}
|
||||
|
||||
void ShareInner::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
||||
void ShareBox::Inner::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
||||
if (update.flags & Notify::PeerUpdate::Flag::NameChanged) {
|
||||
_chatsIndexed->peerNameChanged(update.peer, update.oldNames, update.oldNameFirstChars);
|
||||
}
|
||||
|
@ -311,7 +310,7 @@ void ShareInner::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
|||
updateChat(update.peer);
|
||||
}
|
||||
|
||||
void ShareInner::updateChat(PeerData *peer) {
|
||||
void ShareBox::Inner::updateChat(PeerData *peer) {
|
||||
auto i = _dataMap.find(peer);
|
||||
if (i != _dataMap.cend()) {
|
||||
updateChatName(i.value(), peer);
|
||||
|
@ -319,11 +318,11 @@ void ShareInner::updateChat(PeerData *peer) {
|
|||
}
|
||||
}
|
||||
|
||||
void ShareInner::updateChatName(Chat *chat, PeerData *peer) {
|
||||
void ShareBox::Inner::updateChatName(Chat *chat, PeerData *peer) {
|
||||
chat->name.setText(st::shareNameFont, peer->name, _textNameOptions);
|
||||
}
|
||||
|
||||
void ShareInner::repaintChatAtIndex(int index) {
|
||||
void ShareBox::Inner::repaintChatAtIndex(int index) {
|
||||
if (index < 0) return;
|
||||
|
||||
auto row = index / _columnCount;
|
||||
|
@ -331,7 +330,7 @@ void ShareInner::repaintChatAtIndex(int index) {
|
|||
update(rtlrect(_rowsLeft + qFloor(column * _rowWidthReal), row * _rowHeight, _rowWidth, _rowHeight, width()));
|
||||
}
|
||||
|
||||
ShareInner::Chat *ShareInner::getChatAtIndex(int index) {
|
||||
ShareBox::Inner::Chat *ShareBox::Inner::getChatAtIndex(int index) {
|
||||
if (index < 0) return nullptr;
|
||||
auto row = ([this, index]() -> Dialogs::Row* {
|
||||
if (_filter.isEmpty()) return _chatsIndexed->rowAtY(index, 1);
|
||||
|
@ -350,11 +349,11 @@ ShareInner::Chat *ShareInner::getChatAtIndex(int index) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void ShareInner::repaintChat(PeerData *peer) {
|
||||
void ShareBox::Inner::repaintChat(PeerData *peer) {
|
||||
repaintChatAtIndex(chatIndex(peer));
|
||||
}
|
||||
|
||||
int ShareInner::chatIndex(PeerData *peer) const {
|
||||
int ShareBox::Inner::chatIndex(PeerData *peer) const {
|
||||
int index = 0;
|
||||
if (_filter.isEmpty()) {
|
||||
for_const (auto row, _chatsIndexed->all()) {
|
||||
|
@ -380,7 +379,7 @@ int ShareInner::chatIndex(PeerData *peer) const {
|
|||
return -1;
|
||||
}
|
||||
|
||||
void ShareInner::loadProfilePhotos(int yFrom) {
|
||||
void ShareBox::Inner::loadProfilePhotos(int yFrom) {
|
||||
if (yFrom < 0) {
|
||||
yFrom = 0;
|
||||
}
|
||||
|
@ -419,7 +418,7 @@ void ShareInner::loadProfilePhotos(int yFrom) {
|
|||
}
|
||||
}
|
||||
|
||||
ShareInner::Chat *ShareInner::getChat(Dialogs::Row *row) {
|
||||
ShareBox::Inner::Chat *ShareBox::Inner::getChat(Dialogs::Row *row) {
|
||||
auto data = static_cast<Chat*>(row->attached);
|
||||
if (!data) {
|
||||
auto peer = row->history()->peer;
|
||||
|
@ -436,7 +435,7 @@ ShareInner::Chat *ShareInner::getChat(Dialogs::Row *row) {
|
|||
return data;
|
||||
}
|
||||
|
||||
void ShareInner::setActive(int active) {
|
||||
void ShareBox::Inner::setActive(int active) {
|
||||
if (active != _active) {
|
||||
auto changeNameFg = [this](int index, style::color from, style::color to) {
|
||||
if (auto chat = getChatAtIndex(index)) {
|
||||
|
@ -453,7 +452,7 @@ void ShareInner::setActive(int active) {
|
|||
emit mustScrollTo(y, y + _rowHeight);
|
||||
}
|
||||
|
||||
void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
|
||||
void ShareBox::Inner::paintChat(Painter &p, Chat *chat, int index) {
|
||||
auto x = _rowsLeft + qFloor((index % _columnCount) * _rowWidthReal);
|
||||
auto y = _rowsTop + (index / _columnCount) * _rowHeight;
|
||||
|
||||
|
@ -474,13 +473,13 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
|
|||
chat->name.drawLeftElided(p, x + nameLeft, y + nameTop, nameWidth, outerWidth, 2, style::al_top, 0, -1, 0, true);
|
||||
}
|
||||
|
||||
ShareInner::Chat::Chat(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback)
|
||||
ShareBox::Inner::Chat::Chat(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback)
|
||||
: peer(peer)
|
||||
, checkbox(st::sharePhotoCheckbox, std_::move(updateCallback), PaintUserpicCallback(peer))
|
||||
, name(st::sharePhotoCheckbox.imageRadius * 2) {
|
||||
}
|
||||
|
||||
void ShareInner::paintEvent(QPaintEvent *e) {
|
||||
void ShareBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
auto r = e->rect();
|
||||
|
@ -539,20 +538,20 @@ void ShareInner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void ShareInner::enterEvent(QEvent *e) {
|
||||
void ShareBox::Inner::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ShareInner::leaveEvent(QEvent *e) {
|
||||
void ShareBox::Inner::leaveEvent(QEvent *e) {
|
||||
setMouseTracking(false);
|
||||
}
|
||||
|
||||
void ShareInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
void ShareBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
updateUpon(e->pos());
|
||||
setCursor((_upon >= 0) ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
|
||||
void ShareInner::updateUpon(const QPoint &pos) {
|
||||
void ShareBox::Inner::updateUpon(const QPoint &pos) {
|
||||
auto x = pos.x(), y = pos.y();
|
||||
auto row = (y - _rowsTop) / _rowHeight;
|
||||
auto column = qFloor((x - _rowsLeft) / _rowWidthReal);
|
||||
|
@ -567,18 +566,18 @@ void ShareInner::updateUpon(const QPoint &pos) {
|
|||
_upon = upon;
|
||||
}
|
||||
|
||||
void ShareInner::mousePressEvent(QMouseEvent *e) {
|
||||
void ShareBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
updateUpon(e->pos());
|
||||
changeCheckState(getChatAtIndex(_upon));
|
||||
}
|
||||
}
|
||||
|
||||
void ShareInner::onSelectActive() {
|
||||
void ShareBox::Inner::onSelectActive() {
|
||||
changeCheckState(getChatAtIndex(_active > 0 ? _active : 0));
|
||||
}
|
||||
|
||||
void ShareInner::resizeEvent(QResizeEvent *e) {
|
||||
void ShareBox::Inner::resizeEvent(QResizeEvent *e) {
|
||||
_columnSkip = (width() - _columnCount * st::sharePhotoCheckbox.imageRadius * 2) / float64(_columnCount + 1);
|
||||
_rowWidthReal = st::sharePhotoCheckbox.imageRadius * 2 + _columnSkip;
|
||||
_rowsLeft = qFloor(_columnSkip / 2);
|
||||
|
@ -586,7 +585,7 @@ void ShareInner::resizeEvent(QResizeEvent *e) {
|
|||
update();
|
||||
}
|
||||
|
||||
void ShareInner::changeCheckState(Chat *chat) {
|
||||
void ShareBox::Inner::changeCheckState(Chat *chat) {
|
||||
if (!chat) return;
|
||||
|
||||
if (!_filter.isEmpty()) {
|
||||
|
@ -611,11 +610,11 @@ void ShareInner::changeCheckState(Chat *chat) {
|
|||
emit selectedChanged();
|
||||
}
|
||||
|
||||
bool ShareInner::hasSelected() const {
|
||||
bool ShareBox::Inner::hasSelected() const {
|
||||
return _selected.size();
|
||||
}
|
||||
|
||||
void ShareInner::updateFilter(QString filter) {
|
||||
void ShareBox::Inner::updateFilter(QString filter) {
|
||||
_lastQuery = filter.toLower().trimmed();
|
||||
filter = textSearchKey(filter);
|
||||
|
||||
|
@ -694,7 +693,7 @@ void ShareInner::updateFilter(QString filter) {
|
|||
}
|
||||
}
|
||||
|
||||
void ShareInner::peopleReceived(const QString &query, const QVector<MTPPeer> &people) {
|
||||
void ShareBox::Inner::peopleReceived(const QString &query, const QVector<MTPPeer> &people) {
|
||||
_lastQuery = query.toLower().trimmed();
|
||||
if (_lastQuery.at(0) == '@') _lastQuery = _lastQuery.mid(1);
|
||||
int32 already = _byUsernameFiltered.size();
|
||||
|
@ -724,7 +723,7 @@ void ShareInner::peopleReceived(const QString &query, const QVector<MTPPeer> &pe
|
|||
refresh();
|
||||
}
|
||||
|
||||
void ShareInner::refresh() {
|
||||
void ShareBox::Inner::refresh() {
|
||||
auto count = displayedChatsCount();
|
||||
if (count) {
|
||||
auto rows = (count / _columnCount) + (count % _columnCount ? 1 : 0);
|
||||
|
@ -735,13 +734,13 @@ void ShareInner::refresh() {
|
|||
update();
|
||||
}
|
||||
|
||||
ShareInner::~ShareInner() {
|
||||
ShareBox::Inner::~Inner() {
|
||||
for_const (auto chat, _dataMap) {
|
||||
delete chat;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<PeerData*> ShareInner::selected() const {
|
||||
QVector<PeerData*> ShareBox::Inner::selected() const {
|
||||
QVector<PeerData*> result;
|
||||
result.reserve(_dataMap.size());
|
||||
for_const (auto chat, _dataMap) {
|
||||
|
@ -752,8 +751,6 @@ QVector<PeerData*> ShareInner::selected() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
QString appendShareGameScoreUrl(const QString &url, const FullMsgId &fullId) {
|
||||
auto shareHashData = QByteArray(0x10, Qt::Uninitialized);
|
||||
auto shareHashDataInts = reinterpret_cast<int32*>(shareHashData.data());
|
||||
|
|
|
@ -31,14 +31,14 @@ class Row;
|
|||
class IndexedList;
|
||||
} // namespace Dialogs
|
||||
|
||||
namespace internal {
|
||||
class ShareInner;
|
||||
} // namespace internal
|
||||
|
||||
namespace Notify {
|
||||
struct PeerUpdate;
|
||||
} // namespace Notify
|
||||
|
||||
namespace Ui {
|
||||
class IconButton;
|
||||
} // namespace Ui
|
||||
|
||||
QString appendShareGameScoreUrl(const QString &url, const FullMsgId &fullId);
|
||||
void shareGameScoreByHash(const QString &hash);
|
||||
|
||||
|
@ -82,9 +82,10 @@ private:
|
|||
CopyCallback _copyCallback;
|
||||
SubmitCallback _submitCallback;
|
||||
|
||||
ChildWidget<internal::ShareInner> _inner;
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ChildWidget<InputField> _filter;
|
||||
ChildWidget<IconedButton> _filterCancel;
|
||||
ChildWidget<Ui::IconButton> _filterCancel;
|
||||
|
||||
ChildWidget<BoxButton> _copy;
|
||||
ChildWidget<BoxButton> _share;
|
||||
|
@ -108,13 +109,12 @@ private:
|
|||
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class ShareInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class ShareBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ShareInner(QWidget *parent, ShareBox::FilterCallback &&filterCallback);
|
||||
Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallback);
|
||||
|
||||
QVector<PeerData*> selected() const;
|
||||
bool hasSelected() const;
|
||||
|
@ -127,7 +127,7 @@ public:
|
|||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
~ShareInner();
|
||||
~Inner();
|
||||
|
||||
public slots:
|
||||
void onSelectActive();
|
||||
|
@ -208,5 +208,3 @@ private:
|
|||
ByUsernameDatas d_byUsernameFiltered;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
|
1254
Telegram/SourceFiles/boxes/stickers_box.cpp
Normal file
1254
Telegram/SourceFiles/boxes/stickers_box.cpp
Normal file
File diff suppressed because it is too large
Load diff
239
Telegram/SourceFiles/boxes/stickers_box.h
Normal file
239
Telegram/SourceFiles/boxes/stickers_box.h
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
|
||||
class ConfirmBox;
|
||||
|
||||
namespace Ui {
|
||||
class PlainShadow;
|
||||
} // namespace Ui
|
||||
|
||||
class StickersBox : public ItemListBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Section {
|
||||
Installed,
|
||||
Featured,
|
||||
Archived,
|
||||
ArchivedPart,
|
||||
};
|
||||
StickersBox(Section section = Section::Installed);
|
||||
StickersBox(const Stickers::Order &archivedIds);
|
||||
|
||||
~StickersBox();
|
||||
|
||||
public slots:
|
||||
void onStickersUpdated();
|
||||
|
||||
void onCheckDraggingScroll(int localY);
|
||||
void onNoDraggingScroll();
|
||||
void onScrollTimer();
|
||||
|
||||
void onSave();
|
||||
|
||||
private slots:
|
||||
void onScroll();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void closePressed() override;
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
void setup();
|
||||
int32 countHeight() const;
|
||||
void rebuildList();
|
||||
|
||||
void disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req);
|
||||
bool disenableFail(const RPCError &error, mtpRequestId req);
|
||||
void reorderDone(const MTPBool &result);
|
||||
bool reorderFail(const RPCError &result);
|
||||
void saveOrder();
|
||||
|
||||
void updateVisibleTopBottom();
|
||||
void checkLoadMoreArchived();
|
||||
void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result);
|
||||
|
||||
Section _section;
|
||||
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ChildWidget<BoxButton> _save = { nullptr };
|
||||
ChildWidget<BoxButton> _cancel = { nullptr };
|
||||
OrderedSet<mtpRequestId> _disenableRequests;
|
||||
mtpRequestId _reorderRequest = 0;
|
||||
ChildWidget<Ui::PlainShadow> _topShadow = { nullptr };
|
||||
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
|
||||
|
||||
QTimer _scrollTimer;
|
||||
int32 _scrollDelta = 0;
|
||||
|
||||
int _aboutWidth = 0;
|
||||
Text _about;
|
||||
int _aboutHeight = 0;
|
||||
|
||||
mtpRequestId _archivedRequestId = 0;
|
||||
bool _allArchivedLoaded = false;
|
||||
|
||||
};
|
||||
|
||||
int32 stickerPacksCount(bool includeDisabledOfficial = false);
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class StickersBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Section = StickersBox::Section;
|
||||
Inner(QWidget *parent, Section section);
|
||||
Inner(QWidget *parent, const Stickers::Order &archivedIds);
|
||||
|
||||
void rebuild();
|
||||
void updateSize();
|
||||
void updateRows(); // refresh only pack cover stickers
|
||||
bool appendSet(const Stickers::Set &set);
|
||||
bool savingStart() {
|
||||
if (_saving) return false;
|
||||
_saving = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Stickers::Order getOrder() const;
|
||||
Stickers::Order getDisabledSets() const;
|
||||
|
||||
void setVisibleScrollbar(int32 width);
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
|
||||
~Inner();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
|
||||
signals:
|
||||
void checkDraggingScroll(int localY);
|
||||
void noDraggingScroll();
|
||||
|
||||
public slots:
|
||||
void onUpdateSelected();
|
||||
void onClearRecent();
|
||||
void onClearBoxDestroyed(QObject *box);
|
||||
|
||||
private slots:
|
||||
void onImageLoaded();
|
||||
|
||||
private:
|
||||
void setup();
|
||||
void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const;
|
||||
|
||||
void step_shifting(uint64 ms, bool timer);
|
||||
void paintRow(Painter &p, int32 index);
|
||||
void clear();
|
||||
void setActionSel(int32 actionSel);
|
||||
float64 aboveShadowOpacity() const;
|
||||
|
||||
void readVisibleSets();
|
||||
|
||||
void installSet(uint64 setId);
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installFail(uint64 setId, const RPCError &error);
|
||||
|
||||
Section _section;
|
||||
Stickers::Order _archivedIds;
|
||||
|
||||
int32 _rowHeight;
|
||||
struct StickerSetRow {
|
||||
StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id)
|
||||
, sticker(sticker)
|
||||
, count(count)
|
||||
, title(title)
|
||||
, titleWidth(titleWidth)
|
||||
, installed(installed)
|
||||
, official(official)
|
||||
, unread(unread)
|
||||
, disabled(disabled)
|
||||
, recent(recent)
|
||||
, pixw(pixw)
|
||||
, pixh(pixh)
|
||||
, yadd(0, 0) {
|
||||
}
|
||||
uint64 id;
|
||||
DocumentData *sticker;
|
||||
int32 count;
|
||||
QString title;
|
||||
int titleWidth;
|
||||
bool installed, official, unread, disabled, recent;
|
||||
int32 pixw, pixh;
|
||||
anim::ivalue yadd;
|
||||
};
|
||||
using StickerSetRows = QList<StickerSetRow*>;
|
||||
|
||||
void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth);
|
||||
void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
|
||||
int fillSetCount(const Stickers::Set &set) const;
|
||||
QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const;
|
||||
void fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled);
|
||||
|
||||
int countMaxNameWidth() const;
|
||||
|
||||
StickerSetRows _rows;
|
||||
QList<uint64> _animStartTimes;
|
||||
uint64 _aboveShadowFadeStart = 0;
|
||||
anim::fvalue _aboveShadowFadeOpacity = { 0., 0. };
|
||||
Animation _a_shifting;
|
||||
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
int _itemsTop = 0;
|
||||
|
||||
bool _saving = false;
|
||||
|
||||
int _actionSel = -1;
|
||||
int _actionDown = -1;
|
||||
|
||||
int _clearWidth, _removeWidth, _returnWidth, _restoreWidth;
|
||||
|
||||
ConfirmBox *_clearBox = nullptr;
|
||||
|
||||
int _buttonHeight = 0;
|
||||
bool _hasFeaturedButton = false;
|
||||
bool _hasArchivedButton = false;
|
||||
|
||||
QPoint _mouse;
|
||||
int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button
|
||||
int _pressed = -2;
|
||||
QPoint _dragStart;
|
||||
int _started = -1;
|
||||
int _dragging = -1;
|
||||
int _above = -1;
|
||||
|
||||
Ui::RectShadow _aboveShadow;
|
||||
|
||||
int32 _scrollbar = 0;
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -24,15 +24,52 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "core/vector_of_moveable.h"
|
||||
|
||||
class ConfirmBox;
|
||||
|
||||
namespace Ui {
|
||||
class PlainShadow;
|
||||
} // namespace Ui
|
||||
|
||||
class StickerSetInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
class StickerSetBox : public ScrollableBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StickerSetInner(const MTPInputStickerSet &set);
|
||||
StickerSetBox(const MTPInputStickerSet &set);
|
||||
|
||||
public slots:
|
||||
void onStickersUpdated();
|
||||
void onAddStickers();
|
||||
void onShareStickers();
|
||||
void onUpdateButtons();
|
||||
|
||||
void onScroll();
|
||||
|
||||
private slots:
|
||||
void onInstalled(uint64 id);
|
||||
|
||||
signals:
|
||||
void installed(uint64 id);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ScrollableBoxShadow _shadow;
|
||||
BoxButton _add, _share, _cancel, _done;
|
||||
QString _title;
|
||||
|
||||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class StickerSetBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Inner(QWidget *parent, const MTPInputStickerSet &set);
|
||||
|
||||
bool loaded() const;
|
||||
int32 notInstalled() const;
|
||||
|
@ -43,7 +80,7 @@ public:
|
|||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
void install();
|
||||
|
||||
~StickerSetInner();
|
||||
~Inner();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
|
@ -96,253 +133,3 @@ private:
|
|||
int _previewShown = -1;
|
||||
|
||||
};
|
||||
|
||||
class StickerSetBox : public ScrollableBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StickerSetBox(const MTPInputStickerSet &set);
|
||||
|
||||
public slots:
|
||||
void onStickersUpdated();
|
||||
void onAddStickers();
|
||||
void onShareStickers();
|
||||
void onUpdateButtons();
|
||||
|
||||
void onScroll();
|
||||
|
||||
private slots:
|
||||
void onInstalled(uint64 id);
|
||||
|
||||
signals:
|
||||
void installed(uint64 id);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
StickerSetInner _inner;
|
||||
ScrollableBoxShadow _shadow;
|
||||
BoxButton _add, _share, _cancel, _done;
|
||||
QString _title;
|
||||
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
class StickersInner;
|
||||
} // namespace internal
|
||||
|
||||
class StickersBox : public ItemListBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Section {
|
||||
Installed,
|
||||
Featured,
|
||||
Archived,
|
||||
ArchivedPart,
|
||||
};
|
||||
StickersBox(Section section = Section::Installed);
|
||||
StickersBox(const Stickers::Order &archivedIds);
|
||||
|
||||
~StickersBox();
|
||||
|
||||
public slots:
|
||||
void onStickersUpdated();
|
||||
|
||||
void onCheckDraggingScroll(int localY);
|
||||
void onNoDraggingScroll();
|
||||
void onScrollTimer();
|
||||
|
||||
void onSave();
|
||||
|
||||
private slots:
|
||||
void onScroll();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void closePressed() override;
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
void setup();
|
||||
int32 countHeight() const;
|
||||
void rebuildList();
|
||||
|
||||
void disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req);
|
||||
bool disenableFail(const RPCError &error, mtpRequestId req);
|
||||
void reorderDone(const MTPBool &result);
|
||||
bool reorderFail(const RPCError &result);
|
||||
void saveOrder();
|
||||
|
||||
void updateVisibleTopBottom();
|
||||
void checkLoadMoreArchived();
|
||||
void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result);
|
||||
|
||||
Section _section;
|
||||
|
||||
ChildWidget<internal::StickersInner> _inner;
|
||||
ChildWidget<BoxButton> _save = { nullptr };
|
||||
ChildWidget<BoxButton> _cancel = { nullptr };
|
||||
OrderedSet<mtpRequestId> _disenableRequests;
|
||||
mtpRequestId _reorderRequest = 0;
|
||||
ChildWidget<Ui::PlainShadow> _topShadow = { nullptr };
|
||||
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
|
||||
|
||||
QTimer _scrollTimer;
|
||||
int32 _scrollDelta = 0;
|
||||
|
||||
int _aboutWidth = 0;
|
||||
Text _about;
|
||||
int _aboutHeight = 0;
|
||||
|
||||
mtpRequestId _archivedRequestId = 0;
|
||||
bool _allArchivedLoaded = false;
|
||||
|
||||
};
|
||||
|
||||
int32 stickerPacksCount(bool includeDisabledOfficial = false);
|
||||
|
||||
namespace internal {
|
||||
|
||||
class StickersInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Section = StickersBox::Section;
|
||||
StickersInner(Section section);
|
||||
StickersInner(const Stickers::Order &archivedIds);
|
||||
|
||||
void rebuild();
|
||||
void updateSize();
|
||||
void updateRows(); // refresh only pack cover stickers
|
||||
bool appendSet(const Stickers::Set &set);
|
||||
bool savingStart() {
|
||||
if (_saving) return false;
|
||||
_saving = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Stickers::Order getOrder() const;
|
||||
Stickers::Order getDisabledSets() const;
|
||||
|
||||
void setVisibleScrollbar(int32 width);
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
|
||||
~StickersInner();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
|
||||
signals:
|
||||
void checkDraggingScroll(int localY);
|
||||
void noDraggingScroll();
|
||||
|
||||
public slots:
|
||||
void onUpdateSelected();
|
||||
void onClearRecent();
|
||||
void onClearBoxDestroyed(QObject *box);
|
||||
|
||||
private slots:
|
||||
void onImageLoaded();
|
||||
|
||||
private:
|
||||
void setup();
|
||||
void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const;
|
||||
|
||||
void step_shifting(uint64 ms, bool timer);
|
||||
void paintRow(Painter &p, int32 index);
|
||||
void clear();
|
||||
void setActionSel(int32 actionSel);
|
||||
float64 aboveShadowOpacity() const;
|
||||
|
||||
void readVisibleSets();
|
||||
|
||||
void installSet(uint64 setId);
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installFail(uint64 setId, const RPCError &error);
|
||||
|
||||
Section _section;
|
||||
Stickers::Order _archivedIds;
|
||||
|
||||
int32 _rowHeight;
|
||||
struct StickerSetRow {
|
||||
StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id)
|
||||
, sticker(sticker)
|
||||
, count(count)
|
||||
, title(title)
|
||||
, titleWidth(titleWidth)
|
||||
, installed(installed)
|
||||
, official(official)
|
||||
, unread(unread)
|
||||
, disabled(disabled)
|
||||
, recent(recent)
|
||||
, pixw(pixw)
|
||||
, pixh(pixh)
|
||||
, yadd(0, 0) {
|
||||
}
|
||||
uint64 id;
|
||||
DocumentData *sticker;
|
||||
int32 count;
|
||||
QString title;
|
||||
int titleWidth;
|
||||
bool installed, official, unread, disabled, recent;
|
||||
int32 pixw, pixh;
|
||||
anim::ivalue yadd;
|
||||
};
|
||||
using StickerSetRows = QList<StickerSetRow*>;
|
||||
|
||||
void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth);
|
||||
void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
|
||||
int fillSetCount(const Stickers::Set &set) const;
|
||||
QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const;
|
||||
void fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled);
|
||||
|
||||
int countMaxNameWidth() const;
|
||||
|
||||
StickerSetRows _rows;
|
||||
QList<uint64> _animStartTimes;
|
||||
uint64 _aboveShadowFadeStart = 0;
|
||||
anim::fvalue _aboveShadowFadeOpacity = { 0., 0. };
|
||||
Animation _a_shifting;
|
||||
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
int _itemsTop = 0;
|
||||
|
||||
bool _saving = false;
|
||||
|
||||
int _actionSel = -1;
|
||||
int _actionDown = -1;
|
||||
|
||||
int _clearWidth, _removeWidth, _returnWidth, _restoreWidth;
|
||||
|
||||
ConfirmBox *_clearBox = nullptr;
|
||||
|
||||
int _buttonHeight = 0;
|
||||
bool _hasFeaturedButton = false;
|
||||
bool _hasArchivedButton = false;
|
||||
|
||||
QPoint _mouse;
|
||||
int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button
|
||||
int _pressed = -2;
|
||||
QPoint _dragStart;
|
||||
int _started = -1;
|
||||
int _dragging = -1;
|
||||
int _above = -1;
|
||||
|
||||
Ui::RectShadow _aboveShadow;
|
||||
|
||||
int32 _scrollbar = 0;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
|
|
@ -243,7 +243,7 @@ structure::Variable ParsedFile::readVariable(const QString &name) {
|
|||
structure::Variable result = { composeFullName(name) };
|
||||
if (auto value = readValue()) {
|
||||
result.value = value;
|
||||
if (value.type().tag != structure::TypeTag::Struct) {
|
||||
if (value.type().tag != structure::TypeTag::Struct || !value.copyOf().empty()) {
|
||||
assertNextToken(BasicType::Semicolon);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -529,14 +529,14 @@ void CoverWidget::onAddMember() {
|
|||
if (_peerChat->count >= Global::ChatSizeMax() && _peerChat->amCreator()) {
|
||||
Ui::showLayer(new ConvertToSupergroupBox(_peerChat));
|
||||
} else {
|
||||
Ui::showLayer(new ContactsBox(_peerChat, MembersFilterRecent));
|
||||
Ui::showLayer(new ContactsBox(_peerChat, MembersFilter::Recent));
|
||||
}
|
||||
} else if (_peerChannel && _peerChannel->mgInfo) {
|
||||
MembersAlreadyIn already;
|
||||
for_const (auto user, _peerChannel->mgInfo->lastParticipants) {
|
||||
already.insert(user);
|
||||
}
|
||||
Ui::showLayer(new ContactsBox(_peerChannel, MembersFilterRecent, already));
|
||||
Ui::showLayer(new ContactsBox(_peerChannel, MembersFilter::Recent, already));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -700,13 +700,13 @@ int ChannelMembersWidget::resizeGetHeight(int newWidth) {
|
|||
|
||||
void ChannelMembersWidget::onAdmins() {
|
||||
if (auto channel = peer()->asChannel()) {
|
||||
Ui::showLayer(new MembersBox(channel, MembersFilterAdmins));
|
||||
Ui::showLayer(new MembersBox(channel, MembersFilter::Admins));
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelMembersWidget::onMembers() {
|
||||
if (auto channel = peer()->asChannel()) {
|
||||
Ui::showLayer(new MembersBox(channel, MembersFilterRecent));
|
||||
Ui::showLayer(new MembersBox(channel, MembersFilter::Recent));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -164,9 +164,9 @@ void SettingsWidget::onNotificationsChange() {
|
|||
|
||||
void SettingsWidget::onManageAdmins() {
|
||||
if (auto chat = peer()->asChat()) {
|
||||
Ui::showLayer(new ContactsBox(chat, MembersFilterAdmins));
|
||||
Ui::showLayer(new ContactsBox(chat, MembersFilter::Admins));
|
||||
} else if (auto channel = peer()->asChannel()) {
|
||||
Ui::showLayer(new MembersBox(channel, MembersFilterAdmins));
|
||||
Ui::showLayer(new MembersBox(channel, MembersFilter::Admins));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "boxes/emojibox.h"
|
||||
#include "boxes/stickersetbox.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "boxes/downloadpathbox.h"
|
||||
#include "boxes/connectionbox.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_stickers.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "boxes/stickersetbox.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "inline_bots/inline_bot_result.h"
|
||||
#include "inline_bots/inline_bot_layout_item.h"
|
||||
#include "dialogs/dialogs_layout.h"
|
||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "stdafx.h"
|
||||
#include "stickers.h"
|
||||
|
||||
#include "boxes/stickersetbox.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "lang.h"
|
||||
#include "apiwrap.h"
|
||||
|
|
|
@ -24,8 +24,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "lang.h"
|
||||
#include "application.h"
|
||||
#include "ui/scrollarea.h"
|
||||
#include "ui/buttons/icon_button.h"
|
||||
#include "boxes/contactsbox.h"
|
||||
#include "countries.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -192,7 +194,88 @@ void CountryInput::setText(const QString &newText) {
|
|||
_text = _st.font->elided(newText, width() - _st.textMrg.left() - _st.textMrg.right());
|
||||
}
|
||||
|
||||
CountrySelectInner::CountrySelectInner() : TWidget()
|
||||
CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxWidth)
|
||||
, _inner(this)
|
||||
, _filter(this, st::boxSearchField, lang(lng_country_ph))
|
||||
, _filterCancel(this, st::boxSearchCancel)
|
||||
, _topShadow(this) {
|
||||
ItemListBox::init(_inner, st::boxScrollSkip, st::boxTitleHeight + _filter->height());
|
||||
|
||||
connect(_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(_filter, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel()));
|
||||
connect(_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
||||
connect(_inner, SIGNAL(countryChosen(const QString&)), this, SIGNAL(countryChosen(const QString&)));
|
||||
|
||||
_filterCancel->setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
void CountrySelectBox::onSubmit() {
|
||||
_inner->chooseCountry();
|
||||
}
|
||||
|
||||
void CountrySelectBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Down) {
|
||||
_inner->selectSkip(1);
|
||||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner->selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner->selectSkipPage(scrollArea()->height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner->selectSkipPage(scrollArea()->height(), -1);
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void CountrySelectBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
paintTitle(p, lang(lng_country_select));
|
||||
}
|
||||
|
||||
void CountrySelectBox::resizeEvent(QResizeEvent *e) {
|
||||
ItemListBox::resizeEvent(e);
|
||||
_filter->resize(width(), _filter->height());
|
||||
_filter->moveToLeft(0, st::boxTitleHeight);
|
||||
_filterCancel->moveToRight(0, st::boxTitleHeight);
|
||||
_inner->resize(width(), _inner->height());
|
||||
_topShadow.setGeometry(0, st::boxTitleHeight + _filter->height(), width(), st::lineWidth);
|
||||
}
|
||||
|
||||
void CountrySelectBox::showAll() {
|
||||
_filter->show();
|
||||
if (_filter->getLastText().isEmpty()) {
|
||||
_filterCancel->hide();
|
||||
} else {
|
||||
_filterCancel->show();
|
||||
}
|
||||
_topShadow.show();
|
||||
ItemListBox::showAll();
|
||||
}
|
||||
|
||||
void CountrySelectBox::onFilterCancel() {
|
||||
_filter->setText(QString());
|
||||
}
|
||||
|
||||
void CountrySelectBox::onFilterUpdate() {
|
||||
scrollArea()->scrollToY(0);
|
||||
if (_filter->getLastText().isEmpty()) {
|
||||
_filterCancel->hide();
|
||||
} else {
|
||||
_filterCancel->show();
|
||||
}
|
||||
_inner->updateFilter(_filter->getLastText());
|
||||
}
|
||||
|
||||
void CountrySelectBox::doSetInnerFocus() {
|
||||
_filter->setFocus();
|
||||
}
|
||||
|
||||
CountrySelectBox::Inner::Inner(QWidget *parent) : ScrolledWidget(parent)
|
||||
, _rowHeight(st::countryRowHeight)
|
||||
, _sel(0)
|
||||
, _mouseSel(false) {
|
||||
|
@ -239,7 +322,7 @@ CountrySelectInner::CountrySelectInner() : TWidget()
|
|||
updateFilter();
|
||||
}
|
||||
|
||||
void CountrySelectInner::paintEvent(QPaintEvent *e) {
|
||||
void CountrySelectBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
QRect r(e->rect());
|
||||
p.setClipRect(r);
|
||||
|
@ -283,11 +366,11 @@ void CountrySelectInner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void CountrySelectInner::enterEvent(QEvent *e) {
|
||||
void CountrySelectBox::Inner::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void CountrySelectInner::leaveEvent(QEvent *e) {
|
||||
void CountrySelectBox::Inner::leaveEvent(QEvent *e) {
|
||||
_mouseSel = false;
|
||||
setMouseTracking(false);
|
||||
if (_sel >= 0) {
|
||||
|
@ -296,13 +379,13 @@ void CountrySelectInner::leaveEvent(QEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void CountrySelectInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
void CountrySelectBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void CountrySelectInner::mousePressEvent(QMouseEvent *e) {
|
||||
void CountrySelectBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
|
@ -311,7 +394,7 @@ void CountrySelectInner::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void CountrySelectInner::updateFilter(QString filter) {
|
||||
void CountrySelectBox::Inner::updateFilter(QString filter) {
|
||||
filter = textSearchKey(filter);
|
||||
|
||||
QStringList f;
|
||||
|
@ -366,7 +449,7 @@ void CountrySelectInner::updateFilter(QString filter) {
|
|||
}
|
||||
}
|
||||
|
||||
void CountrySelectInner::selectSkip(int32 dir) {
|
||||
void CountrySelectBox::Inner::selectSkip(int32 dir) {
|
||||
_mouseSel = false;
|
||||
|
||||
int cur = (_sel >= 0) ? _sel : -1;
|
||||
|
@ -384,13 +467,13 @@ void CountrySelectInner::selectSkip(int32 dir) {
|
|||
update();
|
||||
}
|
||||
|
||||
void CountrySelectInner::selectSkipPage(int32 h, int32 dir) {
|
||||
void CountrySelectBox::Inner::selectSkipPage(int32 h, int32 dir) {
|
||||
int32 points = h / _rowHeight;
|
||||
if (!points) return;
|
||||
selectSkip(points * dir);
|
||||
}
|
||||
|
||||
void CountrySelectInner::chooseCountry() {
|
||||
void CountrySelectBox::Inner::chooseCountry() {
|
||||
QString result;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_sel >= 0 && _sel < countriesAll.size()) {
|
||||
|
@ -404,11 +487,11 @@ void CountrySelectInner::chooseCountry() {
|
|||
emit countryChosen(result);
|
||||
}
|
||||
|
||||
void CountrySelectInner::refresh() {
|
||||
void CountrySelectBox::Inner::refresh() {
|
||||
resize(width(), countriesNow->length() ? (countriesNow->length() * _rowHeight + st::countriesSkip) : st::noContactsHeight);
|
||||
}
|
||||
|
||||
void CountrySelectInner::updateSel() {
|
||||
void CountrySelectBox::Inner::updateSel() {
|
||||
if (!_mouseSel) return;
|
||||
|
||||
QPoint p(mapFromGlobal(_lastMousePos));
|
||||
|
@ -422,89 +505,8 @@ void CountrySelectInner::updateSel() {
|
|||
}
|
||||
}
|
||||
|
||||
void CountrySelectInner::updateSelectedRow() {
|
||||
void CountrySelectBox::Inner::updateSelectedRow() {
|
||||
if (_sel >= 0) {
|
||||
update(0, st::countriesSkip + _sel * _rowHeight, width(), _rowHeight);
|
||||
}
|
||||
}
|
||||
|
||||
CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxWidth)
|
||||
, _inner()
|
||||
, _filter(this, st::boxSearchField, lang(lng_country_ph))
|
||||
, _filterCancel(this, st::boxSearchCancel)
|
||||
, _topShadow(this) {
|
||||
ItemListBox::init(&_inner, st::boxScrollSkip, st::boxTitleHeight + _filter.height());
|
||||
|
||||
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(&_filter, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(&_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
||||
connect(&_inner, SIGNAL(countryChosen(const QString&)), this, SIGNAL(countryChosen(const QString&)));
|
||||
|
||||
_filterCancel.setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
void CountrySelectBox::onSubmit() {
|
||||
_inner.chooseCountry();
|
||||
}
|
||||
|
||||
void CountrySelectBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Down) {
|
||||
_inner.selectSkip(1);
|
||||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner.selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner.selectSkipPage(scrollArea()->height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner.selectSkipPage(scrollArea()->height(), -1);
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void CountrySelectBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
paintTitle(p, lang(lng_country_select));
|
||||
}
|
||||
|
||||
void CountrySelectBox::resizeEvent(QResizeEvent *e) {
|
||||
ItemListBox::resizeEvent(e);
|
||||
_filter.resize(width(), _filter.height());
|
||||
_filter.moveToLeft(0, st::boxTitleHeight);
|
||||
_filterCancel.moveToRight(0, st::boxTitleHeight);
|
||||
_inner.resize(width(), _inner.height());
|
||||
_topShadow.setGeometry(0, st::boxTitleHeight + _filter.height(), width(), st::lineWidth);
|
||||
}
|
||||
|
||||
void CountrySelectBox::showAll() {
|
||||
_filter.show();
|
||||
if (_filter.getLastText().isEmpty()) {
|
||||
_filterCancel.hide();
|
||||
} else {
|
||||
_filterCancel.show();
|
||||
}
|
||||
_topShadow.show();
|
||||
ItemListBox::showAll();
|
||||
}
|
||||
|
||||
void CountrySelectBox::onFilterCancel() {
|
||||
_filter.setText(QString());
|
||||
}
|
||||
|
||||
void CountrySelectBox::onFilterUpdate() {
|
||||
scrollArea()->scrollToY(0);
|
||||
if (_filter.getLastText().isEmpty()) {
|
||||
_filterCancel.hide();
|
||||
} else {
|
||||
_filterCancel.show();
|
||||
}
|
||||
_inner.updateFilter(_filter.getLastText());
|
||||
}
|
||||
|
||||
void CountrySelectBox::doSetInnerFocus() {
|
||||
_filter.setFocus();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
QString findValidCode(QString fullCode);
|
||||
|
||||
class CountrySelect;
|
||||
class InputField;
|
||||
|
||||
namespace Ui {
|
||||
class IconButton;
|
||||
} // namespace Ui
|
||||
|
||||
class CountryInput : public QWidget {
|
||||
Q_OBJECT
|
||||
|
@ -63,11 +68,48 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class CountrySelectInner : public TWidget {
|
||||
namespace internal {
|
||||
class CountrySelectInner;
|
||||
} // namespace internal
|
||||
|
||||
class CountrySelectBox : public ItemListBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CountrySelectInner();
|
||||
CountrySelectBox();
|
||||
|
||||
signals:
|
||||
void countryChosen(const QString &iso);
|
||||
|
||||
public slots:
|
||||
void onFilterUpdate();
|
||||
void onFilterCancel();
|
||||
void onSubmit();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void doSetInnerFocus() override;
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ChildWidget<InputField> _filter;
|
||||
ChildWidget<Ui::IconButton> _filterCancel;
|
||||
|
||||
ScrollableBoxShadow _topShadow;
|
||||
|
||||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class CountrySelectBox::Inner : public ScrolledWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Inner(QWidget *parent);
|
||||
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
|
@ -104,34 +146,3 @@ private:
|
|||
QPoint _lastMousePos;
|
||||
|
||||
};
|
||||
|
||||
class CountrySelectBox : public ItemListBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CountrySelectBox();
|
||||
|
||||
signals:
|
||||
void countryChosen(const QString &iso);
|
||||
|
||||
public slots:
|
||||
void onFilterUpdate();
|
||||
void onFilterCancel();
|
||||
void onSubmit();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void doSetInnerFocus() override;
|
||||
void showAll() override;
|
||||
|
||||
private:
|
||||
CountrySelectInner _inner;
|
||||
InputField _filter;
|
||||
IconedButton _filterCancel;
|
||||
|
||||
ScrollableBoxShadow _topShadow;
|
||||
|
||||
};
|
||||
|
|
|
@ -21,10 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#pragma once
|
||||
|
||||
#include "ui/widgets/continuous_slider.h"
|
||||
|
||||
namespace style {
|
||||
struct FilledSlider;
|
||||
} // namespace style
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
|
|
|
@ -21,10 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#pragma once
|
||||
|
||||
#include "ui/widgets/continuous_slider.h"
|
||||
|
||||
namespace style {
|
||||
struct MediaSlider;
|
||||
} // namespace style
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
|
|
|
@ -183,6 +183,8 @@
|
|||
'<(src_loc)/boxes/languagebox.h',
|
||||
'<(src_loc)/boxes/localstoragebox.cpp',
|
||||
'<(src_loc)/boxes/localstoragebox.h',
|
||||
'<(src_loc)/boxes/members_box.cpp',
|
||||
'<(src_loc)/boxes/members_box.h',
|
||||
'<(src_loc)/boxes/notifications_box.cpp',
|
||||
'<(src_loc)/boxes/notifications_box.h',
|
||||
'<(src_loc)/boxes/passcodebox.cpp',
|
||||
|
@ -199,6 +201,8 @@
|
|||
'<(src_loc)/boxes/sharebox.h',
|
||||
'<(src_loc)/boxes/stickersetbox.cpp',
|
||||
'<(src_loc)/boxes/stickersetbox.h',
|
||||
'<(src_loc)/boxes/stickers_box.cpp',
|
||||
'<(src_loc)/boxes/stickers_box.h',
|
||||
'<(src_loc)/boxes/usernamebox.cpp',
|
||||
'<(src_loc)/boxes/usernamebox.h',
|
||||
'<(src_loc)/core/basic_types.h',
|
||||
|
|
Loading…
Add table
Reference in a new issue