Skip to content

Monday, 29 July 2024

So after filtering out tiny movements and duplicate outputs, the thing left is to look at small corner inputs. Here's the three pointer that I'm working on in kis_tool_freehand:paint: ( Lets say the scenario is that we are drawing a straight line from left to right) We start at point(0,0) Right now there is no last drawn pixel, just a current pixel and a waiting pixel that is set to the current pixel . If there is another doStroke or mouse release we just draw this pixel. (basically always draw this pixel) Try to imagine that the waiting pixel is basically the current pixel that performs the drawing, but always slightly lags behind.

We moved the cursor to (0,1) That last waiting pixel of the last iteration is drawn, and becomes last drawn pixel. Now we are at point(0,1) where both the current pixel and waiting pixel is. Now we wait for the next doStroke or mouse up. Here is where basically nothing happens just waiting on another point to see if we are allowed to draw this waiting pixel.

two scenarios here: We moved the cursor to (0,2) from (0,1) 1.) If the NEXT currentpixel is still in the same x or y axis as the last drawn pixel, the waiting pixel is drawn and we reset waiting pixel = currentpixel.

We moved the cursor to (1,1) instead from (0,1) 2.) If the NEXT currentpixel is NOT in the same x or y axis as the the last drawn pixel, the waiting pixel is not drawn and we reset waiting pixel = currentpixel.

Now we are at (1,1) and we can practically restart from the start again. There is "no last drawn pixel", and we just draw at (1,1) and then apply the rest again (waiting for the next pixel, checking if its in a line. If so draw it, if not update waiting pixel without drawing and then restart again.)

A few problem that has come up is that, compared to other programs with pixel-perfect, this doesn't seem to proactively draw at the same time AND reactively get rid of the corner ( when you draw a straight line, the corner pixel does seem to pop up UNTIL you input a third non-striaghtline pixel, in which the last pixel in the previous line disappears ). I was wondering if there is a way that I can erase reactively like this as well, or maybe calling draw on m_d->previousPaintInformation with the previous color. The other problem I'm dealing with is the initialization of these Qpoints might be a little flawed because, depending on the stroke speed or the type of stroke, since at paint we might completely skip some pixels. I also need to work on some sub-pixel inaccuracies, probably by getting rid of floats.

This is a very exciting month if you’re waiting for more artist-oriented improvements in the Wayland session!

Plasma

[Feature] Pen calibration is merged! If you have the time and supported hardware, try it out in Neon Unstable and see if the math needs tweaking. I also begun adding tests for this calibration tool. [6.2] [NLnet]

The finalized calibration screen.

[Feature] You can now bind mouse buttons (with modifier keys) to tablet pen or pad buttons, or disable them entirely! [6.2] [NLnet]

A long-awaited feature in the Wayland session!

[Bugfix] Fixed the pen tester ahead of it breaking in Qt 6.8 since tablet pens can drag the window. [6.2]

[Feature] Mention that setting the orientation is not supported, on hardware where it isn’t. Some people have already commented we can do even better than this, so I plan on tackling that next month. [6.2]

What the combo box looks like now, on unsupported hardware.

[Bugfix] Disable the tablet tester when no tablets are connected. This is because the tablet tester only responds to pen input, so it’s useless without any. [6.2]

KWin

[Feature] Support disabling buttons in the rebind filter. [6.2] [NLnet]

[Feature] Support pressing keyboard modifiers alongside mouse buttons. [6.2] [NLnet]

[Feature] Set the mouse cursor position when rebinding tablet buttons to mouse buttons. This is to fix odd situations where you have a tablet button bound to right-click, and context menus open in the wrong place. [6.2] [NLnet]

[Testing] Added more test coverage for the ButtonRebindFilter. [NLnet]

NeoChat

[Feature] Add an option to block invites from users who you may not know, to help users being spammed by bad actors on Matrix. This is could also be useful if you’re only using your Matrix account to communicate with friends & family. [24.08]

The option to toggle this new safety feature.

[Bugfix] Try not to display ghost notifications for invites. This is meant to be an addition to the above feature, to prevent users from being spammed. [24.08]

[Bugfix] Don’t mark invite notifications as persistent. This is also meant to cut down on the possible notification spam. This is especially important on KDE Plasma Desktop which doesn’t handle notification spam well at all, at the moment. [24.08]

[Feature] Made the ignored list look better when you have no one in it. [24.11]

[Feature] Cleaned up the account editor page and also add some icons to break up how text-heavy it is here. [24.11]

[Feature] Added a “Show QR code” button to the account menu so you don’t have to dig into the settings to find this. [24.11]

[Feature] Suggest what to do on the empty welcome screen. [24.11]

Tokodon

[Feature] Added an option to open the pop-out status composer by default. [24.08]

[Feature] Allow pasting images directly from the Internet and just make pasting images all-around better. [24.08]

[Bugfix] Silently fail when servers don’t implement featured tags on profiles. This is common for lots of non-Mastodon servers. [24.08]

PlasmaTube

[Feature] Added basic support for SponsorBlock which is turned off by default, but you can enable under Settings. You can’t configure which server to use (it’s possible, just not through the UI) or what specific categories to block yet. You do have the option to have PlasmaTube inform you when you’re inside of a sponsored segment or have it auto-skip. [24.08]

[Feature] Added a proper error page to the video player while my Invidious server is borked due to YouTube changes. It will display the error given by Invidious, and also a button to open the original webpage. [24.11]

Note that there’s a link in there, but even on Invidious it’s unclickable.

That’s all for this month!

Sunday, 28 July 2024

Miscellaneous improvements

After my gargantuan post around the overhauled navigation gestures (and a still-in-progress one about KWin corner touch gesture support I'll hopefully have ready soon:tm:) let's tackle a few more smaller things. I'll try to make these somewhat regular (dare I say maybe even monthly?), but let's see how that shakes out, probably more like every 2-3 months if at all.

As an exciting update, near the end of June (the 25th to be exact) I got accepted to the KDE dev team. This means I now have the ability to properly manage submitted issues on GitLab and, only slightly terrifyingly, I'm now allowed to push code changes to the main repositories and review MRs. Let's see when, if ever, this feeling of trepidation over having to make quadruple sure I don't accidentally do stupid stuff subsides. Should it even subside or is being very extra super duper careful a good thing. I'll keep you posted whenever I find an answer to that :D

Anyways, let's get to code changes:

Merged Changes

Task Switcher/Gesture Navigation

  • I sat down and overhauled some of the animations around the navigation gestures of the mobile task switcher: The diagonal quick switch should now look smoother and not be nearly-instantaneous and the flick to homescreen is now a tad smoother and actually makes the task preview smaller while animating instead of looking like it's opening the selected task before suddenly vanishing.
  • Fixed minor logic bug around task switcher quick switch gesture. It should now correctly open the task switcher when you're trying to quick switch towards the end of a list - if there's nothing to quick switch to, it's better to open the full task switcher instead of just returning to the app you were in before.
  • I added a task icon list to the task scrub gesture in the switcher to make it visually more distinct to the "normal" task switcher and provide more useful info about the open apps you can switch to. In case you didn't know: In gesture-only mode w (I'll admit this one is a bit older, but this is the first installment of this kind of post so I'm not tooooo strict on the "in July" part): I'm still tracking an issue with this where when the task list becomes too long it's not properly centered anymore, but that should be a fairly simple fix once I get to it.
  • The main task switcher opening gesture now stops tracking the finger 1:1 in the vertical direction once it's moved a bit past its "fully activated" point. This is a bit awkward to explain, but basically it makes it "more reluctant" to follow the finger infinitely far up. If that still doesn't make sense, here's a video:
  • The task switcher gestures now have a haptic feedback in some places: When the conditions are met for the task switcher to open (eg: gesture progress is far enough and finger movement speed is slow enough) and when the task scrub mode starts there'll now be a bit of haptic feedback.

Misc

I've done some bug triaging and reproduction here and there, as well as tried to keep up to date on merge requests in the Plasma Mobile world. I still haven't really done a proper review and merge, but I'm trying to look through all of the other ones to hopefully learn how good reviews look like so at some point I'll be able to do them.

Unfinished

  • I tried my hand at fixing the task switcher navigation gestures being always active instead of just when the gesture navigation mode is actually turned on. To do this properly we probably need to refactor the mobileshellsettings plugin to be accessible via C++ (it's just a QML plugin currently), so let's see how that goes.
  • I started work on more mobile friendly notification popups. The new design uses a swipe-to-dismiss interaction instead of having a close button. While technically "working" from a functionality perspective, the visuals are kind of broken still. I hope to have this complete by 6.2, but there's still some open questions. I'll probably have to get in touch with more experienced Plasma devs to brainstorm why this is going wrong so badly, but I've not quite given up at bashing my head against this myself. Oh and before I forget: this also affects Plasma Desktop when in Touch/Tablet Mode.

Upcoming

For the next month I wanna try and finish up my work on KWin touch corner gestures (and get another oversized blog post out about those) and then implement them into Plasma Mobile. Once that is done I want to do more bug fixing, triaging and looking at knocking out some tickets for planned bigger picture improvements for 6.2. Let's see next month if a) I get any of this done or b) I even manage to make a blog post since I'll not be home for a while

Saturday, 27 July 2024

Future 聊天室

功能

账号管理

  • 实现登录、注册、注销
  • 实现找回密码(提高)

好友管理

  • 实现好友的添加、删除、查询操作
  • 实现显示好友在线状态
  • 禁止不存在好友关系的用户间的私聊
  • 实现屏蔽好友消息
  • 实现好友间聊天

群管理

  • 实现群组的创建、解散
  • 实现用户申请加入群组
  • 实现用户查看已加入的群组
  • 实现群组成员退出已加入的群组
  • 实现群组成员查看群组成员列表
  • 实现群主对群组管理员的添加和删除
  • 实现群组管理员批准用户加入群组
  • 实现群组管理员/群主从群组中移除用户
  • 实现群组内聊天功能

聊天功能

  • 实现查看历史消息记录
  • 实现用户间在线聊天
  • 实现在线用户对离线用户发送消息,离线用户上线后获得通知
  • 实现在线发送文件
  • 实现在线用户对离线用户发送文件,离线用户上线后获得通知/接收
  • 实现后台发送文件
  • 实现用户在线时,消息的实时通知
    • 收到好友请求
    • 收到私聊
    • 收到加群申请

其他

  • 使用 C++编程语言
  • 使用 I/O 多路复用完成本项目
    • C++:Epoll ET 模式
  • 使用数据库完成数据存储
    • Redis 和 mysql
    • 历史消息采用redis做告诉缓存,mysql来存储大量历史消息
  • 数据库中数据的存储和取用使用序列化和反序列化完成(Json)
  • 支持大量客户端同时访问
  • 实现服务器日志,记录服务器的状态信息
  • C/S 双端均支持在 CLI/Web 自行指定 IP:Port
  • 实现具有高稳定性的客户端和服务器,防止在用户非法输入时崩溃或异常
    • 实现 TCP 心跳检测

遇到的问题

  • 在客户端因某些原因异常退出时,服务端将无法正常处理其他请求.

    • 开始时服务端没有将新连接的描述符设置为非阻塞模式,导致客户端异常退出时服务端的接收recv一直在阻塞着读取,且无法处理其他请求
  • 如何往线程池中传入成员函数.

    • auto task = [](){     类的成员函数 } m_pool.submit(task);
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30

      * `Tcp`传输为字节流传输,采用在每条消息前面加上`长度`来正确接收每条请求.
      * 在代码中往`redis`数据库中添加好友申请数据时,没有正确插入.
      * 由于好友申请当中包含时间,姓名等信息,中间含有**空格**,在redis的哈希表中无法插入.
      * 经过查阅在redis哈希表中,**空格**可以用`+`代替,在遇到`+`时会被转义为**空格**,或者存储为**十六进制**,但是这种方法在终端中的**空格**为灰色.

      * 在聊天界面如果输入带有`%`,服务器直接挂掉.

      * ```c++
      int redisAsyncContext::Lpush(const std::string &key, const std::string &value)
      {
      //std::string cmd = "lpush " + key + " " + value;
      this->m_reply = (redisReply *)redisCommand(this->m_connettion, "LPUSH %s %s", key.c_str(), value.c_str());
      // 检查 m_reply 是否为 NULL
      if (this->m_reply == NULL) {
      std::cerr << "Error: redisCommand returned NULL" << std::endl;
      return -1; // 或其他合适的错误值
      }

      // 检查 m_reply 类型
      if (this->m_reply->type != REDIS_REPLY_INTEGER) {
      std::cerr << "Error: Expected integer reply" << std::endl;
      freeReplyObject(this->m_reply);
      return -1; // 或其他合适的错误值
      }
      int num = this->m_reply->integer;
      freeReplyObject(this->m_reply);
      std::cout << "G" << std::endl;
      return num;
      }
    • 在执行下面两句是,%会被替换为cmd.c_str(),导致无法将消息插入历史记录表,导致出现错误.

      1
      2
      std::string cmd = "lpush " + key + " " + value;
      this->m_reply = (redisReply *)redisCommand(this->m_connettion, cmd.c_str());
    • 只要更改为下面即没有问题

      1
      this->m_reply = (redisReply *)redisCommand(this->m_connettion, "LPUSH %s %s", key.c_str(), value.c_str());
  • 在某次测试时,新注册账号id为0614897828,导致与该账号聊天的账号进入聊天界面时,0614897828发送的消息会在他人界面显示为通知消息.

    • 由于与人聊天时会在数据库中创建有排序集合来记录某人正在聊天的人的id.运行时通过查看发现,其余账号与0614897828聊天时,数据库中记录账号为614897828.
    • 更换为首位非0的id就不会出现该问题.
    • redis会将有序集合中的score字段字符串中的0去除.将从字符串的首位非0开始存储.
  • 在进入好友私聊界面时,客户端新建了来接收消息,同时主线程发消息,主线程通过判断用户是否键入Esc来退出聊天界面,在输入Esc时,接收消息线程无法正确回收,无法退出聊天界面.

    • 在接收消息线程中来判断标志位来结束该线程,主线程在键入Esc时,将标志位设置为false,但由于客户端的recv为阻塞,导致无法及时获取到标志位的更改.
    • 在键入Esc时,服务器向客户端发送退出信号,这样就可以正确及时的获取到标志位的更改,从而正确退出.
  • 在进行发送文件时,服务器会先将文件存储在本地,但是服务器存储的文件会多写入一些信息,导致接收文件大小偏大.

    • 由于在用户登陆进入之后,会有一个线程每5秒向服务器送送刷新请求,导致服务器会将刷新请求当作文件内容写入文件,导致接收文件不一致
    • 在进入文件收发菜单后,关闭实时刷新,在文件结束后,再将实时刷新打开.
  • 实现后台发送文件,由于会有实时刷新的存在,会导致文件发送不准确.

    • 在发送文件时,重新创建一个socket连接到服务器,在将发送这个文件交给另外一个线程
    • 初始时在用户选择发送文件时开始线程,但会导致主线程与发送线程会同时运行菜单.主线程继续循环菜单,而发送线程运行获取发送文件的信息。
      • 更改线程开始时间,在用户选择发送文件时,获取到发送文件信息后,在启动线程.
      • 新连接的socket发送文件后,服务器不用手动断开连接,服务器有心跳检测,会在一段时间后断开.

eventfd

详解

是一个Linux系统调用,也是一种进程间通信(IPC)机制,主要通过使用文件描述符生成和使用事件通知.

提供了一种在不同进程之间或同一进程内的线程之间的同步事件的方法.

异常处理

异常是程序在执行期间产生的问题。c++异常是指在程序运行时发生的特殊情况.

异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw

关键字:try、catch、throw

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常

  • try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块

1
2
3
4
5
6
7
8
9
10
11
12
13
try
{
// 保护代码
}catch( ExceptionName e1 )
{
// catch 块
}catch( ExceptionName e2 )
{
// catch 块
}catch( ExceptionName eN )
{
// catch 块
}

nlohmann::json

链接

SIGPIPE

SIGPIPE 是一种信号,当一个进程尝试向一个已经关闭的或不可写的管道或套接字写数据时,会触发这个信号。默认情况下,接收到 SIGPIPE 信号的进程会终止。这在网络编程中会导致一些问题,因为如果客户端断开连接,服务器进程在写入数据时会因为这个信号而意外退出。

在网络编程中,特别是使用套接字进行通信时,忽略 SIGPIPE 信号是一个常见的做法。这样可以防止进程因为 SIGPIPE 信号而意外终止。相反,程序可以通过检测 sendwrite 操作的返回值来处理错误,从而使程序更加健壮。

后续问题

  1. 初始客户端构思方面的缺陷,导致实时消息没有线程及时接收。

    当前处理方式为服务端将通知消息放入数据库当中,客户端在登陆之后,增加一个线程来定时执行刷新函数,刷新数据库中的通知消息

    可以优化为在客户端登陆之后,采用多线程的方式来处理相关操作.

  2. 目前只有在历史消息这一操作涉及到redis+mysql的处理方式.

    可以将一些重要信息也采用redis+mysql的处理方式(涉及到redis的存储方式,redis存储于内存当中,会造成数据丢失的情况)

    可以考虑将redis全部做为缓存的形式,将重要信息与历史消息类似,达到一定情况下放入mysql,使数据更加的持久化.

后续学习

  1. 继续学习epoll的相关内容.

  2. 了解其余网络框架,使得该项目的服务端更加的健壮.

  3. 了解消息队列的信息同步的问题.

  4. 熟悉零拷贝的过程,以及零拷贝的具体实现.

  5. 序列化的相关协议,json与其他序列化的区别、json的优点,以及为什么不用其他的序列化

  6. 数据库的深入学习,了解redis的缓存穿透、缓存雪崩、缓存击穿。加强对mysql数据库的学习.

  7. 加强对网络协议相关知识的学习.

Thursday, 25 July 2024

The past weeks involved a lot of work surrounding the implementation of Acrobat specific methods for processing form fields, added support for different types of form widgets and some UI improvements were made or are being worked upon. A detailed list of MRs merged and raised is described below.

MRs merged:

  • AFTime_Keystroke implementation : This method implementation specifies what input keystrokes are allowed in a form field accepting time information. !MR987
  • AFSpecial_Keystroke implementation : This method implementation specifies what input keystrokes are allowed in form fields of special type i.e. those that accept as input phone numbers, ssn and zip codes. !MR1013
  • AFPercent_Keystroke and AFNumber_Keystroke methods implemented : These methods specify input keystrokes for percents and numerical data. !MR988
  • Implement AFDate_KeystrokeEx and AFDate_FormatEx methods. : For correctly accepting input dates and formatting them according to some pre-specified format. !MR1017
  • Global object implementation : A very basic implementation of global object that allows users to read and write to the global object. Persistence and subscription not supported as of now. !MR1016
  • Commit values and restore: Implemented the feature to restore values to the previous committed value upon entering a value that is rejected by a keystroke action.!MR985
  • Fix numerical interpretation in form fields: Calculations were suffering from a major bug 474661 that caused incorrect results when using different locales. This was fixed in the !MR992. The MR focused on how numerical values should be interpreted in form fields.
  • Implemented DocClose, DocWillPrint, DocDidPrint, DocWillSave and DocDidSave events: Now actions are triggered during these events with the changes introduced in the !MR1019.
  • Radio Buttons and Check Boxes size fix: Now radio buttons and check boxes are painted with correct size and resized when zooming to provide a better user experience. !MR1015
  • Implement value (getter), numItems, currentValueIndices properties and getItemAt for FormFieldChoices: These methods were introduced to improve the functionality of FormFieldChoices. !MR1031
  • ResetForm functionality in Poppler: The Reset form functionality was added to the Qt frontend in Poppler. Introduced in this commit

Along with these, more MRs are under works for things like implementing UI experience when using form fields and extending functionality of different types of form fields and actions.

See you next time. Cheers!

Wednesday, 24 July 2024

Multiple Subtitle Track

I continued to refine the feature proposed in my previous blog. We can now add new layers directly on the timeline by simply dragging the existing subtitle out of the bottom border of the subtitle track. Adding, moving, and deleting subtitles work as before, now with layer support.

I also added an indicator to the header of the subtitle track. It looks like this:

Besides setting a style to a specific subtitle event, I also plan to add the feature of setting different default styles for different subtitle layers. This will allow us to easily apply a consistent style to groups of subtitles within each layer.

Improved Subtitle Manager

Layer management is now integrated into the subtitle manager, giving it a fresh new look.

The duplicate and delete operations now work for layers as well.

Automatic Conversion of .srt Subtitle

To better test and develop the style feature, I switched the subtitle storage format to .ass. With the help of my mentor, we can now automatically convert the .srt files from old projects to .ass files while keeping the original .srt file.

There are still some minor issues with style conversion, such as incorrect font sizes. However, I believe it’s time to shift my focus to the styling widget and address these bugs later. The next two weeks will be dedicated to style management, which is the most important part of the project, so stay tuned!

Tuesday, 23 July 2024

This release fixes some bugs. Have a look at the changelog for more details.

Changelog

Bugfixes:

  • Fix file extension for downloads when mime type is empty (lnj)
  • Fix file downloads without a source URL could be started (lnj)
  • Fix file messages are never marked as sent (lnj)
  • Fix message body of previous file selection was used (lnj)
  • Fix missing receipt request (for green checkmark) on media messages (lnj)
  • Fix outgoing encrypted media messages are displayed as unencrypted (lnj)

Download

Or install Kaidan from your distribution:

Packaging status

Dear fans of music & open source music players,
in preparation of the upcoming Amarok 3.1 release, a beta release (3.0.81) has been prepared.

As is observable from the ChangeLog, in addition to various bugfixes, there will be some, but not that many, new features included in the upcoming version. However, there has been a lot of Qt6 compatibility preparation work done under the hood, so version number 3.1 reflects the amount of changed code better than 3.0.2 would. 3.1.0 is likely to be released in early August, and all help catching any regressions during this period is highly appreciated. (n.b. one won't be able to compile a Qt6 Amarok with 3.1 yet, but perhaps with the eventual 3.2)

The source tarball is available on download.kde.org and it has been signed with Tuomas Nurmi's GPG key. There doesn't appear to be many binary packages of the beta available, at least at the moment, but the various nightly git builds provided by various splendid packagers are also based on corresponding source code, so using them and reporting findings is also a valid way to participate in the beta test effort.

Happy listening!

Kirigami Addons 1.4 is out! This release introduce a new module to manage actions similar to that we can find in the QtWidgets world with KXmlGui. This was not written from scratch but upstream the existing infrastructure from Merkuro (ex-Kalendar) and Marknote. These two applications have already been ported to this new module and more like Tokodon or KDE Keychain will follow soon.

This includes a shortcut editor to assign and modify the shortcuts of an application and a command bar to quickly search and trigger actions

Shortcut editor
Shortcut editor

Command bar
Command bar

Similar to KXmlGui, the actions are defined in C++, which allows to make use KStandardActions and get consistent shortcuts accross all your applications.

class MyApplication : public AbstractKirigamiApplication
{
 Q_OBJECT
 QML_ELEMENT

public:
 explicit MyApplication(QObject *parent = nullptr);

 void setupActions() override;

Q_SIGNALS:
 void addNotebook();
};

MyApplication::MyApplication(QObject *parent)
 : AbstractKirigamiApplication(parent)
{
 setupActions();
}

void MyApplication::setupActions()
{
 AbstractKirigamiApplication::setupActions();

 auto actionName = QLatin1String("add_notebook");
 if (KAuthorized::authorizeAction(actionName)) {
 auto action = mainCollection()->addAction(actionName, this, &MyApplication::addNotebook);
 action->setText(i18nc("@action:inmenu", "New Notebook"));
 action->setIcon(QIcon::fromTheme(QStringLiteral("list-add-symbolic")));
 mainCollection()->addAction(action->objectName(), action);
 mainCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N));
 }
}

These new actions can then be used from QML thanks to the new Kirigami.Action::fromQAction property.

import org.kde.kirigamiaddons.statefulapp as StatefulApp
import org.kde.kirigamiaddons.settings as Settings

StatefulApp.StatefulWindow {
 id: root

 windowName: 'Main'
 application: MyApplication {
 configurationView: Settings.ConfigurationView { ... }
 }

 Kirigami.Action {
 fromQAction: MyApplication.action('add_notebook')
 }

 Connections {
 target: MyApplication

 function onAddNotebook(): void {
 ...
 }
 }
}

There is a new template available in KAppTemplate, which allows you to kickstart your new Kirigami application with the basic skeleton with this new module and other “Kirigami Addons” modules.

Other Changes

The FormCard design was tweaked a bit more when using a dark theme, thanks to James and Joshua for their feedback.

Speaking of FormCard, with the development of KeyChain, I ended up adding a new component to the FormCard collection: FormTextAreaDelegate. This component is the equivalent of FormTextFieldDelegate but with a TextArea instead. FormComboBoxDelegate and FormTextFieldDelegate also received a bunch of new properties and functions to proxy the underlying QtQuick.Controls component.

Evgeniy Harchenko tweaked a bit the headers of the TableView component.

Finally, a new contributor Andreas Gattringer fixed a crash in the video maximizing component which was affecting NeoChat.

Packager Section

You can find the package on download.kde.org and it has been signed with my GPG key.

Building QML Android Applications

Qt Creator uses Gradle for project building. Once your project code is ready, select the Android kit for building in Qt Creator. Click build, and Qt Creator will generate Gradle configuration files for you. However, you may encounter errors such as:

Execution failed for task ':processDebugResources'. A failure occurred while executing com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask$TaskAction Android resource linking failed aapt2 E 07-23 15:59:44 51907 51907 LoadedArsc.cpp:94] RES_TABLE_TYPE_TYPE entry offsets overlap actual entry data. aapt2 E 07-23 15:59:44 51907 51907 ApkAssets.cpp:149] Failed to load resources table in APK '/home/zhy/Android/Sdk/platforms/android-35/android.jar'.

This is because the current Gradle plugin version does not support android-35. See How to fix "Execution failed for task ':app:processDebugResources'. > Android resource linking failed"[Android/Flutter] - Stack Overflow

To resolve this issue, you need to modify the Gradle configuration.

Navigate to the /build/Qt_6_7_2_Clang_arm64_v8a-Debug/android-build folder in your project.

Open the build.gradle file and locate the dependencies block:

dependencies {
        classpath 'com.android.tools.build:gradle:7.4.1'
    }

com.android.tools.build:gradle:7.4.1 refers to the Android Gradle Plugin (AGP). This default version is from 2022 and is quite outdated.

You can find the latest version here: Maven Repository: com.android.tools.build » gradle

Update the plugin version to a newer one, for example:

    dependencies {
        classpath 'com.android.tools.build:gradle:8.4.1'
    }

Additionally, when upgrading the plugin version, ensure compatibility with the Gradle version.

Check the relationship between the Gradle and AGP versions here: Android Gradle plugin 8.5 release notes | Android Studio | Android Developers

Reference: Could not find com.android.tools.build:gradle:7.3.3. error found in build.gradle file - Stack Overflow

Therefore, you should use at least Gradle version 8.6 to support this plugin.

Navigate to the ./gradle/wrapper folder and open the gradle-wrapper.properties file. This file defines the Gradle version used by the project.

Find the line: distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip

Change it to:

distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip

This update specifies that the project will use Gradle version 8.6.

After making these changes, click on build. It will automatically download the specified version of Gradle and then download the necessary Gradle plugins.

If successful, you can find the built APK at ./build/outputs/apk/debug.

Running and Installing APK

In a Linux environment, you can use the adb command to install the APK on your Android device. Alternatively, you can use Qt Creator for one-click deployment.

After connecting your Android device via USB, use the adb command to install the APK:

adb install android-build-debug.apk

Make sure that your Android device has Developer Mode enabled. You can find specific instructions on how to enable Developer Mode based on your device model through an online search.

If you want to share the screen on your phone on PC, you can use scrcpy: Genymobile/scrcpy: Display and control your Android device