Typing on a TV with a remote is the worst part of almost any media app. A server address, a user name and a password, entered one letter at a time with a D-pad, is where a lot of people give up, and they give up before the app has played anything. In Yonto Player the answer is a button called Set up from your phone. The TV shows a QR code, your phone opens a page with the same form, and you type on a real keyboard.
This post is about the design: why the two devices talk through a service on the internet and not directly, and why what comes back from the phone only fills in a form.
What you see
On a TV, the forms for adding or editing a source have Set up from your phone at the top. You choose it and the TV shows a QR code, with its address written beside it for a camera that will not cooperate. You scan the code, or open the address in your phone's browser, and a page opens with the same form. You fill it in and choose Send to the TV. The TV's form fills in and says "Filled in from your phone. Check it, then save."
Nothing is saved until you choose Save with the remote. That last step is deliberate, and it is the one the rest of the design is built around.
One channel, several forms
The same mechanism fills in more than a source. It also takes the address of a plugin repository and the address of a plugin. Each of those is just a different list of fields, and a plugin's fields are the ones it declares, so the phone page matches the plugins installed on that TV. There is one editor and one set of rules, and the phone is another way to type into it.
When you edit a source you already have, the page starts empty. You fill in only what you want to change, and whatever you leave empty keeps what is saved.
Why not a page on the local network?
The obvious design is for the TV to serve a small page on your Wi-Fi and for the phone to open it. I looked at that first and decided against it, for reasons that all come down to networks I do not control:
- A router can isolate its clients from each other, a mesh's guest network is a separate network, and a TV can sit on a different subnet from the phone. A page on the local network just does not load.
- A page on a local address cannot, in practice, have a certificate, so a password typed into it would cross the Wi-Fi in plain HTTP.
- Opening a port on a TV is an invitation to anyone else on the same network.
So the TV and the phone never talk to each other. Both talk to a small service on the internet, which works like a mailbox: the TV opens a session and shows its QR code, the phone's page leaves the answer there, and the TV picks it up.
There is no short code to type instead of scanning. The QR code carries what the phone needs to open the form, and a code on its own would not be enough for that.
What travels, and for how long
What you type goes from your phone to the TV encrypted, so that the service cannot read it. A session lasts ten minutes and takes a single answer. The docs say it is deleted once the TV has it or the code runs out, apart from an encrypted copy that the server's disk snapshots keep for up to seven days.
The flow, in a sketch
This is a simplified sketch of one session with generic names, not the app's code:
TV asks the service for a session TV shows a QR code for the session's page Phone scans it; the page shows the form the TV described Phone you type, then choose "Send to the TV" TV receives the answer and fills in its own form TV shows "Filled in from your phone. Check it, then save." You choose Save with the remote A reply only fills in a form
This is the part I care about most. What comes back from the phone is data, not an instruction. Here is a tiny sketch of its shape, with generic names:
// Simplified sketch. data class Reply( val kind: String, // one of the kinds the form offered val name: String?, val values: Map<String, String>, // field id to what was typed ) The TV checks a reply against the form it showed, and the only thing it does with a valid one is put the values into that form. The form then goes through the same checks as if you had typed it, and the remote is what saves it.
Takeaways
If you build something like this for a device with a bad keyboard, the lessons are small. Skip the local-network page. Make the reply data that fills in a form you already trust. And keep the last decision on the device with the screen.


