Skip to content

Project Recap: Porting ISO Image Writer to QML

Monday, 15 September 2025  |  Akki ( @Holychicken )

tldr: ISO Image Writer ported to QML, allows automatic fetching of the latest ISOs, allows users to download directly from a URL and some more glitter

ISO Image Writer is a tool that allows users to flash image files onto their USB sticks. Previously, this tool was written with Qt Widgets, but as we shift away from this approach, a port was needed to convert the app to use QML instead.

Talk is cheap, show me the results

Main Screen

initial_ui_welcome

This is the main screen. Like the rest of the UI, it's gone through a lot of iterations:

initial_ui_welcome initial_ui_welcome

I found nailing the UI to be the hardest part. As a technical person, you focus on functionality—that's why UI/UX designer jobs exist in the first place. But in hindsight, I was just making excuses to avoid learning something new. UI goes much deeper than the colors or orientation; it's based on the psychology of users and how to make something that looks good (visceral design), works well (behavioral design), and makes users feel connected to the KDE philosophy (reflective design).

I spent a lot of time learning about what makes good design and would highly recommend reading this article. It covers the different levels of design and what makes a production-ready experience.

initial_ui_welcome

Users can also drop images directly onto the application window.

Automatic Image Selection

One requested feature was for users to select an ISO directly from the app, and the app takes care of downloading and flashing.

In the first iteration, I had a release.json file with hardcoded ISO-specific information:

{
    "ubuntu": {
        "name": "Ubuntu",
        "version": "25.04",
        "edition": "Desktop",
        "description": "Popular Linux distribution based on Debian, known for ease of use and strong community support",
        "url": "https://releases.ubuntu.com/25.04/ubuntu-25.04-desktop-amd64.iso",
        "hash": "f33e0828511732e73f32fb0a69a0305f6d729cf653b6a22f30691238d9755866",
        "hash_algo": "sha256"
    },
....

Users would select an ISO, the application would look at the URL → download it → verify the checksum → continue with flashing 🎉

There's an underlying problem with this approach: it relies on hardcoded URLs. For a distribution like Ubuntu, which releases new point releases (i.e., Ubuntu 24.04.1, 24.04.2, 24.04.3), this would mean our URLs drift out of sync quickly and would need constant checking. This isn't something that we want, so I decided to implement automatic fetching of ISOs.

Fetching logic

There's a new class in the project called releasefetch. Its job is to find and return the latest releases of the ISOs:

#define FEDORA_URL "https://fedoraproject.org//releases.json"
#define KUBUNTU_URL "https://cdimage.ubuntu.com/kubuntu/releases/"
#define KDENEON_URL "https://files.kde.org/neon/images/user/current/"

We have the above endpoints that contain information like the checksum and the link to the actual image.

  • Fedora makes it really easy with a single releases.json that we can parse and obtain the information from:
[
  {
    "version": "42",
    "arch": "aarch64",
    "link": "https://download.fedoraproject.org/pub/fedora/linux/releases/42/COSMIC-Atomic/aarch64/images/Fedora-COSMIC-Atomic-aarch64-42.1.1.ociarchive",
    "variant": "COSMIC-Atomic",
    "subvariant": "COSMIC-Atomic",
    "sha256": "c0e6fe4d3130a2ec3c8e1f4def67238c83c0a3a29c9134ee4ce34d6fbe9e4290",
    "size": "2368383488"
  },
  • Kubuntu, on the other hand, provides a rather simple webpage that we can scrape and obtain the information from:
<html><head>
  <title>Index of /kubuntu/releases</title>
 <body>
<h1>Index of /kubuntu/releases</h1>
<ul><li><a href="/kubuntu/"> Parent Directory</a></li>
<li><a href="16.04/"> 16.04/</a></li>
<li><a href="18.04.5/"> 18.04.5/</a></li>

Each list item points to the release page of that specific version.

  • KDE Neon has a special endpoint https://files.kde.org/neon/images/user/current/ that always contains the latest release, so we can just scrape information from that.

The releasefetch.cpp class contains functions and utilities to help parse this information and provide it to the QML frontend.

Credit where credit is due: I referenced quickemu/quickget to understand how we can query up-to-date information about these releases. Our pipeline could have been simplified by using distro-api, but unfortunately it's no longer maintained.

With this logic, the frontend queries for the latest releases every time we select the Automatic installation method and:

initial_ui_welcome

Select one of these distributions or provide a link to your own → select the USB and you are set:

initial_ui_welcome

The application will download the image and flash it all in one go:

initial_ui_welcome initial_ui_welcome

Miscellaneous

Here are some other improvements that didn't warrant a section of their own:

  • QML gives us a fileDialog type that opens up a file picker, but the problem is that it doesn't match the desktop theme sometimes. To fix this, I added a bridge that exposes QFileDialog from C++ to QML. The application looks much nicer now.

  • The class interface of usbdevicemodel, flashcontroller, and others had to be updated to work with QML. Also, flashcontroller had to be made non-blocking so that we can see the flashing progress.

RoadMap

There are some other things that I think would improve the application even more and some things that I couldn't get to:

  • Add more image listings

  • Add more checks throughout the codebase

    • Update the ISO fetching logic such that it also checks the checksum automatically (the functionality is already in place, just needs to be tested and tweaked)

Closing remarks

It feels good to have completed this task. I feel that with more people getting annoyed by Windows and their spyware, they are moving towards *nix (The year of Linux desktop soon??), and this tool will make the journey ever so smoother. I learned a lot—this is not a personal project and had to be treated that way. Learning how to follow design principles, writing pragmatic code, etc. Thanks again to my mentors Harald and Nate for the supervision and helping me make the right decisions. Thanks to all the people that emailed me their thoughts and helped me make more informed decisions. Google Summer of Code is over, but I hope to stick around and take my progress to an actual release, so wish me luck.

if you want to download the branch and test it out, I'd love to hear feedback from you. Branch

if you want to follow along with the discussions I had with the community, click here

Socials:

Website: Tcombinator.dev

E-mail: asa297@sfu.ca

Invent: @holychicken:matrix.org