A lot has happened since the last release, so let me bring you up to speed on what is cooking for the 0.4 release.
We’ve been mostly focusing on ironing out UX problems all over the place. It turns out, when writing desktop applications using QtQuick you’ll be ending up with a lot of details to figure out for yourself.
We noticed that we end up modifying most components (buttons, listviews, treeviews, ….), so we ended up “subclassing” (as far as that exists in QML), most components. In some cases this is just to consistently set some default options which we would otherwise have to duplicate, in some cases it’s about styling where we have to replace default styling either for pure visual reasons (to make it pretty), or for additional functionality (proper focus indicators).
In some cases it’s even behavioral as in the scrolling case you’ll see later on.
In any case, it’s very well worth it to create your own components as soon as you realize you can’t live with the defaults (or rely on the defaults of a framework like Kirigami), because you’ll have a much easier time at maintaining consistency, improving existing components and generally just end up with much cleaner code.
One of the first issues to tackle was the scrolling behavior. Scrolling is mostly implemented in Flickable, though i.e. QtQuick.Controls.ScrollView overrides it’s behavior to provide a more desktopy scroll feeling. The problem is indeed that Flickables flicking behavior is absolutely unusable on a desktop system. It depends a lot on your input devices, with some high-precision trackpads it apparently ends up doing alright, but in general it’s just designed for touch interaction.
- Way to fast scrolling speed.
- The flicking is way to long and only stoppable by scrolling in the opposite direction (at least with my trackpad and mouse).
- Difficulties in fine positioning e.g. a listview, scrolling is generally already too fast and sometimes the view just dashes off.
These problems are unfortunately not solvable by somehow configuring the Flickable (Believe me, I’ve tried), so what we ended up doing is
overriding its behavior. This is done using a MouseArea that we overlay with the flickable (ScrollHelper.qml) and then manually control the scrolling position.
This is a very similar approach to what also QtQuick.Controls.ScrollView does and what Kirigami does as well for some of its components.
It’s not perfect and apparently doesn’t yet play nicely with some mice as the fine tuning is difficult with various input devices. There is a variety of high/low precision devices, some of which give pixel deltas (so absolute positioning), and some of them give angle deltas (which are some sort of ticks), and some of them of course give both and don’t tell you which to use. What seems to work best is trying to calculate both into absolute pixel deltas and then just use either of the values (preferably the pixel delta one it seems). This will give you about the behavior you get in e.g. a browser, so that works IMO nicely.
For most components this was fortunately easy to add since we already had custom components for them, so we could just add the ScrollHelper there.
For others like the TreeView it was a bit more involved. The reason is that the TreeView itself is already a ScrollView, which not only implements a different scrolling behavior, but also brings its own scrollbars which look different from what we’re using everywhere else. The solution ended up being to wrap it with another Flickable so we can use our usual approach. Not pretty, but the fewer components we have that implement the same thing yet again in a different way the better.
As I started to look into keyboard navigation the first thing I noticed was that the focus visualization was severely lacking. If you move around in the UI by keyboard only you always need to be able to follow the currently focused item, but many of our components didn’t differentiate between having keyboard focus or being selected and sometimes lacked a focus visualization altogether. The result was that the focus would randomly vanish as you for instance focused an already selected element in a listview, or you couldn’t differentiate if you have now moved the focus to another list-item or already selected it.
The result of it all is a highlighting scheme that we have now applied fairly consistently:
- We have a highlight for selected items
- We have a lighter highlight for focus
- …and we draw a border around items that have focus but are somehow not suitable for the light highlight. This is typically either because it’s i.e. text content (where a highlight would be distracting), or because it’s an item that is already selected (highlight over highlight doesn’t really work).
Once again we were only able to implement this because we had the necessary components in place.
Next up came keyboard navigation. I already took a couple of stabs at this, so I was determined to solve this for good this time. Alas, it wasn’t exactly trivial. The most important thing to remember is that you will need a lot of FocusScopes. FocusScopes are used to componentize the UI into focusable areas that can then have focusable subareas and so on. This allows your custom built component that typically consists of a couple of items to deal with focus in it’s own little domain, without worrying about the rest of the application. It’s quite a bit of manual work with a lot of experimenting, so it’s best done early in the development process.
The rest is then about juggling the focus and focusOnTab properties to direct the focus to the correct places.
Of course arrow-key navigation still needs to be implemented separately, which is done for all list- and treeviews.
The result of this is that it’s now possible to completely (I think?) navigate kube by keyboard.
There are some rough edges like the webview stealing the focus every time it loads something (something we can only fix with Qt 5.9, which is taking it’s sweet time to become available on my distro), and there is work to be done on shortcuts, but the basics are in place now.
While at it working on accessibility stuff we figured it’s about time we prepare translations as well. We’ll be using Qt based translations because it seems to be good enough and the QML integration of ki18n comes with some unwelcome dependencies. Nothing unsolvable of course but the mantra is definitely not to have dependencies that we don’t know what for.
Anyways, Michael went through the codebase and converted all strings to translatable, and we have a Messages.sh script, so that should be pretty much good to go now. I don’t think we’ll have translations for 0.4 already, but it’s good to have the infrastructure in place.
Another interesting little challenge was when we noticed that it’s sometimes convenient to copy some text you see on your screen. It’s actually pretty annoying if you have to manually type off the address you just looked up in the address book. However, if you’re just using QtQuick.Controls2.Label, that’s exactly what you’re going to have to do.
Cursor based selection, as we’re used to from most desktop applications, has a couple of challenges.
- If you have to implement that cursor/selection stuff yourself it’s actually rather complicated.
- The text you want to copy is more often than not distributed over a couple of labels that are somehow positioned relative to each other, which makes implementing cursor based selection even more complicated.
- Because you’re copying visually randomly distributed labels and end up with a single blob of text it’s not trivial to turn that into usable plaintext. We all know the moment you paste something from a website into a text document and it just ends up being an unrecognizable mess.
- Cursor based selection is not going to be great with touch interaction (which we’ll want eventually).
The solution we settled for instead is that of selectable items. In essence a selectable item is a manual grouping of a couple of labels that can be copied as once using a shortcut or a context menu action. This allows the programmer to prepare useful chunks of copyable information (say an address in an addressbook), and allows him to make sure it also ends up in a sane formatting, no matter how it’s displayed in the view itself.
The downside of this is of course that you can no longer just copy random bits of a text you see, it’s all or nothing. But since you’re going to paste it into a text editor anyways that shouldn’t be a big deal. The benefit of it, and I think this is a genuine improvement, is that you can just quickly copy something and you always get the same result, and you don’t have to deal with finicky cursor positions that just missed that one letter again.
The flatpak now actually works! Still not perfect (you need to use –devel), but try for yourself: Instructions
Thanks to Aleix Pol we should have nightly builds available as well =)
Other changes include:
- The threading index now merges subthreads once all messages become available. This is necessary to correctly build the threading index if messages are not delivered in order (so there is a missing link between messages). Because we build a persistent threading index when receiving the messages (so we can avoid doing that in memory on every load), we have to detect that case and merge the two subthreads that exist before the missing link becomes available.
- The conversation view was ported away from QtQuick’s ListView. The ListView was only usable with non-uniformly sized items through a couple of hacks and never played well with positioning at the last mail in the conversation. We’re now using a custom solution based on a Flickable + Column + Repeater, which works much better. This means we’re always rendering all mails in a thread, but we had to do that before anyways (otherwise scrolling became impossible), and we could also improve it with the new solution by only rendering currently visible mails (at the cost of loosing an accurate scrollbar).
- The email parsing was moved into it’s own threads. Gpgme is dead slow, so (email-)threads containing signatures would visibly stutter (Without signature the parsing is ~1ms, with ~150ms. With encryption we can easily go up to ~1s). With the new code this no longer blocks the view and multiple mails are parsed in parallel, which makes it nice and snappy.
- Lot’s of cleanup and porting to QtQuick.Controls2.
- Lot’s of fixes big and small.
It’s been a busy couple of weeks.
The annual Randa meeting is coming up and it needs your support! Randa will give us another week of concentrated effort to work on Kube’s keyboard navigation, translation and other interaction issues we still have. Those sprints are very valuable for us, and are in dire need of support to finance the whole endavour, so any help would be more than welcome: https://www.kde.org/fundraisers/randameetings2017/