Add "Read Text Aloud" context menu action for messages
This merge request adds a simple "Read Text Aloud" menu action to the context menu for chat messages. When clicked, the message text will be read aloud using text-to-speech. The intention behind this change is to make it easier for myself and other low-vision users to use Matrix, without needing to use a system-wide screen reader, in cases where the user still has enough sight left to navigate a computer faster without a screen reader. I'd eventually like to have it read " said ," so that the message sender gets read aloud as well, but for now it just reads the plaintext message contents. Another problem, at least on my computer specifically, is that the voice's accent doesn't seem correct. For whatever reason, on my system, messages are read in a Scottish accent which is harder for me to understand. Other apps don't do that, so I'm not sure what's going on there. I do not want to hardcode a specific voice/locale, since I want this feature to work well for everyone and not just me. @teams/qa Please do break my code! :) - I've only tested with basic text messages. @teams/usability Not sure if I put the context menu action in an ideal place, it's grouped in the same area as clipboard actions like "Copy Text." @teams/localization How could I go about getting author names to be read aloud in a way that's properly translated for other languages? I'm not experienced with i18n.
This commit is contained in:
committed by
Tobias Fella
parent
054f87cae2
commit
7a078b2d34
@@ -200,6 +200,10 @@ add_library(neochat STATIC
|
||||
models/pollanswermodel.h
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/TextToSpeechWrapper.qml PROPERTIES
|
||||
QT_QML_SINGLETON_TYPE TRUE
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
QT_QML_SINGLETON_TYPE TRUE
|
||||
)
|
||||
@@ -260,6 +264,7 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||
qml/AvatarTabButton.qml
|
||||
qml/SpaceDrawer.qml
|
||||
qml/OsmLocationPlugin.qml
|
||||
qml/TextToSpeechWrapper.qml
|
||||
qml/FullScreenMap.qml
|
||||
qml/LocationsPage.qml
|
||||
qml/LocationMapItem.qml
|
||||
|
||||
@@ -189,6 +189,7 @@ Kirigami.ApplicationWindow {
|
||||
NeoChatSettingsView.window = root;
|
||||
NeoChatSettingsView.connection = root.connection;
|
||||
WindowController.setBlur(pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
|
||||
TextToSpeechWrapper.warmUp();
|
||||
if (ShareHandler.text && root.connection) {
|
||||
root.handleShare()
|
||||
}
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtTextToSpeech
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
import org.kde.neochat
|
||||
|
||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
|
||||
@@ -83,6 +88,13 @@ DelegateContextMenu {
|
||||
Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + root.eventId);
|
||||
}
|
||||
}
|
||||
QQC2.Action {
|
||||
text: i18nc("@action:inmenu", "Read Text Aloud")
|
||||
icon.name: "audio-speakers-symbolic"
|
||||
onTriggered: {
|
||||
TextToSpeechWrapper.say(i18nc("@info text-to-speech %1 is author %2 is message text", "%1 said %2", root.author.displayName, root.plainText))
|
||||
}
|
||||
}
|
||||
Kirigami.Action {
|
||||
separator: true
|
||||
}
|
||||
|
||||
24
src/qml/TextToSpeechWrapper.qml
Normal file
24
src/qml/TextToSpeechWrapper.qml
Normal file
@@ -0,0 +1,24 @@
|
||||
// SPDX-FileCopyrightText: 2025 Ritchie Frodomar <alkalinethunder@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import QtTextToSpeech
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
readonly property TextToSpeech tts: TextToSpeech {
|
||||
id: tts
|
||||
}
|
||||
|
||||
function warmUp() {
|
||||
// TODO: This method is called on startup to avoid a UI freeze the first time you read a message aloud, but there's nothing for it to do.
|
||||
// This would be a good place to check if TTS can actually be used.
|
||||
}
|
||||
|
||||
function say(text: String) {
|
||||
tts.say(text)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user