Added spoiler support to input field.

This commit is contained in:
23rd 2021-12-19 17:06:21 +03:00
parent bcf16c6c80
commit ee4a94c122
6 changed files with 45 additions and 0 deletions

View file

@ -139,4 +139,8 @@ QString Integration::phraseFormattingMonospace() {
return "Monospace";
}
QString Integration::phraseFormattingSpoiler() {
return "Spoiler";
}
} // namespace Ui

View file

@ -70,6 +70,7 @@ public:
[[nodiscard]] virtual QString phraseFormattingUnderline();
[[nodiscard]] virtual QString phraseFormattingStrikeOut();
[[nodiscard]] virtual QString phraseFormattingMonospace();
[[nodiscard]] virtual QString phraseFormattingSpoiler();
};

View file

@ -70,6 +70,10 @@ QString SeparatorsMono() {
return Separators(QString::fromUtf8("*~/"));
}
QString SeparatorsSpoiler() {
return Separators(QString::fromUtf8("|*~/"));
}
QString ExpressionHashtag() {
return QString::fromUtf8("(^|[") + ExpressionSeparators(QString::fromUtf8("`\\*/")) + QString::fromUtf8("])#[\\w]{2,64}([\\W]|$)");
}
@ -1271,6 +1275,14 @@ QString MarkdownPreBadAfter() {
return QString::fromLatin1("`");
}
QString MarkdownSpoilerGoodBefore() {
return SeparatorsSpoiler();
}
QString MarkdownSpoilerBadAfter() {
return QString::fromLatin1("|");
}
bool IsValidProtocol(const QString &protocol) {
static const auto list = CreateValidProtocols();
return list.contains(base::crc32(protocol.constData(), protocol.size() * sizeof(QChar)));
@ -2087,6 +2099,7 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
EntityType::Italic,
EntityType::Underline,
EntityType::StrikeOut,
EntityType::Spoiler,
EntityType::Code,
EntityType::Pre,
};
@ -2193,6 +2206,8 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
result.set(EntityType::Code);
} else if (single == Ui::InputField::kTagPre) {
result.set(EntityType::Pre);
} else if (single == Ui::InputField::kTagSpoiler) {
result.set(EntityType::Spoiler);
} else {
result.link = single.toString();
}
@ -2281,6 +2296,7 @@ TextWithTags::Tags ConvertEntitiesToTextTags(
break;
case EntityType::Code: push(Ui::InputField::kTagCode); break; // #TODO entities
case EntityType::Pre: push(Ui::InputField::kTagPre); break;
case EntityType::Spoiler: push(Ui::InputField::kTagSpoiler); break;
}
}
if (!toRemove.empty()) {

View file

@ -291,6 +291,8 @@ QString MarkdownCodeGoodBefore();
QString MarkdownCodeBadAfter();
QString MarkdownPreGoodBefore();
QString MarkdownPreBadAfter();
QString MarkdownSpoilerGoodBefore();
QString MarkdownSpoilerBadAfter();
// Text preprocess.
QString Clean(const QString &text);

View file

@ -44,6 +44,7 @@ const auto &kTagUnderline = InputField::kTagUnderline;
const auto &kTagStrikeOut = InputField::kTagStrikeOut;
const auto &kTagCode = InputField::kTagCode;
const auto &kTagPre = InputField::kTagPre;
const auto &kTagSpoiler = InputField::kTagSpoiler;
const auto kTagCheckLinkMeta = QString("^:/:/:^");
const auto kNewlineChars = QString("\r\n")
+ QChar(0xfdd0) // QTextBeginningOfFrame
@ -230,6 +231,7 @@ constexpr auto kTagItalicIndex = 1;
constexpr auto kTagStrikeOutIndex = 2;
constexpr auto kTagCodeIndex = 3;
constexpr auto kTagPreIndex = 4;
constexpr auto kTagSpoilerIndex = 5;
constexpr auto kInvalidPosition = std::numeric_limits<int>::max() / 2;
class TagSearchItem {
@ -373,6 +375,13 @@ const std::vector<TagStartExpression> &TagStartExpressions() {
TextUtilities::MarkdownPreBadAfter(),
TextUtilities::MarkdownPreGoodBefore()
},
{
kTagSpoiler,
TextUtilities::MarkdownSpoilerGoodBefore(),
TextUtilities::MarkdownSpoilerBadAfter(),
TextUtilities::MarkdownSpoilerBadAfter(),
TextUtilities::MarkdownSpoilerGoodBefore()
},
};
return cached;
}
@ -385,6 +394,7 @@ const std::map<QString, int> &TagIndices() {
{ kTagStrikeOut, kTagStrikeOutIndex },
{ kTagCode, kTagCodeIndex },
{ kTagPre, kTagPreIndex },
{ kTagSpoiler, kTagSpoilerIndex },
};
return cached;
}
@ -702,6 +712,7 @@ QTextCharFormat PrepareTagFormat(
auto result = QTextCharFormat();
auto font = st.font;
auto color = std::optional<style::color>();
auto bg = std::optional<style::color>();
const auto applyOne = [&](QStringView tag) {
if (IsValidMarkdownLink(tag)) {
color = st::defaultTextPalette.linkFg;
@ -716,6 +727,8 @@ QTextCharFormat PrepareTagFormat(
} else if (tag == kTagCode || tag == kTagPre) {
color = st::defaultTextPalette.monoFg;
font = font->monospace();
} else if (tag == kTagSpoiler) {
bg = st::defaultTextPalette.spoilerActiveBg;
}
};
for (const auto &tag : TextUtilities::SplitTags(tag)) {
@ -724,6 +737,9 @@ QTextCharFormat PrepareTagFormat(
result.setFont(font);
result.setForeground(color.value_or(st.textFg));
result.setProperty(kTagProperty, tag);
if (bg) {
result.setBackground(*bg);
}
return result;
}
@ -842,6 +858,7 @@ const QString InputField::kTagUnderline = QStringLiteral("^^");
const QString InputField::kTagStrikeOut = QStringLiteral("~~");
const QString InputField::kTagCode = QStringLiteral("`");
const QString InputField::kTagPre = QStringLiteral("```");
const QString InputField::kTagSpoiler = QStringLiteral("||");
class InputField::Inner final : public QTextEdit {
public:
@ -2819,6 +2836,8 @@ bool InputField::handleMarkdownKey(QKeyEvent *e) {
toggleSelectionMarkdown(kTagStrikeOut);
} else if (matches(kMonospaceSequence)) {
toggleSelectionMarkdown(kTagCode);
} else if (matches(kSpoilerSequence)) {
toggleSelectionMarkdown(kTagSpoiler);
} else if (matches(kClearFormatSequence)) {
clearSelectionMarkdown();
} else if (matches(kEditLinkSequence) && _editLinkCallback) {
@ -3578,6 +3597,7 @@ void InputField::addMarkdownActions(
addtag(integration.phraseFormattingUnderline(), QKeySequence::Underline, kTagUnderline);
addtag(integration.phraseFormattingStrikeOut(), kStrikeOutSequence, kTagStrikeOut);
addtag(integration.phraseFormattingMonospace(), kMonospaceSequence, kTagCode);
addtag(integration.phraseFormattingSpoiler(), kSpoilerSequence, kTagSpoiler);
if (_editLinkCallback) {
submenu->addSeparator();

View file

@ -26,6 +26,7 @@ const auto kClearFormatSequence = QKeySequence("ctrl+shift+n");
const auto kStrikeOutSequence = QKeySequence("ctrl+shift+x");
const auto kMonospaceSequence = QKeySequence("ctrl+shift+m");
const auto kEditLinkSequence = QKeySequence("ctrl+k");
const auto kSpoilerSequence = QKeySequence("ctrl+shift+p");
class PopupMenu;
@ -171,6 +172,7 @@ public:
static const QString kTagStrikeOut;
static const QString kTagCode;
static const QString kTagPre;
static const QString kTagSpoiler;
InputField(
QWidget *parent,