[UnigramDev/Unigram/develop](https://github.com/UnigramDev/Unigram/tree/develop) • [cb58591](https://github.com/UnigramDev/Unigram/commit/cb5859128b87f328294f892f7e0bf4995f9167c5) • _1 files, +26/-6_
Stop allocating per character in the emoticon replacement

OnCharacterReceived runs for every character typed. It built a byte array and a
string just to recover the first char of the code point, then used Max and a
capturing FirstOrDefault over the candidates. The first char comes straight off
the code point now and the two LINQ calls are loops.

The Consolas check moved behind the candidate lookup, so a keystroke that can't
end an emoticon no longer pays for a call into the text host, and EndsWith is
ordinal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

[UnigramDev/Unigram/develop](https://github.com/UnigramDev/Unigram/tree/develop) • [584d7d2](https://github.com/UnigramDev/Unigram/commit/584d7d2e2ec849412e2d8bcb4f68f8054883b861) • _1 files, +14/-12_
Don't recreate every custom emoji source on each keystroke

UpdateEntities assigned a new CustomEmojiFileSource to every player on every
text change. Each one sends getCustomEmojiStickers from its constructor and
re-runs AnimatedImage.Load. It only assigns when the id actually differs now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

[UnigramDev/Unigram/develop](https://github.com/UnigramDev/Unigram/tree/develop) • [2e3d283](https://github.com/UnigramDev/Unigram/commit/2e3d2836442e3e20c1f474c5f045c327b5211fe5) • _1 files, +17/-2_
Stop splitting the whole message to find the inline bot

SearchInlineBotResults runs on every keystroke, and split the entire message on
spaces to look at its first word - plus two substrings before that - all of it
dead unless an inline bot is being addressed. That check comes first now, and
the first word is taken with IndexOf.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

[UnigramDev/Unigram/develop](https://github.com/UnigramDev/Unigram/tree/develop) • [f8b16ac](https://github.com/UnigramDev/Unigram/commit/f8b16ac721eaa116750b9325cddfa4e2e9fc1abb) • _1 files, +57/-32_
Don't ask for a link preview when the text can't hold a URL

CheckMessageBoxEmpty sent getLinkPreview on every keystroke whatever the text:
the whole message serialized to JSON, through the TDLib queue, and a dispatcher
hop back into another full GetText to check staleness, plus the four whole
string copies Format() makes.

A URL always carries either an explicit scheme or a dot before its top level
domain, so a scan that can be wrong about a link being there but never about one
not being there now gates all of it. The clear-the-preview block that appeared
twice became one method.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

[#unigram](?q=%23unigram)