Compare commits
83 Commits
work/fuf/d
...
1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5837a208a | ||
|
|
3b45c0b2f7 | ||
|
|
e1a72816d0 | ||
|
|
aea46c547f | ||
|
|
fe009f764e | ||
|
|
8c14f8d2eb | ||
|
|
559da66197 | ||
|
|
759496620f | ||
|
|
1f7b1ad29f | ||
|
|
9338567137 | ||
|
|
75d2488dbc | ||
|
|
4bed6a07cd | ||
|
|
cb1c9d1869 | ||
|
|
76b2d4ac49 | ||
|
|
5fc931484e | ||
|
|
e60ed3b889 | ||
|
|
1314567fde | ||
|
|
047aa793e7 | ||
|
|
d60f8f4dfa | ||
|
|
20139c08d8 | ||
|
|
fb59bac165 | ||
|
|
5a65dc4d9a | ||
|
|
03ec17366e | ||
|
|
15137cd704 | ||
|
|
2aea0015ba | ||
|
|
f6fd099808 | ||
|
|
04082fc095 | ||
|
|
bc977c3fc6 | ||
|
|
c4c283c85a | ||
|
|
56f49fabf7 | ||
|
|
fe407a3421 | ||
|
|
bbe539885e | ||
|
|
ff978b9586 | ||
|
|
885b75e35f | ||
|
|
cb81eaf26f | ||
|
|
22732b801b | ||
|
|
ae3e395b47 | ||
|
|
96c91e2a35 | ||
|
|
e36204bbd8 | ||
|
|
1804140ac0 | ||
|
|
5a28a93ab6 | ||
|
|
76bd529c3c | ||
|
|
293288a0b6 | ||
|
|
51b6593f96 | ||
|
|
51e73568c4 | ||
|
|
e461e2098b | ||
|
|
79ceb45fae | ||
|
|
0c292b34ff | ||
|
|
db6640ba49 | ||
|
|
3827249f0c | ||
|
|
f40a3daef4 | ||
|
|
8d2608a230 | ||
|
|
3e5628def3 | ||
|
|
3b3673fdff | ||
|
|
d81e4c417d | ||
|
|
44d3f628d9 | ||
|
|
0db9c0454f | ||
|
|
e5c65a662e | ||
|
|
8913aa8a66 | ||
|
|
5db3e14ae6 | ||
|
|
c5a3fc0431 | ||
|
|
fc791d41fa | ||
|
|
127ad19109 | ||
|
|
066ea4f8bd | ||
|
|
cf60337b27 | ||
|
|
98672cf870 | ||
|
|
abd03299ec | ||
|
|
41b64f977c | ||
|
|
ac75dd57c0 | ||
|
|
1d3d61ed77 | ||
|
|
1e047a8ff1 | ||
|
|
530b4c24a0 | ||
|
|
ada7bcef65 | ||
|
|
ad4ca3ad9e | ||
|
|
4103c44eb5 | ||
|
|
dd4ed7539e | ||
|
|
52ad911b2d | ||
|
|
f09dff979e | ||
|
|
0476398f91 | ||
|
|
41993bfe24 | ||
|
|
b3d90ebf82 | ||
|
|
ef0a6e276c | ||
|
|
a104968a29 |
@@ -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
|
# 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)
|
cmake_policy(SET CMP0063 OLD)
|
||||||
|
|
||||||
ecm_setup_version(1.1.80
|
ecm_setup_version(1.2.0
|
||||||
VARIABLE_PREFIX NEOCHAT
|
VARIABLE_PREFIX NEOCHAT
|
||||||
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
|
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
|
set_package_properties(Qt5 PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
PURPOSE "Basic application components"
|
PURPOSE "Basic application components"
|
||||||
@@ -67,6 +67,7 @@ if(ANDROID)
|
|||||||
PURPOSE "Encrypted communications"
|
PURPOSE "Encrypted communications"
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
|
find_package(Qt5 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||||
find_package(KF5QQC2DesktopStyle ${KF5_MIN_VERSION} REQUIRED)
|
find_package(KF5QQC2DesktopStyle ${KF5_MIN_VERSION} REQUIRED)
|
||||||
set_package_properties(KF5QQC2DesktopStyle PROPERTIES
|
set_package_properties(KF5QQC2DesktopStyle PROPERTIES
|
||||||
TYPE RUNTIME
|
TYPE RUNTIME
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
|
|
||||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|||||||
@@ -7,14 +7,16 @@
|
|||||||
|
|
||||||
# first try to find cmark-config.cmake
|
# 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/'
|
# 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)
|
if(cmark_FOUND AND TARGET cmark::cmark)
|
||||||
# found it!
|
# found it!
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(FindPkgConfig)
|
find_package(PkgConfig QUIET)
|
||||||
pkg_check_modules(PC_CMARK QUIET cmark)
|
if(PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules(PC_CMARK QUIET cmark)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT CMARK_INCLUDE_DIR)
|
if(NOT CMARK_INCLUDE_DIR)
|
||||||
find_path(CMARK_INCLUDE_DIR
|
find_path(CMARK_INCLUDE_DIR
|
||||||
|
|||||||
@@ -76,7 +76,11 @@ ToolBar {
|
|||||||
* background colors being very different from the QPalette::Base color.
|
* 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.
|
* 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
|
leftPadding: mirrored ? 0 : Kirigami.Units.largeSpacing
|
||||||
rightPadding: !mirrored ? 0 : Kirigami.Units.largeSpacing
|
rightPadding: !mirrored ? 0 : Kirigami.Units.largeSpacing
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
@@ -165,12 +169,18 @@ ToolBar {
|
|||||||
nextItemInFocusChain(false).forceActiveFocus(Qt.TabFocusReason)
|
nextItemInFocusChain(false).forceActiveFocus(Qt.TabFocusReason)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let decrementedIndex = completionMenu.currentIndex - 1
|
if (!autoAppeared) {
|
||||||
// Wrap around to the last item
|
let decrementedIndex = completionMenu.currentIndex - 1
|
||||||
if (decrementedIndex < 0) {
|
// Wrap around to the last item
|
||||||
decrementedIndex = Math.max(completionMenu.count - 1, 0) // 0 if count == 0
|
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: {
|
Keys.onTabPressed: {
|
||||||
@@ -187,7 +197,7 @@ ToolBar {
|
|||||||
|
|
||||||
// ignore first time tab was clicked so that user can select
|
// ignore first time tab was clicked so that user can select
|
||||||
// first emoji/user
|
// first emoji/user
|
||||||
if (autoAppeared === false) {
|
if (!autoAppeared) {
|
||||||
let incrementedIndex = completionMenu.currentIndex + 1;
|
let incrementedIndex = completionMenu.currentIndex + 1;
|
||||||
// Wrap around to the first item
|
// Wrap around to the first item
|
||||||
if (incrementedIndex > completionMenu.count - 1) {
|
if (incrementedIndex > completionMenu.count - 1) {
|
||||||
@@ -370,8 +380,10 @@ ToolBar {
|
|||||||
|
|
||||||
function complete() {
|
function complete() {
|
||||||
documentHandler.replaceAutoComplete(completionMenu.currentDisplayText);
|
documentHandler.replaceAutoComplete(completionMenu.currentDisplayText);
|
||||||
if (completionMenu.completionType === "username") {
|
if (completionMenu.completionType === ChatDocumentHandler.User
|
||||||
userAutocompleted[completionMenu.currentDisplayText] = completionMenu.currentUserId;
|
&& completionMenu.currentDisplayText.length > 0
|
||||||
|
&& completionMenu.currentItem.userId.length > 0) {
|
||||||
|
userAutocompleted[completionMenu.currentDisplayText] = completionMenu.currentItem.userId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,6 +227,14 @@ Item {
|
|||||||
chatBar.inputFieldForceActiveFocusTriggered()
|
chatBar.inputFieldForceActiveFocusTriggered()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: RoomManager
|
||||||
|
|
||||||
|
function onCurrentRoomChanged() {
|
||||||
|
chatBar.userAutocompleted = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ChatBoxHelper
|
target: ChatBoxHelper
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ Popup {
|
|||||||
property alias delegate: completionListView.delegate
|
property alias delegate: completionListView.delegate
|
||||||
|
|
||||||
// Autocomplee text
|
// Autocomplee text
|
||||||
property string currentDisplayText: currentItem && currentItem.displayName ? currentItem.displayName : ""
|
property string currentDisplayText: currentItem && (currentItem.displayName ?? "")
|
||||||
property string currentUserId: currentItem && currentItem.id ? currentItem.id : ""
|
|
||||||
|
|
||||||
property int completionType: ChatDocumentHandler.Emoji
|
property int completionType: ChatDocumentHandler.Emoji
|
||||||
property int beginPosition: 0
|
property int beginPosition: 0
|
||||||
@@ -78,6 +77,7 @@ Popup {
|
|||||||
id: usernameItem
|
id: usernameItem
|
||||||
width: ListView.view.width ?? implicitWidth
|
width: ListView.view.width ?? implicitWidth
|
||||||
property string displayName: modelData.displayName
|
property string displayName: modelData.displayName
|
||||||
|
property string userId: modelData.id
|
||||||
leading: Kirigami.Avatar {
|
leading: Kirigami.Avatar {
|
||||||
implicitHeight: Kirigami.Units.gridUnit
|
implicitHeight: Kirigami.Units.gridUnit
|
||||||
implicitWidth: implicitHeight
|
implicitWidth: implicitHeight
|
||||||
@@ -86,11 +86,6 @@ Popup {
|
|||||||
}
|
}
|
||||||
text: modelData.displayName
|
text: modelData.displayName
|
||||||
onClicked: completeTriggered();
|
onClicked: completeTriggered();
|
||||||
Component.onCompleted: {
|
|
||||||
completionMenu.currentUserId = Qt.binding(() => {
|
|
||||||
return modelData.id ?? "";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,4 +5,3 @@ ReplyPane 1.0 ReplyPane.qml
|
|||||||
AttachmentPane 1.0 AttachmentPane.qml
|
AttachmentPane 1.0 AttachmentPane.qml
|
||||||
CompletionMenu 1.0 CompletionMenu.qml
|
CompletionMenu 1.0 CompletionMenu.qml
|
||||||
EmojiPickerPane 1.0 EmojiPickerPane.qml
|
EmojiPickerPane 1.0 EmojiPickerPane.qml
|
||||||
TypingPane 1.0 TypingPane.qml
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import QtQuick.Particles 2.15
|
|||||||
|
|
||||||
import org.kde.kirigami 2.15 as Kirigami
|
import org.kde.kirigami 2.15 as Kirigami
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
id: item
|
id: item
|
||||||
property bool enabled: false
|
property bool enabled: false
|
||||||
property int effectInterval: Kirigami.Units.veryLongDuration*10;
|
property int effectInterval: Kirigami.Units.veryLongDuration*10;
|
||||||
@@ -27,11 +27,6 @@ Rectangle {
|
|||||||
fireworksTimer.start()
|
fireworksTimer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// backgroundColor
|
|
||||||
color: Kirigami.Theme.backgroundColor
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
|
||||||
Kirigami.Theme.inherit: false
|
|
||||||
|
|
||||||
// Confetti
|
// Confetti
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ LoginStep {
|
|||||||
readonly property var homeserver: customHomeserver.visible ? customHomeserver.text : serverCombo.currentText
|
readonly property var homeserver: customHomeserver.visible ? customHomeserver.text : serverCombo.currentText
|
||||||
property bool loading: false
|
property bool loading: false
|
||||||
|
|
||||||
title: i18n("@title", "Select a Homeserver")
|
title: i18nc("@title", "Select a Homeserver")
|
||||||
|
|
||||||
action: Kirigami.Action {
|
action: Kirigami.Action {
|
||||||
enabled: LoginHelper.homeserverReachable && !customHomeserver.visible || customHomeserver.acceptableInput
|
enabled: LoginHelper.homeserverReachable && !customHomeserver.visible || customHomeserver.acceptableInput
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ MouseArea {
|
|||||||
id: replyButton
|
id: replyButton
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
implicitHeight: replyName.implicitHeight + (loader.item ? loader.item.height : 0) + Kirigami.Units.largeSpacing
|
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: {
|
Component.onCompleted: {
|
||||||
parent.Layout.fillWidth = true;
|
parent.Layout.fillWidth = true;
|
||||||
parent.Layout.preferredWidth = Qt.binding(function() { return implicitWidth; })
|
parent.Layout.preferredWidth = Qt.binding(function() { return implicitWidth; })
|
||||||
@@ -32,7 +32,7 @@ MouseArea {
|
|||||||
id: avatatReply
|
id: avatatReply
|
||||||
anchors.left: replyLeftBorder.right
|
anchors.left: replyLeftBorder.right
|
||||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
anchors.leftMargin: Kirigami.Units.smallSpacing
|
||||||
width: Kirigami.Units.gridUnit
|
width: visible ? Kirigami.Units.gridUnit : 0
|
||||||
height: Kirigami.Units.gridUnit
|
height: Kirigami.Units.gridUnit
|
||||||
sourceSize.width: width
|
sourceSize.width: width
|
||||||
sourceSize.height: height
|
sourceSize.height: height
|
||||||
@@ -79,7 +79,7 @@ MouseArea {
|
|||||||
textMessage: reply.display
|
textMessage: reply.display
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
wrapMode: Text.WordWrap
|
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
|
x: Kirigami.Units.smallSpacing * 3 + avatatReply.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ QQC2.ItemDelegate {
|
|||||||
property bool isEmote: false
|
property bool isEmote: false
|
||||||
property bool cardBackground: true
|
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 saveFileAs()
|
||||||
signal openExternally()
|
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 {
|
SectionDelegate {
|
||||||
id: sectionDelegate
|
id: sectionDelegate
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.left: parent.left
|
anchors.left: avatar.left
|
||||||
anchors.leftMargin: Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
anchors.leftMargin: Kirigami.Units.smallSpacing
|
||||||
visible: model.showSection
|
visible: model.showSection
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Avatar {
|
Kirigami.Avatar {
|
||||||
id: avatar
|
id: avatar
|
||||||
width: Kirigami.Units.gridUnit * 2
|
width: visible || Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 : 0
|
||||||
height: width
|
height: width
|
||||||
sourceSize.width: width
|
sourceSize.width: width
|
||||||
sourceSize.height: width
|
sourceSize.height: width
|
||||||
@@ -74,7 +74,7 @@ QQC2.ItemDelegate {
|
|||||||
|
|
||||||
visible: model.showAuthor && Config.showAvatarInTimeline
|
visible: model.showAuthor && Config.showAvatarInTimeline
|
||||||
name: model.author.name ?? model.author.displayName
|
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
|
color: model.author.color
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -94,7 +94,7 @@ QQC2.ItemDelegate {
|
|||||||
|
|
||||||
QQC2.Control {
|
QQC2.Control {
|
||||||
id: bubble
|
id: bubble
|
||||||
topPadding: Kirigami.Units.largeSpacing
|
topPadding: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
leftPadding: 0
|
leftPadding: 0
|
||||||
rightPadding: 0
|
rightPadding: 0
|
||||||
@@ -103,6 +103,8 @@ QQC2.ItemDelegate {
|
|||||||
top: avatar.top
|
top: avatar.top
|
||||||
left: avatar.right
|
left: avatar.right
|
||||||
leftMargin: Kirigami.Units.smallSpacing
|
leftMargin: Kirigami.Units.smallSpacing
|
||||||
|
right: Config.showAvatarInTimeline ? undefined : parent.right
|
||||||
|
rightMargin: Config.showAvatarInTimeline ? undefined : Kirigami.Units.largeSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
@@ -112,10 +114,10 @@ QQC2.ItemDelegate {
|
|||||||
id: rowLayout
|
id: rowLayout
|
||||||
visible: model.showAuthor && !isEmote
|
visible: model.showAuthor && !isEmote
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
|
||||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||||
Layout.preferredWidth: nameLabel.implicitWidth + timeLabel.implicitWidth + 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
|
implicitHeight: visible ? nameLabel.implicitHeight : 0
|
||||||
|
|
||||||
QQC2.Label {
|
QQC2.Label {
|
||||||
@@ -131,6 +133,19 @@ QQC2.ItemDelegate {
|
|||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
color: author.color
|
color: author.color
|
||||||
wrapMode: Text.Wrap
|
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 {
|
QQC2.Label {
|
||||||
id: timeLabel
|
id: timeLabel
|
||||||
@@ -157,7 +172,7 @@ QQC2.ItemDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
background: Kirigami.ShadowedRectangle {
|
background: Kirigami.ShadowedRectangle {
|
||||||
visible: cardBackground
|
visible: cardBackground && Config.showAvatarInTimeline
|
||||||
color: model.isHighlighted ? Kirigami.Theme.positiveBackgroundColor : Kirigami.Theme.backgroundColor
|
color: model.isHighlighted ? Kirigami.Theme.positiveBackgroundColor : Kirigami.Theme.backgroundColor
|
||||||
radius: Kirigami.Units.smallSpacing
|
radius: Kirigami.Units.smallSpacing
|
||||||
shadow.size: Kirigami.Units.smallSpacing
|
shadow.size: Kirigami.Units.smallSpacing
|
||||||
@@ -170,13 +185,12 @@ QQC2.ItemDelegate {
|
|||||||
Loader {
|
Loader {
|
||||||
id: loader
|
id: loader
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: bubble.left
|
||||||
leftMargin: Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing * 2
|
|
||||||
right: parent.right
|
right: parent.right
|
||||||
top: bubble.bottom
|
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
|
//Layout.bottomMargin: readMarker ? Kirigami.Units.smallSpacing : 0
|
||||||
active: eventType !== "state" && eventType !== "notice" && reaction != undefined && reaction.length > 0
|
active: eventType !== "state" && eventType !== "notice" && reaction != undefined && reaction.length > 0
|
||||||
visible: active
|
visible: active
|
||||||
|
|||||||
106
imports/NeoChat/Component/TypingPane.qml
Normal file
106
imports/NeoChat/Component/TypingPane.qml
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@ module NeoChat.Component
|
|||||||
FullScreenImage 1.0 FullScreenImage.qml
|
FullScreenImage 1.0 FullScreenImage.qml
|
||||||
ChatTextInput 1.0 ChatTextInput.qml
|
ChatTextInput 1.0 ChatTextInput.qml
|
||||||
FancyEffectsContainer 1.0 FancyEffectsContainer.qml
|
FancyEffectsContainer 1.0 FancyEffectsContainer.qml
|
||||||
|
TypingPane 1.0 TypingPane.qml
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ Kirigami.OverlaySheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kirigami.BasicListItem {
|
Kirigami.BasicListItem {
|
||||||
visible: user !== room.localUser && room.canSendState("kick")
|
visible: user !== room.localUser && room.canSendState("kick") && room.containsUser(user.id)
|
||||||
|
|
||||||
action: Kirigami.Action {
|
action: Kirigami.Action {
|
||||||
text: i18n("Kick this user")
|
text: i18n("Kick this user")
|
||||||
@@ -116,14 +116,14 @@ Kirigami.OverlaySheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kirigami.BasicListItem {
|
Kirigami.BasicListItem {
|
||||||
visible: user !== room.localUser && room.canSendState("ban")
|
visible: user !== room.localUser && room.canSendState("ban") && !room.isUserBanned(user.id)
|
||||||
|
|
||||||
action: Kirigami.Action {
|
action: Kirigami.Action {
|
||||||
text: i18n("Ban this user")
|
text: i18n("Ban this user")
|
||||||
icon.name: "im-ban-user"
|
icon.name: "im-ban-user"
|
||||||
icon.color: Kirigami.Theme.negativeTextColor
|
icon.color: Kirigami.Theme.negativeTextColor
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
room.banMember(user.id)
|
room.ban(user.id)
|
||||||
root.close()
|
root.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ Kirigami.OverlaySheet {
|
|||||||
text: i18n("Open a private chat")
|
text: i18n("Open a private chat")
|
||||||
icon.name: "document-send"
|
icon.name: "document-send"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
Controller.activeConnection.requestDirectChat(user)
|
Controller.openOrCreateDirectChat(user);
|
||||||
root.close()
|
root.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ Kirigami.ScrollablePage {
|
|||||||
sortFilterRoomListModel.index(index, 0)), ItemSelectionModel.SelectCurrent)
|
sortFilterRoomListModel.index(index, 0)), ItemSelectionModel.SelectCurrent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Keys.onEnterPressed: enterRoomAction.trigger()
|
||||||
|
Keys.onReturnPressed: enterRoomAction.trigger()
|
||||||
bold: unreadCount > 0
|
bold: unreadCount > 0
|
||||||
label: name ?? ""
|
label: name ?? ""
|
||||||
subtitle: {
|
subtitle: {
|
||||||
@@ -202,7 +204,7 @@ Kirigami.ScrollablePage {
|
|||||||
}
|
}
|
||||||
delegate: Kirigami.BasicListItem {
|
delegate: Kirigami.BasicListItem {
|
||||||
checkable: true
|
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
|
onClicked: Controller.activeConnection = model.connection
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|||||||
@@ -23,13 +23,18 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
/// It's not readonly because of the seperate window view.
|
/// It's not readonly because of the seperate window view.
|
||||||
property var currentRoom: RoomManager.currentRoom
|
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
|
title: currentRoom.displayName
|
||||||
|
|
||||||
signal switchRoomUp()
|
signal switchRoomUp()
|
||||||
signal switchRoomDown()
|
signal switchRoomDown()
|
||||||
|
|
||||||
onCurrentRoomChanged: ChatBoxHelper.clearEditReply()
|
onCurrentRoomChanged: {
|
||||||
|
hasScrolledUpBefore = false;
|
||||||
|
ChatBoxHelper.clearEditReply()
|
||||||
|
}
|
||||||
|
|
||||||
ActionsHandler {
|
ActionsHandler {
|
||||||
id: actionsHandler
|
id: actionsHandler
|
||||||
@@ -221,7 +226,6 @@ Kirigami.ScrollablePage {
|
|||||||
visible: !invitation.visible
|
visible: !invitation.visible
|
||||||
|
|
||||||
readonly property int largestVisibleIndex: count > 0 ? indexAt(contentX + (width / 2), contentY + height - 1) : -1
|
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
|
readonly property bool isLoaded: page.width * page.height > 10
|
||||||
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
@@ -232,20 +236,38 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
model: !isLoaded ? undefined : sortedMessageEventModel
|
model: !isLoaded ? undefined : sortedMessageEventModel
|
||||||
|
|
||||||
onContentYChanged: fetchMoreContent()
|
|
||||||
|
|
||||||
function fetchMoreContent() {
|
|
||||||
if(!noNeedMoreContent && contentY - 5000 < originY) {
|
|
||||||
currentRoom.getPreviousContent(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageEventModel {
|
MessageEventModel {
|
||||||
id: messageEventModel
|
id: messageEventModel
|
||||||
|
|
||||||
room: currentRoom
|
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 {
|
QQC2.Popup {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
@@ -343,9 +365,10 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
innerObject: TextDelegate {
|
innerObject: TextDelegate {
|
||||||
isEmote: true
|
isEmote: true
|
||||||
|
Layout.fillWidth: !Config.showAvatarInTimeline
|
||||||
Layout.maximumWidth: emoteContainer.bubbleMaxWidth
|
Layout.maximumWidth: emoteContainer.bubbleMaxWidth
|
||||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
|
||||||
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
|
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
|
||||||
TapHandler {
|
TapHandler {
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
@@ -369,10 +392,11 @@ Kirigami.ScrollablePage {
|
|||||||
hoverComponent: hoverActions
|
hoverComponent: hoverActions
|
||||||
|
|
||||||
innerObject: TextDelegate {
|
innerObject: TextDelegate {
|
||||||
|
Layout.fillWidth: !Config.showAvatarInTimeline
|
||||||
Layout.maximumWidth: messageContainer.bubbleMaxWidth
|
Layout.maximumWidth: messageContainer.bubbleMaxWidth
|
||||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||||
Layout.bottomMargin: Kirigami.Units.largeSpacing
|
Layout.bottomMargin: Kirigami.Units.largeSpacing
|
||||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
|
||||||
TapHandler {
|
TapHandler {
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onTapped: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody)
|
onTapped: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody)
|
||||||
@@ -394,9 +418,10 @@ Kirigami.ScrollablePage {
|
|||||||
onReplyClicked: goToEvent(eventID)
|
onReplyClicked: goToEvent(eventID)
|
||||||
|
|
||||||
innerObject: TextDelegate {
|
innerObject: TextDelegate {
|
||||||
|
Layout.fillWidth: !Config.showAvatarInTimeline
|
||||||
Layout.maximumWidth: noticeContainer.bubbleMaxWidth
|
Layout.maximumWidth: noticeContainer.bubbleMaxWidth
|
||||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
|
||||||
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
|
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -550,7 +575,9 @@ Kirigami.ScrollablePage {
|
|||||||
Timer {
|
Timer {
|
||||||
id: makeMeDisapearTimer
|
id: makeMeDisapearTimer
|
||||||
interval: Kirigami.Units.humanMoment * 2
|
interval: Kirigami.Units.humanMoment * 2
|
||||||
onTriggered: currentRoom.markAllMessagesAsRead();
|
onTriggered: if (QQC2.ApplicationWindow.window.visibility !== QQC2.ApplicationWindow.Hidden) {
|
||||||
|
currentRoom.markAllMessagesAsRead();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView.onPooled: makeMeDisapearTimer.stop()
|
ListView.onPooled: makeMeDisapearTimer.stop()
|
||||||
@@ -577,7 +604,9 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
if (view.atYEnd) {
|
if (view.atYEnd) {
|
||||||
// easy case just mark everything as read
|
// easy case just mark everything as read
|
||||||
currentRoom.markAllMessagesAsRead();
|
if (QQC2.ApplicationWindow.window.visibility !== QQC2.ApplicationWindow.Hidden) {
|
||||||
|
currentRoom.markAllMessagesAsRead();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +651,7 @@ Kirigami.ScrollablePage {
|
|||||||
QQC2.RoundButton {
|
QQC2.RoundButton {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: Kirigami.Units.largeSpacing
|
anchors.bottomMargin: Kirigami.Units.largeSpacing + messageListView.headerItem.height
|
||||||
anchors.rightMargin: Kirigami.Units.largeSpacing
|
anchors.rightMargin: Kirigami.Units.largeSpacing
|
||||||
implicitWidth: Kirigami.Units.gridUnit * 2
|
implicitWidth: Kirigami.Units.gridUnit * 2
|
||||||
implicitHeight: Kirigami.Units.gridUnit * 2
|
implicitHeight: Kirigami.Units.gridUnit * 2
|
||||||
@@ -633,6 +662,7 @@ Kirigami.ScrollablePage {
|
|||||||
action: Kirigami.Action {
|
action: Kirigami.Action {
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
goToLastMessage();
|
goToLastMessage();
|
||||||
|
currentRoom.markAllMessagesAsRead();
|
||||||
}
|
}
|
||||||
icon.name: "go-down"
|
icon.name: "go-down"
|
||||||
}
|
}
|
||||||
@@ -643,10 +673,10 @@ Kirigami.ScrollablePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
updateReadMarker()
|
|
||||||
if (currentRoom) {
|
if (currentRoom) {
|
||||||
if (currentRoom.timelineSize < 20)
|
if (currentRoom.timelineSize < 20) {
|
||||||
currentRoom.getPreviousContent(50)
|
currentRoom.getPreviousContent(50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
positionViewAtBeginning();
|
positionViewAtBeginning();
|
||||||
@@ -705,8 +735,12 @@ Kirigami.ScrollablePage {
|
|||||||
header: TypingPane {
|
header: TypingPane {
|
||||||
id: typingPane
|
id: typingPane
|
||||||
visible: !loadingIndicator.visible && currentRoom && currentRoom.usersTyping.length > 0
|
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(", ")) : ""
|
labelText: visible ? i18ncp(
|
||||||
width: parent.width
|
"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
|
height: visible ? implicitHeight : 0
|
||||||
Behavior on height {
|
Behavior on height {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -747,6 +781,7 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
background: FancyEffectsContainer {
|
background: FancyEffectsContainer {
|
||||||
id: fancyEffectsContainer
|
id: fancyEffectsContainer
|
||||||
|
z: 100
|
||||||
|
|
||||||
enabled: Config.showFancyEffects
|
enabled: Config.showFancyEffects
|
||||||
|
|
||||||
@@ -847,7 +882,6 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
/// Open context menu for normal message
|
/// Open context menu for normal message
|
||||||
function openMessageContext(author, message, eventId, source, eventType, formattedBody) {
|
function openMessageContext(author, message, eventId, source, eventType, formattedBody) {
|
||||||
console.log("message", message)
|
|
||||||
const contextMenu = messageDelegateContextMenu.createObject(page, {
|
const contextMenu = messageDelegateContextMenu.createObject(page, {
|
||||||
author: author,
|
author: author,
|
||||||
message: message,
|
message: message,
|
||||||
|
|||||||
@@ -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 {
|
ScrollView {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@@ -168,16 +178,6 @@ Kirigami.OverlayDrawer {
|
|||||||
boundsBehavior: Flickable.DragOverBounds
|
boundsBehavior: Flickable.DragOverBounds
|
||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
|
|
||||||
header: Pane {
|
|
||||||
padding: Kirigami.Units.smallSpacing
|
|
||||||
implicitWidth: parent.width
|
|
||||||
z: 2
|
|
||||||
contentItem: Kirigami.SearchField {
|
|
||||||
id: userListSearchField
|
|
||||||
onTextChanged: sortedMessageEventModel.filterString = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model: KSortFilterProxyModel {
|
model: KSortFilterProxyModel {
|
||||||
id: sortedMessageEventModel
|
id: sortedMessageEventModel
|
||||||
|
|
||||||
|
|||||||
@@ -8,41 +8,44 @@ Name[cs]=NeoChat
|
|||||||
Name[de]=NeoChat
|
Name[de]=NeoChat
|
||||||
Name[en_GB]=NeoChat
|
Name[en_GB]=NeoChat
|
||||||
Name[es]=NeoChat
|
Name[es]=NeoChat
|
||||||
|
Name[eu]=NeoChat
|
||||||
Name[fi]=NeoChat
|
Name[fi]=NeoChat
|
||||||
Name[fr]=NeoChat
|
Name[fr]=NeoChat
|
||||||
Name[ia]=Neochat
|
Name[ia]=Neochat
|
||||||
Name[it]=NeoChat
|
Name[it]=NeoChat
|
||||||
|
Name[ko]=NeoChat
|
||||||
Name[nl]=NeoChat
|
Name[nl]=NeoChat
|
||||||
Name[nn]=NeoChat
|
Name[nn]=NeoChat
|
||||||
Name[pa]=ਨਿਓ-ਚੈਟ
|
Name[pa]=ਨਿਓ-ਚੈਟ
|
||||||
Name[pl]=NeoChat
|
Name[pl]=NeoChat
|
||||||
Name[pt]=NeoChat
|
|
||||||
Name[pt_BR]=NeoChat
|
Name[pt_BR]=NeoChat
|
||||||
Name[ro]=NeoChat
|
Name[ro]=NeoChat
|
||||||
|
Name[sk]=NeoChat
|
||||||
Name[sl]=NeoChat
|
Name[sl]=NeoChat
|
||||||
Name[sv]=NeoChat
|
Name[sv]=NeoChat
|
||||||
Name[ta]=நியோச்சாட்
|
Name[ta]=நியோச்சாட்
|
||||||
Name[uk]=NeoChat
|
Name[uk]=NeoChat
|
||||||
Name[x-test]=xxNeoChatxx
|
Name[x-test]=xxNeoChatxx
|
||||||
|
Name[zh_CN]=NeoChat
|
||||||
DesktopEntry=org.kde.neochat
|
DesktopEntry=org.kde.neochat
|
||||||
Comment=A client for matrix, the decentralized communication protocol
|
Comment=A client for matrix, the decentralized communication protocol
|
||||||
Comment[az]=Matrix üçün müştəri, mərkəzləşməmiş kommunikasiya protokolu
|
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]=Un client per al Matrix, el protocol de comunicacions descentralitzat
|
||||||
Comment[ca@valencia]=Un client per a 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[de]=Ein Programm für Matrix, das dezentrale Kommunikationsprotokoll
|
||||||
Comment[en_GB]=A client for matrix, the decentralised communication protocol
|
Comment[en_GB]=A client for matrix, the decentralised communication protocol
|
||||||
Comment[es]=Un cliente para Matrix, el protocolo de comunicaciones descentralizado
|
Comment[es]=Un cliente para Matrix, el protocolo de comunicaciones descentralizado
|
||||||
Comment[eu]=Matrix, deszentralizatutako komunikazio protokolorako, bezero bat
|
Comment[eu]=Matrix, deszentralizatutako komunikazio protokolorako, bezero bat
|
||||||
Comment[fi]=Hajautetun Matrix-viestintäyhteyskäytännön asiakasohjelma
|
Comment[fi]=Hajautetun Matrix-viestintäyhteyskäytännön asiakasohjelma
|
||||||
Comment[fr]=Un client pour « Matrix », le protocole décentralisé de communications.
|
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[it]=Un client per matrix, il protocollo di comunicazione decentralizzato
|
||||||
|
Comment[ko]=Matrix, 분산 대화 프로토콜 클라이언트
|
||||||
Comment[nl]=Een client voor matrix, het gedecentraliseerde communicatieprotocol
|
Comment[nl]=Een client voor matrix, het gedecentraliseerde communicatieprotocol
|
||||||
Comment[nn]=Klient for Matrix, den desentraliserte lynmeldingsprotokollen.
|
Comment[nn]=Klient for Matrix, den desentraliserte lynmeldingsprotokollen.
|
||||||
Comment[pa]=ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ
|
Comment[pa]=ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ
|
||||||
Comment[pl]=Program do obsługi matriksa, rozproszonego protokołu porozumiewania się
|
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[pt_BR]=Um cliente para o Matrix, o protocolo de comunicação decentralizado
|
||||||
Comment[ro]=Client pentru Matrix, protocolul de comunicare descentralizată
|
Comment[ro]=Client pentru Matrix, protocolul de comunicare descentralizată
|
||||||
Comment[sk]=Klient pre matrix, decentralizovaný komunikačný protokol
|
Comment[sk]=Klient pre matrix, decentralizovaný komunikačný protokol
|
||||||
@@ -68,6 +71,7 @@ Name[fr]=Nouveau message
|
|||||||
Name[hu]=Új üzenet
|
Name[hu]=Új üzenet
|
||||||
Name[ia]=Nove message
|
Name[ia]=Nove message
|
||||||
Name[it]=Nuovo messaggio
|
Name[it]=Nuovo messaggio
|
||||||
|
Name[ko]=새 메시지
|
||||||
Name[nl]=Nieuw bericht
|
Name[nl]=Nieuw bericht
|
||||||
Name[nn]=Ny melding
|
Name[nn]=Ny melding
|
||||||
Name[pa]=ਨਵਾਂ ਸੁਨੇਹਾ
|
Name[pa]=ਨਵਾਂ ਸੁਨੇਹਾ
|
||||||
@@ -93,8 +97,9 @@ Comment[eu]=Mezu berri bat dago
|
|||||||
Comment[fi]=Saapui uusi viesti
|
Comment[fi]=Saapui uusi viesti
|
||||||
Comment[fr]=Il y a un nouveau message
|
Comment[fr]=Il y a un nouveau message
|
||||||
Comment[hu]=Új üzenet érkezett
|
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[it]=È presente un nuovo messaggio
|
||||||
|
Comment[ko]=새 메시지가 있음
|
||||||
Comment[nl]=Er is een nieuw bericht
|
Comment[nl]=Er is een nieuw bericht
|
||||||
Comment[nn]=Du har ei ny melding
|
Comment[nn]=Du har ei ny melding
|
||||||
Comment[pa]=ਨਵਾਂ ਸੁਨੇਹਾ ਹੈ
|
Comment[pa]=ਨਵਾਂ ਸੁਨੇਹਾ ਹੈ
|
||||||
|
|||||||
@@ -12,22 +12,24 @@
|
|||||||
<name xml:lang="de">NeoChat</name>
|
<name xml:lang="de">NeoChat</name>
|
||||||
<name xml:lang="en-GB">NeoChat</name>
|
<name xml:lang="en-GB">NeoChat</name>
|
||||||
<name xml:lang="es">NeoChat</name>
|
<name xml:lang="es">NeoChat</name>
|
||||||
|
<name xml:lang="eu">NeoChat</name>
|
||||||
<name xml:lang="fi">NeoChat</name>
|
<name xml:lang="fi">NeoChat</name>
|
||||||
<name xml:lang="fr">NeoChat</name>
|
<name xml:lang="fr">NeoChat</name>
|
||||||
<name xml:lang="ia">Neochat</name>
|
<name xml:lang="ia">Neochat</name>
|
||||||
<name xml:lang="id">NeoChat</name>
|
|
||||||
<name xml:lang="it">NeoChat</name>
|
<name xml:lang="it">NeoChat</name>
|
||||||
|
<name xml:lang="ko">NeoChat</name>
|
||||||
<name xml:lang="nl">NeoChat</name>
|
<name xml:lang="nl">NeoChat</name>
|
||||||
<name xml:lang="nn">NeoChat</name>
|
<name xml:lang="nn">NeoChat</name>
|
||||||
<name xml:lang="pa">ਨਿਓ-ਚੈਟ</name>
|
<name xml:lang="pa">ਨਿਓ-ਚੈਟ</name>
|
||||||
<name xml:lang="pl">NeoChat</name>
|
<name xml:lang="pl">NeoChat</name>
|
||||||
<name xml:lang="pt">NeoChat</name>
|
|
||||||
<name xml:lang="pt-BR">NeoChat</name>
|
<name xml:lang="pt-BR">NeoChat</name>
|
||||||
|
<name xml:lang="sk">NeoChat</name>
|
||||||
<name xml:lang="sl">NeoChat</name>
|
<name xml:lang="sl">NeoChat</name>
|
||||||
<name xml:lang="sv">NeoChat</name>
|
<name xml:lang="sv">NeoChat</name>
|
||||||
<name xml:lang="ta">நியோச்சாட்</name>
|
<name xml:lang="ta">நியோச்சாட்</name>
|
||||||
<name xml:lang="uk">NeoChat</name>
|
<name xml:lang="uk">NeoChat</name>
|
||||||
<name xml:lang="x-test">xxNeoChatxx</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>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="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>
|
<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="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="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="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="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="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="nl">Een client voor matrix, het gedecentraliseerde communicatieprotocol</summary>
|
||||||
<summary xml:lang="nn">Ein klient for Matrix, den desentraliserte lynmeldingsprotokollen</summary>
|
<summary xml:lang="nn">Ein klient for Matrix, den desentraliserte lynmeldingsprotokollen</summary>
|
||||||
<summary xml:lang="pa">ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ</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="sv">En klient för Matrix, det decentraliserade kommunikationsprotokollet</summary>
|
||||||
<summary xml:lang="uk">Клієнт matrix, децентралізованого протоколу обміну даними</summary>
|
<summary xml:lang="uk">Клієнт matrix, децентралізованого протоколу обміну даними</summary>
|
||||||
<summary xml:lang="x-test">xxA client for matrix, the decentralized communication protocolxx</summary>
|
<summary xml:lang="x-test">xxA client for matrix, the decentralized communication protocolxx</summary>
|
||||||
|
<summary xml:lang="zh-CN">分布式通讯协议 Matrix 的客户端</summary>
|
||||||
<description>
|
<description>
|
||||||
<p>A client for matrix, the decentralized communication protocol.</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">Matrix üçün müştəri, mərkəzləşməmiş kommunikasiya protokolu.</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">Un client per al Matrix, el protocol de comunicacions descentralitzat.</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">Un client per al Matrix, el protocol de comunicacions descentralitzat.</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="cs">Klient pro decentralizovaný komunikační protokol 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="de">Ein Programm für Matrix, das dezentrale Kommunikationsprotokoll.</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="en-GB">A client for matrix, the decentralised communication 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="es">Un cliente para Matrix, el protocolo de comunicaciones descentralizado.</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="eu">Matrix, deszentralizatutako komunikazio protokolorako bezero bat.</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="fi">Asiakas Matrixille, hajautetulle viestintäyhteyskäytännölle.</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="fr">Un client « Matrix », le protocole décentralisé de communications.</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="hu">Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz.</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="ia">Un cliente per Matrix, le protocollo de communication decentralisate.</p>
|
<p xml:lang="ko">NeoChat은 Matrix 클라이언트입니다. Matrix 프로토콜을 사용하여 가족, 동료, 친구에게 텍스트 메시지, 동영상, 오디오 파일을 전송할 수 있습니다.</p>
|
||||||
<p xml:lang="id">Klien untuk matrix, protokol komunikasi terdesentralisasi.</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="it">Un client per matrix, il protocollo di comunicazione decentralizzato.</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="nl">Een client voor matrix, het gedecentraliseerde communicatieprotocol.</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="nn">Ein klient for Matrix, den desentraliserte lynmeldingsprotokollen.</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="pa">ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ।</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="pl">Program do obsługi matriksa, rozproszonego protokołu porozumiewania się.</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="pt">Um cliente para o Matrix, o protocolo de comunicação descentralizado.</p>
|
<p xml:lang="uk">NeoChat — клієнт мережі обміну повідомленнями Matrix. За допомогою цієї програми ви зможете надсилати текстові повідомлення, відео та звукові файли вашій родині, колегам та друзям за допомогою протоколу Matrix.</p>
|
||||||
<p xml:lang="pt-BR">Um cliente do Matrix, o protocolo de comunicação descentralizado.</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="sk">Klient pre matrix, decentralizovaný komunikačný protokol.</p>
|
<p xml:lang="zh-CN">NeoChat 是一个 Matrix 客户端。 它允许您使用 Matrix 协议向您的家人、同事和朋友发送文本消息、视频和音频文件。</p>
|
||||||
<p xml:lang="sl">Odjemalec za matrix, decentralizirani komunikacijski protokol.</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="sv">En klient för Matrix, det decentraliserade kommunikationsprotokollet.</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="uk">Клієнт matrix, децентралізованого протоколу обміну даними.</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="x-test">xxA client for matrix, the decentralized communication protocol.xx</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>
|
</description>
|
||||||
<url type="homepage">https://apps.kde.org/neochat/</url>
|
<url type="homepage">https://apps.kde.org/neochat/</url>
|
||||||
<url type="bugtracker">https://invent.kde.org/network/neochat/-/issues</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="ia">Le communitate de KDE</developer_name>
|
||||||
<developer_name xml:lang="id">Komunitas 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="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="nl">De KDE gemeenschap</developer_name>
|
||||||
<developer_name xml:lang="nn">KDE-fellesskapet</developer_name>
|
<developer_name xml:lang="nn">KDE-fellesskapet</developer_name>
|
||||||
<developer_name xml:lang="pa">ਕੇਡੀਈ ਕਮਿਊਨਟੀ</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="sv">KDE-gemenskapen</developer_name>
|
||||||
<developer_name xml:lang="uk">Спільнота KDE</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="x-test">xxThe KDE Communityxx</developer_name>
|
||||||
|
<developer_name xml:lang="zh-CN">KDE 社区</developer_name>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<project_license>GPL-3.0</project_license>
|
<project_license>GPL-3.0</project_license>
|
||||||
<value key="KDE::matrix">#neochat:kde.org</value>
|
<value key="KDE::matrix">#neochat:kde.org</value>
|
||||||
<screenshots>
|
<screenshots>
|
||||||
<screenshot type="default">
|
<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>
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
<content_rating type="oars-1.1">
|
<content_rating type="oars-1.1">
|
||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
</content_rating>
|
</content_rating>
|
||||||
<releases>
|
<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 <message>.</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 urgency="critical" version="1.1.1" date="2021-02-23"/>
|
||||||
<release version="1.1.0" date="2021-02-22">
|
<release version="1.1.0" date="2021-02-22">
|
||||||
<description>
|
<description>
|
||||||
@@ -134,7 +191,7 @@
|
|||||||
<p>We added a few commands to NeoChat (/shrug, /lenny, /join, /ignore, ...).</p>
|
<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>
|
<p>We improved the Plasma integration a bit. Now the number of unread messages is displayed in the Plasma Taskbar.</p>
|
||||||
</description>
|
</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>
|
||||||
<release version="1.0.1" date="2021-01-13">
|
<release version="1.0.1" date="2021-01-13">
|
||||||
<description>
|
<description>
|
||||||
|
|||||||
@@ -7,26 +7,29 @@ Name[cs]=NeoChat
|
|||||||
Name[de]=NeoChat
|
Name[de]=NeoChat
|
||||||
Name[en_GB]=NeoChat
|
Name[en_GB]=NeoChat
|
||||||
Name[es]=NeoChat
|
Name[es]=NeoChat
|
||||||
|
Name[eu]=NeoChat
|
||||||
Name[fi]=NeoChat
|
Name[fi]=NeoChat
|
||||||
Name[fr]=NeoChat
|
Name[fr]=NeoChat
|
||||||
Name[ia]=Neochat
|
Name[ia]=Neochat
|
||||||
Name[it]=NeoChat
|
Name[it]=NeoChat
|
||||||
|
Name[ko]=NeoChat
|
||||||
Name[nl]=NeoChat
|
Name[nl]=NeoChat
|
||||||
Name[nn]=NeoChat
|
Name[nn]=NeoChat
|
||||||
Name[pa]=ਨਿਓ-ਚੈਟ
|
Name[pa]=ਨਿਓ-ਚੈਟ
|
||||||
Name[pl]=NeoChat
|
Name[pl]=NeoChat
|
||||||
Name[pt]=NeoChat
|
|
||||||
Name[pt_BR]=NeoChat
|
Name[pt_BR]=NeoChat
|
||||||
Name[ro]=NeoChat
|
Name[ro]=NeoChat
|
||||||
|
Name[sk]=NeoChat
|
||||||
Name[sl]=NeoChat
|
Name[sl]=NeoChat
|
||||||
Name[sv]=NeoChat
|
Name[sv]=NeoChat
|
||||||
Name[ta]=நியோச்சாட்
|
Name[ta]=நியோச்சாட்
|
||||||
Name[uk]=NeoChat
|
Name[uk]=NeoChat
|
||||||
Name[x-test]=xxNeoChatxx
|
Name[x-test]=xxNeoChatxx
|
||||||
|
Name[zh_CN]=NeoChat
|
||||||
GenericName=Matrix Client
|
GenericName=Matrix Client
|
||||||
GenericName[az]=Matrix Müştərisi
|
GenericName[az]=Matrix Müştərisi
|
||||||
GenericName[ca]=Client de Matrix
|
GenericName[ca]=Client del Matrix
|
||||||
GenericName[ca@valencia]=Client de Matrix
|
GenericName[ca@valencia]=Client del Matrix
|
||||||
GenericName[cs]=Klient protokolu Matrix
|
GenericName[cs]=Klient protokolu Matrix
|
||||||
GenericName[de]=Matrix-Programm
|
GenericName[de]=Matrix-Programm
|
||||||
GenericName[en_GB]=Matrix Client
|
GenericName[en_GB]=Matrix Client
|
||||||
@@ -35,8 +38,9 @@ GenericName[eu]=Matrix bezeroa
|
|||||||
GenericName[fi]=Matrix-asiakas
|
GenericName[fi]=Matrix-asiakas
|
||||||
GenericName[fr]=Client « Matrix »
|
GenericName[fr]=Client « Matrix »
|
||||||
GenericName[hu]=Matrix kliens
|
GenericName[hu]=Matrix kliens
|
||||||
GenericName[ia]=Cliente de Matrice
|
GenericName[ia]=Cliente de Matrix
|
||||||
GenericName[it]=Client Matrix
|
GenericName[it]=Client Matrix
|
||||||
|
GenericName[ko]=Matrix 클라이언트
|
||||||
GenericName[nl]=Matrix-client
|
GenericName[nl]=Matrix-client
|
||||||
GenericName[nn]=Matrix-klient
|
GenericName[nn]=Matrix-klient
|
||||||
GenericName[pa]=ਮੈਟਰਿਕਸ ਕਲਾਈਂਟ
|
GenericName[pa]=ਮੈਟਰਿਕਸ ਕਲਾਈਂਟ
|
||||||
@@ -64,6 +68,7 @@ Comment[fr]=Client pour le protocole « Matrix »
|
|||||||
Comment[hu]=Kliens a Matrix protokollhoz
|
Comment[hu]=Kliens a Matrix protokollhoz
|
||||||
Comment[ia]=Cliente per le protocollo de Matrix
|
Comment[ia]=Cliente per le protocollo de Matrix
|
||||||
Comment[it]=Client per il protocollo Matrix
|
Comment[it]=Client per il protocollo Matrix
|
||||||
|
Comment[ko]=Matrix 프로토콜용 클라이언트
|
||||||
Comment[nl]=Client voor het Matrix-protocol
|
Comment[nl]=Client voor het Matrix-protocol
|
||||||
Comment[nn]=Lynmeldingsklient for Matrix-protokollen
|
Comment[nn]=Lynmeldingsklient for Matrix-protokollen
|
||||||
Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ
|
Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ Kirigami.ApplicationWindow {
|
|||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
text: i18n("Devices")
|
text: i18n("Devices")
|
||||||
iconName: "network-connect"
|
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
|
enabled: pageStack.layers.currentItem.title !== i18n("Devices") && Controller.accountCount > 0
|
||||||
},
|
},
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
|
|||||||
1
res.qrc
1
res.qrc
@@ -17,6 +17,7 @@
|
|||||||
<file>imports/NeoChat/Component/qmldir</file>
|
<file>imports/NeoChat/Component/qmldir</file>
|
||||||
<file>imports/NeoChat/Component/FullScreenImage.qml</file>
|
<file>imports/NeoChat/Component/FullScreenImage.qml</file>
|
||||||
<file>imports/NeoChat/Component/FancyEffectsContainer.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</file>
|
||||||
<file>imports/NeoChat/Component/ChatBox/ChatBox.qml</file>
|
<file>imports/NeoChat/Component/ChatBox/ChatBox.qml</file>
|
||||||
<file>imports/NeoChat/Component/ChatBox/ChatBar.qml</file>
|
<file>imports/NeoChat/Component/ChatBox/ChatBar.qml</file>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ add_executable(neochat
|
|||||||
../res.qrc
|
../res.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
if(${Quotient_VERSION_MINOR} GREATER 6)
|
if(Quotient_VERSION_MINOR GREATER 6)
|
||||||
target_compile_definitions(neochat PRIVATE QUOTIENT_07)
|
target_compile_definitions(neochat PRIVATE QUOTIENT_07)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include <QMovie>
|
#include <QMovie>
|
||||||
|
#include <QNetworkConfigurationManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
@@ -29,7 +31,6 @@
|
|||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <QNetworkConfigurationManager>
|
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
#include "neochatuser.h"
|
#include "neochatuser.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "roommanager.h"
|
||||||
#include <KStandardShortcut>
|
#include <KStandardShortcut>
|
||||||
|
|
||||||
#ifndef Q_OS_ANDROID
|
#ifndef Q_OS_ANDROID
|
||||||
@@ -67,7 +69,7 @@ Controller::Controller(QObject *parent)
|
|||||||
if (NeoChatConfig::self()->systemTray()) {
|
if (NeoChatConfig::self()->systemTray()) {
|
||||||
trayIcon->show();
|
trayIcon->show();
|
||||||
connect(trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
|
connect(trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
|
||||||
QApplication::setQuitOnLastWindowClosed(false);
|
QGuiApplication::setQuitOnLastWindowClosed(false);
|
||||||
}
|
}
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::SystemTrayChanged, this, [=]() {
|
connect(NeoChatConfig::self(), &NeoChatConfig::SystemTrayChanged, this, [=]() {
|
||||||
if (NeoChatConfig::self()->systemTray()) {
|
if (NeoChatConfig::self()->systemTray()) {
|
||||||
@@ -77,7 +79,7 @@ Controller::Controller(QObject *parent)
|
|||||||
trayIcon->hide();
|
trayIcon->hide();
|
||||||
disconnect(trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
|
disconnect(trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
|
||||||
}
|
}
|
||||||
QApplication::setQuitOnLastWindowClosed(!NeoChatConfig::self()->systemTray());
|
QGuiApplication::setQuitOnLastWindowClosed(!NeoChatConfig::self()->systemTray());
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ Controller::Controller(QObject *parent)
|
|||||||
invokeLogin();
|
invokeLogin();
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(QApplication::instance(), &QCoreApplication::aboutToQuit, QApplication::instance(), [] {
|
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [] {
|
||||||
NeoChatConfig::self()->save();
|
NeoChatConfig::self()->save();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -427,7 +429,8 @@ bool Controller::supportSystemTray() const
|
|||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
return true;
|
QString de = getenv("XDG_CURRENT_DESKTOP");
|
||||||
|
return de != QStringLiteral("GNOME") && de != QStringLiteral("Pantheon");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,13 +499,13 @@ int Controller::accountCount() const
|
|||||||
|
|
||||||
bool Controller::quitOnLastWindowClosed()
|
bool Controller::quitOnLastWindowClosed()
|
||||||
{
|
{
|
||||||
return QApplication::quitOnLastWindowClosed();
|
return QGuiApplication::quitOnLastWindowClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::setQuitOnLastWindowClosed(bool value)
|
void Controller::setQuitOnLastWindowClosed(bool value)
|
||||||
{
|
{
|
||||||
if (quitOnLastWindowClosed() != value) {
|
if (quitOnLastWindowClosed() != value) {
|
||||||
QApplication::setQuitOnLastWindowClosed(value);
|
QGuiApplication::setQuitOnLastWindowClosed(value);
|
||||||
Q_EMIT quitOnLastWindowClosedChanged();
|
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
|
QString Controller::formatByteSize(double size, int precision) const
|
||||||
{
|
{
|
||||||
return KFormat().formatByteSize(size, precision);
|
return KFormat().formatByteSize(size, precision);
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QMediaPlayer>
|
#include <QMediaPlayer>
|
||||||
#include <QMenu>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <KAboutData>
|
#include <KAboutData>
|
||||||
@@ -21,6 +19,7 @@ class QNetworkConfigurationManager;
|
|||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
class NeoChatUser;
|
||||||
class QQuickWindow;
|
class QQuickWindow;
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -86,6 +85,8 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
|
Q_INVOKABLE QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
|
||||||
Q_INVOKABLE QString formatByteSize(double size, int precision = 1) const;
|
Q_INVOKABLE QString formatByteSize(double size, int precision = 1) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE void openOrCreateDirectChat(NeoChatUser *user);
|
||||||
private:
|
private:
|
||||||
explicit Controller(QObject *parent = nullptr);
|
explicit Controller(QObject *parent = nullptr);
|
||||||
~Controller() override;
|
~Controller() override;
|
||||||
|
|||||||
14
src/main.cpp
14
src/main.cpp
@@ -12,6 +12,12 @@
|
|||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#else
|
||||||
|
#include <QApplication>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <KAboutData>
|
#include <KAboutData>
|
||||||
#ifdef HAVE_KDBUSADDONS
|
#ifdef HAVE_KDBUSADDONS
|
||||||
#include <KDBusService>
|
#include <KDBusService>
|
||||||
@@ -57,7 +63,7 @@ Q_DECL_EXPORT
|
|||||||
#endif
|
#endif
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||||
|
|
||||||
@@ -84,7 +90,7 @@ int main(int argc, char *argv[])
|
|||||||
app.setFont(font);
|
app.setFont(font);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QApplication::setOrganizationName("KDE");
|
QGuiApplication::setOrganizationName("KDE");
|
||||||
|
|
||||||
KAboutData about(QStringLiteral("neochat"),
|
KAboutData about(QStringLiteral("neochat"),
|
||||||
i18n("NeoChat"),
|
i18n("NeoChat"),
|
||||||
@@ -98,7 +104,7 @@ int main(int argc, char *argv[])
|
|||||||
about.setOrganizationDomain("kde.org");
|
about.setOrganizationDomain("kde.org");
|
||||||
|
|
||||||
KAboutData::setApplicationData(about);
|
KAboutData::setApplicationData(about);
|
||||||
QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.neochat")));
|
QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.neochat")));
|
||||||
|
|
||||||
#ifdef HAVE_KDBUSADDONS
|
#ifdef HAVE_KDBUSADDONS
|
||||||
KDBusService service(KDBusService::Unique);
|
KDBusService service(KDBusService::Unique);
|
||||||
@@ -224,5 +230,5 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return QApplication::exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
inline QVariantMap userAtEvent(NeoChatUser *user, NeoChatRoom *room, const RoomEvent &evt)
|
||||||
{
|
{
|
||||||
Q_UNUSED(evt)
|
Q_UNUSED(evt)
|
||||||
@@ -405,6 +421,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
|||||||
const KFormat format;
|
const KFormat format;
|
||||||
return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat);
|
return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat);
|
||||||
}
|
}
|
||||||
|
case SpecialMarksRole:
|
||||||
|
return EventStatus::Hidden;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -532,9 +550,6 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
|||||||
if (is<RedactionEvent>(evt) || is<ReactionEvent>(evt)) {
|
if (is<RedactionEvent>(evt) || is<ReactionEvent>(evt)) {
|
||||||
return EventStatus::Hidden;
|
return EventStatus::Hidden;
|
||||||
}
|
}
|
||||||
if (evt.isRedacted()) {
|
|
||||||
return EventStatus::Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evt.isStateEvent() && static_cast<const StateEventBase &>(evt).repeatsState()) {
|
if (evt.isStateEvent() && static_cast<const StateEventBase &>(evt).repeatsState()) {
|
||||||
return EventStatus::Hidden;
|
return EventStatus::Hidden;
|
||||||
@@ -667,7 +682,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
|||||||
auto i = index(r);
|
auto i = index(r);
|
||||||
if (data(i, SpecialMarksRole) != EventStatus::Hidden) {
|
if (data(i, SpecialMarksRole) != EventStatus::Hidden) {
|
||||||
return data(i, AuthorRole) != data(idx, AuthorRole) || data(i, EventTypeRole) != data(idx, EventTypeRole)
|
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) {
|
if (role == ReactionRole) {
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ private:
|
|||||||
[[nodiscard]] QDateTime makeMessageTimestamp(const Quotient::Room::rev_iter_t &baseIt) const;
|
[[nodiscard]] QDateTime makeMessageTimestamp(const Quotient::Room::rev_iter_t &baseIt) const;
|
||||||
[[nodiscard]] static QString renderDate(const QDateTime ×tamp);
|
[[nodiscard]] static QString renderDate(const QDateTime ×tamp);
|
||||||
|
|
||||||
|
bool canFetchMore(const QModelIndex &parent) const override;
|
||||||
|
void fetchMore(const QModelIndex &parent) override;
|
||||||
|
|
||||||
void refreshLastUserEvents(int baseTimelineRow);
|
void refreshLastUserEvents(int baseTimelineRow);
|
||||||
void refreshEventRoles(int row, const QVector<int> &roles = {});
|
void refreshEventRoles(int row, const QVector<int> &roles = {});
|
||||||
int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {});
|
int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {});
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <cmark.h>
|
#include <cmark.h>
|
||||||
|
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
@@ -685,3 +684,8 @@ bool NeoChatRoom::isInvite() const
|
|||||||
{
|
{
|
||||||
return joinState() == JoinState::Invite;
|
return joinState() == JoinState::Invite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NeoChatRoom::isUserBanned(const QString &user) const
|
||||||
|
{
|
||||||
|
return getCurrentState<RoomMemberEvent>(user)->membership() == MembershipType::Ban;
|
||||||
|
}
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public:
|
|||||||
[[nodiscard]] QString eventToString(const RoomEvent &evt, Qt::TextFormat format = Qt::PlainText, bool removeReply = true) const;
|
[[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 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 canSendEvent(const QString &eventType) const;
|
||||||
Q_INVOKABLE [[nodiscard]] bool canSendState(const QString &eventType) const;
|
Q_INVOKABLE [[nodiscard]] bool canSendState(const QString &eventType) const;
|
||||||
|
|||||||
@@ -346,12 +346,12 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
|
|||||||
if (room->isFavourite()) {
|
if (room->isFavourite()) {
|
||||||
return RoomType::Favorite;
|
return RoomType::Favorite;
|
||||||
}
|
}
|
||||||
if (room->isDirectChat()) {
|
|
||||||
return RoomType::Direct;
|
|
||||||
}
|
|
||||||
if (room->isLowPriority()) {
|
if (room->isLowPriority()) {
|
||||||
return RoomType::Deprioritized;
|
return RoomType::Deprioritized;
|
||||||
}
|
}
|
||||||
|
if (room->isDirectChat()) {
|
||||||
|
return RoomType::Direct;
|
||||||
|
}
|
||||||
return RoomType::Normal;
|
return RoomType::Normal;
|
||||||
}
|
}
|
||||||
if (role == UnreadCountRole) {
|
if (role == UnreadCountRole) {
|
||||||
|
|||||||
Reference in New Issue
Block a user