## yuroyami/syncplay-mobile — v0.23.0…v0.24.0

_209+ commits._

### Features
- **Size a chat image halfway between the old one and the new** (ec9c861)
- **Add a per-user time offset, so two rips can be watched together** (f21f7a7)
- **Add slash commands to the chat box** (3e968c4)
- **Add previews for the drawn control set, and hold the coverage floor** (0d21474)
- **Add detekt, configured for this repo, and clear what it found** (60a8339)
- **A new file reaches the parts of the room that show what is playing** (35efec1)
- **The room speaks: readiness, connection changes and new messages reach a screen reader** (ee9e16d)
- **The add key's morph runs on one progress value, both contents measured up front, on a standard curve** (463a4d1)
- **The add key's morph grows the gradient block out of its own corner instead of leaning on a size transform that never drew** (d82a22e)
- **The add key's card stays violet, with dark ink on the gradient, and takes the right side for itself** (a2dda03)
- **The playlist strip lists rows, the roster has one cycling toggler, and the add key's gradient grows into the card** (59b6b6a)

### Fixes
- **Fix the GIF drawer: the loop, the loading, and the labels** (ff34117)
- **Decide the server endpoint in one place, and fix the blank-host case** (f579946)
- **A bug report says which engine, which build and which device** (19c04b2)
- **Bug reports arrive with the facts, and the docs describe the code that exists** (e888696)

### Backend
- **Ship one universal APK per flavor, and write the release page in three parts** (8b72d5c)
- **Put fading chat under the notices, on the centre line** (b7322c7)
- **Call the site YT wherever a person reads it** (2e1f916)
- **Tell buffering through the play key itself** (301c5fc)
- **The single-file fixes: ten of them** (923e85c)
- **The one-line fixes: eight of them** (0f90630)
- **Wave 4: keys out of the log, a store that recovers, a backup worth having** (0e57e3b)
- **Tag outbound work and inbound lines with their socket** (e68ca63)
- **Drop stays dropped, indexes stay inside the list, sizes keep their zeros** (822ed18)
- **Make /room a real transition, cap every roster insert, cursor the log** (dec5713)
- **Serialize the sync anchor, own the readiness collector, settle a room change** (20552b5)
- **Apply the time offset everywhere, and stop cutting names at 16** (7c5899d)
- **Make Wave 1 compile and pass on every target** (b9c1736)
- **Gate every release upload on one verify job** (4bfb42e)
- **Keep the iOS 16 geometry API off iOS 14, and settle the TLS promise** (2521792)
- **One 35-character room limit, and a managed name is refused rather than cut** (5f681e3)
- **Enforce required encryption before the first byte, not after a refusal** (e00bf6a)
- **Trust the host a URL really names** (c22261a)
- **Give auto-sizing a 5sp floor, and stop shipping stale short labels** (2575d94)
- **Translate the stepper arrows and write down how strings work now** (b746aa2)
- **Translate the app into all seven languages** (c008992)
- **Check the app in every language it ships** (cfcb903)
- **Move the settings registry, plurals and lists to Lyricist** (79fd22a)
- **Read screen and room strings through Lyricist** (b843ade)
- **Generate the app's strings as Kotlin with Lyricist** (165b5d0)
- **Give notices their own room category** (47bc3ef)
- **Stop the roster golden from opening a tooltip on itself** (4afaf78)
- **Take KitePlayer 0.0.23, so a link over https plays** (39cc745)
- **Bring the codebase reference back in line with what is there** (18d4981)
- **Show the aspect-ratio key for KitePlayer again** (bbaa05a)
- **Drop the blank lines out of every chat line** (575cc14)
- **Open the room's tools only once it has a player, and hold the HUD while nothing plays** (8da57e5)
- **Give the roster two views and file details worth reading** (5fb313b)
- **Edit a colour inside the settings panel without crashing the room** (1c7a001)
- **Say what each setting does, and show its value in the unit people read** (8712c45)
- **Check for a newer release from the About popup** (3ddbbbc)
- **Rebuild the home form around the window it is given** (8dfb7aa)
- **Shrink a label instead of cutting it** (a25ef31)
- **Work out a filled control's label from the fill it paints** (d74d9b6)
- **Register the room's media session with the service that hosts it** (29d36c7)
- **Name the SwiftNIO exception the way Kotlin exports it** (c11464b)
- **Take NewPipe Extractor 0.26.5** (b9bb84e)
- **Say KiteFFmpeg where the text still said KiteCodec** (4d23b3e)
- **Record a KitePlayer track pick so the language pass stops undoing it** (0fcd323)
- **Pin the desktop KitePlayer view to the Compose canvas** (e36cdcd)
- **Move to KitePlayer 0.0.22** (4581286)
- **Name all eight gates in the aggregate task's description** (10d1aa6)
- **Use the explicit backing fields the compiler flag was already enabling** (f59296c)
- **Give Android and desktop a shared source set, and stop maintaining Netty twice** (37d8507)
- **Generate the version table instead of typing it** (425fab2)
- **Document what this codebase now expects you to know** (4da364e)
- **Say that the desktop app exists, and how to run and release the thing** (948030a)
- **Let a playlist change be taken back** (7c577ad)
- **Give the room a real media session** (0488ce1)
- **Export and import settings** (ba2596c)
- **Keep chat off the subtitles** (3c376bb)
- **Cap what one client can do to a hosted room** (8b7ed36)
- **Remember where a file was left, and offer to pick it up** (c8c4df5)
- **Turn the untrusted-link dead end into a question** (bc359cd)
- **Make the three drift thresholds settings** (a22af1a)
- **Measure the clock offset from the timestamps already on the wire** (92bc3a0)
- **Say who the room is waiting for, and start it once nobody is** (bc23706)
- **Make the local library override opt-in instead of always on** (08d7a7b)
- **Ship the desktop app, keep the symbols, and tell people what changed** (8ccf1cb)
- **Give the release its notes, and stop the store copy from being too long** (e0035ca)
- **Make the position we advertise a function, and test it** (6a9b112)
- **Fail the design ratchet on a clickable that announces nothing** (c787403)
- **Enforce the engine destroy contract at build time** (7fde310)
- **Fail the build when a preference nobody can reach is declared** (21b4b3c)
- **Four build gates for rules nothing was checking** (0041b93)
- **Measure coverage where a gap is a real risk** (4c5c110)
- **Enforce the rule that inbound protocol code throws only SerializationException** (861ef3a)
- **Make the sync decision a function, and test it** (fa44a91)
- **Draw the connection lock instead of importing one** (9a33ca9)
- **Split the two longest files along their real seams** (f67c432)
- **Stop the roster's file marker from speaking in colour alone** (0d50414)
- **Make the glass shade follow the theme instead of assuming a dark room** (46fa312)
- **Give the locked room a way out that the user can find** (5c5f59a)
- **Show whether the room's connection is encrypted** (45ed5ad)
- **Actually copy the managed-room password to the clipboard** (5e054b9)
- **Stop logging from blocking whoever called it** (9dd8b4f)
- **Give the chat and playlist lists stable keys** (663c899)
- **Show media language names in the reader's own language** (1cc5917)
- **Read the room's position once, and say out loud that reading it mutates** (171e9df)
- **One clock for the sync core and the hosted server** (33402df)
- **Keep Set{"features"} inbound-only, and prove it stays that way** (d4b6785)
- **Pin the app's own backends to HTTPS** (ca951e1)
- **The local release task checks what it is about to hand you, and the desktop shell is registered** (607e648)
- **The prebuilt FFmpeg library gets its provenance, and Gradle's own download is verified** (d09f9b9)
- **Controls say what is selected, tap targets reach the platform minimum, and imports are tidied** (ef09e59)
- **The store listing describes this app, and there are release notes to publish** (3f7d72b)
- **The two source rewrites become real tasks, and the module with all the code gets linted** (d73238f)
- **Picture-in-picture morphs out of the video, and the room stops rebuilding its own surface** (07d5a4f)
- **Three dependencies with no callers stop shipping, and Netty ships the parts we use** (4af637d)
- **Dead resources stop shipping, and translators stop maintaining them** (d75be7f)
- **About can tell you what the app is built from and whether there is a newer one** (f9dcbc8)
- **Volume and brightness are reachable without a swipe** (f548e36)
- **Preferences are read off the main thread, and a test can point them somewhere else** (9e4cf90)
- **Desktop arrow keys reach the room, and Display Language does something** (0019f88)
- **The hosting screen and its notifications speak the app's language** (d29817c)
- **Startup stops loading a crypto library on the main thread** (ddba942)
- **The Android callback stops holding a dead window, and a launch intent has to be ours** (bbd01c1)
- **The end of a file moves the playlist on by one, not by however many people are watching** (39fdc92)
- **The room says when it is waiting, and KitePlayer draws where the glass can see it** (aa5bdd2)
- **Chat clocks read the way the device reads, and a television keeps its chrome on screen** (ee35e02)
- **Chat colours follow the theme until someone picks otherwise** (67f5fd3)
- **The GIF service can be told to stop recognising you** (d87a74a)
- **A subtitle picked on its own keeps its file grant on iOS** (e57302b)
- **A track pick is typed, survives a reload on every engine, and says what it is for** (ea72ae4)
- **A controller can set someone else's readiness, and audio-only links resolve** (f47b560)
- **Video stops paying for a blur the device cannot draw, and hidden GIFs stop decoding** (3506343)
- **The room can follow the device's rotation** (a1dea29)
- **A release with no keystore fails instead of shipping unsigned APKs under release names** (d0fc539)
- **Chat stops fetching strangers' hosts on sight, and a stuck room can retry now** (6d71bb4)
- **Tests that could not fail now can** (5481871)
- **A playlist with the same filename twice can move between the two entries** (41f1bc4)
- **A room is one link now, and pasting the operator string lands where it should** (51a1bdf)
- **A wrong operator password is the sender's business, and the iOS server writes in order** (9908917)
- **The room notices a silent divergence, and knows where each person actually is** (2d02acc)
- **A crash reaches the platform, and the saved password stops travelling** (cb5cf57)
- **Glass stops capturing a screen nobody is looking at** (fb93569)
- **Selecting a playlist item starts it from the top, and a failed subtitle search says why** (845062b)
- **The hosted server drops a client that has gone quiet, and one room's password stops unlocking another** (42660e8)
- **TLS checks who the server is, on all three transports** (a34389b)
- **A handshake that never finishes now ends, and two sends keep their order** (213e1c1)
- **A backgrounded phone follows the room instead of dragging it back** (2c1586e)
- **An engine stopping on its own is no longer a pause for the whole room** (820aee1)
- **One playhead the whole app reads, and a room that waits for the last engine to finish dying** (1dfeff3)
- **Settings follow the device's language, trust YouTube out of the box, and can refuse a plain server** (5f87f22)
- **The room can say what went wrong, in words that are not developer notes** (f8d8197)
- **A device with no translation for a player-category name no longer crashes the settings** (c6c52a9)
- **Merge the audit folders into one gitignored ledger, refresh the docs, and mask the transient bar fade-out on Android 15 and older** (6875d5f)
- **Volume is one ladder with two rungs: the device's own level to 100, then the engine's gain where it has any** (93e70f9)
- **On a phone on its side the home form fits at rest: dense blocks, breathing room between them, and scrolling only once the host panel opens** (be856dd)
- **The home form adapts to the window: one spread column, a centred two-column block, or two pinned columns on a phone on its side** (4ef5eca)

_Recap by [Repo Wrapped](https://repowrapped.com/gh/yuroyami/syncplay-mobile?utm_source=github-action)._