mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 23:53:58 +02:00
Slightly refactored FieldAutocomplete.
This commit is contained in:
parent
2ac425f350
commit
cf56658664
4 changed files with 155 additions and 52 deletions
|
@ -45,8 +45,10 @@ FieldAutocomplete::FieldAutocomplete(
|
||||||
, _scroll(this, st::mentionScroll) {
|
, _scroll(this, st::mentionScroll) {
|
||||||
_scroll->setGeometry(rect());
|
_scroll->setGeometry(rect());
|
||||||
|
|
||||||
|
using Inner = internal::FieldAutocompleteInner;
|
||||||
|
|
||||||
_inner = _scroll->setOwnedWidget(
|
_inner = _scroll->setOwnedWidget(
|
||||||
object_ptr<internal::FieldAutocompleteInner>(
|
object_ptr<Inner>(
|
||||||
_controller,
|
_controller,
|
||||||
this,
|
this,
|
||||||
&_mrows,
|
&_mrows,
|
||||||
|
@ -55,18 +57,41 @@ FieldAutocomplete::FieldAutocomplete(
|
||||||
&_srows));
|
&_srows));
|
||||||
_inner->setGeometry(rect());
|
_inner->setGeometry(rect());
|
||||||
|
|
||||||
connect(_inner, SIGNAL(mentionChosen(not_null<UserData*>,FieldAutocomplete::ChooseMethod)), this, SIGNAL(mentionChosen(not_null<UserData*>,FieldAutocomplete::ChooseMethod)));
|
_inner->scrollToRequested(
|
||||||
connect(_inner, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)), this, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)));
|
) | rpl::start_with_next([=](Inner::ScrollTo data) {
|
||||||
connect(_inner, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod)), this, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod)));
|
_scroll->scrollToY(data.top, data.bottom);
|
||||||
connect(_inner, SIGNAL(stickerChosen(not_null<DocumentData*>,FieldAutocomplete::ChooseMethod)), this, SIGNAL(stickerChosen(not_null<DocumentData*>,FieldAutocomplete::ChooseMethod)));
|
}, lifetime());
|
||||||
connect(_inner, SIGNAL(mustScrollTo(int, int)), _scroll, SLOT(scrollToY(int, int)));
|
|
||||||
|
|
||||||
_scroll->show();
|
_scroll->show();
|
||||||
_inner->show();
|
_inner->show();
|
||||||
|
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
connect(_scroll, SIGNAL(geometryChanged()), _inner, SLOT(onParentGeometryChanged()));
|
connect(
|
||||||
|
_scroll,
|
||||||
|
&Ui::ScrollArea::geometryChanged,
|
||||||
|
_inner,
|
||||||
|
&Inner::onParentGeometryChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocomplete::mentionChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::MentionChosen> {
|
||||||
|
return _inner->mentionChosen();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocomplete::hashtagChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::HashtagChosen> {
|
||||||
|
return _inner->hashtagChosen();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocomplete::botCommandChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::BotCommandChosen> {
|
||||||
|
return _inner->botCommandChosen();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocomplete::stickerChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::StickerChosen> {
|
||||||
|
return _inner->stickerChosen();
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldAutocomplete::~FieldAutocomplete() = default;
|
FieldAutocomplete::~FieldAutocomplete() = default;
|
||||||
|
@ -583,9 +608,10 @@ bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) {
|
||||||
&& ((key >= Qt::Key_1 && key <= Qt::Key_9)
|
&& ((key >= Qt::Key_1 && key <= Qt::Key_9)
|
||||||
|| key == Qt::Key_Q
|
|| key == Qt::Key_Q
|
||||||
|| key == Qt::Key_W)) {
|
|| key == Qt::Key_W)) {
|
||||||
bool handled = false;
|
|
||||||
emit moderateKeyActivate(key, &handled);
|
return _moderateKeyActivateCallback
|
||||||
return handled;
|
? _moderateKeyActivateCallback(key)
|
||||||
|
: false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -878,29 +904,37 @@ bool FieldAutocompleteInner::moveSel(int key) {
|
||||||
bool FieldAutocompleteInner::chooseSelected(FieldAutocomplete::ChooseMethod method) const {
|
bool FieldAutocompleteInner::chooseSelected(FieldAutocomplete::ChooseMethod method) const {
|
||||||
if (!_srows->empty()) {
|
if (!_srows->empty()) {
|
||||||
if (_sel >= 0 && _sel < _srows->size()) {
|
if (_sel >= 0 && _sel < _srows->size()) {
|
||||||
emit stickerChosen((*_srows)[_sel].document, method);
|
_stickerChosen.fire({ (*_srows)[_sel].document, method });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!_mrows->empty()) {
|
} else if (!_mrows->empty()) {
|
||||||
if (_sel >= 0 && _sel < _mrows->size()) {
|
if (_sel >= 0 && _sel < _mrows->size()) {
|
||||||
emit mentionChosen(_mrows->at(_sel).user, method);
|
_mentionChosen.fire({ _mrows->at(_sel).user, method });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!_hrows->empty()) {
|
} else if (!_hrows->empty()) {
|
||||||
if (_sel >= 0 && _sel < _hrows->size()) {
|
if (_sel >= 0 && _sel < _hrows->size()) {
|
||||||
emit hashtagChosen('#' + _hrows->at(_sel), method);
|
_hashtagChosen.fire({ '#' + _hrows->at(_sel), method });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!_brows->empty()) {
|
} else if (!_brows->empty()) {
|
||||||
if (_sel >= 0 && _sel < _brows->size()) {
|
if (_sel >= 0 && _sel < _brows->size()) {
|
||||||
const auto user = _brows->at(_sel).user;
|
const auto user = _brows->at(_sel).user;
|
||||||
const auto command = _brows->at(_sel).command;
|
const auto command = _brows->at(_sel).command;
|
||||||
int32 botStatus = _parent->chat() ? _parent->chat()->botStatus : ((_parent->channel() && _parent->channel()->isMegagroup()) ? _parent->channel()->mgInfo->botStatus : -1);
|
const auto botStatus = _parent->chat()
|
||||||
if (botStatus == 0 || botStatus == 2 || _parent->filter().indexOf('@') > 0) {
|
? _parent->chat()->botStatus
|
||||||
emit botCommandChosen('/' + command->command + '@' + user->username, method);
|
: ((_parent->channel() && _parent->channel()->isMegagroup())
|
||||||
} else {
|
? _parent->channel()->mgInfo->botStatus
|
||||||
emit botCommandChosen('/' + command->command, method);
|
: -1);
|
||||||
}
|
|
||||||
|
const auto insertUsername = (botStatus == 0
|
||||||
|
|| botStatus == 2
|
||||||
|
|| _parent->filter().indexOf('@') > 0);
|
||||||
|
const auto commandString = QString("/%1%2")
|
||||||
|
.arg(command->command)
|
||||||
|
.arg(insertUsername ? ('@' + user->username) : QString());
|
||||||
|
|
||||||
|
_botCommandChosen.fire({ commandString, method });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,10 +1034,15 @@ void FieldAutocompleteInner::setSel(int sel, bool scroll) {
|
||||||
|
|
||||||
if (scroll && _sel >= 0) {
|
if (scroll && _sel >= 0) {
|
||||||
if (_srows->empty()) {
|
if (_srows->empty()) {
|
||||||
emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight);
|
_scrollToRequested.fire({
|
||||||
|
_sel * st::mentionHeight,
|
||||||
|
(_sel + 1) * st::mentionHeight });
|
||||||
} else {
|
} else {
|
||||||
int32 row = _sel / _stickersPerRow;
|
int32 row = _sel / _stickersPerRow;
|
||||||
emit mustScrollTo(st::stickerPanPadding + row * st::stickerPanSize.height(), st::stickerPanPadding + (row + 1) * st::stickerPanSize.height());
|
const auto padding = st::stickerPanPadding;
|
||||||
|
_scrollToRequested.fire({
|
||||||
|
padding + row * st::stickerPanSize.height(),
|
||||||
|
padding + (row + 1) * st::stickerPanSize.height() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1131,4 +1170,29 @@ void FieldAutocompleteInner::showPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto FieldAutocompleteInner::mentionChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::MentionChosen> {
|
||||||
|
return _mentionChosen.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocompleteInner::hashtagChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::HashtagChosen> {
|
||||||
|
return _hashtagChosen.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocompleteInner::botCommandChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::BotCommandChosen> {
|
||||||
|
return _botCommandChosen.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocompleteInner::stickerChosen() const
|
||||||
|
-> rpl::producer<FieldAutocomplete::StickerChosen> {
|
||||||
|
return _stickerChosen.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocompleteInner::scrollToRequested() const
|
||||||
|
-> rpl::producer<ScrollTo> {
|
||||||
|
return _scrollToRequested.events();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
@ -59,7 +59,6 @@ class FieldAutocompleteInner;
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
class FieldAutocomplete final : public Ui::RpWidget {
|
class FieldAutocomplete final : public Ui::RpWidget {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FieldAutocomplete(
|
FieldAutocomplete(
|
||||||
|
@ -90,6 +89,23 @@ public:
|
||||||
ByTab,
|
ByTab,
|
||||||
ByClick,
|
ByClick,
|
||||||
};
|
};
|
||||||
|
struct MentionChosen {
|
||||||
|
not_null<UserData*> user;
|
||||||
|
ChooseMethod method;
|
||||||
|
};
|
||||||
|
struct HashtagChosen {
|
||||||
|
QString hashtag;
|
||||||
|
ChooseMethod method;
|
||||||
|
};
|
||||||
|
struct BotCommandChosen {
|
||||||
|
QString command;
|
||||||
|
ChooseMethod method;
|
||||||
|
};
|
||||||
|
struct StickerChosen {
|
||||||
|
not_null<DocumentData*> sticker;
|
||||||
|
ChooseMethod method;
|
||||||
|
};
|
||||||
|
|
||||||
bool chooseSelected(ChooseMethod method) const;
|
bool chooseSelected(ChooseMethod method) const;
|
||||||
|
|
||||||
bool stickersShown() const {
|
bool stickersShown() const {
|
||||||
|
@ -102,15 +118,16 @@ public:
|
||||||
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setModerateKeyActivateCallback(Fn<bool(int)> callback) {
|
||||||
|
_moderateKeyActivateCallback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void hideFast();
|
void hideFast();
|
||||||
|
|
||||||
signals:
|
rpl::producer<MentionChosen> mentionChosen() const;
|
||||||
void mentionChosen(not_null<UserData*> user, FieldAutocomplete::ChooseMethod method) const;
|
rpl::producer<HashtagChosen> hashtagChosen() const;
|
||||||
void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const;
|
rpl::producer<BotCommandChosen> botCommandChosen() const;
|
||||||
void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const;
|
rpl::producer<StickerChosen> stickerChosen() const;
|
||||||
void stickerChosen(not_null<DocumentData*> sticker, FieldAutocomplete::ChooseMethod method) const;
|
|
||||||
|
|
||||||
void moderateKeyActivate(int key, bool *outHandled) const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void showAnimated();
|
void showAnimated();
|
||||||
|
@ -160,11 +177,12 @@ private:
|
||||||
QRect _boundings;
|
QRect _boundings;
|
||||||
bool _addInlineBots;
|
bool _addInlineBots;
|
||||||
|
|
||||||
int32 _width, _height;
|
|
||||||
bool _hiding = false;
|
bool _hiding = false;
|
||||||
|
|
||||||
Ui::Animations::Simple _a_opacity;
|
Ui::Animations::Simple _a_opacity;
|
||||||
|
|
||||||
|
Fn<bool(int)> _moderateKeyActivateCallback;
|
||||||
|
|
||||||
friend class internal::FieldAutocompleteInner;
|
friend class internal::FieldAutocompleteInner;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -174,9 +192,13 @@ namespace internal {
|
||||||
class FieldAutocompleteInner final
|
class FieldAutocompleteInner final
|
||||||
: public Ui::RpWidget
|
: public Ui::RpWidget
|
||||||
, private base::Subscriber {
|
, private base::Subscriber {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
struct ScrollTo {
|
||||||
|
int top;
|
||||||
|
int bottom;
|
||||||
|
};
|
||||||
|
|
||||||
FieldAutocompleteInner(
|
FieldAutocompleteInner(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<FieldAutocomplete*> parent,
|
not_null<FieldAutocomplete*> parent,
|
||||||
|
@ -192,14 +214,13 @@ public:
|
||||||
void setRecentInlineBotsInRows(int32 bots);
|
void setRecentInlineBotsInRows(int32 bots);
|
||||||
void rowsUpdated();
|
void rowsUpdated();
|
||||||
|
|
||||||
signals:
|
rpl::producer<FieldAutocomplete::MentionChosen> mentionChosen() const;
|
||||||
void mentionChosen(not_null<UserData*> user, FieldAutocomplete::ChooseMethod method) const;
|
rpl::producer<FieldAutocomplete::HashtagChosen> hashtagChosen() const;
|
||||||
void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const;
|
rpl::producer<FieldAutocomplete::BotCommandChosen>
|
||||||
void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const;
|
botCommandChosen() const;
|
||||||
void stickerChosen(not_null<DocumentData*> sticker, FieldAutocomplete::ChooseMethod method) const;
|
rpl::producer<FieldAutocomplete::StickerChosen> stickerChosen() const;
|
||||||
void mustScrollTo(int scrollToTop, int scrollToBottom);
|
rpl::producer<ScrollTo> scrollToRequested() const;
|
||||||
|
|
||||||
public slots:
|
|
||||||
void onParentGeometryChanged();
|
void onParentGeometryChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -242,6 +263,12 @@ private:
|
||||||
|
|
||||||
bool _previewShown = false;
|
bool _previewShown = false;
|
||||||
|
|
||||||
|
rpl::event_stream<FieldAutocomplete::MentionChosen> _mentionChosen;
|
||||||
|
rpl::event_stream<FieldAutocomplete::HashtagChosen> _hashtagChosen;
|
||||||
|
rpl::event_stream<FieldAutocomplete::BotCommandChosen> _botCommandChosen;
|
||||||
|
rpl::event_stream<FieldAutocomplete::StickerChosen> _stickerChosen;
|
||||||
|
rpl::event_stream<ScrollTo> _scrollToRequested;
|
||||||
|
|
||||||
base::Timer _previewTimer;
|
base::Timer _previewTimer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -382,15 +382,33 @@ HistoryWidget::HistoryWidget(
|
||||||
|
|
||||||
InitMessageField(controller, _field);
|
InitMessageField(controller, _field);
|
||||||
_fieldAutocomplete->hide();
|
_fieldAutocomplete->hide();
|
||||||
connect(_fieldAutocomplete, &FieldAutocomplete::mentionChosen, this, [=](not_null<UserData*> user) {
|
|
||||||
onMentionInsert(user);
|
_fieldAutocomplete->mentionChosen(
|
||||||
|
) | rpl::start_with_next([=](FieldAutocomplete::MentionChosen data) {
|
||||||
|
onMentionInsert(data.user);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_fieldAutocomplete->hashtagChosen(
|
||||||
|
) | rpl::start_with_next([=](FieldAutocomplete::HashtagChosen data) {
|
||||||
|
onHashtagOrBotCommandInsert(data.hashtag, data.method);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_fieldAutocomplete->botCommandChosen(
|
||||||
|
) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) {
|
||||||
|
onHashtagOrBotCommandInsert(data.command, data.method);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_fieldAutocomplete->stickerChosen(
|
||||||
|
) | rpl::start_with_next([=](FieldAutocomplete::StickerChosen data) {
|
||||||
|
sendExistingDocument(data.sticker, Api::SendOptions());
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_fieldAutocomplete->setModerateKeyActivateCallback([=](int key) {
|
||||||
|
return _keyboard->isHidden()
|
||||||
|
? false
|
||||||
|
: _keyboard->moderateKeyActivate(key);
|
||||||
});
|
});
|
||||||
connect(_fieldAutocomplete, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)), this, SLOT(onHashtagOrBotCommandInsert(QString,FieldAutocomplete::ChooseMethod)));
|
|
||||||
connect(_fieldAutocomplete, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod)), this, SLOT(onHashtagOrBotCommandInsert(QString,FieldAutocomplete::ChooseMethod)));
|
|
||||||
connect(_fieldAutocomplete, &FieldAutocomplete::stickerChosen, this, [=](not_null<DocumentData*> document) {
|
|
||||||
sendExistingDocument(document, Api::SendOptions());
|
|
||||||
});
|
|
||||||
connect(_fieldAutocomplete, SIGNAL(moderateKeyActivate(int,bool*)), this, SLOT(onModerateKeyActivate(int,bool*)));
|
|
||||||
if (_supportAutocomplete) {
|
if (_supportAutocomplete) {
|
||||||
supportInitAutocomplete();
|
supportInitAutocomplete();
|
||||||
}
|
}
|
||||||
|
@ -3921,10 +3939,6 @@ void HistoryWidget::onMembersDropdownShow() {
|
||||||
_membersDropdown->otherEnter();
|
_membersDropdown->otherEnter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onModerateKeyActivate(int index, bool *outHandled) {
|
|
||||||
*outHandled = _keyboard->isHidden() ? false : _keyboard->moderateKeyActivate(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HistoryWidget::pushTabbedSelectorToThirdSection(
|
bool HistoryWidget::pushTabbedSelectorToThirdSection(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const Window::SectionShow ¶ms) {
|
const Window::SectionShow ¶ms) {
|
||||||
|
|
|
@ -325,8 +325,6 @@ private slots:
|
||||||
void onInlineBotCancel();
|
void onInlineBotCancel();
|
||||||
void onMembersDropdownShow();
|
void onMembersDropdownShow();
|
||||||
|
|
||||||
void onModerateKeyActivate(int index, bool *outHandled);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using TabbedPanel = ChatHelpers::TabbedPanel;
|
using TabbedPanel = ChatHelpers::TabbedPanel;
|
||||||
using TabbedSelector = ChatHelpers::TabbedSelector;
|
using TabbedSelector = ChatHelpers::TabbedSelector;
|
||||||
|
|
Loading…
Add table
Reference in a new issue