Compare commits

...

83 Commits

Author SHA1 Message Date
l10n daemon script
f5837a208a SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2022-03-05 02:49:38 +00:00
l10n daemon script
3b45c0b2f7 GIT_SILENT made messages (after extraction) 2021-12-29 02:19:23 +00:00
l10n daemon script
e1a72816d0 GIT_SILENT made messages (after extraction) 2021-10-25 01:44:33 +00:00
l10n daemon script
aea46c547f GIT_SILENT made messages (after extraction) 2021-10-23 01:40:12 +00:00
l10n daemon script
fe009f764e GIT_SILENT made messages (after extraction) 2021-08-31 01:57:32 +00:00
l10n daemon script
8c14f8d2eb SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-07-28 02:18:15 +00:00
l10n daemon script
559da66197 GIT_SILENT made messages (after extraction) 2021-07-28 01:43:57 +00:00
l10n daemon script
759496620f SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-07-26 02:17:04 +00:00
l10n daemon script
1f7b1ad29f SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-07-20 02:18:30 +00:00
l10n daemon script
9338567137 GIT_SILENT made messages (after extraction) 2021-07-20 01:42:10 +00:00
l10n daemon script
75d2488dbc GIT_SILENT made messages (after extraction) 2021-07-05 01:42:44 +00:00
l10n daemon script
4bed6a07cd GIT_SILENT made messages (after extraction) 2021-06-28 01:56:28 +00:00
l10n daemon script
cb1c9d1869 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-06-16 02:24:26 +00:00
l10n daemon script
76b2d4ac49 GIT_SILENT made messages (after extraction) 2021-06-16 01:50:18 +00:00
l10n daemon script
5fc931484e SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-06-14 02:13:57 +00:00
l10n daemon script
e60ed3b889 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-06-13 02:20:41 +00:00
l10n daemon script
1314567fde GIT_SILENT made messages (after extraction) 2021-06-13 01:46:53 +00:00
l10n daemon script
047aa793e7 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-06-07 02:15:39 +00:00
l10n daemon script
d60f8f4dfa GIT_SILENT made messages (after extraction) 2021-06-07 01:41:55 +00:00
l10n daemon script
20139c08d8 GIT_SILENT made messages (after extraction) 2021-06-06 01:44:24 +00:00
l10n daemon script
fb59bac165 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-06-04 02:26:16 +00:00
l10n daemon script
5a65dc4d9a GIT_SILENT made messages (after extraction) 2021-06-04 01:50:31 +00:00
l10n daemon script
03ec17366e SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-06-03 02:27:05 +00:00
l10n daemon script
15137cd704 GIT_SILENT made messages (after extraction) 2021-06-03 01:51:44 +00:00
l10n daemon script
2aea0015ba GIT_SILENT made messages (after extraction) 2021-06-02 01:41:00 +00:00
l10n daemon script
f6fd099808 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-06-01 02:13:55 +00:00
l10n daemon script
04082fc095 GIT_SILENT made messages (after extraction) 2021-06-01 01:40:17 +00:00
Carl Schwan
bc977c3fc6 Update apstream screenshots 2021-05-31 20:26:07 +02:00
Carl Schwan
c4c283c85a Update versioning to 1.2.0 2021-05-31 17:25:35 +02:00
Carl Schwan
56f49fabf7 Don't mark message as read when the current window is not visible
Fix #378

(cherry picked from commit 87d1fefae2)
2021-05-31 17:22:09 +02:00
Carl Schwan
fe407a3421 Mark all message as read when clicking on down button
Fix #379

(cherry picked from commit 6e5bca4928)
2021-05-31 17:22:03 +02:00
l10n daemon script
bbe539885e GIT_SILENT made messages (after extraction)
(cherry picked from commit 4d236a201b)
2021-05-31 16:58:08 +02:00
Carl Schwan
ff978b9586 Update Appstream 2021-05-31 16:57:50 +02:00
Noah Davis
885b75e35f Move TypingIndicator to the right side
So that it's less likely to cover message text.
2021-05-31 16:54:41 +02:00
Srevin Saju
cb81eaf26f feat: show the username and avatar again on date-change
when the clock hits 00:00 in the user's time zone, but in the
case of a continuous discussion, it is likely that "Today"
date-change marker would obstruct the conversation, and the
username and avatar would be missing.


(cherry picked from commit 3e78bff8a1)
2021-05-29 22:16:42 +00:00
Carl Schwan
22732b801b Don't steal focus in panel search field
(cherry picked from commit 807112fb19)
2021-05-30 00:06:58 +02:00
Carl Schwan
ae3e395b47 Reinitialize completion list after switching room
(cherry picked from commit e15e10d319)
2021-05-29 23:55:58 +02:00
Carl Schwan
96c91e2a35 Make sure we only add non empty name or display name in autocompletion
list

Otherwise this will breaks when replacing names later

(cherry picked from commit c7fd5cc511)
2021-05-29 23:15:26 +02:00
Carl Schwan
e36204bbd8 Open room when pressing Enter or Return
Fix #381

(cherry picked from commit b37152ff89)
2021-05-29 20:16:45 +02:00
Arnav Rawat
1804140ac0 Restore I-Beam cursor on hover
Should not cause issues with themes


(cherry picked from commit df0ad391ba)
2021-05-28 13:35:05 +00:00
Carl Schwan
5a28a93ab6 Fix reverse tabbing not working in autocompletion
Now call autocomplete() also for shift+tab

Fix #377

(cherry picked from commit 3329739d55)
2021-05-28 14:57:35 +02:00
Carl Schwan
76bd529c3c Fix size of replies in mesage delegate 2021-05-28 14:53:43 +02:00
Carl Schwan
293288a0b6 Fix completion when tabing users
This was caused by weird bindings. Now just access the userId value
directly.

Fix #324

(cherry picked from commit d9125148fe)
2021-05-28 14:27:44 +02:00
Carl Schwan
51b6593f96 Better read market handling: Mark room as read when scrolling to the
bottom

Fix #372

(cherry picked from commit db0f421811)
2021-05-28 14:07:19 +02:00
Carl Schwan
51e73568c4 Fix date being show too often
(cherry picked from commit 3d251b9b25)
2021-05-28 14:07:19 +02:00
Carl Schwan
e461e2098b Don't use SystemTray integration on GNOME and ElementaryOS
These platforms don't support it so hiding NeoChat in the tray in these
platforms is not a good idea and other a rather poor user experience.

(cherry picked from commit 13888401fa)
2021-05-28 14:07:19 +02:00
Hannah von Reth
79ceb45fae Fix Windows builds
(cherry picked from commit 92fcff1dce)
2021-05-28 14:07:19 +02:00
Nicolas Fella
0c292b34ff Remove minSdk version from AndroidManifest
(cherry picked from commit 41838d01df)
2021-05-28 14:07:19 +02:00
Nicolas Fella
db6640ba49 Fix Android ifdef
(cherry picked from commit af75cebba1)
2021-05-28 14:07:19 +02:00
Nicolas Fella
3827249f0c remove spurious QFileDialog include
(cherry picked from commit 1cec672c0a)
2021-05-28 14:07:19 +02:00
Nicolas Fella
f40a3daef4 remove spurious QMenu include
(cherry picked from commit bd5f6c9c9e)
2021-05-28 14:07:19 +02:00
Nicolas Fella
8d2608a230 Use QGuiApplication instead of QApplication where appropriate
(cherry picked from commit 6e04d343b7)
2021-05-28 14:07:19 +02:00
Nicolas Fella
3e5628def3 Don't find Widgets on Android
(cherry picked from commit 454e35433b)
2021-05-28 12:09:01 +00:00
Tobias Fella
3b3673fdff Fix multiple headers for the same sections
(cherry picked from commit 4dea02197c)
2021-05-28 12:08:32 +00:00
Adriaan de Groot
d81e4c417d CMake: various tidying-up
(cherry picked from commit 294f0c7e1a)
2021-05-28 12:07:48 +00:00
Carl Schwan
44d3f628d9 Fix username autocompletion 2021-05-28 14:02:03 +02:00
Carl Schwan
0db9c0454f pushReplace more
(cherry picked from commit 7cd9f788dd)
2021-05-28 12:05:59 +00:00
Noah Davis
e5c65a662e Use 3 dot typing indicator, clean up code a bit.
Move TypingIndicator.qml out of ChatBox folder.
It wasn't part of the ChatBox.

fixes #367 by eliding instead of wrapping text


(cherry picked from commit bbcf4239a4)
2021-05-27 14:18:05 +00:00
l10n daemon script
8913aa8a66 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-05-26 02:28:13 +00:00
l10n daemon script
5db3e14ae6 GIT_SILENT made messages (after extraction) 2021-05-26 01:52:33 +00:00
l10n daemon script
c5a3fc0431 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-05-25 02:21:15 +00:00
l10n daemon script
fc791d41fa GIT_SILENT made messages (after extraction) 2021-05-25 01:47:45 +00:00
Carl Schwan
127ad19109 Fix minor bugs
(cherry picked from commit d14674c2cd)
2021-05-24 14:55:28 +00:00
Carl Schwan
066ea4f8bd Make sure message are loaded when scrolling to the top
(cherry picked from commit 49c1736f7c)
2021-05-24 14:53:11 +00:00
Carl Schwan
cf60337b27 Make effects more visible
(cherry picked from commit db62f06de4)
2021-05-24 14:52:55 +00:00
l10n daemon script
98672cf870 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-05-24 02:13:42 +00:00
l10n daemon script
abd03299ec GIT_SILENT made messages (after extraction) 2021-05-24 01:39:11 +00:00
Carl Schwan
41b64f977c Fix creating broken direct chat for user with a direct chat already open
Just enter the existing room instead of trying to create a new one but
broken.

Fix !237


(cherry picked from commit 0dbb56ba1e)
2021-05-23 19:51:30 +00:00
Carl Schwan
ac75dd57c0 Minor optimization
(cherry picked from commit 7bdfdc0eec)
2021-05-23 16:33:13 +00:00
Carl Schwan
1d3d61ed77 Fix loading events when scrolling or opening a room for the first time
Fix #362


(cherry picked from commit bae7813f68)
2021-05-23 16:31:41 +00:00
Carl Schwan
1e047a8ff1 Fix mode without avatar
It seems that this mode didn't get much love when I added the bubbles so
it was quite broken. This patches removes the bubbles and fix the
alignment issues when using this mode.

We probably should rename it to compact mode in a follow up commit (but
not this one so we can backport it to the stable branch).


(cherry picked from commit dded804f00)
2021-05-23 16:30:55 +00:00
l10n daemon script
530b4c24a0 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-05-23 02:12:00 +00:00
l10n daemon script
ada7bcef65 GIT_SILENT made messages (after extraction) 2021-05-23 01:38:51 +00:00
Carl Schwan
ad4ca3ad9e Fix i18n
(cherry picked from commit dbb43addc8)
2021-05-22 16:24:24 +00:00
Tobias Fella
4103c44eb5 Don't hide redacted events
(cherry picked from commit 135b2e49fa)
2021-05-22 12:18:07 +00:00
Tobias Fella
dd4ed7539e Revert "Fix showing multiple deleted messages from the same author"
This reverts commit b48c9bdadc.


(cherry picked from commit 011f649cbf)
2021-05-22 12:17:45 +00:00
Tobias Fella
52ad911b2d Revert "Show deleted messages"
This reverts commit 116f883699.


(cherry picked from commit 36a2f5719f)
2021-05-22 12:17:20 +00:00
Tobias Fella
f09dff979e Fix banning users
(cherry picked from commit af6880b2ca)
2021-05-22 12:09:43 +00:00
Tobias Fella
0476398f91 Don't offer banning users that are already banned
(cherry picked from commit 48d1fa27cf)
2021-05-22 12:09:20 +00:00
Tobias Fella
41993bfe24 Don't offer to kick users that already left
(cherry picked from commit bd893adb34)
2021-05-21 22:42:45 +00:00
Tobias Fella
b3d90ebf82 Fix showing multiple deleted messages from the same author
(cherry picked from commit b48c9bdadc)
2021-05-21 22:42:15 +00:00
Tobias Fella
ef0a6e276c Show deleted messages
We used to show those, then a bug was fixed in the code that was
supposed to hide them.


(cherry picked from commit 116f883699)
2021-05-21 22:41:46 +00:00
Tobias Fella
a104968a29 Prioritize "low priority" over "direct chat" in roomList categories
There's no exact right or wrong here, but if a room was explicitly
marked as "low priority", we should honor this tag.

Fixes a slight inconsistency with the implementation in Element

Fixes #357


(cherry picked from commit 3ea783b370)
2021-05-21 19:12:00 +00:00
32 changed files with 431 additions and 216 deletions

View File

@@ -34,12 +34,12 @@ endif()
# Fix a crash due to problems with quotient's event system. Can probably be removed once the reworked event system is in
cmake_policy(SET CMP0063 OLD)
ecm_setup_version(1.1.80
ecm_setup_version(1.2.0
VARIABLE_PREFIX NEOCHAT
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
)
find_package(Qt5 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Widgets Core Quick Gui QuickControls2 Multimedia Svg)
find_package(Qt5 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core Quick Gui QuickControls2 Multimedia Svg)
set_package_properties(Qt5 PROPERTIES
TYPE REQUIRED
PURPOSE "Basic application components"
@@ -67,6 +67,7 @@ if(ANDROID)
PURPOSE "Encrypted communications"
)
else()
find_package(Qt5 ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF5QQC2DesktopStyle ${KF5_MIN_VERSION} REQUIRED)
set_package_properties(KF5QQC2DesktopStyle PROPERTIES
TYPE RUNTIME

View File

@@ -53,7 +53,6 @@
</activity>
</application>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

View File

@@ -7,14 +7,16 @@
# first try to find cmark-config.cmake
# path to a file not in the search path can be set with 'cmake -Dcmark_DIR=some/path/'
find_package(cmark CONFIG)
find_package(cmark CONFIG QUIET)
if(cmark_FOUND AND TARGET cmark::cmark)
# found it!
return()
endif()
include(FindPkgConfig)
pkg_check_modules(PC_CMARK QUIET cmark)
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_CMARK QUIET cmark)
endif()
if(NOT CMARK_INCLUDE_DIR)
find_path(CMARK_INCLUDE_DIR

View File

@@ -76,7 +76,11 @@ ToolBar {
* background colors being very different from the QPalette::Base color.
* Luckily, none of the Qt QQC2 styles do that and neither do KDE's QQC2 styles.
*/
background: null
background: MouseArea {
acceptedButtons: Qt.NoButton
cursorShape: Qt.IBeamCursor
z: 1
}
leftPadding: mirrored ? 0 : Kirigami.Units.largeSpacing
rightPadding: !mirrored ? 0 : Kirigami.Units.largeSpacing
topPadding: 0
@@ -165,12 +169,18 @@ ToolBar {
nextItemInFocusChain(false).forceActiveFocus(Qt.TabFocusReason)
return
}
let decrementedIndex = completionMenu.currentIndex - 1
// Wrap around to the last item
if (decrementedIndex < 0) {
decrementedIndex = Math.max(completionMenu.count - 1, 0) // 0 if count == 0
if (!autoAppeared) {
let decrementedIndex = completionMenu.currentIndex - 1
// Wrap around to the last item
if (decrementedIndex < 0) {
decrementedIndex = Math.max(completionMenu.count - 1, 0) // 0 if count == 0
}
completionMenu.currentIndex = decrementedIndex
} else {
autoAppeared = false;
}
completionMenu.currentIndex = decrementedIndex
chatBar.complete();
}
Keys.onTabPressed: {
@@ -187,7 +197,7 @@ ToolBar {
// ignore first time tab was clicked so that user can select
// first emoji/user
if (autoAppeared === false) {
if (!autoAppeared) {
let incrementedIndex = completionMenu.currentIndex + 1;
// Wrap around to the first item
if (incrementedIndex > completionMenu.count - 1) {
@@ -370,8 +380,10 @@ ToolBar {
function complete() {
documentHandler.replaceAutoComplete(completionMenu.currentDisplayText);
if (completionMenu.completionType === "username") {
userAutocompleted[completionMenu.currentDisplayText] = completionMenu.currentUserId;
if (completionMenu.completionType === ChatDocumentHandler.User
&& completionMenu.currentDisplayText.length > 0
&& completionMenu.currentItem.userId.length > 0) {
userAutocompleted[completionMenu.currentDisplayText] = completionMenu.currentItem.userId;
}
}
}

View File

@@ -227,6 +227,14 @@ Item {
chatBar.inputFieldForceActiveFocusTriggered()
}
Connections {
target: RoomManager
function onCurrentRoomChanged() {
chatBar.userAutocompleted = {};
}
}
Connections {
target: ChatBoxHelper

View File

@@ -22,8 +22,7 @@ Popup {
property alias delegate: completionListView.delegate
// Autocomplee text
property string currentDisplayText: currentItem && currentItem.displayName ? currentItem.displayName : ""
property string currentUserId: currentItem && currentItem.id ? currentItem.id : ""
property string currentDisplayText: currentItem && (currentItem.displayName ?? "")
property int completionType: ChatDocumentHandler.Emoji
property int beginPosition: 0
@@ -78,6 +77,7 @@ Popup {
id: usernameItem
width: ListView.view.width ?? implicitWidth
property string displayName: modelData.displayName
property string userId: modelData.id
leading: Kirigami.Avatar {
implicitHeight: Kirigami.Units.gridUnit
implicitWidth: implicitHeight
@@ -86,11 +86,6 @@ Popup {
}
text: modelData.displayName
onClicked: completeTriggered();
Component.onCompleted: {
completionMenu.currentUserId = Qt.binding(() => {
return modelData.id ?? "";
});
}
}
}

View File

@@ -1,66 +0,0 @@
/* SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.de>
* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
* SPDX-FileCopyrightText: 2021 Srevin Saju <srevinsaju@sugarlabs.org>
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.14 as Kirigami
import org.kde.neochat 1.0
Loader {
id: root
property var typingNotification: null
active: visible
sourceComponent: Pane {
id: typingPane
padding: fontMetrics.lineSpacing * 0.25
spacing: 0
Kirigami.Theme.colorSet: Kirigami.Theme.View
contentItem: RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
spacing: 0
FontMetrics {
id: fontMetrics
font: typingLabel.font
}
Label {
id: typingLabel
textFormat: TextEdit.RichText
wrapMode: Label.Wrap
text: typingNotification
}
BusyIndicator {
running: root.active
Layout.alignment: Qt.AlignRight
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
}
}
background: Item {
Rectangle {
height: 1
property color borderColor: Kirigami.Theme.textColor
color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.1)
anchors {
left: typingIndicatorBackground.left
right: typingIndicatorBackground.right
bottom: typingIndicatorBackground.top
}
}
Rectangle {
anchors.fill: parent
id: typingIndicatorBackground
color: Kirigami.Theme.backgroundColor
}
}
}
}

View File

@@ -5,4 +5,3 @@ ReplyPane 1.0 ReplyPane.qml
AttachmentPane 1.0 AttachmentPane.qml
CompletionMenu 1.0 CompletionMenu.qml
EmojiPickerPane 1.0 EmojiPickerPane.qml
TypingPane 1.0 TypingPane.qml

View File

@@ -8,7 +8,7 @@ import QtQuick.Particles 2.15
import org.kde.kirigami 2.15 as Kirigami
Rectangle {
Item {
id: item
property bool enabled: false
property int effectInterval: Kirigami.Units.veryLongDuration*10;
@@ -27,11 +27,6 @@ Rectangle {
fireworksTimer.start()
}
// backgroundColor
color: Kirigami.Theme.backgroundColor
Kirigami.Theme.colorSet: Kirigami.Theme.Window
Kirigami.Theme.inherit: false
// Confetti
Timer {

View File

@@ -15,7 +15,7 @@ LoginStep {
readonly property var homeserver: customHomeserver.visible ? customHomeserver.text : serverCombo.currentText
property bool loading: false
title: i18n("@title", "Select a Homeserver")
title: i18nc("@title", "Select a Homeserver")
action: Kirigami.Action {
enabled: LoginHelper.homeserverReachable && !customHomeserver.visible || customHomeserver.acceptableInput

View File

@@ -15,7 +15,7 @@ MouseArea {
id: replyButton
Layout.fillWidth: true
implicitHeight: replyName.implicitHeight + (loader.item ? loader.item.height : 0) + Kirigami.Units.largeSpacing
implicitWidth: Math.min(bubbleMaxWidth, Math.max((loader.item ? loader.item.width : 0), replyName.implicitWidth)) + Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3
implicitWidth: Math.min(bubbleMaxWidth, Math.max((loader.item ? loader.item.width + Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing : 0), replyName.implicitWidth)) + Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3
Component.onCompleted: {
parent.Layout.fillWidth = true;
parent.Layout.preferredWidth = Qt.binding(function() { return implicitWidth; })
@@ -32,7 +32,7 @@ MouseArea {
id: avatatReply
anchors.left: replyLeftBorder.right
anchors.leftMargin: Kirigami.Units.smallSpacing
width: Kirigami.Units.gridUnit
width: visible ? Kirigami.Units.gridUnit : 0
height: Kirigami.Units.gridUnit
sourceSize.width: width
sourceSize.height: height
@@ -79,7 +79,7 @@ MouseArea {
textMessage: reply.display
textFormat: Text.RichText
wrapMode: Text.WordWrap
width: Math.min(implicitWidth, bubbleMaxWidth) - Kirigami.Units.smallSpacing * 5 - avatatReply.width
width: Math.min(implicitWidth, bubbleMaxWidth - Kirigami.Units.largeSpacing * 3)
x: Kirigami.Units.smallSpacing * 3 + avatatReply.width
}
}

View File

@@ -21,7 +21,7 @@ QQC2.ItemDelegate {
property bool isEmote: false
property bool cardBackground: true
readonly property int bubbleMaxWidth: Math.min(width - Kirigami.Units.gridUnit * 2 - Kirigami.Units.largeSpacing * 4, Kirigami.Units.gridUnit * 20)
readonly property int bubbleMaxWidth: !Config.showAvatarInTimeline ? width : Math.min(width - Kirigami.Units.gridUnit * 2 - Kirigami.Units.largeSpacing * 4, Kirigami.Units.gridUnit * 20)
signal saveFileAs()
signal openExternally()
@@ -48,20 +48,20 @@ QQC2.ItemDelegate {
}
}
height: sectionDelegate.height + Math.max(avatar.height, bubble.implicitHeight) + loader.height + (model.showAuthor ? Kirigami.Units.smallSpacing : 0)
height: sectionDelegate.height + Math.max(avatar.height, bubble.implicitHeight) + loader.height + (model.showAuthor ? Kirigami.Units.smallSpacing : 0) - (Config.showAvatarInTimeline ? 0 : Kirigami.Units.largeSpacing)
SectionDelegate {
id: sectionDelegate
width: parent.width
anchors.left: parent.left
anchors.leftMargin: Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
anchors.left: avatar.left
anchors.leftMargin: Kirigami.Units.smallSpacing
visible: model.showSection
height: visible ? implicitHeight : 0
}
Kirigami.Avatar {
id: avatar
width: Kirigami.Units.gridUnit * 2
width: visible || Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 : 0
height: width
sourceSize.width: width
sourceSize.height: width
@@ -74,7 +74,7 @@ QQC2.ItemDelegate {
visible: model.showAuthor && Config.showAvatarInTimeline
name: model.author.name ?? model.author.displayName
source: model.author.avatarMediaId ? ("image://mxc/" + model.author.avatarMediaId) : ""
source: visible && model.author.avatarMediaId ? ("image://mxc/" + model.author.avatarMediaId) : ""
color: model.author.color
MouseArea {
@@ -94,7 +94,7 @@ QQC2.ItemDelegate {
QQC2.Control {
id: bubble
topPadding: Kirigami.Units.largeSpacing
topPadding: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
@@ -103,6 +103,8 @@ QQC2.ItemDelegate {
top: avatar.top
left: avatar.right
leftMargin: Kirigami.Units.smallSpacing
right: Config.showAvatarInTimeline ? undefined : parent.right
rightMargin: Config.showAvatarInTimeline ? undefined : Kirigami.Units.largeSpacing
}
contentItem: ColumnLayout {
@@ -112,10 +114,10 @@ QQC2.ItemDelegate {
id: rowLayout
visible: model.showAuthor && !isEmote
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.preferredWidth: nameLabel.implicitWidth + timeLabel.implicitWidth + Kirigami.Units.largeSpacing
Layout.maximumWidth: bubbleMaxWidth - Kirigami.Units.largeSpacing * 2
Layout.maximumWidth: bubbleMaxWidth
implicitHeight: visible ? nameLabel.implicitHeight : 0
QQC2.Label {
@@ -131,6 +133,19 @@ QQC2.ItemDelegate {
font.weight: Font.Bold
color: author.color
wrapMode: Text.Wrap
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
room: currentRoom,
user: author.object,
displayName: author.displayName,
avatarMediaId: author.avatarMediaId,
avatarUrl: author.avatarUrl
}).open();
}
}
}
QQC2.Label {
id: timeLabel
@@ -157,7 +172,7 @@ QQC2.ItemDelegate {
}
background: Kirigami.ShadowedRectangle {
visible: cardBackground
visible: cardBackground && Config.showAvatarInTimeline
color: model.isHighlighted ? Kirigami.Theme.positiveBackgroundColor : Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
@@ -170,13 +185,12 @@ QQC2.ItemDelegate {
Loader {
id: loader
anchors {
left: parent.left
leftMargin: Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing * 2
left: bubble.left
right: parent.right
top: bubble.bottom
topMargin: active ? Kirigami.Units.smallSpacing : 0
topMargin: active && Config.showAvatarInTimeline ? Kirigami.Units.smallSpacing : 0
}
height: active ? item.implicitHeight + Kirigami.Units.smallSpacing : 0
height: active ? item.implicitHeight : 0
//Layout.bottomMargin: readMarker ? Kirigami.Units.smallSpacing : 0
active: eventType !== "state" && eventType !== "notice" && reaction != undefined && reaction.length > 0
visible: active

View File

@@ -0,0 +1,106 @@
/* SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.de>
* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
* SPDX-FileCopyrightText: 2021 Srevin Saju <srevinsaju@sugarlabs.org>
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.14 as Kirigami
import org.kde.neochat 1.0
Loader {
id: root
property string labelText: ""
active: visible
sourceComponent: Pane {
id: typingPane
leftPadding: Kirigami.Units.largeSpacing
rightPadding: Kirigami.Units.largeSpacing
topPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.largeSpacing
FontMetrics {
id: fontMetrics
}
contentItem: RowLayout {
spacing: typingPane.spacing
Row {
id: dotRow
property int duration: 400
spacing: Kirigami.Units.smallSpacing
Repeater {
model: 3
delegate: Rectangle {
id: dot
color: Kirigami.Theme.textColor
radius: height/2
implicitWidth: fontMetrics.xHeight
implicitHeight: fontMetrics.xHeight
// rotating 45 degrees makes the dots look a bit smoother when scaled up
rotation: 45
opacity: 0.5
scale: 1
// FIXME: Sometimes the animation timings for each
// dot drift slightly reletative to each other.
// Not everyone can see this, but I'm pretty sure it's there.
SequentialAnimation {
running: true
PauseAnimation { duration: dotRow.duration * index / 2 }
SequentialAnimation {
loops: Animation.Infinite
ParallelAnimation {
// Animators unfortunately sync up instead of being
// staggered, so I'm using NumberAnimations instead.
NumberAnimation {
target: dot; property: "scale";
from: 1; to: 1.33
duration: dotRow.duration
}
NumberAnimation {
target: dot; property: "opacity"
from: 0.5; to: 1
duration: dotRow.duration
}
}
ParallelAnimation {
NumberAnimation {
target: dot; property: "scale"
from: 1.33; to: 1
duration: dotRow.duration
}
NumberAnimation {
target: dot; property: "opacity"
from: 1; to: 0.5
duration: dotRow.duration
}
}
PauseAnimation { duration: dotRow.duration }
}
}
}
}
}
Label {
id: typingLabel
elide: Text.ElideRight
text: root.labelText
}
}
leftInset: !mirrored ? 0 : -background.radius
rightInset: mirrored ? 0 : -background.radius
bottomInset: -background.radius
background: Rectangle {
radius: 3
color: Kirigami.Theme.backgroundColor
border.color: Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.2)
border.width: 1
}
}
}

View File

@@ -2,3 +2,4 @@ module NeoChat.Component
FullScreenImage 1.0 FullScreenImage.qml
ChatTextInput 1.0 ChatTextInput.qml
FancyEffectsContainer 1.0 FancyEffectsContainer.qml
TypingPane 1.0 TypingPane.qml

View File

@@ -104,7 +104,7 @@ Kirigami.OverlaySheet {
}
}
Kirigami.BasicListItem {
visible: user !== room.localUser && room.canSendState("kick")
visible: user !== room.localUser && room.canSendState("kick") && room.containsUser(user.id)
action: Kirigami.Action {
text: i18n("Kick this user")
@@ -116,14 +116,14 @@ Kirigami.OverlaySheet {
}
}
Kirigami.BasicListItem {
visible: user !== room.localUser && room.canSendState("ban")
visible: user !== room.localUser && room.canSendState("ban") && !room.isUserBanned(user.id)
action: Kirigami.Action {
text: i18n("Ban this user")
icon.name: "im-ban-user"
icon.color: Kirigami.Theme.negativeTextColor
onTriggered: {
room.banMember(user.id)
room.ban(user.id)
root.close()
}
}
@@ -133,7 +133,7 @@ Kirigami.OverlaySheet {
text: i18n("Open a private chat")
icon.name: "document-send"
onTriggered: {
Controller.activeConnection.requestDirectChat(user)
Controller.openOrCreateDirectChat(user);
root.close()
}
}

View File

@@ -125,6 +125,8 @@ Kirigami.ScrollablePage {
sortFilterRoomListModel.index(index, 0)), ItemSelectionModel.SelectCurrent)
}
}
Keys.onEnterPressed: enterRoomAction.trigger()
Keys.onReturnPressed: enterRoomAction.trigger()
bold: unreadCount > 0
label: name ?? ""
subtitle: {
@@ -202,7 +204,7 @@ Kirigami.ScrollablePage {
}
delegate: Kirigami.BasicListItem {
checkable: true
checked: Controller.activeConnection.localUser.id === model.user.id
checked: Controller.activeConnection && Controller.activeConnection.localUser.id === model.user.id
onClicked: Controller.activeConnection = model.connection
Layout.fillWidth: true
Layout.fillHeight: true

View File

@@ -23,13 +23,18 @@ Kirigami.ScrollablePage {
/// It's not readonly because of the seperate window view.
property var currentRoom: RoomManager.currentRoom
/// Used to determine if scrolling to the bottom should mark the message as unread
property bool hasScrolledUpBefore: false;
title: currentRoom.displayName
signal switchRoomUp()
signal switchRoomDown()
onCurrentRoomChanged: ChatBoxHelper.clearEditReply()
onCurrentRoomChanged: {
hasScrolledUpBefore = false;
ChatBoxHelper.clearEditReply()
}
ActionsHandler {
id: actionsHandler
@@ -221,7 +226,6 @@ Kirigami.ScrollablePage {
visible: !invitation.visible
readonly property int largestVisibleIndex: count > 0 ? indexAt(contentX + (width / 2), contentY + height - 1) : -1
readonly property bool noNeedMoreContent: !currentRoom || currentRoom.eventsHistoryJob || currentRoom.allHistoryLoaded
readonly property bool isLoaded: page.width * page.height > 10
spacing: Kirigami.Units.smallSpacing
@@ -232,20 +236,38 @@ Kirigami.ScrollablePage {
model: !isLoaded ? undefined : sortedMessageEventModel
onContentYChanged: fetchMoreContent()
function fetchMoreContent() {
if(!noNeedMoreContent && contentY - 5000 < originY) {
currentRoom.getPreviousContent(20);
}
}
MessageEventModel {
id: messageEventModel
room: currentRoom
}
Timer {
interval: 1000
running: messageListView.atYBeginning
triggeredOnStart: true
onTriggered: {
if (messageListView.atYBeginning && messageEventModel.canFetchMore(messageEventModel.index(0, 0))) {
messageEventModel.fetchMore(messageEventModel.index(0, 0));
}
}
repeat: true
}
// HACK: The view should do this automatically but doesn't.
onAtYBeginningChanged: if (atYBeginning && messageEventModel.canFetchMore(messageEventModel.index(0, 0))) {
messageEventModel.fetchMore(messageEventModel.index(0, 0));
}
onAtYEndChanged: if (atYEnd && hasScrolledUpBefore) {
if (QQC2.ApplicationWindow.window.visibility !== QQC2.ApplicationWindow.Hidden) {
currentRoom.markAllMessagesAsRead();
}
hasScrolledUpBefore = false;
} else if (!atYEnd) {
hasScrolledUpBefore = true;
}
QQC2.Popup {
anchors.centerIn: parent
@@ -343,9 +365,10 @@ Kirigami.ScrollablePage {
innerObject: TextDelegate {
isEmote: true
Layout.fillWidth: !Config.showAvatarInTimeline
Layout.maximumWidth: emoteContainer.bubbleMaxWidth
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
TapHandler {
acceptedButtons: Qt.RightButton
@@ -369,10 +392,11 @@ Kirigami.ScrollablePage {
hoverComponent: hoverActions
innerObject: TextDelegate {
Layout.fillWidth: !Config.showAvatarInTimeline
Layout.maximumWidth: messageContainer.bubbleMaxWidth
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.bottomMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
TapHandler {
acceptedButtons: Qt.RightButton
onTapped: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody)
@@ -394,9 +418,10 @@ Kirigami.ScrollablePage {
onReplyClicked: goToEvent(eventID)
innerObject: TextDelegate {
Layout.fillWidth: !Config.showAvatarInTimeline
Layout.maximumWidth: noticeContainer.bubbleMaxWidth
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
}
}
@@ -550,7 +575,9 @@ Kirigami.ScrollablePage {
Timer {
id: makeMeDisapearTimer
interval: Kirigami.Units.humanMoment * 2
onTriggered: currentRoom.markAllMessagesAsRead();
onTriggered: if (QQC2.ApplicationWindow.window.visibility !== QQC2.ApplicationWindow.Hidden) {
currentRoom.markAllMessagesAsRead();
}
}
ListView.onPooled: makeMeDisapearTimer.stop()
@@ -577,7 +604,9 @@ Kirigami.ScrollablePage {
if (view.atYEnd) {
// easy case just mark everything as read
currentRoom.markAllMessagesAsRead();
if (QQC2.ApplicationWindow.window.visibility !== QQC2.ApplicationWindow.Hidden) {
currentRoom.markAllMessagesAsRead();
}
return;
}
@@ -622,7 +651,7 @@ Kirigami.ScrollablePage {
QQC2.RoundButton {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: Kirigami.Units.largeSpacing
anchors.bottomMargin: Kirigami.Units.largeSpacing + messageListView.headerItem.height
anchors.rightMargin: Kirigami.Units.largeSpacing
implicitWidth: Kirigami.Units.gridUnit * 2
implicitHeight: Kirigami.Units.gridUnit * 2
@@ -633,6 +662,7 @@ Kirigami.ScrollablePage {
action: Kirigami.Action {
onTriggered: {
goToLastMessage();
currentRoom.markAllMessagesAsRead();
}
icon.name: "go-down"
}
@@ -643,10 +673,10 @@ Kirigami.ScrollablePage {
}
Component.onCompleted: {
updateReadMarker()
if (currentRoom) {
if (currentRoom.timelineSize < 20)
currentRoom.getPreviousContent(50)
if (currentRoom.timelineSize < 20) {
currentRoom.getPreviousContent(50);
}
}
positionViewAtBeginning();
@@ -705,8 +735,12 @@ Kirigami.ScrollablePage {
header: TypingPane {
id: typingPane
visible: !loadingIndicator.visible && currentRoom && currentRoom.usersTyping.length > 0
typingNotification: visible ? i18ncp("Message displayed when some users are typing", "%2 is typing", "%2 are typing", currentRoom.usersTyping.length, currentRoom.usersTyping.map(user => user.displayName).join(", ")) : ""
width: parent.width
labelText: visible ? i18ncp(
"Message displayed when some users are typing", "%2 is typing", "%2 are typing",
currentRoom.usersTyping.length,
currentRoom.usersTyping.map(user => user.displayName).join(", ")
) : ""
anchors.right: parent.right
height: visible ? implicitHeight : 0
Behavior on height {
NumberAnimation {
@@ -747,6 +781,7 @@ Kirigami.ScrollablePage {
background: FancyEffectsContainer {
id: fancyEffectsContainer
z: 100
enabled: Config.showFancyEffects
@@ -847,7 +882,6 @@ Kirigami.ScrollablePage {
/// Open context menu for normal message
function openMessageContext(author, message, eventId, source, eventType, formattedBody) {
console.log("message", message)
const contextMenu = messageDelegateContextMenu.createObject(page, {
author: author,
message: message,

View File

@@ -157,6 +157,16 @@ Kirigami.OverlayDrawer {
}
}
Pane {
padding: Kirigami.Units.smallSpacing
implicitWidth: parent.width
z: 2
contentItem: Kirigami.SearchField {
id: userListSearchField
onAccepted: sortedMessageEventModel.filterString = text;
}
}
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
@@ -168,16 +178,6 @@ Kirigami.OverlayDrawer {
boundsBehavior: Flickable.DragOverBounds
activeFocusOnTab: true
header: Pane {
padding: Kirigami.Units.smallSpacing
implicitWidth: parent.width
z: 2
contentItem: Kirigami.SearchField {
id: userListSearchField
onTextChanged: sortedMessageEventModel.filterString = text;
}
}
model: KSortFilterProxyModel {
id: sortedMessageEventModel

View File

@@ -8,41 +8,44 @@ Name[cs]=NeoChat
Name[de]=NeoChat
Name[en_GB]=NeoChat
Name[es]=NeoChat
Name[eu]=NeoChat
Name[fi]=NeoChat
Name[fr]=NeoChat
Name[ia]=Neochat
Name[it]=NeoChat
Name[ko]=NeoChat
Name[nl]=NeoChat
Name[nn]=NeoChat
Name[pa]=ਨਿਓ-ਚੈਟ
Name[pl]=NeoChat
Name[pt]=NeoChat
Name[pt_BR]=NeoChat
Name[ro]=NeoChat
Name[sk]=NeoChat
Name[sl]=NeoChat
Name[sv]=NeoChat
Name[ta]=நியோச்சாட்
Name[uk]=NeoChat
Name[x-test]=xxNeoChatxx
Name[zh_CN]=NeoChat
DesktopEntry=org.kde.neochat
Comment=A client for matrix, the decentralized communication protocol
Comment[az]=Matrix üçün müştəri, mərkəzləşməmiş kommunikasiya protokolu
Comment[ca]=Un client per a Matrix, el protocol de comunicacions descentralitzat
Comment[ca@valencia]=Un client per a Matrix, el protocol de comunicacions descentralitzat
Comment[ca]=Un client per al Matrix, el protocol de comunicacions descentralitzat
Comment[ca@valencia]=Un client per al Matrix, el protocol de comunicacions descentralitzat
Comment[cs]=Klient pro decentralizovaný komunikační protokol matrix
Comment[de]=Ein Programm für Matrix, das dezentrale Kommunikationsprotokoll
Comment[en_GB]=A client for matrix, the decentralised communication protocol
Comment[es]=Un cliente para Matrix, el protocolo de comunicaciones descentralizado
Comment[eu]=Matrix, deszentralizatutako komunikazio protokolorako, bezero bat
Comment[fi]=Hajautetun Matrix-viestintäyhteyskäytännön asiakasohjelma
Comment[fr]=Un client pour « Matrix », le protocole décentralisé de communications.
Comment[hu]=Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz
Comment[ia]=Un cliente per Matrix, le protocollo de communication decentralisate
Comment[ia]=Un cliente per matrix, le protocollo de communication decentralisate
Comment[it]=Un client per matrix, il protocollo di comunicazione decentralizzato
Comment[ko]=Matrix, 분산 대화 프로토콜 클라이언트
Comment[nl]=Een client voor matrix, het gedecentraliseerde communicatieprotocol
Comment[nn]=Klient for Matrix, den desentraliserte lynmeldings­protokollen.
Comment[pa]=ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ
Comment[pl]=Program do obsługi matriksa, rozproszonego protokołu porozumiewania się
Comment[pt]=Um cliente para o Matrix, o protocolo descentralizado de comunicações
Comment[pt_BR]=Um cliente para o Matrix, o protocolo de comunicação decentralizado
Comment[ro]=Client pentru Matrix, protocolul de comunicare descentralizată
Comment[sk]=Klient pre matrix, decentralizovaný komunikačný protokol
@@ -68,6 +71,7 @@ Name[fr]=Nouveau message
Name[hu]=Új üzenet
Name[ia]=Nove message
Name[it]=Nuovo messaggio
Name[ko]=새 메시지
Name[nl]=Nieuw bericht
Name[nn]=Ny melding
Name[pa]=ਨਵਾਂ ਸੁਨੇਹਾ
@@ -93,8 +97,9 @@ Comment[eu]=Mezu berri bat dago
Comment[fi]=Saapui uusi viesti
Comment[fr]=Il y a un nouveau message
Comment[hu]=Új üzenet érkezett
Comment[ia]=Il ha un nove message
Comment[ia]=Isto es un nove message
Comment[it]=È presente un nuovo messaggio
Comment[ko]=새 메시지가 있음
Comment[nl]=Er is een nieuw bericht
Comment[nn]=Du har ei ny melding
Comment[pa]=ਨਵਾਂ ਸੁਨੇਹਾ ਹੈ

View File

@@ -12,22 +12,24 @@
<name xml:lang="de">NeoChat</name>
<name xml:lang="en-GB">NeoChat</name>
<name xml:lang="es">NeoChat</name>
<name xml:lang="eu">NeoChat</name>
<name xml:lang="fi">NeoChat</name>
<name xml:lang="fr">NeoChat</name>
<name xml:lang="ia">Neochat</name>
<name xml:lang="id">NeoChat</name>
<name xml:lang="it">NeoChat</name>
<name xml:lang="ko">NeoChat</name>
<name xml:lang="nl">NeoChat</name>
<name xml:lang="nn">NeoChat</name>
<name xml:lang="pa">ਨਿਓ-ਚੈਟ</name>
<name xml:lang="pl">NeoChat</name>
<name xml:lang="pt">NeoChat</name>
<name xml:lang="pt-BR">NeoChat</name>
<name xml:lang="sk">NeoChat</name>
<name xml:lang="sl">NeoChat</name>
<name xml:lang="sv">NeoChat</name>
<name xml:lang="ta">நியோச்சாட்</name>
<name xml:lang="uk">NeoChat</name>
<name xml:lang="x-test">xxNeoChatxx</name>
<name xml:lang="zh-CN">NeoChat</name>
<summary>A client for matrix, the decentralized communication protocol</summary>
<summary xml:lang="az">Matrix üçün müştəri, mərkəzləşməmiş kommunikasiya protokolu</summary>
<summary xml:lang="ca">Un client per al Matrix, el protocol de comunicacions descentralitzat</summary>
@@ -40,9 +42,10 @@
<summary xml:lang="fi">Asiakas Matrixille, hajautetulle viestintäyhteyskäytännölle</summary>
<summary xml:lang="fr">Un client pour « Matrix », le protocole décentralisé de communications.</summary>
<summary xml:lang="hu">Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz</summary>
<summary xml:lang="ia">Un cliente per Matrix, le protocollo de communication decentralisate</summary>
<summary xml:lang="ia">Un cliente per matrix, le protocollo de communication decentralisate</summary>
<summary xml:lang="id">Klien untuk matrix, protokol komunikasi terdesentralisasi</summary>
<summary xml:lang="it">Un client per matrix, il protocollo di comunicazione decentralizzato</summary>
<summary xml:lang="ko">Matrix, 분산 대화 프로토콜 클라이언트</summary>
<summary xml:lang="nl">Een client voor matrix, het gedecentraliseerde communicatieprotocol</summary>
<summary xml:lang="nn">Ein klient for Matrix, den desentraliserte lynmeldings­protokollen</summary>
<summary xml:lang="pa">ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ</summary>
@@ -54,33 +57,74 @@
<summary xml:lang="sv">En klient för Matrix, det decentraliserade kommunikationsprotokollet</summary>
<summary xml:lang="uk">Клієнт matrix, децентралізованого протоколу обміну даними</summary>
<summary xml:lang="x-test">xxA client for matrix, the decentralized communication protocolxx</summary>
<summary xml:lang="zh-CN">分布式通讯协议 Matrix 的客户端</summary>
<description>
<p>A client for matrix, the decentralized communication protocol.</p>
<p xml:lang="az">Matrix üçün müştəri, mərkəzləşməmiş kommunikasiya protokolu.</p>
<p xml:lang="ca">Un client per al Matrix, el protocol de comunicacions descentralitzat.</p>
<p xml:lang="ca-valencia">Un client per al Matrix, el protocol de comunicacions descentralitzat.</p>
<p xml:lang="cs">Klient pro decentralizovaný komunikační protokol matrix.</p>
<p xml:lang="de">Ein Programm für Matrix, das dezentrale Kommunikationsprotokoll.</p>
<p xml:lang="en-GB">A client for matrix, the decentralised communication protocol.</p>
<p xml:lang="es">Un cliente para Matrix, el protocolo de comunicaciones descentralizado.</p>
<p xml:lang="eu">Matrix, deszentralizatutako komunikazio protokolorako bezero bat.</p>
<p xml:lang="fi">Asiakas Matrixille, hajautetulle viestintäyhteyskäytännölle.</p>
<p xml:lang="fr">Un client « Matrix », le protocole décentralisé de communications.</p>
<p xml:lang="hu">Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz.</p>
<p xml:lang="ia">Un cliente per Matrix, le protocollo de communication decentralisate.</p>
<p xml:lang="id">Klien untuk matrix, protokol komunikasi terdesentralisasi.</p>
<p xml:lang="it">Un client per matrix, il protocollo di comunicazione decentralizzato.</p>
<p xml:lang="nl">Een client voor matrix, het gedecentraliseerde communicatieprotocol.</p>
<p xml:lang="nn">Ein klient for Matrix, den desentraliserte lynmeldings­protokollen.</p>
<p xml:lang="pa">ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ।</p>
<p xml:lang="pl">Program do obsługi matriksa, rozproszonego protokołu porozumiewania się.</p>
<p xml:lang="pt">Um cliente para o Matrix, o protocolo de comunicação descentralizado.</p>
<p xml:lang="pt-BR">Um cliente do Matrix, o protocolo de comunicação descentralizado.</p>
<p xml:lang="sk">Klient pre matrix, decentralizovaný komunikačný protokol.</p>
<p xml:lang="sl">Odjemalec za matrix, decentralizirani komunikacijski protokol.</p>
<p xml:lang="sv">En klient för Matrix, det decentraliserade kommunikationsprotokollet.</p>
<p xml:lang="uk">Клієнт matrix, децентралізованого протоколу обміну даними.</p>
<p xml:lang="x-test">xxA client for matrix, the decentralized communication protocol.xx</p>
<p>NeoChat is a Matrix client. It allows you to send text messages, videos and audio files to your family, colleagues and friends using the Matrix protocol.</p>
<p xml:lang="az">NeoChat Mtrix müştərisidir. O, Matrix protokolundan istifadə edərək, ailənizə, dostlarınıza, iş yoldaşlarınıza mətn, səsli və görüntülü ismarıclar göndərməyə imkan verir.</p>
<p xml:lang="ca">El NeoChat és un client de Matrix. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics usant el protocol Matrix.</p>
<p xml:lang="ca-valencia">El NeoChat és un client de Matrix. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics usant el protocol Matrix.</p>
<p xml:lang="de">NeoChat ist ein Matrix-Client. Er ermöglicht Ihnen das Senden von Textnachrichten, Videos und Audiodateien an Ihre Familie, Kollegen und Freunde unter Verwendung des Matrix-Protokolls.</p>
<p xml:lang="en-GB">NeoChat is a Matrix client. It allows you to send text messages, videos and audio files to your family, colleagues and friends using the Matrix protocol.</p>
<p xml:lang="es">NeoChat es un cliente para Matrix. Le permite enviar mensajes de texto, vídeos y archivos de sonido a su familia, compañeros de trabajo y amigos usando el protocolo Matrix.</p>
<p xml:lang="eu">NeoChat Matrix bezero bat da. Familiari, lankideei eta lagunei testu-mezuak, bideoak eta audio-fitxategiak bidaltzeko aukera ematen du, Matrix protokoloa erabiliz.</p>
<p xml:lang="fi">NeoChat on Matrix-asiakas. Sillä voi lähettää perheelle, tuttaville ja kavereille tekstiviestejä sekä video- ja äänitiedostoja Matrix-yhteyskäytännöllä.</p>
<p xml:lang="fr">NeoChat est un client Matrix. Il vous permet d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos amis en utilisant le protocole Matrix.</p>
<p xml:lang="ia">NeoChat es un cliente de Matrix. Illo te permitte inviar messager de texto, files de video e audio a tu familia, collegas e amicos usante le protocollo de Matrix.</p>
<p xml:lang="it">NeoChat è un client Matrix. Ti consente di inviare messaggi di testo, file video e audio a familiari, colleghi e amici utilizzando il protocollo Matrix.</p>
<p xml:lang="ko">NeoChat은 Matrix 클라이언트입니다. Matrix 프로토콜을 사용하여 가족, 동료, 친구에게 텍스트 메시지, 동영상, 오디오 파일을 전송할 수 있습니다.</p>
<p xml:lang="nl">NeoChat is een Matrix-client. Het biedt u het verzenden van tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden met het Matrix-protocol.</p>
<p xml:lang="pl">NeoChat jest programem do Matrisa. Umożliwia wysyłanie wiadomości tekstowych, filmów oraz dźwięku do twojej rodziny, znajomych oraz przyjaciół poprzez protokół Matriksa.</p>
<p xml:lang="pt-BR">O NeoChat é um cliente Matrix. Ele permite a você enviar mensagens de texto, arquivos de vídeo e áudio para seus familiares, colegas e amigos usando o protocolo Matrix.</p>
<p xml:lang="sk">NeoChat je Matrix klient. Umožňuje vám posielať textové správy, videá a zvukové súbory rodine, kolegom a priateľom pomocou protokolu Matrix.</p>
<p xml:lang="sl">NeoChat je odjemalec Matrixa. Dovoljuje vam pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, kolegom in prijateljem z uporabo protokola Matrix.</p>
<p xml:lang="sv">NeoChat är en Matrix-klient. Den låter dig skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner med användning av Matrix-protokollet.</p>
<p xml:lang="uk">NeoChat — клієнт мережі обміну повідомленнями Matrix. За допомогою цієї програми ви зможете надсилати текстові повідомлення, відео та звукові файли вашій родині, колегам та друзям за допомогою протоколу Matrix.</p>
<p xml:lang="x-test">xxNeoChat is a Matrix client. It allows you to send text messages, videos and audio files to your family, colleagues and friends using the Matrix protocol.xx</p>
<p xml:lang="zh-CN">NeoChat 是一个 Matrix 客户端。 它允许您使用 Matrix 协议向您的家人、同事和朋友发送文本消息、视频和音频文件。</p>
<p>Matrix is a decentralized communication protocol, putting the user back in control. Currently NeoChat implements large part of the protocol with the exception of encrypted chats and video chat.</p>
<p xml:lang="az">Matrix, istifadəçini nəzarətdə saxlayan, mərkəzləşməmişi rabitə protokoludur. NeoChat, söhbətin və video əlaqəsinin şifrələnməsindən başqa bir çox protokolları həyata keçirə bilir.</p>
<p xml:lang="ca">Matrix és un protocol de comunicacions descentralitzat, que retorna el control a l'usuari. Actualment el NeoChat implementa una gran part del protocol amb l'excepció dels xats encriptats i els xats de vídeo.</p>
<p xml:lang="ca-valencia">Matrix és un protocol de comunicacions descentralitzat, que retorna el control a l'usuari. Actualment el NeoChat implementa una gran part del protocol amb l'excepció dels xats encriptats i els xats de vídeo.</p>
<p xml:lang="de">Matrix ist ein dezentralisiertes Kommunikationsprotokoll, das dem Benutzer wieder die Kontrolle zurückgibt. Derzeit implementiert NeoChat einen großen Teil des Protokolls mit der Ausnahme von verschlüsselten Chats und Video-Chat.</p>
<p xml:lang="en-GB">Matrix is a decentralised communication protocol, putting the user back in control. Currently NeoChat implements large part of the protocol with the exception of encrypted chats and video chat.</p>
<p xml:lang="es">Matrix es un protocolo de comunicaciones descentralizado, que devuelve el control al usuario. En la actualidad, NeoChat implementa gran parte del protocolo con la excepción de chats cifrados y chats de vídeo.</p>
<p xml:lang="eu">Matrix komunikazio-protokolo deszentralizatu bat da, erabiltzaileari kontrola itzultzen diona. Gaur egun, NeoChat-ek protokoloaren zati handi bat inplementatzen du, berriketa zifratuak eta bideo berriketak izan ezik.</p>
<p xml:lang="fi">Matrix on hajautettu viestintäyhteyskäytäntö, joka antaa hallinnan takaisin käyttäjille. NeoChat tarjoaa nykyisellään valtaosan yhteyskäytännöstä salattuja keskustelu- ja videokeskusteluja lukuun ottamatta.</p>
<p xml:lang="fr">Matrix est un protocole de communication décentralisé, donnant le contrôle à l'utilisateur. Actuellement, NeoChat met en œuvre une grande partie du protocole, à l'exception des discussions chiffrées et du chat vidéo.</p>
<p xml:lang="ia">Matrix es un protocollo de communication decentrate, ponente le usator in le controlo. Currentemente NeoChat implementa un grande parte del protocollo con le exception de conversationes cryptate e conversationes video.</p>
<p xml:lang="it">Matrix è un protocollo di comunicazione decentralizzato, che restituisce all'utente il controllo. Attualmente NeoChat implementa gran parte del protocollo ad eccezione delle chat cifrate e delle chat video.</p>
<p xml:lang="ko">Matrix는 사용자에게 제어권을 돌려 주는 분산 통신 프로토콜입니다. NeoChat은 암호화된 대화 및 영상 통화를 제외한 프로토콜의 대부분 기능을 구현합니다.</p>
<p xml:lang="nl">Matrix is een gedecentraliseerd communicatieprotocol, dat de gebruiker de controle teruggeeft. Op dit moment implementeert NeoChat grote delen van het protocol met de uitzondering van versleutelde chats en video-chat.</p>
<p xml:lang="pl">Matrix jest protokołem rozproszonego porozumiewania się oddający użytkownikowi jego władzę. Obecnie NeoChat obsługuje dużą część protokołu poza szyfrowanymi rozmowami tekstowymi i z obrazem.</p>
<p xml:lang="pt-BR">O Matrix é um protocolo de comunicação descentralizado, colocando o usuário de volta no controle. Atualmente o NeoChat implementa grande parte do protocolo com a exceção de bate-papos criptografados e bate-papo por vídeo.</p>
<p xml:lang="sk">Matrix je decentralizovaný komunikačný protokol, ktorý používateľovi vracia kontrolu. V súčasnosti NeoChat implementuje veľkú časť protokolu s výnimkou šifrovaných chatov a videohovorov.</p>
<p xml:lang="sl">Matrix je decentraliziran komunikacijski protokol, kjer ima uporabnik uporabnik kontrolo rabe. Trenutno ima NeoChat izveden velik del protokola z izjemo šifriranih klepetov in video klepetov.</p>
<p xml:lang="sv">Matrix är ett decentraliserat kommunikationsprotokoll, som ger tillbaka kontrollen till användaren. För närvarande implementerar NeoChat en stor del av protokollet, med undantag för krypterad chatt och videochatt.</p>
<p xml:lang="uk">Matrix — протокол децентралізованого спілкування, який передає контроль над даними користувачеві. У поточній версії NeoChat реалізовано більшу частину протоколу, окрім зашифрованого спілкування та відеоспілкування.</p>
<p xml:lang="x-test">xxMatrix is a decentralized communication protocol, putting the user back in control. Currently NeoChat implements large part of the protocol with the exception of encrypted chats and video chat.xx</p>
<p xml:lang="zh-CN">Matrix 是一个分布式通讯协议,使用户重新得到控制权。 目前NeoChat 实现了协议的大部分,除了加密聊天和视频聊天。</p>
<p>NeoChat works both on mobile and desktop while providing a consistent user experience.</p>
<p xml:lang="az">Vahid istifadəçi interfeysi ilə təmin olunan NeoChat, həm mobil telefonda həm də kompyuterlərdə işləyir.</p>
<p xml:lang="ca">El NeoChat funciona en els mòbils i a l'escriptori, proporcionant una experiència d'usuari coherent.</p>
<p xml:lang="ca-valencia">El NeoChat funciona en els mòbils i a l'escriptori, proporcionant una experiència d'usuari coherent.</p>
<p xml:lang="de">NeoChat funktioniert sowohl auf dem Mobiltelefon als auch auf dem Arbeitsfläche und bietet ein einheitliches Benutzererlebnis. </p>
<p xml:lang="en-GB">NeoChat works both on mobile and desktop while providing a consistent user experience.</p>
<p xml:lang="es">NeoChat funciona en móviles y en el escritorio a la vez que proporciona una experiencia de usuario consistente.</p>
<p xml:lang="eu">NeoChat mugikorretan eta mahaigainean dabil, erabiltzaile esperientzia koherentea eskainiz.</p>
<p xml:lang="fi">NeoChat toimii sekä mobiili- että työpöytäalustoilla tarjoten yhdenmukaisen käyttökokemuksen.</p>
<p xml:lang="fr">NeoChat fonctionne aussi bien sur les mobiles que sur les ordinateurs de bureau, tout en offrant une expérience utilisateur cohérente.</p>
<p xml:lang="ia">NeoChat functiona sia sur mobile que ur scriptorio durante que forni un experientia de usator consistente.</p>
<p xml:lang="it">NeoChat funziona sia su dispositivi mobili che desktop, fornendo un'esperienza utente coerente.</p>
<p xml:lang="ko">NeoChat은 모바일과 데스크톱 모두에서 일관된 사용자 경험을 제공합니다.</p>
<p xml:lang="nl">NeoChat werkt zowel op de mobiel en het bureaublad met het leveren van een consistente gebruikerservaring.</p>
<p xml:lang="pl">NeoChat działa zarówno na urządzeniach przenośnych jak i biurkowych, zapewniając spójne wrażenia użytkownika</p>
<p xml:lang="pt-BR">O NeoChat funciona tanto no celular como no computador enquanto fornece uma experiência consistente ao usuário.</p>
<p xml:lang="sk">NeoChat funguje na mobilných aj stolových počítačoch a poskytuje konzistentný používateľský zážitok.</p>
<p xml:lang="sl">NeoChat deluje tako na mobilnih kot na namiznih platformah z zagotavljanjem konsistentne uporabniške izkušnje.</p>
<p xml:lang="sv">NeoChat fungerar både på mobil och skrivbord och tillhandahåller en konsekvent användarupplevelse.</p>
<p xml:lang="uk">NeoChat працює на мобільних пристроях та звичайних комп'ютерах, маючи однорідний інтерфейс на усіх підтримуваних пристроях.</p>
<p xml:lang="x-test">xxNeoChat works both on mobile and desktop while providing a consistent user experience.xx</p>
<p xml:lang="zh-CN">NeoChat 在移动设备和桌面上均可用,并提供一致的用户体验。</p>
</description>
<url type="homepage">https://apps.kde.org/neochat/</url>
<url type="bugtracker">https://invent.kde.org/network/neochat/-/issues</url>
@@ -102,6 +146,7 @@
<developer_name xml:lang="ia">Le communitate de KDE</developer_name>
<developer_name xml:lang="id">Komunitas KDE</developer_name>
<developer_name xml:lang="it">La comunità KDE</developer_name>
<developer_name xml:lang="ko">KDE 커뮤니티</developer_name>
<developer_name xml:lang="nl">De KDE gemeenschap</developer_name>
<developer_name xml:lang="nn">KDE-fellesskapet</developer_name>
<developer_name xml:lang="pa">ਕੇਡੀਈ ਕਮਿਊਨਟੀ</developer_name>
@@ -113,18 +158,30 @@
<developer_name xml:lang="sv">KDE-gemenskapen</developer_name>
<developer_name xml:lang="uk">Спільнота KDE</developer_name>
<developer_name xml:lang="x-test">xxThe KDE Communityxx</developer_name>
<developer_name xml:lang="zh-CN">KDE 社区</developer_name>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0</project_license>
<value key="KDE::matrix">#neochat:kde.org</value>
<screenshots>
<screenshot type="default">
<image>https://www.plasma-mobile.org/img/post-2020-10/post-2020-10-neochat-timeline.png</image>
<image>https://cdn.kde.org/screenshots/neochat/application-mobile.png</image>
</screenshot>
<screenshot type="default">
<image>https://cdn.kde.org/screenshots/neochat/application.png</image>
</screenshot>
</screenshots>
<content_rating type="oars-1.1">
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<releases>
<release version="1.2.0" date="2021-06-01">
<description>
<p>NeoChat 1.2 brings a major redesign of the user interface. The chat page is now using bubbles for the messages and the input component was completely rewritten with a nicer look as well.</p>
<p>It's now possible to send custom reactions by replying to a comment with /react &lt;message&gt;.</p>
<p>NeoChat now supports opening Matrix URIs from your browser.</p>
</description>
<url>https://carlschwan.eu/2021/06/01/neochat-1.2/</url>
</release>
<release urgency="critical" version="1.1.1" date="2021-02-23"/>
<release version="1.1.0" date="2021-02-22">
<description>
@@ -134,7 +191,7 @@
<p>We added a few commands to NeoChat (/shrug, /lenny, /join, /ignore, ...).</p>
<p>We improved the Plasma integration a bit. Now the number of unread messages is displayed in the Plasma Taskbar.</p>
</description>
<url>https://carlschwan.eu/2020/02/22/neochat-1.1/</url>
<url>https://carlschwan.eu/2021/02/22/neochat-1.1/</url>
</release>
<release version="1.0.1" date="2021-01-13">
<description>

View File

@@ -7,26 +7,29 @@ Name[cs]=NeoChat
Name[de]=NeoChat
Name[en_GB]=NeoChat
Name[es]=NeoChat
Name[eu]=NeoChat
Name[fi]=NeoChat
Name[fr]=NeoChat
Name[ia]=Neochat
Name[it]=NeoChat
Name[ko]=NeoChat
Name[nl]=NeoChat
Name[nn]=NeoChat
Name[pa]=ਨਿਓ-ਚੈਟ
Name[pl]=NeoChat
Name[pt]=NeoChat
Name[pt_BR]=NeoChat
Name[ro]=NeoChat
Name[sk]=NeoChat
Name[sl]=NeoChat
Name[sv]=NeoChat
Name[ta]=நியோச்சாட்
Name[uk]=NeoChat
Name[x-test]=xxNeoChatxx
Name[zh_CN]=NeoChat
GenericName=Matrix Client
GenericName[az]=Matrix Müştərisi
GenericName[ca]=Client de Matrix
GenericName[ca@valencia]=Client de Matrix
GenericName[ca]=Client del Matrix
GenericName[ca@valencia]=Client del Matrix
GenericName[cs]=Klient protokolu Matrix
GenericName[de]=Matrix-Programm
GenericName[en_GB]=Matrix Client
@@ -35,8 +38,9 @@ GenericName[eu]=Matrix bezeroa
GenericName[fi]=Matrix-asiakas
GenericName[fr]=Client « Matrix »
GenericName[hu]=Matrix kliens
GenericName[ia]=Cliente de Matrice
GenericName[ia]=Cliente de Matrix
GenericName[it]=Client Matrix
GenericName[ko]=Matrix 클라이언트
GenericName[nl]=Matrix-client
GenericName[nn]=Matrix-klient
GenericName[pa]=ਮੈਟਰਿਕਸ ਕਲਾਈਂਟ
@@ -64,6 +68,7 @@ Comment[fr]=Client pour le protocole « Matrix »
Comment[hu]=Kliens a Matrix protokollhoz
Comment[ia]=Cliente per le protocollo de Matrix
Comment[it]=Client per il protocollo Matrix
Comment[ko]=Matrix 프로토콜용 클라이언트
Comment[nl]=Client voor het Matrix-protocol
Comment[nn]=Lynmeldings­klient for Matrix-protokollen
Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ

View File

@@ -192,7 +192,7 @@ Kirigami.ApplicationWindow {
Kirigami.Action {
text: i18n("Devices")
iconName: "network-connect"
onTriggered: pageStack.layers.push("qrc:/imports/NeoChat/Page/DevicesPage.qml")
onTriggered: pushReplaceLayer("qrc:/imports/NeoChat/Page/DevicesPage.qml")
enabled: pageStack.layers.currentItem.title !== i18n("Devices") && Controller.accountCount > 0
},
Kirigami.Action {

View File

@@ -17,6 +17,7 @@
<file>imports/NeoChat/Component/qmldir</file>
<file>imports/NeoChat/Component/FullScreenImage.qml</file>
<file>imports/NeoChat/Component/FancyEffectsContainer.qml</file>
<file>imports/NeoChat/Component/TypingPane.qml</file>
<file>imports/NeoChat/Component/ChatBox</file>
<file>imports/NeoChat/Component/ChatBox/ChatBox.qml</file>
<file>imports/NeoChat/Component/ChatBox/ChatBar.qml</file>

View File

@@ -33,7 +33,7 @@ add_executable(neochat
../res.qrc
)
if(${Quotient_VERSION_MINOR} GREATER 6)
if(Quotient_VERSION_MINOR GREATER 6)
target_compile_definitions(neochat PRIVATE QUOTIENT_07)
endif()

View File

@@ -20,7 +20,9 @@
#include <QElapsedTimer>
#include <QFile>
#include <QFileInfo>
#include <QGuiApplication>
#include <QMovie>
#include <QNetworkConfigurationManager>
#include <QNetworkReply>
#include <QPixmap>
#include <QQuickWindow>
@@ -29,7 +31,6 @@
#include <QSysInfo>
#include <QTimer>
#include <utility>
#include <QNetworkConfigurationManager>
#include <signal.h>
@@ -47,6 +48,7 @@
#include "neochatuser.h"
#include "settings.h"
#include "utils.h"
#include "roommanager.h"
#include <KStandardShortcut>
#ifndef Q_OS_ANDROID
@@ -67,7 +69,7 @@ Controller::Controller(QObject *parent)
if (NeoChatConfig::self()->systemTray()) {
trayIcon->show();
connect(trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
QApplication::setQuitOnLastWindowClosed(false);
QGuiApplication::setQuitOnLastWindowClosed(false);
}
connect(NeoChatConfig::self(), &NeoChatConfig::SystemTrayChanged, this, [=]() {
if (NeoChatConfig::self()->systemTray()) {
@@ -77,7 +79,7 @@ Controller::Controller(QObject *parent)
trayIcon->hide();
disconnect(trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
}
QApplication::setQuitOnLastWindowClosed(!NeoChatConfig::self()->systemTray());
QGuiApplication::setQuitOnLastWindowClosed(!NeoChatConfig::self()->systemTray());
});
#endif
@@ -85,7 +87,7 @@ Controller::Controller(QObject *parent)
invokeLogin();
});
QObject::connect(QApplication::instance(), &QCoreApplication::aboutToQuit, QApplication::instance(), [] {
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [] {
NeoChatConfig::self()->save();
});
@@ -427,7 +429,8 @@ bool Controller::supportSystemTray() const
#ifdef Q_OS_ANDROID
return false;
#else
return true;
QString de = getenv("XDG_CURRENT_DESKTOP");
return de != QStringLiteral("GNOME") && de != QStringLiteral("Pantheon");
#endif
}
@@ -496,13 +499,13 @@ int Controller::accountCount() const
bool Controller::quitOnLastWindowClosed()
{
return QApplication::quitOnLastWindowClosed();
return QGuiApplication::quitOnLastWindowClosed();
}
void Controller::setQuitOnLastWindowClosed(bool value)
{
if (quitOnLastWindowClosed() != value) {
QApplication::setQuitOnLastWindowClosed(value);
QGuiApplication::setQuitOnLastWindowClosed(value);
Q_EMIT quitOnLastWindowClosedChanged();
}
}
@@ -592,6 +595,17 @@ void Controller::joinRoom(const QString &alias)
});
}
void Controller::openOrCreateDirectChat(NeoChatUser *user)
{
const auto existing = activeConnection()->directChats();
if (existing.contains(user)) {
RoomManager::instance().enterRoom(static_cast<NeoChatRoom *>(activeConnection()->room(existing.value(user))));
return;
}
activeConnection()->requestDirectChat(user);
}
QString Controller::formatByteSize(double size, int precision) const
{
return KFormat().formatByteSize(size, precision);

View File

@@ -3,9 +3,7 @@
#pragma once
#include <QApplication>
#include <QMediaPlayer>
#include <QMenu>
#include <QObject>
#include <KAboutData>
@@ -21,6 +19,7 @@ class QNetworkConfigurationManager;
#include "user.h"
class NeoChatRoom;
class NeoChatUser;
class QQuickWindow;
using namespace Quotient;
@@ -86,6 +85,8 @@ public:
Q_INVOKABLE QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
Q_INVOKABLE QString formatByteSize(double size, int precision = 1) const;
Q_INVOKABLE void openOrCreateDirectChat(NeoChatUser *user);
private:
explicit Controller(QObject *parent = nullptr);
~Controller() override;

View File

@@ -12,6 +12,12 @@
#include <QQuickWindow>
#include <QDebug>
#ifdef Q_OS_ANDROID
#include <QGuiApplication>
#else
#include <QApplication>
#endif
#include <KAboutData>
#ifdef HAVE_KDBUSADDONS
#include <KDBusService>
@@ -57,7 +63,7 @@ Q_DECL_EXPORT
#endif
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QNetworkProxyFactory::setUseSystemConfiguration(true);
@@ -84,7 +90,7 @@ int main(int argc, char *argv[])
app.setFont(font);
#endif
QApplication::setOrganizationName("KDE");
QGuiApplication::setOrganizationName("KDE");
KAboutData about(QStringLiteral("neochat"),
i18n("NeoChat"),
@@ -98,7 +104,7 @@ int main(int argc, char *argv[])
about.setOrganizationDomain("kde.org");
KAboutData::setApplicationData(about);
QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.neochat")));
QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.neochat")));
#ifdef HAVE_KDBUSADDONS
KDBusService service(KDBusService::Unique);
@@ -224,5 +230,5 @@ int main(int argc, char *argv[])
}
}
#endif
return QApplication::exec();
return app.exec();
}

View File

@@ -370,6 +370,22 @@ int MessageEventModel::rowCount(const QModelIndex &parent) const
}
bool MessageEventModel::canFetchMore(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_currentRoom && !m_currentRoom->eventsHistoryJob() && !m_currentRoom->allHistoryLoaded();
}
void MessageEventModel::fetchMore(const QModelIndex &parent)
{
Q_UNUSED(parent);
if (m_currentRoom) {
m_currentRoom->getPreviousContent(20);
}
}
inline QVariantMap userAtEvent(NeoChatUser *user, NeoChatRoom *room, const RoomEvent &evt)
{
Q_UNUSED(evt)
@@ -405,6 +421,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
const KFormat format;
return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat);
}
case SpecialMarksRole:
return EventStatus::Hidden;
}
return {};
}
@@ -532,9 +550,6 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (is<RedactionEvent>(evt) || is<ReactionEvent>(evt)) {
return EventStatus::Hidden;
}
if (evt.isRedacted()) {
return EventStatus::Hidden;
}
if (evt.isStateEvent() && static_cast<const StateEventBase &>(evt).repeatsState()) {
return EventStatus::Hidden;
@@ -667,7 +682,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
auto i = index(r);
if (data(i, SpecialMarksRole) != EventStatus::Hidden) {
return data(i, AuthorRole) != data(idx, AuthorRole) || data(i, EventTypeRole) != data(idx, EventTypeRole)
|| data(idx, TimeRole).toDateTime().msecsTo(data(i, TimeRole).toDateTime()) > 600000;
|| data(idx, TimeRole).toDateTime().msecsTo(data(i, TimeRole).toDateTime()) > 600000
|| data(idx, TimeRole).toDateTime().toLocalTime().date().day() != data(i, TimeRole).toDateTime().toLocalTime().date().day();
}
}
@@ -684,7 +700,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
}
return true;
return false;
}
if (role == ReactionRole) {

View File

@@ -76,6 +76,9 @@ private:
[[nodiscard]] QDateTime makeMessageTimestamp(const Quotient::Room::rev_iter_t &baseIt) const;
[[nodiscard]] static QString renderDate(const QDateTime &timestamp);
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
void refreshLastUserEvents(int baseTimelineRow);
void refreshEventRoles(int row, const QVector<int> &roles = {});
int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {});

View File

@@ -5,7 +5,6 @@
#include <cmark.h>
#include <QFileDialog>
#include <QFileInfo>
#include <QImageReader>
#include <QMetaObject>
@@ -685,3 +684,8 @@ bool NeoChatRoom::isInvite() const
{
return joinState() == JoinState::Invite;
}
bool NeoChatRoom::isUserBanned(const QString &user) const
{
return getCurrentState<RoomMemberEvent>(user)->membership() == MembershipType::Ban;
}

View File

@@ -98,6 +98,7 @@ public:
[[nodiscard]] QString eventToString(const RoomEvent &evt, Qt::TextFormat format = Qt::PlainText, bool removeReply = true) const;
Q_INVOKABLE [[nodiscard]] bool containsUser(const QString &userID) const;
Q_INVOKABLE [[nodiscard]] bool isUserBanned(const QString &user) const;
Q_INVOKABLE [[nodiscard]] bool canSendEvent(const QString &eventType) const;
Q_INVOKABLE [[nodiscard]] bool canSendState(const QString &eventType) const;

View File

@@ -346,12 +346,12 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
if (room->isFavourite()) {
return RoomType::Favorite;
}
if (room->isDirectChat()) {
return RoomType::Direct;
}
if (room->isLowPriority()) {
return RoomType::Deprioritized;
}
if (room->isDirectChat()) {
return RoomType::Direct;
}
return RoomType::Normal;
}
if (role == UnreadCountRole) {