Skip to content

MOBILE-438: Redraw the embedded block shimmer to the design - #769

Merged
Vailence merged 6 commits into
mission/storiesfrom
feature/MOBILE-438
Sep 9, 2026
Merged

Vailence merged 6 commits into
mission/storiesfrom
feature/MOBILE-438

Conversation

@Vailence

@Vailence Vailence commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

The default shimmer of embedded blocks redrawn to the Figma spec (Mobile Launchpad → «Шиммер вью для встроенных блоков»), paired with Android MOBILE-439. 6 commits: the shimmer, a review pass, a test-stability fix, a lint fix the test build on the base needed, and two review follow-ups.

What changed and why:

  • One tint per palette instead of the old three-stop gradient: #282A2F in light, #FFFFFF in dark, resting at 8 % opacity; the sweep dips to 4 % in light and rises to 16 % in dark. All numbers live in EmbeddedBlockShimmerView.Design and are pinned by tests.
  • The sweep is a CAKeyframeAnimation over the gradient layer's position: the layer is 296 % of the block width, the leading edge travels from −188 % to −8.3 % W in 1 s with an ease-in curve (0.42, 0, 1, 1), 0.6 s of rest on either side, an instant reset — a 2.2 s cycle. The gradient stops sit outside 0…1 so the ramp waits off-screen between sweeps.
  • Every shimmer on screen moves in one beat: a process-wide beatEpoch (CACurrentMediaTime() at first use) is converted into each layer's time space for beginTime, so blocks created seconds apart still sweep together — the same idea as the uptimeMillis epoch on Android.
  • The gradient layer's implicit bounds/position actions are switched off once in setUp: a size change during a sweep must not animate the frame. The sweep is restarted on willEnterForeground, since Core Animation drops animations in the background; the notification center is injected for tests.
  • Blur from the spec (~5.6 % W) is deliberately left out: CALayer has no public blur, and the difference is not visible at these opacities. Reduced Motion is marked open in the spec itself and keeps the normal behaviour for now, as the old shimmer did; a follow-up task decides between a static frame and the sweep.
  • EmbeddedBlockWebViewProvider: the count parameter renamed to renderedCount — SwiftLint 0.59 reads count > 0 on an Int as empty_count and failed the test build on the base.

Tests: EmbeddedBlockShimmerViewTests, 15 Swift Testing cases — palette per interface style, stop locations at rest and at the end of the sweep, key times and timing functions of the sweep, one shared beginTime across two views, the restart on foreground, no implicit animation on resize. The shimmer is hosted under a plain UIView inside the test window: a view placed directly into a per-test UIWindow that is released at the end of the test crashed the process on the next run-loop turn (iOS 26 simulator).

Impact for hosts — the one change a host will see:

  • The placeholder used to be an opaque systemGray5 tile. Now it is a translucent mask: 8 % of one tint over whatever the host draws underneath, and the tint follows the system appearance (#282A2F in light, #FFFFFF in dark), not the actual background. On a white, a dark and a brand-green host background in both appearances the shimmer reads as intended. A dark host screen under the light appearance, or a light screen under the dark one, gets a placeholder that is almost invisible: 8 % of near-black on near-black. Hosts with such screens should set the container's placeholderView; the integration guide says so.
  • QA: check the default shimmer on a dark host background in the light appearance and on a light background in the dark appearance, besides the standard screens.

Full run on iPhone 17: 1931 passed, 3 failed — the three DateFormatMigrationTests cases fail in this local environment on iOS 26 regardless of branch and do not touch embedded blocks. swiftlint --strict clean.

https://tracker.yandex.ru/MOBILE-438

Vailence added 4 commits September 7, 2026 16:29
The page reports how many elements it rendered as an Int: SwiftLint
0.59 flags the comparison anyway, and the test build fails on it.
One tint over the host's background whose opacity alone changes:
#282A2F in light with a 4% dip, #FFFFFF in dark with a 16% peak, 8%
elsewhere. A gradient layer 296% of the block's width sweeps from
-188% to -8.3% in one second with ease-in, resting 0.6 s at both ends
and jumping back. Every shimmer anchors its cycle to one shared clock,
so several blocks on a screen move to the same beat.
The rendered count gets a name the empty_count rule does not mistake
for a collection, so the lint directive goes. The shimmer takes its
notification center from the outside, and the tests post the foreground
notification to a private one instead of the process-wide center. A
resize snaps rather than animating the tint into the new bounds. The
class comment states the blur's share of the ramp correctly and notes
that the shared beat depends on the host leaving the layer clock alone.
A view placed straight into a UIWindow that is released at the end of
a test left the test process crashing on the next run-loop turn, about
every other run. In the SDK the shimmer always sits inside the block
container, so the tests now give it a host view inside the window too.
@Vailence
Vailence requested a review from justSmK September 7, 2026 22:09
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor
TestsPassed ✅SkippedFailedTime ⏱
Unit tests report2138 ran2138 ✅1m 52s 127ms

Comment thread Mindbox/EmbeddedBlocks/WebView/EmbeddedBlockWebViewProvider.swift Outdated
Comment thread Mindbox/EmbeddedBlocks/Container/EmbeddedBlockShimmerView.swift
Comment thread Mindbox/EmbeddedBlocks/Container/EmbeddedBlockShimmerView.swift
Comment thread Mindbox/EmbeddedBlocks/Container/EmbeddedBlockShimmerView.swift Outdated
Comment thread Mindbox/EmbeddedBlocks/Container/EmbeddedBlockShimmerView.swift Outdated
@justSmK
justSmK self-requested a review September 8, 2026 11:41
@Vailence
Vailence merged commit 22be7ce into mission/stories Sep 9, 2026
6 checks passed
@Vailence
Vailence deleted the feature/MOBILE-438 branch September 9, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants