Progress on Kube

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.

Kube Components

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.

Scrolling

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.

Problems include:

  • 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.

Focus visualization

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.

Keyboard navigation

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.

Translations

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.

Copyable labels

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).

Screenshot_20170819_232959

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.

Flatpak

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.

Randa

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/

Thanks!

Release of Kube 0.3.1

“Kube is a modern communication and collaboration client built with QtQuick on top of a high performance, low resource usage core. It provides online and offline access to all your mail, contacts, calendars, notes, todo’s and more. With a strong focus on usability, the team works with designers and UX experts from the ground up, to build a product that is not only visually appealing but also a joy to use.”

For more info, head over to: kube.kde.org

Kube 0.3.1 is out the door.

Over the past months we’ve been working hard on turning Kube into something more useful than a pure techpreview, and while Kube 0.3.1 still isn’t anywhere near production ready, I can finally say that I can use it for most of my email needs.

First, let’s get out of the way what doesn’t work just yet so you know what you can expect.

  • We don’t provide any upgrade path, so with every release it is necessary to run “sinksh upgrade” manually, which currently simply nukes all your local caches (but not the config, so you’ll just have to resync).
  • Email sending is limited to plaintext (we convert html mails to plaintext on reply).
  • Passwords are stored in plaintext in configuration files, which may not be acceptable to you.
  • It’s of course also possible that you will experience unpleasant surprises if you use it for any relevant emailing.
  • The scrolling experience depends a lot on your input devices. This seems to be a Qt internal defect that we hope will resolve itself with Qt 5.9.

What we do have though is:

  • A working composer that is right now very basic but has a lot of potential (more about that in a separate blogpost).
  • Support for reading encrypted and and signed mails (although the UI support is still very basic for details on validitiy etc).
  • A basic CardDAV based Addressbook.
  • A fairly pleasant reading experience (IMO anyways).

Lot’s of work also went into the application architecture, UI feedback for user interactions (e.g. progress during synchronization), cleanup of our dependency tree and the concept of how we will continue to evolve Kube.

The UI team did excellent work on the UI front (surprise!) and has cleaned up the look considerably. Due to the realization that our look depends a lot on the looks of the icon theme, we are now shipping an icon theme with Kube (based on breeze). This will also further our goal to work equally well on a variety of platforms where we cannot assume a specific icon theme to be available.

We have also transitioned mostly to QtQuickControls2, the remaining bits will require Qt 5.9. We’ll then plan on staying on this LTS release for the time being.

Overall, while not quite ready for prime time, this release marks a very important milestone on our road to a production ready release and I’m very happy to have a lot of issues, that have been bothering us for long, finally resolved.
I also think that while we’ll still have to do one or the other large change every now and then, the codebase can now start to settle as we have resolved our largest problems.

If you’d like to read more or give it a shot, please head over to kube.kde.org for installation instructions for experimental builds for Fedora 25 and Archlinux.

Tarballs

https://download.kde.org/unstable/sink/0.3.0/src/sink-0.3.0.tar.xz.mirrorlist
https://download.kde.org/unstable/kube/0.3.1/src/kube-0.3.1.tar.xz.mirrorlist

Randa

Unfortunately I can’t attend Akademy this year, but if you’d like to work on Kube, talk to us, have a Beer or just go for a hike, make sure to come to Randa for the annual Randa Meetings from the 10.09.2017 – 16.09.2017. To register click here.

Kube’s dependency situation is finally resolved

We’ve worked on this for the past two years and have finally reached an acceptable state where we don’t end up pulling in hundreds of packages.

While initial implementations of things like the email message parser and the DAV and IMAP library brought huge dependencies like KIO, DBus and even Akonadi (that would arguably have been resolvable on a packaging level, but… not a great situation anyways). With all that removed Kube now depends on ~75 packages less (the exact number will depend on factors such as your distros packaging), as well as drastically reducing it’s runtime entanglement (we no longer need dbus, klauncher, external KIO processes, …).

The new dependency situation looks approximately like this:

  • Qt: (We’ll bump that soon to 5.9 for some Qt Quick Controls2 improvements, and then plan on staying on this LTS release)
  • KIMAP2: Used for IMAP access, depending on KMime and Qt.
  • KDav2: Used for DAV access, depending on Qt.
  • KAsync: A pure Qt library that is extensively used in Sink.
  • KMime: Used for mailparsing, depending on Qt.
  • KContacts: Used for parsing VCard, depending on Qt.
  • lmdb: Our key value-store that is a simple C library.
  • flatbuffers: Also part of our storage and a simple self-contained C++ library.
  • QGpgme: Part of gpgme, used for crypto stuff.
  • KCodecs: A tier1 framework used for some parsing tasks.
  • KPackage: A tier2 framework for packaging qml.
  • KCoreAddons: A tier1 framework that we need for KJob.
  • libcurl: Currently used for its SMTP implementation.

And that’s about it. This means we’re now in a situation where each and every dependency that we have is justified and there for a reason. We’re also in a position where most dependencies can be individually replaced should there be a need to so.
This not only makes me much more confident that we can maintain this system in the long run and makes porting to other platforms feasible, it’s also just a much, much healthier situation to be in for a software project.

In case you are wondering, here’s an incomplete list of packages that we used to depend on and no longer do (based on Fedora 25 packaging, check out rpmreaper to recursively query dependencies):

 grantlee-qt5
 kdepim-apps-libs
 kf5-akonadi-contacts
 kf5-akonadi-mime
 kf5-akonadi-search
 kf5-akonadi-server
 kf5-akonadi-server-mysql
 kf5-grantleetheme
 kf5-kauth
 kf5-kbookmarks
 kf5-kcalendarcore
 kf5-kcompletion
 kf5-kconfig-gui
 kf5-kconfigwidgets
 kf5-kdbusaddons
 kf5-kded
 kf5-kdelibs4support
 kf5-kdelibs4support-libs
 kf5-kdoctools
 kf5-kemoticons
 kf5-kiconthemes
 kf5-kidentitymanagement
 kf5-kimap
 kf5-kinit
 kf5-kio-file-widgets
 kf5-kitemmodels
 kf5-kldap
 kf5-kmailtransport
 kf5-kmbox
 kf5-knewstuff
 kf5-knotifications
 kf5-kparts
 kf5-kpimtextedit
 kf5-krunner
 kf5-kservice
 kf5-ktextwidgets
 kf5-kunitconversion
 kf5-kwallet-libs
 kf5-kwidgetsaddons
 kf5-kwindowsystem
 kf5-kxmlgui
 kf5-libgravatar
 kf5-libkdepim
 kf5-libkleo
 kf5-messagelib
 kf5-pimcommon
 kf5-solid-libs
 kf5-sonnet-ui
 kf5-syntax-highlighting
 kf5-threadweaver
 libaio
 libical
 libsphinxclient
 lsof
 m4
 mariadb
 mariadb-common
 mariadb-config
 mariadb-errmsg
 mariadb-libs
 mariadb-server
 mariadb-server-utils
 net-tools
 perl-DBD-MySQL
 perl-DBI
 perl-Math-BigInt
 perl-Math-Complex
 perl-Storable
 postgresql-libs
 qt5-qtbase-mysql
 rsync
 sphinx

Kube: Views and Workflows

“Kube is a modern communication and collaboration client built with QtQuick on top of a high performance, low resource usage core. It provides online and offline access to all your mail, contacts, calendars, notes, todo’s and more. With a strong focus on usability, the team works with designers and UX experts from the ground up, to build a product that is not only visually appealing but also a joy to use.”

For more info, head over to: kube.kde.org

Ever since we started working on Kube we faced the conundrum of how to allow Kube to innovate and to provide actual additional value to whatever is already existing out there, while not ending up being a completely theoretical exercise of what could be done, but doesn’t really work in practice. In other words, we want to solve actual problems, but do so in “better” ways than what’s already out there, because otherwise, why bother?

I put “better” into quotes because this is of course subjective, but let me elaborate a bit on what I mean by that.

Traditionally, communication and organization has been dealt with using fairly disjoint tools, that we as users then combine in whatever arbitrary fashion that is useful to us.

For instance:

  • EMail
  • Chat
  • Voice/Video Chat
  • Calendaring
  • Taskmanagement
  • Notetaking

However, these are just tools that may help us work towards a goal, but often don’t support us directly in what we’re actually trying to accomplish.

My goto example; Jane wants to have a meeting with Jim and Bob:

  • Jane tries to find a timeslot that works for all of them (by mail, phone, personally…)
  • She then creates an event in her calendar and invites Jim and Bob, who can in turn accept or decline (scheduling)
  • The meeting will probably have an Agenda that is perhaps distributed over email, or within the event description
  • A meeting room might need to be booked, or an online service might need to be decided.
  • Once the meeting takes place the agenda needs to be followed and notes need to be taken.
  • Meeting minutes and some actionable items come out of the meeting, that then, depending on the type of meeting, may need to be approved by all participants.
  • So finally the approved meeting minutes are distributed and the actionable items are assigned, and perhaps the whole thing is archived somewhere for posterity.

As you can see, a seemingly simple task can actually become a fairly complex workflow, and while we do have a toolbox that helps with some of those steps, nothing really ties the whole thing together.

And that’s precisely where I think we can improve.

Instead of trying to do yet another IMAP client, or yet another calendaring application a far more interesting aspect is how can we improve our workflows, whatever tools that might involve.
Will that involve some email, and some calendaring and some notetaking? Probably, but it’s just a means to and end and not an end by itself.

So if we think about the meeting scheduling workflow there is a variety of ways how we can support Jane:

  • The scheduling can be supported by:
    • Traditional iCal based scheduling
    • An email message to invite someone by text.
    • Some external service like doodle.com
  • The agenda can be structured as a todo-list that you can check off during the meeting (perhaps with time limits assigend for each agenda item)
  • An online meeting space can be integrated, directly offering the agenda and collaborative note-taking.
  • The distribution and approval of meeting minutes can be automated, resulting in a timeline of past meetings, including meeting minutes and actionable items (tasks) that fell out of it.

That means however that rather than building disjoint views for email, calendar and chat, perhaps we would help Jane more if we built and actual UI for that specific purpose, and other UI’s for other purposes.

Views

So in an ideal world we’d have an ideal tool for every task the user ever has to execute which would mean we fully understand each individual user and all his responsibilities and favorite workflows….
Probably not going to happen anytime soon.

While there are absolutely reachable goals like Jane’s meeting workflow above, they all come at significant implementation cost and we can’t hope to implement enough of them right off the bat in adequate quality.
What we can do however is keeping that mindset of building workflows rather than IMAP/iCal/… clients and setting a target somewhere far off on the horizon and try to build useful stuff along the way.

For us that means that we’ve now set the basic structure of Kube as a set of “Views” that are used as containers for those workflows.

KubeViewSwitcher

This is a purposefully loose concept that will allow us to transition gradually from fairly traditional and generic views to more purposeful and specific views because we can introduce new views and phase out old ones, once their purpose is helped better by a more specific view.

Some of our initial view ideas are drafted up here: https://phabricator.kde.org/T6029

What we’re starting out with is this:

  • A Conversations view:
    While this initially is a fairly standard email view, it will eventually become a conversation centric view where you can follow and pick up on ongoing conversations no matter on what medium (email, chat, …).

kube_mailview

  • A People view:
    While also serving the purpose of an addressbook it is first and foremost a people centric way to interact with Kube.
    Perhaps you just want to start a conversation that way, or perhaps you want to lookup past interactions you had with the person.

kube_addressbook

  • A composer view:
    Initially a fairly standard email composer but eventually this will be much more about content creation and less about email specifically.
    The idea is that what you actually want to do if you’re opening the composer is to write some content. Perhaps this content will end up as email,
    or perhaps it will just end up on a note that will eventually be turned into a blogpost, chances are you don’t even know before you’re done writing.
    This is why the composer implements a workflow that starts with the starting point (your drafts) then goes over to the actual composer to create the content, and finally allows you to do something with the content, i.e. publish or store it somewhere (for now that only supports sending it by email or saving it as draft, but a note/blog/… could be equally viable goals).

The idea of all this is that we can initially build fairly standard and battle-tested layouts and over time work our way towards more specialized, better solutions. It also allows us to offload some perhaps necessary, but not central features to a secondary view, keeping us from having to stuff all available features into the single “email” view, and allowing us to specialize the views for the usecases they’re built for.

Kube::Fabric

“Kube is a modern communication and collaboration client built with QtQuick on top of a high performance, low resource usage core. It provides online and offline access to all your mail, contacts, calendars, notes, todo’s and more. With a strong focus on usability, the team works with designers and UX experts from the ground up, to build a product that is not only visually appealing but also a joy to use.”

For more info, head over to: kube.kde.org

One of the key features of QML is to be able to describe the UI in a declarative fashion, resulting in code that closely represents the visual hierarchy.
This is nice for writing UI’s because you can think very visually and then just turn that into code.
A couple of trial and error cycles later you typically end up with a result that reflects approximately what you sketched out on paper.

However, interactions with the UI are also handled from QML, and this is where this becomes problematic. User interactions with QML result in some signals or API calls on some component, typically some signal handler, and that’s where your application code takes over and tries to do something useful with that interaction. Perhaps we trigger some visual change, or we call a function on a controller object that does further work. Because we try to encapsulate and build interfaces we might build an API for the complete component that can then be used by the users of the component to further interact with the system.
This can quickly get complex with a growing number of interactions and components.

The straightforward implementation is to just forward the necessary API through your components, but that creates a lot of friction in the development process. A simple move of a button may result in drastic changes where that button is within the visual hierarchy, and if we have to forward the API for that we end up writing a lot of boilerplate code for what ought to be a trivial change.

Item {
    id: root
    property signal reply
    Button {
        onClicked: root.reply()
    }
}

One alternative approach is to abuse the QML Context to avoid forwarding the API (so we just call to some magic component id), but this results in components that are not self-contained and that just call to some magic “singleton” objects to communicate with the rest of the application.
Not great in my opinion.

Item {
    id: root
    Button {
        onClicked: applicationController.reply() //Let's hope applicationController is defined somewhere
    }
}

The approach we’ve chosen in Kube is to introduce a mechanism that is orthogonal to the visual hierarchy. Kube::Fabric is a simple messagebus where messages can be published and subscribed to. A clicked button may for instance post a message to the bus that is called “Kube.Messages.reply”. This message may then be handled by any component listening on the messagebus. Case in point; the main component has a handler that will open a composer and fill it with the quoted message so you can fill in your reply.

So the “Fabric” creates a separate communication plane that “weaves” the various UI components together into something functional. It allows us to concentrate on the user experience when working on the UI without having to worry how we can eventually wire up the component to the other bits required (and it gives us an explicit point where we interconnect parts over the fabric), and thus allows us to write cleaner code while moving faster.

Item {
    id: root
    Button {
        onClicked: Kube.Fabric.postMessage(Kube.Messages.reply, {"mail": model.mail, "isDraft": model.draft})
    }
}

API vs. Protocols

The API approach tightly couples components together and eventually leads to situations where we i.e. have multiple versions of the same API call because we’re dealing with some new requirements but we have to maintain compatibility for existing users of the API. This problem is then further amplified by duplicating API’s throughout the visual hierarchy.

The Fabric rather builds a protocol approach. The fabric becomes the transport layer, the messages posted form the protocol. While the messages form the contract and thus also require that no parameter is removed or changed, they can be expanded without affecting existing users of the message.
New parameters don’t bother any existing users and thus allow for much more flexibility with little (development) overhead.

Other applications

Another part where we started to use the fabric extensively is for notifications. A component that listens for notifications from Sink (Error/Progress/Status/…), simply feeds those notifications into the fabric, allowing various UI components to react to those notifications as a appropriate. This approach allows us to feed notifications from a variety of sources into the system, so they can be dealt with in a uniform way.

Code

In actual code it is used like this.

Posting a message from QML:

 Kube.Fabric.postMessage(Kube.Messages.reply, {"mail": model.mail, "isDraft": model.draft})

Posting a message from C++ (message being a QVariantMap):

Fabric::Fabric{}.postMessage("errorNotification", message);

Listening for messages in QML:

Kube.Listener {
    filter: Kube.Messages.reply
    onMessageReceived: kubeViews.openComposerWithMail(message.mail, false)
}

Lookout

The fabric is right now rather simplistic and we’ll keep it that way until we see actual requirements for more. However, I think there is interesting potential in separating message-buses by assigning different fabrics to different components, with a parent fabric to hold everything together. This would enable components to first handle a message locally before resorting to a parent fabric if necessary. For the reply button that could mean spawning an inline-reply editor instead of switching the whole application state into compose mode.

Release of Kube 0.1.0

It’s finally done! Kube 0.1.0 is out the door.

First off, this is a tech preview really and not meant for production use.

However, this marks a very important step for us, as it lifts us out of a rather long stretch of doing the ground work to get regular development up and running. With that out of the way we can now move in a steadier fashion, milestone by milestone.

That said, it’s also the perfect time to get involved!
We’re planning our milestones on phabricator, at least the ones within reach, so that’s the place to follow development along and where you can contribute, be it with ideas, feedback, packaging, builds on new platforms or, last but not least, code.

So what is there yet?

You can setup an IMAP account, you can read your mail (even encrypted), you can move messages around or delete them, and you can even write some mails.

kube_main

BUT there are of course a lot of missing bits:

  • GMail support is not great (it needs some extra treatment because GMail IMAP doesn’t really behave like IMAP), so you’ll see some duplicated messages.
  • We don’t offer an upgrade path between versions yet. You’ll have to nuke your local cache from time to time and resync.
  • User feedback in the UI is limited.
  • A lot of commonly expected functions are not existing yet.
  • ….

As you see… tech preview =)

What’s next?

We’ll focus on getting a solid mail client together first, so that’s what the next few milestones are all about.

The next milestone will focus on getting an addressbook ready, and after that we’ll focus on search for a bit.

I hope we can scope the milestones approximately ~1 month, but we’ll have to see how well that works. In any case releases will be done only once the milestone is reached, and if that takes a little longer, so be it.

Packaging

This also marks the point where it starts to make sense to package Kube.
I’ve built some packages on copr already which might help packagers as a start. I’ll also maintain a .spec file in the dist/ subdirectory for the kube and sink repositories (that you are welcome to use).

Please note that the codebase is not yet prepared for translations, so please wait with any translation efforts (of course patches to get translation going are very welcome).

In order to release Kube a couple of other dependencies are released with it (see also their separate release announcements):

  • sink-0.1.0: Being the heart of Kube, it will also see regular releases in the near future.
  • kimap2-0.1.0: The brushed up imap library that we use in sink.
  • kasync-0.1.0: Heavily used in sink for writing asynchronous code.

Tarballs

Kube: Accounts

Kube is a next generation communication and collaboration client, built with QtQuick on top of a high performance, low resource usage core called Sink.
It provides online and offline access to all your mail, contacts, calendars, notes, todo’s etc.
Kube has a strong focus on usability and the team works with designers and Ux experts from the ground up, to build a product that is not only visually appealing but also a joy to use.

To learn more about Kube, please see here.

Kube’s Account System

Data ownership

Kube is a network application at its core. That doesn’t mean you can’t use it without network (even permanently), but you’d severely limit its capabilities given that it’s meant to be a communication and collaboration tool.

Since network communication typically happens over a variety of services where you have a personal account, an account provides a good starting point for our domain model. If you have a system with large amounts of data that are constantly changing it’s vital to have a clear understanding of data ownership within the system. In Kube, this is always an account.

By putting the account front and center we ensure that we don’t have any data that just belongs to the system as a whole. This is important because it becomes very complex to work with data that “belongs to everyone” once we try to synchronize that data with various backends. If we modify a dataset should that replicate to all copies of it? What if one backend already deleted that record? Would that mean we also have to remove it from the other services?
And what if we have a second client that has a different set of account connected?
If we ensure that we always only have a single owner, we can avoid all those issues and build a more reliable and predictable system.

The various views can of course still correlate data across accounts where useful, e.g. to show a single person entry instead of one contact per addressbook, but they then also have to make sure that it is clear what happens if you go and modfiy e.g. the address of that person (Do we modify all copies in all accounts? What happens if one copy goes out of sync again because you used the webinterface?).

Last but not least we ensure this way that we have a clear path to synchronize all data to a backend eventually, even if we can’t do so immediately. E.g. because the backend in use does not support that data type yet.

The only bit of data that is stored outside of the account is data specific to the device in use, such as configuration data for the application itself. Data that isn’t hard to recreate, is easy to migrate and backup, and very little data in the first place.

Account backends

Most services provide you with a variety of data for an individual account. Whether you use Kolabnow, Google or a set of local Maildirs and ICal files,
you typically have access to Contact, Mails, Events, Todos and many more. Fortunately most services provide access to most data through open protocols,
but unfortunately we often end up in a situation where we need a variety of protocols to get to all data.

Within Sink we call each backend a “Resource”. A resource typically has a process to synchronize data to an offline cache, and then makes that data accessible through a standardized interface. This ensures that even if one resource synchronizes email over IMAP and another just gathers it from a local Maildir,
the data is accessible to the application through the same interface.

Because various accounts use various combinations of protocols, accounts can mix and match various resources to provide access to all data they have.
A Kolab account for instance, could combine an IMAP resource for email, a CALDAV resource for calendars and CARDDAV resource for contacts, plus any additional resources for instant messaging, notes, … you get the idea. Alternatively we could decide to get to all data over JMAP (a potential IMAP successor with support for more datatypes than just email) and thus implement a JMAP resource instead (which again could be reused by other accounts with the same requirements).

diagram

 

Specialized accounts

While accounts within Sink are mostly an assembly of some resources with some extra configuration, on the Kube side a QML plugin is used (we’re using KPackage for that) to define the configuration UI for the account. Because accounts are ideally just an assembly of a couple of existing Sink resources with a QML file to define the configuration UI, it becomes very cheap to create account plugins specific to a service. So while a generic IMAP account settings page could look like this:

imapaccount

… a Kolabnow setup page could look like this (and this already includes the setup of all resources including IMAP, CALDAV, CARDDAV, etc.):

kolabaccount

Because we can build all we know about the service directly into that UI, the user is optimally supported and all that is left ideally, are the credentials.

Conclusion

In the end the aim of this setup is that a user first starting Kube selects the service(s) he uses, enters his credentials and he’s good to go.
In a corporate setup, login and service can of course be preconfigured, so all that is left is whatever is used for authentication (such as a password).

By ensuring all data lives under the account we ensure no data ends up in limbo with unclear ownership, so all your devices have the same dataset available, and connecting a new devices is a matter of entering credentials.

This also helps simplifying backup, migration and various deployment scenarios.