UnigramDev/Unigram/develop • 1208597 • 2 files, +57/-1
Focus the editor when its window opens
The caret only ever appeared after re-activating the editor window. Two reasons,
both of them ordering:
TryFocus focused the document before the control. The JS view.focus() sets
document.activeElement inside a browser whose host has no focus — ProseMirror
even draws its selection — but the keyboard stays with XAML. Focusing the
control is what routes input into the web content; the document call only
places the caret, so it has to come second.
And ViewService.OpenAsync activates the window as soon as its content exists,
which is long before CoreWebView2 does. XAML's initial focus lands on the
WebView2 while it has no controller to forward it to, so that GotFocus goes
nowhere — and focusing it later is a no-op, because the control already has it.
Re-activating the window worked precisely because it raised GotFocus again.
Focus is now taken on activation (deferred, since XAML assigns its own while
activating) and, when the control is the one already holding it, moved off and
back so the transition actually happens.
Also drops the WebView2's Source: Initialize navigates to the same file through
the editor.unigram virtual host, so setting both loaded the whole editor twice
— two parses of the bundle and two ProseMirror mounts per open.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 2302a74 • 1 files, +2/-2
Hook SizeChanged to the right container
UnigramDev/Unigram/develop • 5e572a3 • 2 files, +9/-7
Fix purchase button
UnigramDev/Unigram/develop • 34ecd82 • 2 files, +8/-0
Fix default editor state
#unigram
Focus the editor when its window opens
The caret only ever appeared after re-activating the editor window. Two reasons,
both of them ordering:
TryFocus focused the document before the control. The JS view.focus() sets
document.activeElement inside a browser whose host has no focus — ProseMirror
even draws its selection — but the keyboard stays with XAML. Focusing the
control is what routes input into the web content; the document call only
places the caret, so it has to come second.
And ViewService.OpenAsync activates the window as soon as its content exists,
which is long before CoreWebView2 does. XAML's initial focus lands on the
WebView2 while it has no controller to forward it to, so that GotFocus goes
nowhere — and focusing it later is a no-op, because the control already has it.
Re-activating the window worked precisely because it raised GotFocus again.
Focus is now taken on activation (deferred, since XAML assigns its own while
activating) and, when the control is the one already holding it, moved off and
back so the transition actually happens.
Also drops the WebView2's Source: Initialize navigates to the same file through
the editor.unigram virtual host, so setting both loaded the whole editor twice
— two parses of the bundle and two ProseMirror mounts per open.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 2302a74 • 1 files, +2/-2
Hook SizeChanged to the right container
UnigramDev/Unigram/develop • 5e572a3 • 2 files, +9/-7
Fix purchase button
UnigramDev/Unigram/develop • 34ecd82 • 2 files, +8/-0
Fix default editor state
#unigram
UnigramDev/Unigram/develop • 50ca959 • 32 files, +2975/-60
Pin vcpkg with a manifest instead of a hand-prepared checkout
Setting up the unmanaged dependencies meant cloning vcpkg at a 2024 commit,
editing the ffmpeg portfile by hand to insert an 85-flag `--enable-*` string,
applying Libraries/vcpkg.patch to vcpkg's own MSBuild targets, running
`vcpkg integrate install`, and installing fourteen packages per triplet from
the command line. None of it was verifiable, and that baseline can no longer
build from scratch: the msys2 runtime package it pins has fallen off every
mirror, so vcpkg_fixup_pkgconfig fails with a 404.
vcpkg.json pins 2026.03.18 and declares what is actually used. That is nine
ports, not the fourteen that were installed: cppwinrt comes from the NuGet
package and flatbuffers from the submodule, while dav1d, libvpx and
libjpeg-turbo resolve transitively. The commit matches the one TDLib
documents, so openssl and zlib cannot drift between the tdjson.dll we ship
and the copies the app links -- they reach the flat package root under the
same names from both.
ffmpeg needs a modified portfile for its decoder list, so it is vendored as
an overlay port, taken from the registry at 7.1.2 with the flag line applied.
It wins over the baseline's 8.0.1, which keeps the sonames at avcodec-61 and
avoids ffmpeg 8 removing avcodec_close out from under tgcalls. Moving to 8 is
now a self-contained change.
Directory.Build.props finds vcpkg without any environment variable -- a
checkout beside the repository, or the copy that ships with Visual Studio --
and turns off the machine-wide integration so the pin cannot be bypassed. A
guard reports a checkout older than the pin, which otherwise fails as "no
version database entry", since vcpkg reads the version database from the
working tree rather than from the pinned commit.
The runtime DLLs are copied through ReferenceCopyLocalPaths rather than
vcpkg's applocal step, which made Libraries/vcpkg.patch necessary in the first
place. applocal does not run when the linker is skipped or when a project is
only queried for its packaging outputs, and the DLLs then go missing with no
error; the patch covered one of those cases and never the other. Declaring
them also puts them in the app's own output folder, which applocal never did.
openssl and zlib are excluded there because Libraries/tdjson ships the copies
tdjson.dll was linked against, under the same file names.
Libraries/tdjson/build.ps1 builds TDLib from the same manifest and the same
installed tree, so there is one openssl and one zlib in the build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Pin vcpkg with a manifest instead of a hand-prepared checkout
Setting up the unmanaged dependencies meant cloning vcpkg at a 2024 commit,
editing the ffmpeg portfile by hand to insert an 85-flag `--enable-*` string,
applying Libraries/vcpkg.patch to vcpkg's own MSBuild targets, running
`vcpkg integrate install`, and installing fourteen packages per triplet from
the command line. None of it was verifiable, and that baseline can no longer
build from scratch: the msys2 runtime package it pins has fallen off every
mirror, so vcpkg_fixup_pkgconfig fails with a 404.
vcpkg.json pins 2026.03.18 and declares what is actually used. That is nine
ports, not the fourteen that were installed: cppwinrt comes from the NuGet
package and flatbuffers from the submodule, while dav1d, libvpx and
libjpeg-turbo resolve transitively. The commit matches the one TDLib
documents, so openssl and zlib cannot drift between the tdjson.dll we ship
and the copies the app links -- they reach the flat package root under the
same names from both.
ffmpeg needs a modified portfile for its decoder list, so it is vendored as
an overlay port, taken from the registry at 7.1.2 with the flag line applied.
It wins over the baseline's 8.0.1, which keeps the sonames at avcodec-61 and
avoids ffmpeg 8 removing avcodec_close out from under tgcalls. Moving to 8 is
now a self-contained change.
Directory.Build.props finds vcpkg without any environment variable -- a
checkout beside the repository, or the copy that ships with Visual Studio --
and turns off the machine-wide integration so the pin cannot be bypassed. A
guard reports a checkout older than the pin, which otherwise fails as "no
version database entry", since vcpkg reads the version database from the
working tree rather than from the pinned commit.
The runtime DLLs are copied through ReferenceCopyLocalPaths rather than
vcpkg's applocal step, which made Libraries/vcpkg.patch necessary in the first
place. applocal does not run when the linker is skipped or when a project is
only queried for its packaging outputs, and the DLLs then go missing with no
error; the patch covered one of those cases and never the other. Declaring
them also puts them in the app's own output folder, which applocal never did.
openssl and zlib are excluded there because Libraries/tdjson ships the copies
tdjson.dll was linked against, under the same file names.
Libraries/tdjson/build.ps1 builds TDLib from the same manifest and the same
installed tree, so there is one openssl and one zlib in the build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
UnigramDev/Unigram/develop • a0f0499 • 36 files, +3941/-0
Add a benchmark harness for the TDLib JSON path
Measures what Client.Receive and ClientJson.FromJson actually cost per payload,
on all three toolchains in play: the desktop JIT under BenchmarkDotNet, UWP on
.NET 10 with NativeAOT, and UWP on .NET Native, which is what ships. One Suite.cs
runs on all three so their numbers line up row for row.
Nothing here touches the app. The projects reference Telegram.Generators and
Libraries/tdjson/td_api.tl and link ClientJson.cs, so the code under test is the
generated parser rather than a copy that would drift from it. Round trips go
through the real tdjson.dll using TDLib's own offline test methods, which need no
account and no network.
Findings are written up in Telegram.Benchmarks/README.md. The load-bearing one:
UWP resolves System.Memory's netstandard2.0 asset, so Span<T> is not the runtime's
own and indexing one costs ~10x what the same access over byte[] or byte* costs.
That accounts for the parse being ~3x slower on .NET Native than the desktop
numbers suggested, and it is why Json/TdJsonReader.cs walks raw memory instead:
3.1-3.7x faster than Utf8JsonReader there, with the same allocations.
That reader is a prototype and is not wired into the generator yet. It is
bounds-checked against truncated input, proven by a guard-page sweep over every
prefix of every corpus payload - 70,512 of them - and Validation.cs runs on all
three hosts, so agreement with Utf8JsonReader is checked against the
netstandard2.0 System.Text.Json as well as the net10.0 one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Add a benchmark harness for the TDLib JSON path
Measures what Client.Receive and ClientJson.FromJson actually cost per payload,
on all three toolchains in play: the desktop JIT under BenchmarkDotNet, UWP on
.NET 10 with NativeAOT, and UWP on .NET Native, which is what ships. One Suite.cs
runs on all three so their numbers line up row for row.
Nothing here touches the app. The projects reference Telegram.Generators and
Libraries/tdjson/td_api.tl and link ClientJson.cs, so the code under test is the
generated parser rather than a copy that would drift from it. Round trips go
through the real tdjson.dll using TDLib's own offline test methods, which need no
account and no network.
Findings are written up in Telegram.Benchmarks/README.md. The load-bearing one:
UWP resolves System.Memory's netstandard2.0 asset, so Span<T> is not the runtime's
own and indexing one costs ~10x what the same access over byte[] or byte* costs.
That accounts for the parse being ~3x slower on .NET Native than the desktop
numbers suggested, and it is why Json/TdJsonReader.cs walks raw memory instead:
3.1-3.7x faster than Utf8JsonReader there, with the same allocations.
That reader is a prototype and is not wired into the generator yet. It is
bounds-checked against truncated input, proven by a guard-page sweep over every
prefix of every corpus payload - 70,512 of them - and Validation.cs runs on all
three hosts, so agreement with Utf8JsonReader is checked against the
netstandard2.0 System.Text.Json as well as the net10.0 one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
UnigramDev/Unigram/emoji-drawer-detach • e7263f1 • 3 files, +37/-1
Detach the emoji and sticker drawers from their collections
InvalidComObjectException — "COM object that has been separated from its
underlying RCW cannot be used" — reported by crash telemetry on 12.9.1,
raised from MvxObservableCollection.ReplaceWith inside
EmojiDrawerViewModel.Update.
EmojiDrawer's CollectionViewSource and its two toolbars bind straight to the
view model's collections, so their native peers subscribe to CollectionChanged.
Deactivate() only called Bindings.StopTracking(), which stops the bindings from
updating but leaves the value they already pushed in place, and it runs right
before XamlMarkupHelper.UnloadObject destroys those peers. The view model
subscribes to the aggregator in its constructor and Handle queues Update on the
UI thread, so a queued update outlives the drawer and raises into the dead
peers.
Clear the collection sources in Deactivate so nothing native is still attached
once the peers go away. StickerDrawer has the same shape and the same terminal
Deactivate contract, so it gets the same treatment.
EmojiMenuFlyout never deactivated its drawer at all, and only one of its three
constructors subscribed to Popup.Closed; move that subscription into Initialize
and tear the drawer down there, matching what StickerPanel does when it unloads
a drawer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Detach the emoji and sticker drawers from their collections
InvalidComObjectException — "COM object that has been separated from its
underlying RCW cannot be used" — reported by crash telemetry on 12.9.1,
raised from MvxObservableCollection.ReplaceWith inside
EmojiDrawerViewModel.Update.
EmojiDrawer's CollectionViewSource and its two toolbars bind straight to the
view model's collections, so their native peers subscribe to CollectionChanged.
Deactivate() only called Bindings.StopTracking(), which stops the bindings from
updating but leaves the value they already pushed in place, and it runs right
before XamlMarkupHelper.UnloadObject destroys those peers. The view model
subscribes to the aggregator in its constructor and Handle queues Update on the
UI thread, so a queued update outlives the drawer and raises into the dead
peers.
Clear the collection sources in Deactivate so nothing native is still attached
once the peers go away. StickerDrawer has the same shape and the same terminal
Deactivate contract, so it gets the same treatment.
EmojiMenuFlyout never deactivated its drawer at all, and only one of its three
constructors subscribed to Popup.Closed; move that subscription into Initialize
and tear the drawer down there, matching what StickerPanel does when it unloads
a drawer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
UnigramDev/Unigram/gallery-close-input • 3dd9796 • 1 files, +39/-6
Stop the gallery from taking input while it closes
Closing the gallery is animated: OnBackRequestedOverride calls Unload()
synchronously, which drops the data context, while Hide() only runs when the
closing animation completes. In between the window is still visible and still
hit-testable, so a click on a caption hyperlink ran Caption_TextEntityClick
with a null ViewModel and crashed in the MessageDelegate constructor
(NullReferenceException, reported by crash telemetry on 12.9.1). The caption
sits outside ScrollingHost, so the tap-to-close handler never consumes it.
Unload() now clears IsHitTestVisible, which closes the whole "input after
unload" family instead of one handler at a time; Caption_TextEntityClick is
guarded as well, because a focused hyperlink can still be invoked from the
keyboard or by automation, neither of which hit tests.
Also fix the same method leaving the window on screen forever: the connected
animation's Completed was subscribed before TryStart, and when TryStart failed
translate became false, so neither Hide() was reachable. Hide() now runs off
the fade batch, which is started on every path, and Completed is subscribed
only when the animation actually started.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Stop the gallery from taking input while it closes
Closing the gallery is animated: OnBackRequestedOverride calls Unload()
synchronously, which drops the data context, while Hide() only runs when the
closing animation completes. In between the window is still visible and still
hit-testable, so a click on a caption hyperlink ran Caption_TextEntityClick
with a null ViewModel and crashed in the MessageDelegate constructor
(NullReferenceException, reported by crash telemetry on 12.9.1). The caption
sits outside ScrollingHost, so the tap-to-close handler never consumes it.
Unload() now clears IsHitTestVisible, which closes the whole "input after
unload" family instead of one handler at a time; Caption_TextEntityClick is
guarded as well, because a focused hyperlink can still be invoked from the
keyboard or by automation, neither of which hit tests.
Also fix the same method leaving the window on screen forever: the connected
animation's Completed was subscribed before TryStart, and when TryStart failed
translate became false, so neither Hide() was reachable. Hide() now runs off
the fade batch, which is started on every path, and Completed is subscribed
only when the animation actually started.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
telegramdesktop/tdesktop/nightly • 76ed82b • 2 files, +5/-3
Allowed skipping video cover in document reply preview.
telegramdesktop/tdesktop/nightly • 3bdf527 • 5 files, +29/-0
Added video cover edit actions to send menu.
telegramdesktop/tdesktop/nightly • d668349 • 3 files, +77/-22
Added video cover change support to EditTextMessage.
telegramdesktop/tdesktop/nightly • 943501c • 6 files, +647/-9
Added video cover editing to media edit manager.
telegramdesktop/tdesktop/nightly • 40df230 • 8 files, +71/-20
Added video cover editing to inline message edit controls.
telegramdesktop/tdesktop/nightly • 754fabb • 2 files, +4/-1
Added marked text context to confirm box label.
telegramdesktop/tdesktop/nightly • 585f02f • 2 files, +26/-4
Added passkey name and icon to delete confirmation box.
telegramdesktop/tdesktop/nightly • e395862 • 1 files, +9/-4
Added submit by Enter to security key PIN box.
telegramdesktop/tdesktop/nightly • 570add0 • 1 files, +10/-5
Aligned PIN field with box rows in security key PIN box.
telegramdesktop/tdesktop/nightly • e8f73fb • 2 files, +11/-3
Fixed crash on tab activation before strip sync in profile tabs host.
telegramdesktop/tdesktop/nightly • 4af7d76 • 1 files, +10/-5
Fixed reserved strip height for lent out strip in profile tabs host.
telegramdesktop/tdesktop/nightly • a25c608 • 3 files, +243/-0
Added saved chats tab adapter with message search driver.
telegramdesktop/tdesktop/nightly • 903a2f0 • 2 files, +45/-8
Added saved messages mode to profile top bar.
#tdesktop
Allowed skipping video cover in document reply preview.
telegramdesktop/tdesktop/nightly • 3bdf527 • 5 files, +29/-0
Added video cover edit actions to send menu.
telegramdesktop/tdesktop/nightly • d668349 • 3 files, +77/-22
Added video cover change support to EditTextMessage.
telegramdesktop/tdesktop/nightly • 943501c • 6 files, +647/-9
Added video cover editing to media edit manager.
telegramdesktop/tdesktop/nightly • 40df230 • 8 files, +71/-20
Added video cover editing to inline message edit controls.
telegramdesktop/tdesktop/nightly • 754fabb • 2 files, +4/-1
Added marked text context to confirm box label.
telegramdesktop/tdesktop/nightly • 585f02f • 2 files, +26/-4
Added passkey name and icon to delete confirmation box.
telegramdesktop/tdesktop/nightly • e395862 • 1 files, +9/-4
Added submit by Enter to security key PIN box.
telegramdesktop/tdesktop/nightly • 570add0 • 1 files, +10/-5
Aligned PIN field with box rows in security key PIN box.
telegramdesktop/tdesktop/nightly • e8f73fb • 2 files, +11/-3
Fixed crash on tab activation before strip sync in profile tabs host.
telegramdesktop/tdesktop/nightly • 4af7d76 • 1 files, +10/-5
Fixed reserved strip height for lent out strip in profile tabs host.
telegramdesktop/tdesktop/nightly • a25c608 • 3 files, +243/-0
Added saved chats tab adapter with message search driver.
telegramdesktop/tdesktop/nightly • 903a2f0 • 2 files, +45/-8
Added saved messages mode to profile top bar.
#tdesktop
🫡3
telegramdesktop/tdesktop/nightly • 87a2b06 • 2 files, +44/-23
Added saved messages tabs page to profile section.
telegramdesktop/tdesktop/nightly • 4e8eac7 • 2 files, +5/-4
Routed saved messages info to profile media tabs page.
telegramdesktop/tdesktop/nightly • 4c12446 • 2 files, +4/-1
Added empty field guard for typing send progress in composers.
telegramdesktop/tdesktop/nightly • 385beb2 • 2 files, +82/-7
Added animated round check to filled shapes menu item.
telegramdesktop/tdesktop/nightly • c0fe794 • 2 files, +113/-15
Added radial fill animation to shape icons in shapes menu.
telegramdesktop/tdesktop/nightly • 07da399 • 3 files, +18/-16
Added subpixel precision to dialogs quick action swipe.
telegramdesktop/tdesktop/nightly • 967a02d • 2 files, +12/-3
Added row-scoped repaint for dialogs quick action swipe.
telegramdesktop/tdesktop/nightly • ca067f3 • 2 files, +50/-0
Added pin on top helpers to calls window.
telegramdesktop/tdesktop/nightly • 487472e • 4 files, +135/-2
Added pin on top button to private call panel.
telegramdesktop/tdesktop/nightly • 5352793 • 2 files, +4/-2
Added ability to edit video cover in chats with bots.
telegramdesktop/tdesktop/nightly • ca4c0ae • 1 files, +6/-3
Added width clamp for name and status labels in call panel.
telegramdesktop/tdesktop/nightly • 6a96d9d • 9 files, +382/-5
Moved call button widget from lib_ui to td_ui.
telegramdesktop/tdesktop/nightly • 775c02d • 3 files, +34/-3
Added round mouse hit area to call buttons.
#tdesktop
Added saved messages tabs page to profile section.
telegramdesktop/tdesktop/nightly • 4e8eac7 • 2 files, +5/-4
Routed saved messages info to profile media tabs page.
telegramdesktop/tdesktop/nightly • 4c12446 • 2 files, +4/-1
Added empty field guard for typing send progress in composers.
telegramdesktop/tdesktop/nightly • 385beb2 • 2 files, +82/-7
Added animated round check to filled shapes menu item.
telegramdesktop/tdesktop/nightly • c0fe794 • 2 files, +113/-15
Added radial fill animation to shape icons in shapes menu.
telegramdesktop/tdesktop/nightly • 07da399 • 3 files, +18/-16
Added subpixel precision to dialogs quick action swipe.
telegramdesktop/tdesktop/nightly • 967a02d • 2 files, +12/-3
Added row-scoped repaint for dialogs quick action swipe.
telegramdesktop/tdesktop/nightly • ca067f3 • 2 files, +50/-0
Added pin on top helpers to calls window.
telegramdesktop/tdesktop/nightly • 487472e • 4 files, +135/-2
Added pin on top button to private call panel.
telegramdesktop/tdesktop/nightly • 5352793 • 2 files, +4/-2
Added ability to edit video cover in chats with bots.
telegramdesktop/tdesktop/nightly • ca4c0ae • 1 files, +6/-3
Added width clamp for name and status labels in call panel.
telegramdesktop/tdesktop/nightly • 6a96d9d • 9 files, +382/-5
Moved call button widget from lib_ui to td_ui.
telegramdesktop/tdesktop/nightly • 775c02d • 3 files, +34/-3
Added round mouse hit area to call buttons.
#tdesktop
🫡3
telegramdesktop/tdesktop/nightly • 956cf99 • 4 files, +193/-2
Added hover tooltips for call panel buttons when labels do not fit.
telegramdesktop/tdesktop/nightly • 396fca8 • 1 files, +1/-1
Fixed recursive repaint in toast widget.
telegramdesktop/tdesktop/nightly • 8c00760 • 2 files, +16/-3
Increased mouse priority for recognized text in media viewer.
telegramdesktop/tdesktop/nightly • 881d654 • 1 files, +1/-1
Fixed slideshow controls in exported rich message html.
telegramdesktop/tdesktop/nightly • 464e4f7 • 1 files, +1/-1
Fixed footer color in dark theme of exported rich message html.
telegramdesktop/tdesktop/nightly • 72721f7 • 1 files, +7/-9
Increased font sizes in exported rich message html.
telegramdesktop/tdesktop/nightly • 9b2013f • 8 files, +159/-120
Added optional shortcut for opening article editor.
telegramdesktop/tdesktop/nightly • 16d76be • 2 files, +3/-0
Added text restriction check for article editor in composers.
telegramdesktop/tdesktop/nightly • c03a610 • 2 files, +28/-3
Fixed article editor opening for replies to ephemeral messages.
telegramdesktop/tdesktop/nightly • a77a4bc • 3 files, +36/-4
Fixed article editor window position relative to calling window.
telegramdesktop/tdesktop/nightly • 192510b • 2 files, +10/-0
Added minimal shown time guard for clicks in reactions selector.
telegramdesktop/tdesktop/nightly • 6a5ff36 • 1 files, +3/-0
Fixed stale visible region for grown tab pages in profile tabs host.
telegramdesktop/tdesktop/nightly • 2857245 • 3 files, +52/-0
Moved out media group layout geometry to separate module.
#tdesktop
Added hover tooltips for call panel buttons when labels do not fit.
telegramdesktop/tdesktop/nightly • 396fca8 • 1 files, +1/-1
Fixed recursive repaint in toast widget.
telegramdesktop/tdesktop/nightly • 8c00760 • 2 files, +16/-3
Increased mouse priority for recognized text in media viewer.
telegramdesktop/tdesktop/nightly • 881d654 • 1 files, +1/-1
Fixed slideshow controls in exported rich message html.
telegramdesktop/tdesktop/nightly • 464e4f7 • 1 files, +1/-1
Fixed footer color in dark theme of exported rich message html.
telegramdesktop/tdesktop/nightly • 72721f7 • 1 files, +7/-9
Increased font sizes in exported rich message html.
telegramdesktop/tdesktop/nightly • 9b2013f • 8 files, +159/-120
Added optional shortcut for opening article editor.
telegramdesktop/tdesktop/nightly • 16d76be • 2 files, +3/-0
Added text restriction check for article editor in composers.
telegramdesktop/tdesktop/nightly • c03a610 • 2 files, +28/-3
Fixed article editor opening for replies to ephemeral messages.
telegramdesktop/tdesktop/nightly • a77a4bc • 3 files, +36/-4
Fixed article editor window position relative to calling window.
telegramdesktop/tdesktop/nightly • 192510b • 2 files, +10/-0
Added minimal shown time guard for clicks in reactions selector.
telegramdesktop/tdesktop/nightly • 6a5ff36 • 1 files, +3/-0
Fixed stale visible region for grown tab pages in profile tabs host.
telegramdesktop/tdesktop/nightly • 2857245 • 3 files, +52/-0
Moved out media group layout geometry to separate module.
#tdesktop
🫡3
telegramdesktop/tdesktop/nightly • c3c43a2 • 3 files, +338/-2
Added collage mosaic and slideshow carousel to chat export HTML.
telegramdesktop/tdesktop/nightly • 0f3f761 • 6 files, +142/-0
Added auto scroll on selection drag in translate box and markdown view.
telegramdesktop/tdesktop/nightly • c14dbea • 4 files, +63/-4
Added copy button for translation result to translate box title.
telegramdesktop/tdesktop/nightly • ab46833 • 3 files, +42/-41
Moved imported media resolving from td_iv to editor session.
telegramdesktop/tdesktop/nightly • 915074b • 6 files, +109/-48
Moved editor box and widget data access to editor session.
telegramdesktop/tdesktop/nightly • 3eb9d61 • 15 files, +563/-36
Added HTML flavor with embedded media to rich message copy.
telegramdesktop/tdesktop/nightly • 9b8d55f • 4 files, +90/-35
Added embedded media import from clipboard HTML.
telegramdesktop/tdesktop/nightly • 8cdf3b1 • 4 files, +307/-0
Added marquee label widget with gradient fade and auto scroll.
telegramdesktop/tdesktop/nightly • e9f1f1d • 4 files, +132/-67
[iv-editor] Moved Enter handling into command chain.
telegramdesktop/tdesktop/nightly • a7ad297 • 4 files, +227/-1
[iv-editor] Added list nesting by Tab and Shift+Tab.
telegramdesktop/tdesktop/nightly • a95f7ef • 1 files, +20/-4
[iv-editor] Added list split on Enter in empty item.
telegramdesktop/tdesktop/nightly • 6ee82ed • 1 files, +17/-0
[iv-editor] Added nested list item lift on Backspace.
telegramdesktop/tdesktop/nightly • b1f9e80 • 2 files, +168/-2
[iv-editor] Added joining of next list item on Delete.
#tdesktop
Added collage mosaic and slideshow carousel to chat export HTML.
telegramdesktop/tdesktop/nightly • 0f3f761 • 6 files, +142/-0
Added auto scroll on selection drag in translate box and markdown view.
telegramdesktop/tdesktop/nightly • c14dbea • 4 files, +63/-4
Added copy button for translation result to translate box title.
telegramdesktop/tdesktop/nightly • ab46833 • 3 files, +42/-41
Moved imported media resolving from td_iv to editor session.
telegramdesktop/tdesktop/nightly • 915074b • 6 files, +109/-48
Moved editor box and widget data access to editor session.
telegramdesktop/tdesktop/nightly • 3eb9d61 • 15 files, +563/-36
Added HTML flavor with embedded media to rich message copy.
telegramdesktop/tdesktop/nightly • 9b8d55f • 4 files, +90/-35
Added embedded media import from clipboard HTML.
telegramdesktop/tdesktop/nightly • 8cdf3b1 • 4 files, +307/-0
Added marquee label widget with gradient fade and auto scroll.
telegramdesktop/tdesktop/nightly • e9f1f1d • 4 files, +132/-67
[iv-editor] Moved Enter handling into command chain.
telegramdesktop/tdesktop/nightly • a7ad297 • 4 files, +227/-1
[iv-editor] Added list nesting by Tab and Shift+Tab.
telegramdesktop/tdesktop/nightly • a95f7ef • 1 files, +20/-4
[iv-editor] Added list split on Enter in empty item.
telegramdesktop/tdesktop/nightly • 6ee82ed • 1 files, +17/-0
[iv-editor] Added nested list item lift on Backspace.
telegramdesktop/tdesktop/nightly • b1f9e80 • 2 files, +168/-2
[iv-editor] Added joining of next list item on Delete.
#tdesktop
🫡3
telegramdesktop/tdesktop/nightly • fcdd9e9 • 2 files, +46/-8
[iv-editor] Guarded single form of list item adopting blocks.
telegramdesktop/tdesktop/nightly • 08600f8 • 3 files, +215/-9
[iv-editor] Added pulling of paragraph into list above on Tab.
telegramdesktop/tdesktop/nightly • d528fb3 • 2 files, +52/-0
[iv-editor] Added merging of adjacent lists of same kind.
telegramdesktop/tdesktop/nightly • 7052717 • 1 files, +7/-3
[iv-editor] Added unchecked state for split task items.
telegramdesktop/tdesktop/nightly • aeea752 • 4 files, +126/-4
[iv-editor] Added list input rules with Backspace undo.
telegramdesktop/tdesktop/nightly • 270a399 • 4 files, +77/-1
[iv-editor] Added styled block reset on first Backspace.
telegramdesktop/tdesktop/nightly • a9b2915 • 2 files, +61/-6
[iv-editor] Replaced merge into empty block above with removal.
telegramdesktop/tdesktop/nightly • d333a28 • 3 files, +69/-0
[iv-editor] Added quote exit on Enter in empty last line.
telegramdesktop/tdesktop/nightly • 64f0586 • 2 files, +91/-1
[iv-editor] Added quote exit on Backspace in first line.
telegramdesktop/tdesktop/nightly • d10b922 • 2 files, +66/-3
[iv-editor] Added pulling of block below into quote on Delete.
telegramdesktop/tdesktop/nightly • 008799e • 3 files, +30/-2
[iv-editor] Added heading, quote and code input rules.
telegramdesktop/tdesktop/nightly • 2a0cb17 • 1 files, +0/-3
[iv-editor] Added line inside quote on Enter at its end.
telegramdesktop/tdesktop/nightly • 4e06e31 • 3 files, +146/-3
[iv-editor] Added distribution of selected lines into list items.
#tdesktop
[iv-editor] Guarded single form of list item adopting blocks.
telegramdesktop/tdesktop/nightly • 08600f8 • 3 files, +215/-9
[iv-editor] Added pulling of paragraph into list above on Tab.
telegramdesktop/tdesktop/nightly • d528fb3 • 2 files, +52/-0
[iv-editor] Added merging of adjacent lists of same kind.
telegramdesktop/tdesktop/nightly • 7052717 • 1 files, +7/-3
[iv-editor] Added unchecked state for split task items.
telegramdesktop/tdesktop/nightly • aeea752 • 4 files, +126/-4
[iv-editor] Added list input rules with Backspace undo.
telegramdesktop/tdesktop/nightly • 270a399 • 4 files, +77/-1
[iv-editor] Added styled block reset on first Backspace.
telegramdesktop/tdesktop/nightly • a9b2915 • 2 files, +61/-6
[iv-editor] Replaced merge into empty block above with removal.
telegramdesktop/tdesktop/nightly • d333a28 • 3 files, +69/-0
[iv-editor] Added quote exit on Enter in empty last line.
telegramdesktop/tdesktop/nightly • 64f0586 • 2 files, +91/-1
[iv-editor] Added quote exit on Backspace in first line.
telegramdesktop/tdesktop/nightly • d10b922 • 2 files, +66/-3
[iv-editor] Added pulling of block below into quote on Delete.
telegramdesktop/tdesktop/nightly • 008799e • 3 files, +30/-2
[iv-editor] Added heading, quote and code input rules.
telegramdesktop/tdesktop/nightly • 2a0cb17 • 1 files, +0/-3
[iv-editor] Added line inside quote on Enter at its end.
telegramdesktop/tdesktop/nightly • 4e06e31 • 3 files, +146/-3
[iv-editor] Added distribution of selected lines into list items.
#tdesktop
🫡3
telegramdesktop/tdesktop/nightly • 01f200f • 4 files, +5/-2
[iv-editor] Added instant applying of typed markdown to editor field.
telegramdesktop/tdesktop/nightly • fd2700d • 4 files, +790/-0
[iv-editor] Added markdown structure import on paste.
telegramdesktop/tdesktop/nightly • 19409bf • 2 files, +41/-2
[iv-editor] Added format shortcuts for broader selection.
telegramdesktop/tdesktop/nightly • 238a003 • 4 files, +49/-93
[iv-editor] Moved selection ordering helpers to markdown module.
telegramdesktop/tdesktop/nightly • 77c93c1 • 3 files, +113/-91
[iv-editor] Moved clipboard media helpers to import module.
telegramdesktop/tdesktop/nightly • 45dd962 • 5 files, +77/-52
[iv-editor] Moved theme helpers to markdown module shared with viewer.
telegramdesktop/tdesktop/nightly • 86d3ef2 • 4 files, +120/-69
[iv-editor] Moved article style and metrics to iv_editor_article_style.
telegramdesktop/tdesktop/nightly • 294e93b • 4 files, +374/-303
[iv-editor] Moved formula editing box to iv_editor_math_box.
telegramdesktop/tdesktop/nightly • dcacae4 • 4 files, +955/-774
[iv-editor] Moved owner algebra to iv_editor_prepared_selection.
telegramdesktop/tdesktop/nightly • 348d6bc • 4 files, +510/-411
[iv-editor] Moved table and list menus to iv_editor_structure_menu.
telegramdesktop/tdesktop/nightly • 393e913 • 5 files, +52/-34
[iv-editor] Moved block insert types out of State class.
telegramdesktop/tdesktop/nightly • 9a016cd • 6 files, +500/-420
[iv-editor] Moved block factories to iv_editor_page_blocks.
telegramdesktop/tdesktop/nightly • e72baa6 • 5 files, +342/-240
[iv-editor] Moved ordered list helpers to iv_editor_page_list.
#tdesktop
[iv-editor] Added instant applying of typed markdown to editor field.
telegramdesktop/tdesktop/nightly • fd2700d • 4 files, +790/-0
[iv-editor] Added markdown structure import on paste.
telegramdesktop/tdesktop/nightly • 19409bf • 2 files, +41/-2
[iv-editor] Added format shortcuts for broader selection.
telegramdesktop/tdesktop/nightly • 238a003 • 4 files, +49/-93
[iv-editor] Moved selection ordering helpers to markdown module.
telegramdesktop/tdesktop/nightly • 77c93c1 • 3 files, +113/-91
[iv-editor] Moved clipboard media helpers to import module.
telegramdesktop/tdesktop/nightly • 45dd962 • 5 files, +77/-52
[iv-editor] Moved theme helpers to markdown module shared with viewer.
telegramdesktop/tdesktop/nightly • 86d3ef2 • 4 files, +120/-69
[iv-editor] Moved article style and metrics to iv_editor_article_style.
telegramdesktop/tdesktop/nightly • 294e93b • 4 files, +374/-303
[iv-editor] Moved formula editing box to iv_editor_math_box.
telegramdesktop/tdesktop/nightly • dcacae4 • 4 files, +955/-774
[iv-editor] Moved owner algebra to iv_editor_prepared_selection.
telegramdesktop/tdesktop/nightly • 348d6bc • 4 files, +510/-411
[iv-editor] Moved table and list menus to iv_editor_structure_menu.
telegramdesktop/tdesktop/nightly • 393e913 • 5 files, +52/-34
[iv-editor] Moved block insert types out of State class.
telegramdesktop/tdesktop/nightly • 9a016cd • 6 files, +500/-420
[iv-editor] Moved block factories to iv_editor_page_blocks.
telegramdesktop/tdesktop/nightly • e72baa6 • 5 files, +342/-240
[iv-editor] Moved ordered list helpers to iv_editor_page_list.
#tdesktop
🫡3
telegramdesktop/tdesktop/nightly • 157a7a9 • 4 files, +132/-242
[iv-editor] Moved tag algebra and field chunking to text entities.
telegramdesktop/tdesktop/nightly • cb904fc • 5 files, +158/-149
[iv-editor] Moved media block helpers to iv_editor_page_media.
telegramdesktop/tdesktop/nightly • 723fd1a • 3 files, +100/-74
[iv-editor] Moved block path types out of State class.
telegramdesktop/tdesktop/nightly • d9648c7 • 5 files, +120/-134
[iv-editor] Moved block path helpers to iv_editor_page_path.
telegramdesktop/tdesktop/nightly • fbb5e1c • 5 files, +411/-507
[iv-editor] Moved table grid helpers to iv_editor_page_table_grid.
telegramdesktop/tdesktop/nightly • 9c35b29 • 2 files, +31/-0
[iv-editor] Added replace and edit actions to grouped media menu.
telegramdesktop/tdesktop/nightly • 3389f7c • 4 files, +32/-4
Added activation guard for open editor window in context menu.
telegramdesktop/tdesktop/nightly • af3c5d5 • 3 files, +26/-9
Added returning of composed text to input field in support mode.
telegramdesktop/tdesktop/nightly • 913e805 • 2 files, +41/-13
[iv-editor] Added removal of list from range of selected items.
telegramdesktop/tdesktop/nightly • 429e1a1 • 1 files, +9/-5
[iv-editor] Added removal of task list by its own toolbar action.
telegramdesktop/tdesktop/nightly • 8a67340 • 2 files, +68/-0
[iv-editor] Added removal of lists selected as whole blocks.
telegramdesktop/tdesktop/nightly • e6d0e6a • 1 files, +55/-4
[iv-editor] Added splitting of multiline selection into list items.
telegramdesktop/tdesktop/nightly • 1aa24c3 • 1 files, +1/-3
Allowed copying rich blocks from selection inside one paragraph.
#tdesktop
[iv-editor] Moved tag algebra and field chunking to text entities.
telegramdesktop/tdesktop/nightly • cb904fc • 5 files, +158/-149
[iv-editor] Moved media block helpers to iv_editor_page_media.
telegramdesktop/tdesktop/nightly • 723fd1a • 3 files, +100/-74
[iv-editor] Moved block path types out of State class.
telegramdesktop/tdesktop/nightly • d9648c7 • 5 files, +120/-134
[iv-editor] Moved block path helpers to iv_editor_page_path.
telegramdesktop/tdesktop/nightly • fbb5e1c • 5 files, +411/-507
[iv-editor] Moved table grid helpers to iv_editor_page_table_grid.
telegramdesktop/tdesktop/nightly • 9c35b29 • 2 files, +31/-0
[iv-editor] Added replace and edit actions to grouped media menu.
telegramdesktop/tdesktop/nightly • 3389f7c • 4 files, +32/-4
Added activation guard for open editor window in context menu.
telegramdesktop/tdesktop/nightly • af3c5d5 • 3 files, +26/-9
Added returning of composed text to input field in support mode.
telegramdesktop/tdesktop/nightly • 913e805 • 2 files, +41/-13
[iv-editor] Added removal of list from range of selected items.
telegramdesktop/tdesktop/nightly • 429e1a1 • 1 files, +9/-5
[iv-editor] Added removal of task list by its own toolbar action.
telegramdesktop/tdesktop/nightly • 8a67340 • 2 files, +68/-0
[iv-editor] Added removal of lists selected as whole blocks.
telegramdesktop/tdesktop/nightly • e6d0e6a • 1 files, +55/-4
[iv-editor] Added splitting of multiline selection into list items.
telegramdesktop/tdesktop/nightly • 1aa24c3 • 1 files, +1/-3
Allowed copying rich blocks from selection inside one paragraph.
#tdesktop
🫡3
telegramdesktop/tdesktop/nightly • f39a668 • 5 files, +204/-0
Added accumulating queue for rich message task edits.
telegramdesktop/tdesktop/nightly • a2daa3b • 2 files, +35/-0
Allowed toggling rich message tasks from message itself.
telegramdesktop/tdesktop/nightly • b04eb39 • 2 files, +42/-0
[iv-editor] Added detection of rich structure in pasted data.
telegramdesktop/tdesktop/nightly • 4f7a3d6 • 2 files, +21/-0
[iv-editor] Added pasting of source data into just opened editor.
telegramdesktop/tdesktop/nightly • 69564ef • 7 files, +264/-5
Added rich paste toast above message field.
telegramdesktop/tdesktop/nightly • 0a6a51f • 2 files, +33/-0
[iv-editor] Added plain text offer for pasted markdown.
telegramdesktop/tdesktop/nightly • 5a0a5ef • 1 files, +24/-1
Fixed loss of list items when copying article selection.
telegramdesktop/tdesktop/nightly • cdc4f8a • 5 files, +81/-17
Added rich paste toast to compose controls.
#tdesktop
Added accumulating queue for rich message task edits.
telegramdesktop/tdesktop/nightly • a2daa3b • 2 files, +35/-0
Allowed toggling rich message tasks from message itself.
telegramdesktop/tdesktop/nightly • b04eb39 • 2 files, +42/-0
[iv-editor] Added detection of rich structure in pasted data.
telegramdesktop/tdesktop/nightly • 4f7a3d6 • 2 files, +21/-0
[iv-editor] Added pasting of source data into just opened editor.
telegramdesktop/tdesktop/nightly • 69564ef • 7 files, +264/-5
Added rich paste toast above message field.
telegramdesktop/tdesktop/nightly • 0a6a51f • 2 files, +33/-0
[iv-editor] Added plain text offer for pasted markdown.
telegramdesktop/tdesktop/nightly • 5a0a5ef • 1 files, +24/-1
Fixed loss of list items when copying article selection.
telegramdesktop/tdesktop/nightly • cdc4f8a • 5 files, +81/-17
Added rich paste toast to compose controls.
#tdesktop
🫡3
UnigramDev/Unigram/develop • fd6442f • 1 files, +5/-1
Discard the video resources when the rendering device is replaced (#3350)
VoipVideoOutput's RenderingDeviceReplaced handler only flipped m_resourcesValid
back on, keeping the YUV420 effect and its three input bitmaps, all of which were
realized on the device that had just been replaced. The next frame of the same
size copied into those bitmaps and drew the effect on a context BeginDraw returned
from the new device, which fails with D2DERR_WRONG_RESOURCE_DOMAIN, "The resource
was realized on the wrong render target".
Call the existing ReleaseShader() from the handler, under the m_deviceMutex it
already holds, so the next frame recreates everything against the new device. The
sibling surfaces already do this: FreeformGradientSurface nulls its bitmap and
re-invalidates, and MessageBubbleNineGrid caches no device-bound resources.
Also fix a self-comparison in RenderFrame: finalSize.cy was compared with itself
instead of m_surfaceSize.cy, so a height-only change never resized the drawing
surface.
Reported by crash telemetry on 12.9.1.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Discard the video resources when the rendering device is replaced (#3350)
VoipVideoOutput's RenderingDeviceReplaced handler only flipped m_resourcesValid
back on, keeping the YUV420 effect and its three input bitmaps, all of which were
realized on the device that had just been replaced. The next frame of the same
size copied into those bitmaps and drew the effect on a context BeginDraw returned
from the new device, which fails with D2DERR_WRONG_RESOURCE_DOMAIN, "The resource
was realized on the wrong render target".
Call the existing ReleaseShader() from the handler, under the m_deviceMutex it
already holds, so the next frame recreates everything against the new device. The
sibling surfaces already do this: FreeformGradientSurface nulls its bitmap and
re-invalidates, and MessageBubbleNineGrid caches no device-bound resources.
Also fix a self-comparison in RenderFrame: finalSize.cy was compared with itself
instead of m_surfaceSize.cy, so a height-only change never resized the drawing
surface.
Reported by crash telemetry on 12.9.1.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
telegramdesktop/tdesktop/nightly • 3b35233 • 6 files, +119/-0
[iv-editor] Added joining of typed list with adjacent list of same kind.
telegramdesktop/tdesktop/nightly • 6d68abc • 2 files, +38/-6
[iv-editor] Added joining of lists created by toolbar with neighbours.
telegramdesktop/tdesktop/nightly • 5e3bf43 • 4 files, +18/-2
[iv-editor] Added wrapping of active line into list without selection.
telegramdesktop/tdesktop/nightly • 4f423dd • 1 files, +0/-11
[iv-editor] Added paragraph for text left below converted list line.
telegramdesktop/tdesktop/nightly • cbe78e6 • 1 files, +2/-1
[iv-editor] Removed redundant start pinning for list kept above unwrap.
telegramdesktop/tdesktop/nightly • 0692200 • 2 files, +17/-14
[iv-editor] Added joining of pasted list with neighbours of same kind.
telegramdesktop/tdesktop/nightly • 46faf00 • 5 files, +51/-25
[iv-editor] Added empty list item guard for list insertion.
#tdesktop
[iv-editor] Added joining of typed list with adjacent list of same kind.
telegramdesktop/tdesktop/nightly • 6d68abc • 2 files, +38/-6
[iv-editor] Added joining of lists created by toolbar with neighbours.
telegramdesktop/tdesktop/nightly • 5e3bf43 • 4 files, +18/-2
[iv-editor] Added wrapping of active line into list without selection.
telegramdesktop/tdesktop/nightly • 4f423dd • 1 files, +0/-11
[iv-editor] Added paragraph for text left below converted list line.
telegramdesktop/tdesktop/nightly • cbe78e6 • 1 files, +2/-1
[iv-editor] Removed redundant start pinning for list kept above unwrap.
telegramdesktop/tdesktop/nightly • 0692200 • 2 files, +17/-14
[iv-editor] Added joining of pasted list with neighbours of same kind.
telegramdesktop/tdesktop/nightly • 46faf00 • 5 files, +51/-25
[iv-editor] Added empty list item guard for list insertion.
#tdesktop
🫡3
UnigramDev/Unigram/develop • 3503a0d • 1 files, +11/-2
Register the theme before reading its settings (#3343)
Theme.Current is thread-static and assigned in exactly one place, and that
assignment sat behind a call that can fail:
try
{
_isolatedStore = ApplicationData.Current.LocalSettings.CreateContainer(...);
Current ??= this;
...
}
catch { }
When CreateContainer throws, the catch is silent and the theme never registers
itself. Every later Theme.Current dereference - and they are unguarded across
the message tree, FormattedTextBlock, MessageBubblePanel, ChatBackgroundControl
- is then a NullReferenceException on that view thread.
Reported by crash telemetry on 12.9.1, through OnShareTargetActivated:
SharePage's constructor calls ChatBackgroundControl.Update, which reads
Theme.Current.ChatBackground and dies. The share target view is driven before
it is initialized - the same race as #3320, which moved this crash one frame
later rather than removing it - and ApplicationData is evidently not always
reachable that early.
That the constructor ran at all is not in doubt: SharePage.xaml resolves
StaticResource EmptyHyperlinkButtonStyle from CommonStyles.xaml, a merged
dictionary of Application.Resources that follows <common:Theme /> in the merge
list, so InitializeComponent could not have returned unless the resources of
this view - the theme among them - had been inflated.
Assign Current before the try. It depends on nothing inside it, and losing a
persisted preference should not cost the view its theme. The catch now logs,
since the whole diagnosis rests on inferring which call threw, and an empty
catch is what made that necessary.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 3409687 • 1 files, +12/-1
Guard the geolocation access request in SendLocationPopup (#3344)
Geolocator.RequestAccessAsync is a remote procedure call and throws when the
Windows Geolocation Service (lfsvc) is disabled, which privacy/debloat scripts
routinely do. In FindLocation the call was the only one not wrapped, so the
throw escaped an async void method and reached the unhandled exception handler.
Treat a failed request as "not allowed": the popup keeps the map shimmer, the
same as an explicit denial.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 5316a20 • 1 files, +19/-8
Fix the Topics tab context menu casting to the wrong item type (#3345)
ProfileTopicsTabPage.OnContextRequested was an unadapted copy of the one in
ProfileSavedChatsTabPage: it cast the right-clicked item to SavedMessagesTopic,
which is always null here because this list holds ForumTopic, and it invoked
the saved chats tab's commands instead of the topics tab's own. Right-clicking
any row threw a NullReferenceException, reported by crash telemetry on 12.9.1.
Cast to ForumTopic, route pin/delete to TopicsTab, and gate them on
CanManageTopics the way ForumView's own topic menu does.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Register the theme before reading its settings (#3343)
Theme.Current is thread-static and assigned in exactly one place, and that
assignment sat behind a call that can fail:
try
{
_isolatedStore = ApplicationData.Current.LocalSettings.CreateContainer(...);
Current ??= this;
...
}
catch { }
When CreateContainer throws, the catch is silent and the theme never registers
itself. Every later Theme.Current dereference - and they are unguarded across
the message tree, FormattedTextBlock, MessageBubblePanel, ChatBackgroundControl
- is then a NullReferenceException on that view thread.
Reported by crash telemetry on 12.9.1, through OnShareTargetActivated:
SharePage's constructor calls ChatBackgroundControl.Update, which reads
Theme.Current.ChatBackground and dies. The share target view is driven before
it is initialized - the same race as #3320, which moved this crash one frame
later rather than removing it - and ApplicationData is evidently not always
reachable that early.
That the constructor ran at all is not in doubt: SharePage.xaml resolves
StaticResource EmptyHyperlinkButtonStyle from CommonStyles.xaml, a merged
dictionary of Application.Resources that follows <common:Theme /> in the merge
list, so InitializeComponent could not have returned unless the resources of
this view - the theme among them - had been inflated.
Assign Current before the try. It depends on nothing inside it, and losing a
persisted preference should not cost the view its theme. The catch now logs,
since the whole diagnosis rests on inferring which call threw, and an empty
catch is what made that necessary.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 3409687 • 1 files, +12/-1
Guard the geolocation access request in SendLocationPopup (#3344)
Geolocator.RequestAccessAsync is a remote procedure call and throws when the
Windows Geolocation Service (lfsvc) is disabled, which privacy/debloat scripts
routinely do. In FindLocation the call was the only one not wrapped, so the
throw escaped an async void method and reached the unhandled exception handler.
Treat a failed request as "not allowed": the popup keeps the map shimmer, the
same as an explicit denial.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 5316a20 • 1 files, +19/-8
Fix the Topics tab context menu casting to the wrong item type (#3345)
ProfileTopicsTabPage.OnContextRequested was an unadapted copy of the one in
ProfileSavedChatsTabPage: it cast the right-clicked item to SavedMessagesTopic,
which is always null here because this list holds ForumTopic, and it invoked
the saved chats tab's commands instead of the topics tab's own. Right-clicking
any row threw a NullReferenceException, reported by crash telemetry on 12.9.1.
Cast to ForumTopic, route pin/delete to TopicsTab, and gate them on
CanManageTopics the way ForumView's own topic menu does.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
👍1
UnigramDev/Unigram/develop • f994e66 • 2 files, +6/-2
Fix InvalidCastException opening the gift variants popup on Windows 10 (#3346)
ListViewItemPresenter.SelectedBorderBrush, SelectedPointerOverBorderBrush and
SelectedPressedBorderBrush are declared on IListViewItemPresenter4, introduced
in UniversalApiContract 13.0 (build 22621). On older builds the QueryInterface
behind the setter fails and the projection throws, so GiftVariantsPopup crashed
as soon as the first container was realized.
Guard the three assignments on the property actually being present. Where it is
not, the selection border keeps its default brush.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 5b2a1e1 • 3 files, +18/-2
Let the invite link actually arrive on ChatInviteLinksPage (#3347)
ChatInviteLinksViewModel declares _supergroupId and _basicGroupId but never
assigns them, so Handle(UpdateSupergroupFullInfo) and
Handle(UpdateBasicGroupFullInfo) compared against 0 and never matched. The
"full info will arrive by push" fallback in OnNavigatedToAsync was therefore
dead, and InviteLink stayed null for every chat whose full info wasn't already
cached — which made the header's copy and share buttons dereference null.
Assign both ids, and fix the basic group branch, which asked for
GetBasicGroupFullInfo(supergroup.Id) inside the branch where TryGetSupergroup
had just failed: supergroup is null there, and it was passing a supergroup id
where a basic group id belongs.
InviteLink is also legitimately null for anyone who isn't the creator, since
TDLib only populates the primary link for them, so the header buttons are now
disabled while it is null instead of acting on nothing.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 711f79a • 1 files, +64/-20
Recover from a damaged OCR model archive (#3348)
Extracting Ocr_x64.zip crashed the app with an InvalidDataException,
"The archive entry was compressed using an unsupported compression
method". The message is misleading: Inflater maps zlib's Z_DATA_ERROR
onto that string, and the failure came from mid-entry writes in
DeflateStream.CopyToAsyncStream rather than from ZipArchiveEntry.Open,
so the deflate data was corrupt or truncated, not compressed with a
method the reader doesn't support. Why the local copy was damaged is
not established.
ExtractModelAsync had no try/catch and RecognizeText is async void, so
the failure reached the app unhandled. Catch it, delete the archive so
that the next attempt downloads a fresh copy, delete the partially
written model so that the readiness check in EnsureReadyAsync doesn't
accept it, and report the extraction as unavailable.
Separately, _extractLock.Release() sat outside any finally, so a throw
during extraction leaked the semaphore for the rest of the session:
every later extraction then returned early at Wait(0), leaving OCR
broken until restart.
Reported by crash telemetry on 12.9.1.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Fix InvalidCastException opening the gift variants popup on Windows 10 (#3346)
ListViewItemPresenter.SelectedBorderBrush, SelectedPointerOverBorderBrush and
SelectedPressedBorderBrush are declared on IListViewItemPresenter4, introduced
in UniversalApiContract 13.0 (build 22621). On older builds the QueryInterface
behind the setter fails and the projection throws, so GiftVariantsPopup crashed
as soon as the first container was realized.
Guard the three assignments on the property actually being present. Where it is
not, the selection border keeps its default brush.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 5b2a1e1 • 3 files, +18/-2
Let the invite link actually arrive on ChatInviteLinksPage (#3347)
ChatInviteLinksViewModel declares _supergroupId and _basicGroupId but never
assigns them, so Handle(UpdateSupergroupFullInfo) and
Handle(UpdateBasicGroupFullInfo) compared against 0 and never matched. The
"full info will arrive by push" fallback in OnNavigatedToAsync was therefore
dead, and InviteLink stayed null for every chat whose full info wasn't already
cached — which made the header's copy and share buttons dereference null.
Assign both ids, and fix the basic group branch, which asked for
GetBasicGroupFullInfo(supergroup.Id) inside the branch where TryGetSupergroup
had just failed: supergroup is null there, and it was passing a supergroup id
where a basic group id belongs.
InviteLink is also legitimately null for anyone who isn't the creator, since
TDLib only populates the primary link for them, so the header buttons are now
disabled while it is null instead of acting on nothing.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 711f79a • 1 files, +64/-20
Recover from a damaged OCR model archive (#3348)
Extracting Ocr_x64.zip crashed the app with an InvalidDataException,
"The archive entry was compressed using an unsupported compression
method". The message is misleading: Inflater maps zlib's Z_DATA_ERROR
onto that string, and the failure came from mid-entry writes in
DeflateStream.CopyToAsyncStream rather than from ZipArchiveEntry.Open,
so the deflate data was corrupt or truncated, not compressed with a
method the reader doesn't support. Why the local copy was damaged is
not established.
ExtractModelAsync had no try/catch and RecognizeText is async void, so
the failure reached the app unhandled. Catch it, delete the archive so
that the next attempt downloads a fresh copy, delete the partially
written model so that the readiness check in EnsureReadyAsync doesn't
accept it, and report the extraction as unavailable.
Separately, _extractLock.Release() sat outside any finally, so a throw
during extraction leaked the semaphore for the rest of the session:
every later extraction then returned early at Wait(0), leaving OCR
broken until restart.
Reported by crash telemetry on 12.9.1.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
UnigramDev/Unigram/develop • 27d3ebc • 2 files, +98/-9
Implement BusinessHoursViewModel.ContinueImpl (#3349)
The Done button on Settings > Telegram Business > Opening Hours is bound to
BusinessFeatureViewModelBase.Continue, which calls the abstract ContinueImpl.
BusinessHoursViewModel never implemented it and threw NotImplementedException,
so pressing Done crashed the app every time.
Build a BusinessOpeningHours from the per-day ranges and send it with
SetBusinessOpeningHours, following the other business feature view models:
early-out when nothing changed, toast an error, otherwise go back. Override
HasChanged so the unsaved-changes prompt the base class already carries a
string for actually fires.
The time zone is now resolved on every navigation rather than only when the
user already had opening hours saved, falling back to the first zone at the
current UTC offset, since otherwise a first-time user would have none to send.
Reported by crash telemetry on 12.9.1.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 4b1d459 • 2 files, +40/-11
Give the DWrite custom font collection a valid key (#3351)
CreateCustomFontCollection takes the key size in bytes, but it was given
path1.size() + path2.size(), the summed character length of the two package
paths (~240) — while the key itself is a two-element array of pointers, 16
bytes. DWrite copied ~240 bytes out of a 16-byte stack array on every
PlaceholderImageHelper construction, so the key it stored was partly unrelated
stack memory, and how much varied with the install path length.
The key also pointed at two locals that die when the function returns, so the
pointers DWrite kept were dangling by the time it could hand them back to
CreateEnumeratorFromKey. The paths and the pointer array now live inside the
CustomFontLoader, which stays alive as long as it is registered, and the size
passed is sizeof that array. CustomFontFileEnumerator honours collectionKeySize
instead of assuming two entries.
Close() now unregisters the loader it registered on the shared DWrite factory,
after releasing the collection built from it. The factory is process-wide, so
without this every window thread left a loader and a custom collection on it for
the rest of the session.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Implement BusinessHoursViewModel.ContinueImpl (#3349)
The Done button on Settings > Telegram Business > Opening Hours is bound to
BusinessFeatureViewModelBase.Continue, which calls the abstract ContinueImpl.
BusinessHoursViewModel never implemented it and threw NotImplementedException,
so pressing Done crashed the app every time.
Build a BusinessOpeningHours from the per-day ranges and send it with
SetBusinessOpeningHours, following the other business feature view models:
early-out when nothing changed, toast an error, otherwise go back. Override
HasChanged so the unsaved-changes prompt the base class already carries a
string for actually fires.
The time zone is now resolved on every navigation rather than only when the
user already had opening hours saved, falling back to the first zone at the
current UTC offset, since otherwise a first-time user would have none to send.
Reported by crash telemetry on 12.9.1.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 4b1d459 • 2 files, +40/-11
Give the DWrite custom font collection a valid key (#3351)
CreateCustomFontCollection takes the key size in bytes, but it was given
path1.size() + path2.size(), the summed character length of the two package
paths (~240) — while the key itself is a two-element array of pointers, 16
bytes. DWrite copied ~240 bytes out of a 16-byte stack array on every
PlaceholderImageHelper construction, so the key it stored was partly unrelated
stack memory, and how much varied with the install path length.
The key also pointed at two locals that die when the function returns, so the
pointers DWrite kept were dangling by the time it could hand them back to
CreateEnumeratorFromKey. The paths and the pointer array now live inside the
CustomFontLoader, which stays alive as long as it is registered, and the size
passed is sizeof that array. CustomFontFileEnumerator honours collectionKeySize
instead of assuming two entries.
Close() now unregisters the loader it registered on the shared DWrite factory,
after releasing the collection built from it. The factory is process-wide, so
without this every window thread left a loader and a custom collection on it for
the rest of the session.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
UnigramDev/Unigram/develop • 4425c24 • 1 files, +13/-5
Recompute the message index after removing it from the collection (#3352)
InsertMessageInOrder moves a message by removing it and reinserting it at the
index NextIndexOf computed against the collection as it was *before* the
removal, compensating for the single row that goes away. MessageCollection
removes more than one row: RemoveItem also drops the date or topic separator
that the removal orphans, so a message that was the only one of its day takes
its header with it and the collection shrinks by two. If the message is not the
last row -- a sponsored message below it, say -- the adjusted index is then past
the end and Insert throws ArgumentOutOfRangeException.
Reported by crash telemetry on 12.9.1, reached when a locally pending message
completes: PendingMessage_Completed -> InsertMessage -> InsertMessageInOrder.
Ask NextIndexOf again after the removal rather than trusting the pre-removal
index; clamping would have put the message in the wrong place instead. The
force branch had the same defect -- it reinserted at oldIndex, which is out of
bounds once the header ahead of the message is gone -- so both paths now share
one helper.
Not built: the file parses with Roslyn, nothing more.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Recompute the message index after removing it from the collection (#3352)
InsertMessageInOrder moves a message by removing it and reinserting it at the
index NextIndexOf computed against the collection as it was *before* the
removal, compensating for the single row that goes away. MessageCollection
removes more than one row: RemoveItem also drops the date or topic separator
that the removal orphans, so a message that was the only one of its day takes
its header with it and the collection shrinks by two. If the message is not the
last row -- a sponsored message below it, say -- the adjusted index is then past
the end and Insert throws ArgumentOutOfRangeException.
Reported by crash telemetry on 12.9.1, reached when a locally pending message
completes: PendingMessage_Completed -> InsertMessage -> InsertMessageInOrder.
Ask NextIndexOf again after the removal rather than trusting the pre-removal
index; clamping would have put the message in the wrong place instead. The
force branch had the same defect -- it reinserted at oldIndex, which is out of
bounds once the header ahead of the message is gone -- so both paths now share
one helper.
Not built: the file parses with Roslyn, nothing more.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
UnigramDev/Unigram/chat-preview-teardown • 158f942 • 4 files, +3/-16
Drop the idempotence flag from Deactivate
The handler detaches from both Closed and Unloaded before it tears anything
down, so whichever event arrives first makes the other unreachable and
Deactivate cannot be entered twice from here. The flag was dead, and it
applied to every ChatView rather than the preview - a second Deactivate
elsewhere would have become a silent no-op.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Drop the idempotence flag from Deactivate
The handler detaches from both Closed and Unloaded before it tears anything
down, so whichever event arrives first makes the other unreachable and
Deactivate cannot be entered twice from here. The flag was dead, and it
applied to every ChatView rather than the preview - a second Deactivate
elsewhere would have become a silent no-op.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
UnigramDev/Unigram/develop • de28263 • 1 files, +39/-6
Stop the gallery from taking input while it closes (#3354)
Closing the gallery is animated: OnBackRequestedOverride calls Unload()
synchronously, which drops the data context, while Hide() only runs when the
closing animation completes. In between the window is still visible and still
hit-testable, so a click on a caption hyperlink ran Caption_TextEntityClick
with a null ViewModel and crashed in the MessageDelegate constructor
(NullReferenceException, reported by crash telemetry on 12.9.1). The caption
sits outside ScrollingHost, so the tap-to-close handler never consumes it.
Unload() now clears IsHitTestVisible, which closes the whole "input after
unload" family instead of one handler at a time; Caption_TextEntityClick is
guarded as well, because a focused hyperlink can still be invoked from the
keyboard or by automation, neither of which hit tests.
Also fix the same method leaving the window on screen forever: the connected
animation's Completed was subscribed before TryStart, and when TryStart failed
translate became false, so neither Hide() was reachable. Hide() now runs off
the fade batch, which is started on every path, and Completed is subscribed
only when the animation actually started.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 162781d • 3 files, +37/-1
Detach the emoji and sticker drawers from their collections (#3355)
InvalidComObjectException — "COM object that has been separated from its
underlying RCW cannot be used" — reported by crash telemetry on 12.9.1,
raised from MvxObservableCollection.ReplaceWith inside
EmojiDrawerViewModel.Update.
EmojiDrawer's CollectionViewSource and its two toolbars bind straight to the
view model's collections, so their native peers subscribe to CollectionChanged.
Deactivate() only called Bindings.StopTracking(), which stops the bindings from
updating but leaves the value they already pushed in place, and it runs right
before XamlMarkupHelper.UnloadObject destroys those peers. The view model
subscribes to the aggregator in its constructor and Handle queues Update on the
UI thread, so a queued update outlives the drawer and raises into the dead
peers.
Clear the collection sources in Deactivate so nothing native is still attached
once the peers go away. StickerDrawer has the same shape and the same terminal
Deactivate contract, so it gets the same treatment.
EmojiMenuFlyout never deactivated its drawer at all, and only one of its three
constructors subscribed to Popup.Closed; move that subscription into Initialize
and tear the drawer down there, matching what StickerPanel does when it unloads
a drawer.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Stop the gallery from taking input while it closes (#3354)
Closing the gallery is animated: OnBackRequestedOverride calls Unload()
synchronously, which drops the data context, while Hide() only runs when the
closing animation completes. In between the window is still visible and still
hit-testable, so a click on a caption hyperlink ran Caption_TextEntityClick
with a null ViewModel and crashed in the MessageDelegate constructor
(NullReferenceException, reported by crash telemetry on 12.9.1). The caption
sits outside ScrollingHost, so the tap-to-close handler never consumes it.
Unload() now clears IsHitTestVisible, which closes the whole "input after
unload" family instead of one handler at a time; Caption_TextEntityClick is
guarded as well, because a focused hyperlink can still be invoked from the
keyboard or by automation, neither of which hit tests.
Also fix the same method leaving the window on screen forever: the connected
animation's Completed was subscribed before TryStart, and when TryStart failed
translate became false, so neither Hide() was reachable. Hide() now runs off
the fade batch, which is started on every path, and Completed is subscribed
only when the animation actually started.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 162781d • 3 files, +37/-1
Detach the emoji and sticker drawers from their collections (#3355)
InvalidComObjectException — "COM object that has been separated from its
underlying RCW cannot be used" — reported by crash telemetry on 12.9.1,
raised from MvxObservableCollection.ReplaceWith inside
EmojiDrawerViewModel.Update.
EmojiDrawer's CollectionViewSource and its two toolbars bind straight to the
view model's collections, so their native peers subscribe to CollectionChanged.
Deactivate() only called Bindings.StopTracking(), which stops the bindings from
updating but leaves the value they already pushed in place, and it runs right
before XamlMarkupHelper.UnloadObject destroys those peers. The view model
subscribes to the aggregator in its constructor and Handle queues Update on the
UI thread, so a queued update outlives the drawer and raises into the dead
peers.
Clear the collection sources in Deactivate so nothing native is still attached
once the peers go away. StickerDrawer has the same shape and the same terminal
Deactivate contract, so it gets the same treatment.
EmojiMenuFlyout never deactivated its drawer at all, and only one of its three
constructors subscribed to Popup.Closed; move that subscription into Initialize
and tear the drawer down there, matching what StickerPanel does when it unloads
a drawer.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram