Compare commits

..

1 Commits

Author SHA1 Message Date
Joshua Goins
47df3f9882 Add a way to view banned and invited users 2026-02-03 18:42:20 -05:00
102 changed files with 8578 additions and 8479 deletions

View File

@@ -106,7 +106,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
endif()
find_package(QuotientQt6 0.10.0)
find_package(QuotientQt6 0.9.3)
set_package_properties(QuotientQt6 PROPERTIES
TYPE REQUIRED
DESCRIPTION "Qt wrapper around Matrix API"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -97,9 +97,9 @@ KirigamiComponents.ConvergentContextMenu {
text: i18nc("@action:inmenu Open support dialog", "Support")
icon.name: "help-contents-symbolic"
onTriggered: {
(Qt.createComponent("org.kde.neochat", "SupportDialog").createObject(QQC2.Overlay.overlay, {
Qt.createComponent("org.kde.neochat", "SupportDialog").createObject(QQC2.Overlay.overlay, {
connection: root.connection,
}) as SupportDialog).open();
}).open();
}
}

View File

@@ -4,6 +4,9 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import org.kde.kirigami as Kirigami
import org.kde.neochat

View File

@@ -79,7 +79,7 @@ Components.AbstractMaximizeComponent {
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
QQC2.TextArea {
id: codeTextEdit
id: codeText
topPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
leftPadding: lineNumberColumn.width + lineNumberColumn.anchors.leftMargin + Kirigami.Units.smallSpacing * 2
@@ -100,15 +100,15 @@ Components.AbstractMaximizeComponent {
SyntaxHighlighter {
property string definitionName: Repository.definitionForName(root.language).name
textEdit: definitionName == "None" ? null : codeTextEdit
textEdit: definitionName == "None" ? null : codeText
definition: definitionName
}
ColumnLayout {
id: lineNumberColumn
anchors {
top: codeTextEdit.top
topMargin: codeTextEdit.topPadding + 1
left: codeTextEdit.left
top: codeText.top
topMargin: codeText.topPadding + 1
left: codeText.left
leftMargin: Kirigami.Units.smallSpacing
}
spacing: 0
@@ -116,7 +116,7 @@ Components.AbstractMaximizeComponent {
id: repeater
model: LineModel {
id: lineModel
Component.onCompleted: setDocument(codeTextEdit.textDocument)
Component.onCompleted: setDocument(codeText.textDocument)
}
delegate: QQC2.Label {
id: label

View File

@@ -3,6 +3,8 @@
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import QtQml.Models
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.labs.components as KirigamiComponents

View File

@@ -41,11 +41,13 @@ ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
QQC2.Button {
anchors.bottom: parent.bottom
text: i18n("They match")
icon.name: "dialog-ok"
onClicked: root.accept()
}
QQC2.Button {
anchors.bottom: parent.bottom
text: i18n("They don't match")
icon.name: "dialog-cancel"
onClicked: root.reject()

View File

@@ -9,6 +9,8 @@ import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.kirigamiaddons.labs.components as Components
import org.kde.neochat
Delegates.RoundedItemDelegate {
id: root

View File

@@ -166,7 +166,7 @@ ColumnLayout {
}
RowLayout {
visible: (root.currentRoom.connection as NeoChatConnection).canCheckMutualRooms
visible: root.currentRoom.connection.canCheckMutualRooms
spacing: 0
Layout.topMargin: Kirigami.Units.largeSpacing * 2

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -10,8 +8,8 @@ import QtQuick.Window
import QtQml
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.neochat
import io.github.quotient_im.libquotient
Kirigami.Page {
id: root

View File

@@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtLocation
import QtPositioning

View File

@@ -100,7 +100,7 @@ Kirigami.ApplicationWindow {
function onCurrentRoomChanged() {
if (RoomManager.currentRoom && root.pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) {
let roomPage = root.pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
roomPage.forceActiveFocus();
roomPage.backRequested.connect(event => {
RoomManager.clearCurrentRoom();
@@ -151,6 +151,8 @@ Kirigami.ApplicationWindow {
}
contextDrawer: RoomDrawer {
id: contextDrawer
// This is a memory for all user initiated actions on the drawer, i.e. clicking the button
// It is used to ensure that user choice is remembered when changing pages and expanding and contracting the window width
property bool drawerUserState: NeoChatConfig.autoRoomInfoDrawer
@@ -176,9 +178,9 @@ Kirigami.ApplicationWindow {
// Connect to the onClicked function of the RoomDrawer handle button
Connections {
target: root.contextDrawer.handle.children[0]
target: contextDrawer.handle.children[0]
function onClicked() {
root.contextDrawer.drawerUserState = root.contextDrawer.drawerOpen;
contextDrawer.drawerUserState = contextDrawer.drawerOpen;
}
}

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-only
pragma ComponentBehavior: Bound
import QtQuick
import org.kde.kirigami as Kirigami
@@ -18,7 +16,7 @@ Kirigami.PromptDialog {
customFooterActions: Kirigami.Action {
icon.name: "camera-video-symbolic"
text: root.hasExistingMeeting ? i18nc("@action:button Join the Jitsi meeting", "Join") : i18nc("@action:button Start a new Jitsi meeting", "Start")
text: hasExistingMeeting ? i18nc("@action:button Join the Jitsi meeting", "Join") : i18nc("@action:button Start a new Jitsi meeting", "Start")
onTriggered: root.accept()
}
}

View File

@@ -66,7 +66,7 @@ Kirigami.Dialog {
id: optionModel
readonly property bool allValuesSet: {
for (let i = 0; i < optionModel.rowCount(); i++) {
for( var i = 0; i < optionModel.rowCount(); i++ ) {
if (optionModel.get(i).optionText.length <= 0) {
return false;
}
@@ -83,7 +83,7 @@ Kirigami.Dialog {
function values() {
let textValues = []
for(let i = 0; i < optionModel.rowCount(); i++) {
for( var i = 0; i < optionModel.rowCount(); i++ ) {
textValues.push(optionModel.get(i).optionText);
}
return textValues;

View File

@@ -18,7 +18,7 @@ Kirigami.Page {
required property NeoChatConnection connection
padding: 0
Component.onCompleted: session.camera.start()
Component.onCompleted: camera.start()
Connections {
target: root.QQC2.ApplicationWindow.window
@@ -66,8 +66,12 @@ Kirigami.Page {
CaptureSession {
id: session
camera: Camera {}
imageCapture: ImageCapture {}
camera: Camera {
id: camera
}
imageCapture: ImageCapture {
id: imageCapture
}
videoOutput: viewFinder
}
}

View File

@@ -30,7 +30,7 @@ Kirigami.Page {
type: Kirigami.MessageType.Information
position: Kirigami.InlineMessage.Position.Header
text: xi18nc("@info", "This report will <strong>only</strong> be sent to the administrators of <link>%1</link> (your server).", root.connection.domain)
text: xi18n("This report will <strong>only</strong> be sent to the administrators of <link>%1</link> (your server).", root.connection.domain)
}
QQC2.TextArea {

View File

@@ -104,8 +104,8 @@ Kirigami.Page {
enabled: hasExistingMeeting || canStartNewMeeting
visible: root.currentRoom && !root.currentRoom.isSpace
onTriggered: {
const dialog = Qt.createComponent("org.kde.neochat", "MeetingDialog").createObject(QQC2.Overlay.overlay, { hasExistingMeeting }) as MeetingDialog;
dialog.accepted.connect(doAction);
const dialog = Qt.createComponent("org.kde.neochat", "MeetingDialog").createObject(QQC2.Overlay.overlay, { hasExistingMeeting });
dialog.onAccepted.connect(doAction);
dialog.open();
}
@@ -215,7 +215,7 @@ Kirigami.Page {
}
TapHandler {
onTapped: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomPinnedMessagesPage'), {
onTapped: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomPinnedMessagesPage'), {
room: root.currentRoom
}, {
title: i18nc("@title", "Pinned Messages")

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2026 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-only
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts

View File

@@ -8,6 +8,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.prison
import org.kde.neochat

View File

@@ -5,7 +5,6 @@ import QtQuick
import QtQml
import org.kde.neochat
import io.github.quotient_im.libquotient
VerificationMessage {
id: root

View File

@@ -40,11 +40,9 @@ ColumnLayout {
model: root.connection.getSupportedRoomVersions()
delegate: FormCard.FormTextDelegate {
id: versionDelegate
required property var modelData
text: modelData.id
contentItem.children: QQC2.Label {
text: versionDelegate.modelData.status
text: modelData.status
color: Kirigami.Theme.disabledTextColor
}
}

View File

@@ -11,8 +11,10 @@ bool UserFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceP
if (!m_allowEmpty && m_filterText.length() < 1) {
return false;
}
if (sourceModel()->data(sourceModel()->index(sourceRow, 0), UserListModel::MembershipRole).value<Quotient::Membership>() != Quotient::Membership::Join) {
return false;
if (m_membership != Quotient::Membership::Invalid) {
if (sourceModel()->data(sourceModel()->index(sourceRow, 0), UserListModel::MembershipRole).value<Quotient::Membership>() != m_membership) {
return false;
}
}
return sourceModel()->data(sourceModel()->index(sourceRow, 0), UserListModel::DisplayNameRole).toString().contains(m_filterText, Qt::CaseInsensitive)
|| sourceModel()->data(sourceModel()->index(sourceRow, 0), UserListModel::UserIdRole).toString().contains(m_filterText, Qt::CaseInsensitive);
@@ -41,4 +43,15 @@ void UserFilterModel::setAllowEmpty(bool allowEmpty)
Q_EMIT allowEmptyChanged();
}
Quotient::Membership UserFilterModel::membership() const
{
return m_membership;
}
void UserFilterModel::setMembership(const Quotient::Membership state)
{
m_membership = state;
Q_EMIT membershipChanged();
}
#include "moc_userfiltermodel.cpp"

View File

@@ -3,6 +3,8 @@
#pragma once
#include <Quotient/quotient_common.h>
#include <QQmlEngine>
#include <QSortFilterProxyModel>
@@ -25,7 +27,10 @@ class UserFilterModel : public QSortFilterProxyModel
*/
Q_PROPERTY(QString filterText READ filterText WRITE setFilterText NOTIFY filterTextChanged)
Q_PROPERTY(bool allowEmpty READ allowEmpty WRITE setAllowEmpty NOTIFY allowEmptyChanged)
/**
* @brief Only shows users with this membership state.
*/
Q_PROPERTY(Quotient::Membership membership READ membership WRITE setMembership NOTIFY membershipChanged)
public:
using QSortFilterProxyModel::QSortFilterProxyModel;
@@ -42,11 +47,16 @@ public:
bool allowEmpty() const;
void setAllowEmpty(bool allowEmpty);
Quotient::Membership membership() const;
void setMembership(Quotient::Membership state);
Q_SIGNALS:
void filterTextChanged();
void allowEmptyChanged();
void membershipChanged();
private:
QString m_filterText;
bool m_allowEmpty = false;
Quotient::Membership m_membership = Quotient::Membership::Invalid;
};

View File

@@ -108,7 +108,7 @@ SearchPage {
id: _private
function openManualUserDialog(): void {
let dialog = manualUserDialog.createObject(this, {
connection: root.room.connection
connection: root.connection
}) as ManualUserDialog;
dialog.parent = root.Window.window.overlay;
dialog.accepted.connect(() => {

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt.labs.qmlmodels

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtCore
import QtQuick
import QtQuick.Controls as QQC2
@@ -36,7 +34,7 @@ QQC2.Control {
Layout.fillWidth: true
Layout.margins: Kirigami.Units.largeSpacing
Layout.preferredHeight: active ? (item as Item).implicitHeight : 0
Layout.preferredHeight: active ? item.implicitHeight : 0
active: visible
visible: root.chatBarCache.replyId.length > 0 || root.chatBarCache.attachmentPath.length > 0
@@ -73,7 +71,7 @@ QQC2.Control {
root.chatBarCache.text = text;
}
Keys.onEnterPressed: event => {
Keys.onEnterPressed: {
if (completionMenu.visible) {
completionMenu.complete();
} else if (event.modifiers & Qt.ShiftModifier) {
@@ -82,7 +80,7 @@ QQC2.Control {
_private.post();
}
}
Keys.onReturnPressed: event => {
Keys.onReturnPressed: {
if (completionMenu.visible) {
completionMenu.complete();
} else if (event.modifiers & Qt.ShiftModifier) {
@@ -110,7 +108,7 @@ QQC2.Control {
height: implicitHeight
y: -height - 5
z: 10
connection: root.Message.room.connection as NeoChatConnection
connection: root.Message.room.connection
chatDocumentHandler: documentHandler
margins: 0
Behavior on height {
@@ -167,7 +165,7 @@ QQC2.Control {
text: i18nc("@action:button", "Attach an image or file")
icon.name: "mail-attachment"
onClicked: {
let dialog = (Clipboard.hasImage ? attachDialog : openFileDialog).createObject(QQC2.Overlay.overlay) as QQC2.Dialog;
let dialog = (Clipboard.hasImage ? attachDialog : openFileDialog).createObject(QQC2.Overlay.overlay);
dialog.chosen.connect(path => root.chatBarCache.attachmentPath = path);
dialog.open();
}
@@ -227,6 +225,8 @@ QQC2.Control {
Message.maxContentWidth: paneLoader.item.width
}
QQC2.Button {
id: cancelButton
anchors.top: parent.top
anchors.right: parent.right
@@ -261,9 +261,9 @@ QQC2.Control {
function updateText() {
// This could possibly be undefined due to some esoteric QtQuick issue. Referencing it somewhere in JS is enough.
documentHandler.document;
if (root.chatBarCache?.isEditing && root.chatBarCache.relationMessage.length > 0) {
textArea.text = root.chatBarCache.relationMessage;
documentHandler.updateMentions(root.chatBarCache.editId);
if (chatBarCache?.isEditing && chatBarCache.relationMessage.length > 0) {
textArea.text = chatBarCache.relationMessage;
documentHandler.updateMentions(chatBarCache.editId);
textArea.forceActiveFocus();
textArea.cursorPosition = textArea.text.length;
}

View File

@@ -2,13 +2,12 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-3.0-only
pragma ComponentBehavior: Bound
import QtCore as Core
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import QtQuick.Dialogs as Dialogs
import Qt.labs.qmlmodels
import org.kde.coreaddons
import org.kde.kirigami as Kirigami
@@ -52,7 +51,7 @@ ColumnLayout {
property bool autoOpenFile: false
function saveFileAs() {
const dialog = fileDialog.createObject(QQC2.Overlay.overlay) as Dialogs.FileDialog;
const dialog = fileDialog.createObject(QQC2.Overlay.overlay);
dialog.selectedFile = Message.room.fileNameToDownload(root.eventId);
dialog.open();
}
@@ -71,7 +70,7 @@ ColumnLayout {
states: [
State {
name: "downloadedInstant"
when: root.fileTransferInfo.completed && root.autoOpenFile
when: root.fileTransferInfo.completed && autoOpenFile
PropertyChanges {
openButton.icon.name: "document-open"
@@ -85,7 +84,7 @@ ColumnLayout {
},
State {
name: "downloaded"
when: root.fileTransferInfo.completed && !root.autoOpenFile
when: root.fileTransferInfo.completed && !autoOpenFile
PropertyChanges {
openButton.visible: false
@@ -139,7 +138,7 @@ ColumnLayout {
id: openButton
icon.name: "document-open"
onClicked: {
root.autoOpenFile = true;
autoOpenFile = true;
root.Message.room.downloadTempFile(root.eventId);
}
@@ -167,7 +166,7 @@ ColumnLayout {
onAccepted: {
NeoChatConfig.lastSaveDirectory = currentFolder;
NeoChatConfig.save();
if (root.autoOpenFile) {
if (autoOpenFile) {
UrlHelper.copyTo(root.fileTransferInfo.localPath, selectedFile);
} else {
root.Message.room.download(root.eventId, selectedFile);

View File

@@ -40,7 +40,7 @@ ColumnLayout {
Layout.maximumWidth: Message.maxContentWidth
LiveLocationsModel {
id: locationModel
id: liveLocationModel
eventId: root.eventId
room: Message.room
}
@@ -50,13 +50,13 @@ ColumnLayout {
Layout.preferredWidth: root.Message.maxContentWidth
Layout.preferredHeight: root.Message.maxContentWidth / 16 * 9
map.center: QtPositioning.coordinate(locationModel.boundingBox.y, locationModel.boundingBox.x)
map.center: QtPositioning.coordinate(liveLocationModel.boundingBox.y, liveLocationModel.boundingBox.x)
map.zoomLevel: 15
map.plugin: OsmLocationPlugin.plugin
MapItemView {
model: locationModel
model: liveLocationModel
delegate: LocationMapItem {}
}
@@ -64,7 +64,7 @@ ColumnLayout {
acceptedButtons: Qt.LeftButton
onTapped: {
fullScreenMap.createObject(parent, {
liveLocationModel: locationModel
liveLocationModel: liveLocationModel
})
}
}

View File

@@ -2,10 +2,9 @@
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: GPL-3.0-only
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
@@ -103,7 +102,7 @@ Flow {
}
onClicked: {
var dialog = emojiDialog.createObject(reactButton) as EmojiDialog;
var dialog = emojiDialog.createObject(reactButton);
dialog.showStickers = false;
dialog.chosen.connect(emoji => {
root.Message.room.toggleReaction(root.eventId, emoji);

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt.labs.qmlmodels
@@ -119,7 +117,6 @@ DelegateChooser {
DelegateChoice {
roleValue: MessageComponentType.Location
delegate: MimeComponent {
required property string display
mimeIconSource: "mark-location"
label: display
}
@@ -128,7 +125,6 @@ DelegateChooser {
DelegateChoice {
roleValue: MessageComponentType.LiveLocation
delegate: MimeComponent {
required property string display
mimeIconSource: "mark-location"
label: display
}

View File

@@ -2,8 +2,6 @@
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: GPL-3.0-only
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -61,7 +59,7 @@ Kirigami.OverlayDrawer {
if (_lastX === -1) {
return;
}
if (Application.layoutDirection === Qt.RightToLeft) {
if (Qt.application.layoutDirection === Qt.RightToLeft) {
root.actualWidth = Math.min(root.maxWidth, Math.max(root.minWidth, root.roomDrawerWidth - _lastX + mapToGlobal(mouseX, mouseY).x));
} else {
root.actualWidth = Math.min(root.maxWidth, Math.max(root.minWidth, root.roomDrawerWidth + _lastX - mapToGlobal(mouseX, mouseY).x));
@@ -70,7 +68,7 @@ Kirigami.OverlayDrawer {
}
enabled: true
edge: Application.layoutDirection == Qt.RightToLeft ? Qt.LeftEdge : Qt.RightEdge
edge: Qt.application.layoutDirection == Qt.RightToLeft ? Qt.LeftEdge : Qt.RightEdge
// If modal has been changed and the drawer is closed automatically then dim on popup open will have been switched off in main.qml so switch it back on after the animation completes.
// This is to avoid dim being active for a split second when the drawer is switched to modal which looks terrible.

View File

@@ -1,9 +1,8 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
@@ -104,7 +103,7 @@ Kirigami.Page {
Connections {
target: root.Kirigami.PageStack.pageStack
function onWideModeChanged(): void {
onWideModeChanged: {
if ((root.Kirigami.PageStack.pageStack as Kirigami.PageRow).wideMode) {
root.Kirigami.PageStack.pop();
}

View File

@@ -261,6 +261,7 @@ QQC2.ScrollView {
id: userFilterModel
sourceModel: root.userListModel
allowEmpty: true
membership: JoinRule.Join
}
clip: true

View File

@@ -126,7 +126,7 @@ KirigamiComponents.ConvergentContextMenu {
Kirigami.Action {
text: i18nc("@action:inmenu", "Copy Room Link")
icon.name: "edit-copy"
visible: !root.room.isDirectChat() && root.room.joinRule !== Quotient.JoinRule.Invite
visible: !root.room.isDirectChat() && root.room.joinRule !== Quotient.Invite
onTriggered: {
// The canonical alias (if it exists) otherwise the first available alias
const firstAlias = root.room.aliases[0];

View File

@@ -46,6 +46,7 @@ QQC2.Control {
}
ColumnLayout {
id: column
width: scrollView.width
spacing: 0

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -30,7 +28,7 @@ FormCard.FormCardPage {
interval: 10
running: false
onTriggered: root.QQC2.ApplicationWindow.window.pageStack.layers.push(Qt.createComponent('org.kde.neochat.settings', 'AccountEditorPage'), {
connection: root.initialAccount
connection: initialAccount
}, {
title: i18n("Account editor")
})
@@ -46,7 +44,7 @@ FormCard.FormCardPage {
id: accountDelegate
required property NeoChatConnection connection
Layout.fillWidth: true
onClicked: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).layers.push(Qt.createComponent('org.kde.neochat.settings', 'AccountEditorPage'), {
onClicked: root.QQC2.ApplicationWindow.window.pageStack.layers.push(Qt.createComponent('org.kde.neochat.settings', 'AccountEditorPage'), {
connection: accountDelegate.connection
}, {
title: i18n("Account editor")
@@ -89,7 +87,7 @@ FormCard.FormCardPage {
QQC2.ToolButton {
text: i18n("Logout…")
icon.name: "im-kick-user"
onClicked: (confirmLogoutDialogComponent.createObject(root.QQC2.Overlay.overlay) as ConfirmLogoutDialog).open()
onClicked: confirmLogoutDialogComponent.createObject(root.QQC2.Overlay.overlay).open()
}
Component {
@@ -126,8 +124,8 @@ FormCard.FormCardPage {
property Connections connections: Connections {
target: Controller
function onConnectionAdded() {
if ((root.Kirigami.PageStack.pageStack as Kirigami.PageRow).layers.depth > 2) {
(root.Kirigami.PageStack.pageStack as Kirigami.PageRow).layers.pop();
if (pageStack.layers.depth > 2) {
pageStack.layers.pop();
}
}
}

View File

@@ -52,6 +52,7 @@ ecm_add_qml_module(Settings GENERATE_PLUGIN_SOURCE
RoomAdvancedPage.qml
KeyboardShortcutsPage.qml
Members.qml
MembersList.qml
SOURCES
colorschemer.cpp
threepidaddhelper.cpp

View File

@@ -24,6 +24,7 @@ FormCard.FormCardPage {
required property NeoChatConnection connection
property DevicesModel devicesModel: DevicesModel {
id: devicesModel
connection: root.connection
}
@@ -48,7 +49,7 @@ FormCard.FormCardPage {
standardButtons: Kirigami.Dialog.Ok
})
dialog.open();
root.connection.newKeyVerificationSession.connect(() => {
root.connection.onNewKeyVerificationSession.connect(() => {
dialog.close();
});
}
@@ -75,7 +76,7 @@ FormCard.FormCardPage {
FormCard.AbstractFormDelegate {
Layout.fillWidth: true
visible: root.connection && root.devicesModel.count === 0 // We can assume 0 means loading since there is at least one device
visible: root.connection && devicesModel.count === 0 // We can assume 0 means loading since there is at least one device
contentItem: Kirigami.LoadingPlaceholder {}
}

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtCore as Core
import QtQuick
import QtQuick.Controls as QQC2
@@ -29,7 +27,7 @@ FormCard.FormCardPage {
title: emoticonType === EmoticonFormCard.Stickers ? (newEmoticon ? i18nc("@title:window", "Add Sticker") : i18nc("@title:window", "Edit Sticker")) : (newEmoticon ? i18nc("@title:window", "Add Emoji") : i18nc("@title:window", "Edit Emoji"))
FormCard.FormHeader {
title: root.emoticonType === EmoticonFormCard.Stickers ? i18nc("@info:group", "Sticker") : i18nc("@info:group", "Emoji")
title: emoticonType === EmoticonFormCard.Stickers ? i18nc("@info:group", "Sticker") : i18nc("@info:group", "Emoji")
}
FormCard.FormCard {
FormCard.AbstractFormDelegate {
@@ -44,9 +42,11 @@ FormCard.FormCardPage {
source: root.url
sourceSize.width: Kirigami.Units.gridUnit * 4
sourceSize.height: Kirigami.Units.gridUnit * 4
width: Kirigami.Units.gridUnit * 4
height: Kirigami.Units.gridUnit * 4
Kirigami.Icon {
source: root.emoticonType === EmoticonFormCard.Stickers ? "stickers" : "preferences-desktop-emoticons"
source: emoticonType === EmoticonFormCard.Stickers ? "stickers" : "preferences-desktop-emoticons"
anchors.fill: parent
visible: parent.status !== Image.Ready
}
@@ -73,7 +73,7 @@ FormCard.FormCardPage {
if (fileDialog != null) {
return;
}
fileDialog = root.openFileDialog.createObject(QQC2.Overlay.overlay);
fileDialog = openFileDialog.createObject(QQC2.Overlay.overlay);
fileDialog.chosen.connect(function (receivedSource) {
mouseArea.fileDialog = null;
if (!receivedSource) {
@@ -94,10 +94,12 @@ FormCard.FormCardPage {
}
}
FormCard.FormTextFieldDelegate {
id: shortcode
label: i18n("Shortcode:")
text: root.shortcode
}
FormCard.FormTextFieldDelegate {
id: description
label: i18n("Description:")
text: root.description
}
@@ -105,19 +107,19 @@ FormCard.FormCardPage {
id: save
text: i18n("Save")
icon.name: "document-save"
enabled: !root.newEmoticon || (image.source.toString().length > 0 && root.shortcode && root.description)
enabled: !root.newEmoticon || (image.source.toString().length > 0 && shortcode.text && description.text)
onClicked: {
if (root.newEmoticon) {
root.model.addEmoticon(image.source, root.shortcode, root.description, root.emoticonType === EmoticonFormCard.Stickers ? "sticker" : "emoticon");
model.addEmoticon(image.source, shortcode.text, description.text, emoticonType === EmoticonFormCard.Stickers ? "sticker" : "emoticon");
} else {
if (root.description !== root.description) {
root.model.setEmoticonBody(root.proxyModel.mapToSource(root.proxyModel.index(root.model.index, 0)).row, root.description);
if (description.text !== root.description) {
root.model.setEmoticonBody(proxyModel.mapToSource(proxyModel.index(model.index, 0)).row, description.text);
}
if (root.shortcode !== root.shortcode) {
root.model.setEmoticonShortcode(root.proxyModel.mapToSource(root.proxyModel.index(root.model.index, 0)).row, root.shortcode);
if (shortcode.text !== root.shortcode) {
root.model.setEmoticonShortcode(proxyModel.mapToSource(proxyModel.index(model.index, 0)).row, shortcode.text);
}
if (image.source + "" !== root.url) {
root.model.setEmoticonImage(root.proxyModel.mapToSource(root.proxyModel.index(root.model.index, 0)).row, image.source);
root.model.setEmoticonImage(proxyModel.mapToSource(proxyModel.index(model.index, 0)).row, image.source);
}
}
root.closeDialog();
@@ -125,6 +127,8 @@ FormCard.FormCardPage {
}
}
property Component openFileDialog: Component {
id: openFileDialog
OpenFileDialog {
currentFolder: Core.StandardPaths.standardLocations(Core.StandardPaths.PicturesLocation)[0]
parentWindow: root.Window.window

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -29,8 +27,8 @@ FormCard.FormCardPage {
FormCard.FormCheckDelegate {
text: i18n("Enable notifications for this account")
description: {
if (root.connection.pushNotificationsAvailable) {
if (root.connection.enablePushNotifications) {
if (connection.pushNotificationsAvailable) {
if (connection.enablePushNotifications) {
return i18n("Notifications can appear even when NeoChat isn't running.");
} else {
return i18n("Push notifications are available but could not be enabled.");
@@ -54,6 +52,8 @@ FormCard.FormCardPage {
spacing: Kirigami.Units.largeSpacing
Kirigami.Icon {
source: "data-information"
width: Kirigami.Units.iconSizes.sizeForLabels
height: Kirigami.Units.iconSizes.sizeForLabels
}
QQC2.Label {
text: i18nc("@info", "These are the default notification settings for all rooms. You can customize notifications per-room in the room list or room settings.")
@@ -78,7 +78,7 @@ FormCard.FormCardPage {
}
}
delegate: root.ruleDelegate
delegate: ruleDelegate
}
}
@@ -95,7 +95,7 @@ FormCard.FormCardPage {
}
}
delegate: root.ruleDelegate
delegate: ruleDelegate
}
}
@@ -113,7 +113,7 @@ FormCard.FormCardPage {
}
}
delegate: root.ruleDelegate
delegate: ruleDelegate
}
FormCard.AbstractFormDelegate {
Layout.fillWidth: true
@@ -176,7 +176,7 @@ FormCard.FormCardPage {
}
}
delegate: root.ruleDelegate
delegate: ruleDelegate
}
}
@@ -197,11 +197,12 @@ FormCard.FormCardPage {
}
}
delegate: root.ruleDelegate
delegate: ruleDelegate
}
}
property Component ruleDelegate: Component {
id: ruleDelegate
NotificationRuleItem {
onDeleteRule: {
root.pushRuleModel.removeKeyword(id);

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -39,8 +37,6 @@ FormCard.FormCardPage {
id: repeater
model: root.connection.ignoredUsers()
delegate: FormCard.AbstractFormDelegate {
id: ignoredUserDelegate
required property string modelData
topPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
@@ -50,7 +46,7 @@ FormCard.FormCardPage {
QQC2.Label {
Layout.fillWidth: true
text: ignoredUserDelegate.modelData
text: modelData
elide: Text.ElideRight
Accessible.ignored: true // base class sets this text on root already
}
@@ -58,7 +54,7 @@ FormCard.FormCardPage {
QQC2.ToolButton {
text: i18nc("@action:button", "Unignore this user")
icon.name: "list-remove-symbolic"
onClicked: root.connection.removeFromIgnoredUsers(ignoredUserDelegate.modelData)
onClicked: root.connection.removeFromIgnoredUsers(modelData)
display: QQC2.Button.IconOnly
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered

View File

@@ -2,13 +2,13 @@
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Dialogs
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import io.github.quotient_im.libquotient
import org.kde.neochat
FormCard.FormCardPage {

View File

@@ -14,6 +14,7 @@ import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.kitemmodels
import org.kde.neochat
import io.github.quotient_im.libquotient
FormCard.FormCardPage {
id: root
@@ -28,6 +29,63 @@ FormCard.FormCardPage {
showMute: false
}
Component {
id: bannedMembersPage
MembersList {
title: i18nc("@title", "Banned Members")
membership: Quotient.MembershipMask.Ban
room: root.room
confirmationTitle: i18nc("@title:dialog", "Unban User")
confirmationSubtitle: i18nc("@info %1 is a matrix ID", "Do you really want to unban %1?", currentMemberId)
icon: "checkmark-symbolic"
actionText: i18nc("@action:button", "Unban…")
actionConfirmationText: i18nc("@action:button", "Unban")
actionVisible: root.room.canSendState("ban")
onActionTaken: memberId => root.room.unban(memberId)
}
}
Component {
id: invitedMembersPage
MembersList {
title: i18nc("@title", "Invited Members")
membership: Quotient.MembershipMask.Invite
room: root.room
confirmationTitle: i18nc("@title:dialog", "Uninvite User")
confirmationSubtitle: i18nc("@info %1 is a matrix ID", "Do you really want to uninvite %1?", currentMemberId)
icon: "im-ban-kick-user-symbolic"
actionText: i18nc("@action:button", "Uninvite…")
actionConfirmationText: i18nc("@action:button", "Uninvite")
actionVisible: root.room.canSendState("kick")
onActionTaken: memberId => root.room.kickMember(memberId, "Revoked invite")
}
}
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing * 4
FormCard.FormButtonDelegate {
id: bannedMemberDelegate
icon.name: "im-ban-user-symbolic"
text: i18nc("@action:button", "Banned Members")
onClicked: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).layers.push(bannedMembersPage)
}
FormCard.FormDelegateSeparator {
above: bannedMemberDelegate
below: inviteMemberDelegate
}
FormCard.FormButtonDelegate {
id: inviteMemberDelegate
icon.name: "list-add-user-symbolic"
text: i18nc("@action:button", "Invited Members")
onClicked: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).layers.push(invitedMembersPage)
}
}
FormCard.FormHeader {
title: i18nc("@title", "Privileged Members")
visible: !root.loading
@@ -103,6 +161,7 @@ FormCard.FormCardPage {
id: userListFilterModel
sourceModel: RoomManager.userListModel
filterText: userListSearchField.text
membership: Quotient.MembershipMask.Join
onFilterTextChanged: {
if (filterText.length > 0 && !userListSearchPopup.visible) {

View File

@@ -0,0 +1,95 @@
// SPDX-FileCopyrightText: 2026 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.kitemmodels
import org.kde.neochat
FormCard.FormCardPage {
id: root
required property NeoChatRoom room
property alias membership: userFilterModel.membership
property alias confirmationTitle: actionDialog.title
property alias confirmationSubtitle: actionDialog.subtitle
property string currentMemberId
required property string icon
required property string actionText
required property string actionConfirmationText
required property bool actionVisible
signal actionTaken(memberId: string)
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing * 4
Layout.fillWidth: true
FormCard.FormPlaceholderMessageDelegate {
text: i18nc("@info:placeholder", "No members")
visible: userRepeater.count === 0
}
Repeater {
id: userRepeater
model: UserFilterModel {
id: userFilterModel
sourceModel: RoomManager.userListModel
allowEmpty: true
}
delegate: FormCard.FormTextDelegate {
id: userDelegate
required property string userId
text: userId
textItem.textFormat: Text.PlainText
contentItem.children: RowLayout {
spacing: Kirigami.Units.largeSpacing
QQC2.Button {
icon.name: root.icon
visible: root.actionVisible
text: root.actionText
onClicked: {
root.currentMemberId = userDelegate.userId;
actionDialog.open();
}
}
}
}
}
}
Kirigami.PromptDialog {
id: actionDialog
parent: root.QQC2.Overlay.overlay
footer: QQC2.DialogButtonBox {
standardButtons: QQC2.Dialog.Cancel
QQC2.Button {
icon.name: root.icon
text: root.actionConfirmationText
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
}
}
onAccepted: root.actionTaken(root.currentMemberId)
}
}

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -59,9 +57,9 @@ FormCard.FormCardPage {
FormCard.FormCheckDelegate {
id: rejectInvitationsDelegate
text: i18nc("@option:check", "Reject invitations from unknown users")
description: root.connection.canCheckMutualRooms ? i18nc("@info", "If enabled, NeoChat will reject invitations from users you don't share a room with.") : i18nc("@info", "Your server does not support this setting.")
description: connection.canCheckMutualRooms ? i18nc("@info", "If enabled, NeoChat will reject invitations from users you don't share a room with.") : i18nc("@info", "Your server does not support this setting.")
checked: NeoChatConfig.rejectUnknownInvites
enabled: !NeoChatConfig.isRejectUnknownInvitesImmutable && root.connection.canCheckMutualRooms
enabled: !NeoChatConfig.isRejectUnknownInvitesImmutable && connection.canCheckMutualRooms
onToggled: {
NeoChatConfig.rejectUnknownInvites = checked;
NeoChatConfig.save();
@@ -76,7 +74,7 @@ FormCard.FormCardPage {
text: i18nc("@option:check", "Turn on encryption in new chats")
description: i18nc("@info", "If enabled, NeoChat will use encryption when starting new direct messages.")
checked: NeoChatConfig.preferUsingEncryption
enabled: !NeoChatConfig.isPreferUsingEncryptionImmutable
enabled: !NeoChatConfig.preferUsingEncryptionImmutable
onToggled: {
NeoChatConfig.preferUsingEncryption = checked;
NeoChatConfig.save();

View File

@@ -11,8 +11,6 @@ import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.neochat
FormCard.FormCardPage {
id: root
title: i18nc("@title:window", "Proxy")
property int currentType
property bool proxyConfigChanged: false
@@ -23,10 +21,10 @@ FormCard.FormCardPage {
FormCard.FormRadioDelegate {
id: systemDefault
text: i18n("System Default")
checked: root.currentType === 0
checked: currentType === 0
enabled: !NeoChatConfig.isProxyTypeImmutable
onToggled: {
root.currentType = 0
currentType = 0
}
}
@@ -35,10 +33,10 @@ FormCard.FormCardPage {
FormCard.FormRadioDelegate {
id:noProxy
text: i18n("No Proxy")
checked: root.currentType === 3
enabled: !NeoChatConfig.isProxyTypeImmutable
checked: currentType === 3
enabled: !Config.isProxyTypeImmutable
onToggled: {
root.currentType = 3;
currentType = 3;
}
}
@@ -47,10 +45,10 @@ FormCard.FormCardPage {
FormCard.FormRadioDelegate {
id: http
text: i18n("HTTP")
checked: root.currentType === 1
checked: currentType === 1
enabled: !NeoChatConfig.isProxyTypeImmutable
onToggled: {
root.currentType = 1
currentType = 1
}
}
@@ -59,10 +57,10 @@ FormCard.FormCardPage {
FormCard.FormRadioDelegate {
id: socks5
text: i18n("Socks5")
checked: root.currentType === 2
checked: currentType === 2
enabled: !NeoChatConfig.isProxyTypeImmutable
onToggled: {
root.currentType = 2
currentType = 2
}
}
}
@@ -73,7 +71,7 @@ FormCard.FormCardPage {
FormCard.FormCard {
// It makes no sense to configure proxy settings for "System Default" and "No Proxy"
enabled: root.currentType !== 0 && root.currentType !== 3
enabled: currentType !== 0 && currentType !== 3
FormCard.FormTextFieldDelegate {
id: hostField
@@ -81,7 +79,7 @@ FormCard.FormCardPage {
text: NeoChatConfig.proxyHost
inputMethodHints: Qt.ImhUrlCharactersOnly
onEditingFinished: {
root.proxyConfigChanged = true
proxyConfigChanged = true
}
}
FormCard.FormDelegateSeparator { below: hostField; above: portField }
@@ -103,7 +101,7 @@ FormCard.FormCardPage {
return value // it will add a thousands separator if we don't do this, not sure why
}
onValueChanged: {
root.proxyConfigChanged = true
proxyConfigChanged = true
}
}
}
@@ -115,7 +113,7 @@ FormCard.FormCardPage {
text: NeoChatConfig.proxyUser
inputMethodHints: Qt.ImhUrlCharactersOnly
onEditingFinished: {
root.proxyConfigChanged = true
proxyConfigChanged = true
}
}
FormCard.FormDelegateSeparator { below: userField; above: passwordField }
@@ -126,7 +124,7 @@ FormCard.FormCardPage {
echoMode: TextInput.Password
inputMethodHints: Qt.ImhUrlCharactersOnly
onEditingFinished: {
root.proxyConfigChanged = true
proxyConfigChanged = true
}
}
}
@@ -141,15 +139,15 @@ FormCard.FormCardPage {
QQC2.Button {
text: i18n("Apply")
icon.name: "dialog-ok-apply-symbolic"
enabled: root.currentType !== NeoChatConfig.proxyType || root.proxyConfigChanged
enabled: currentType !== NeoChatConfig.proxyType || proxyConfigChanged
onClicked: {
NeoChatConfig.proxyType = root.currentType;
NeoChatConfig.proxyType = currentType;
NeoChatConfig.proxyHost = hostField.text;
NeoChatConfig.proxyPort = portField.value;
NeoChatConfig.proxyUser = userField.text;
NeoChatConfig.proxyPassword = passwordField.text;
NeoChatConfig.save();
root.proxyConfigChanged = false;
proxyConfigChanged = false;
ProxyController.setApplicationProxy();
}
}

View File

@@ -17,7 +17,7 @@ FormCard.FormCardPage {
property NeoChatRoom room
property PushRuleModel pushRuleModel: PushRuleModel {
connection: root.room.connection as NeoChatConnection
connection: root.room.connection
}
title: i18nc('@title:window', 'Notifications')
@@ -30,37 +30,37 @@ FormCard.FormCardPage {
FormCard.FormRadioDelegate {
icon.name: "globe"
text: i18nc("As in the default notification setting", "Default Settings")
checked: root.room.pushNotificationState === PushNotificationState.Default
enabled: root.room.pushNotificationState !== PushNotificationState.Unknown
checked: room.pushNotificationState === PushNotificationState.Default
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
root.room.pushNotificationState = PushNotificationState.Default;
room.pushNotificationState = PushNotificationState.Default;
}
}
FormCard.FormRadioDelegate {
icon.name: "notifications"
text: i18nc("As in 'notify for all messages'", "All Messages")
checked: root.room.pushNotificationState === PushNotificationState.All
enabled: root.room.pushNotificationState !== PushNotificationState.Unknown
checked: room.pushNotificationState === PushNotificationState.All
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
root.room.pushNotificationState = PushNotificationState.All;
room.pushNotificationState = PushNotificationState.All;
}
}
FormCard.FormRadioDelegate {
icon.name: "im-user"
text: i18nc("As in 'notify when the user is mentioned or the message contains a set keyword'", "@Mentions and Keywords")
checked: root.room.pushNotificationState === PushNotificationState.MentionKeyword
enabled: root.room.pushNotificationState !== PushNotificationState.Unknown
checked: room.pushNotificationState === PushNotificationState.MentionKeyword
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
root.room.pushNotificationState = PushNotificationState.MentionKeyword;
room.pushNotificationState = PushNotificationState.MentionKeyword;
}
}
FormCard.FormRadioDelegate {
icon.name: "notifications-disabled"
text: i18nc("As in 'do not notify for any messages'", "None")
checked: root.room.pushNotificationState === PushNotificationState.Mute
enabled: root.room.pushNotificationState !== PushNotificationState.Unknown
checked: room.pushNotificationState === PushNotificationState.Mute
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
root.room.pushNotificationState = PushNotificationState.Mute;
room.pushNotificationState = PushNotificationState.Mute;
}
}
}
@@ -80,11 +80,16 @@ FormCard.FormCardPage {
}
}
delegate: NotificationRuleItem {
onDeleteRule: {
root.pushRuleModel.removeKeyword(id);
delegate: ruleDelegate
Component {
id: ruleDelegate
NotificationRuleItem {
onDeleteRule: {
root.pushRuleModel.removeKeyword(id);
}
onNotificatonActionChanged: action => root.pushRuleModel.setPushRuleAction(id, action)
}
onNotificatonActionChanged: action => root.pushRuleModel.setPushRuleAction(id, action)
}
}
FormCard.AbstractFormDelegate {

View File

@@ -65,23 +65,23 @@ FormCard.FormCardPage {
FormCard.FormRadioDelegate {
text: i18nc("@option:check", "Private (invite only)")
description: i18nc("@info", "Only invited people can join.")
checked: root.room.joinRule === Quotient.JoinRule.Invite
checked: root.room.joinRule === JoinRule.Invite
enabled: root.room.canSendState("m.room.join_rules")
onCheckedChanged: if (checked && root.room.joinRule != Quotient.JoinRule.Invite) {
root.room.joinRule = Quotient.JoinRule.Invite;
onCheckedChanged: if (checked && root.room.joinRule != JoinRule.Invite) {
root.room.joinRule = JoinRule.Invite;
}
}
FormCard.FormRadioDelegate {
text: i18nc("@option:check", "Space members")
description: i18nc("@info", "Anyone in the selected spaces can find and join.") + (!["8", "9", "10", "11", "12"].includes(root.room.version) ? `\n${root.needUpgradeRoom}` : "")
checked: root.room.joinRule === Quotient.JoinRule.Restricted
checked: root.room.joinRule === JoinRule.Restricted
enabled: root.room.canSendState("m.room.join_rules") && ["8", "9", "10", "11", "12"].includes(root.room.version)
onCheckedChanged: if (checked && root.room.joinRule != Quotient.JoinRule.Restricted) {
onCheckedChanged: if (checked && root.room.joinRule != JoinRule.Restricted) {
(selectSpacesDialog.createObject(QQC2.Overlay.overlay) as SelectSpacesDialog).open();
}
contentItem.children: QQC2.Button {
visible: root.room.joinRule === Quotient.JoinRule.Restricted
visible: root.room.joinRule === JoinRule.Restricted
text: i18nc("@action:button", "Select spaces")
icon.name: "list-add"
@@ -102,20 +102,20 @@ FormCard.FormCardPage {
FormCard.FormRadioDelegate {
text: i18nc("@option:check", "Knock")
description: i18nc("@info", "People not in the room need to request an invite to join the room.") + (!["7", "8", "9", "10", "11", "12"].includes(root.room.version) ? `\n${root.needUpgradeRoom}` : "")
checked: root.room.joinRule === Quotient.JoinRule.Knock
checked: root.room.joinRule === JoinRule.Knock
// https://spec.matrix.org/v1.4/rooms/#feature-matrix
enabled: root.room.canSendState("m.room.join_rules") && ["7", "8", "9", "10", "11", "12"].includes(root.room.version)
onCheckedChanged: if (checked && root.room.joinRule != Quotient.JoinRule.Knock) {
root.room.joinRule = Quotient.JoinRule.Knock;
onCheckedChanged: if (checked && root.room.joinRule != JoinRule.Knock) {
root.room.joinRule = JoinRule.Knock;
}
}
FormCard.FormRadioDelegate {
text: i18nc("@option:check", "Public")
description: i18nc("@option:check", "Anyone can find and join.")
checked: root.room.joinRule === Quotient.JoinRule.Public
checked: root.room.joinRule === JoinRule.Public
enabled: root.room.canSendState("m.room.join_rules")
onCheckedChanged: if (checked && root.room.joinRule != Quotient.JoinRule.Public) {
root.room.joinRule = Quotient.JoinRule.Public;
onCheckedChanged: if (checked && root.room.joinRule != JoinRule.Public) {
root.room.joinRule = JoinRule.Public;
}
}
}

View File

@@ -36,6 +36,7 @@ Kirigami.Dialog {
clip: true
ListView {
id: listView
implicitHeight: contentHeight
currentIndex: -1

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -39,12 +37,12 @@ Kirigami.Dialog {
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
onAccepted: {
let ids = [];
for (let i in spaceGroup.buttons) {
for (var i in spaceGroup.buttons) {
if (spaceGroup.buttons[i].checked) {
ids.push(spaceGroup.buttons[i].modelData.id);
}
}
root.room.setJoinRule(Quotient.JoinRule.Restricted, ids);
root.room.setJoinRule(JoinRule.Restricted, ids);
}
QQC2.ButtonGroup {
@@ -58,7 +56,6 @@ Kirigami.Dialog {
model: root.room.parentObjects(true)
delegate: FormCard.FormCheckDelegate {
id: parentDelegate
required property var modelData
text: modelData.displayName
@@ -70,8 +67,8 @@ Kirigami.Dialog {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
source: parentDelegate.modelData.avatarUrl.toString().length > 0 ? root.room.connection.makeMediaUrl(parentDelegate.modelData.avatarUrl) : ""
name: parentDelegate.modelData.displayName
source: modelData.avatarUrl.toString().length > 0 ? connection.makeMediaUrl(modelData.avatarUrl) : ""
name: modelData.displayName
}
}
}

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -74,7 +72,7 @@ RowLayout {
}
}
QQC2.ToolTip.text: (root.model as ReadMarkerModel)?.readMarkersString ?? ""
QQC2.ToolTip.text: root.model?.readMarkersString ?? ""
QQC2.ToolTip.visible: hoverHandler.hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay

View File

@@ -126,7 +126,7 @@ KirigamiComponents.ConvergentContextMenu {
onClicked: {
if (emojiText.text === "⋮") {
let dialog = emojiDialog.createObject(emojiDelegate) as EmojiDialog;
var dialog = emojiDialog.createObject(emojiDelegate) as EmojiDialog;
dialog.showStickers = false;
dialog.chosen.connect(emoji => {
root.room.toggleReaction(root.eventId, emoji);
@@ -214,7 +214,7 @@ KirigamiComponents.ConvergentContextMenu {
width: Kirigami.Units.gridUnit * 25
});
dialog.accepted.connect(reason => {
root.room.redactEvent(root.eventId, reason);
currentRoom.redactEvent(root.eventId, reason);
});
}
}
@@ -340,7 +340,7 @@ KirigamiComponents.ConvergentContextMenu {
width: Kirigami.Units.gridUnit * 25
});
dialog.accepted.connect(reason => {
root.room.reportEvent(root.eventId, reason);
currentRoom.reportEvent(root.eventId, reason);
});
}
}

View File

@@ -3,6 +3,7 @@
// SPDX-License-Identifier: GPL-3.0-only
import QtQuick
import QtQuick.Layouts
import Qt.labs.qmlmodels
@@ -62,10 +63,12 @@ DelegateChooser {
roleValue: DelegateType.Other
delegate: NeoChatConfig.showAllEvents ? hiddenDelegate : emptyDelegate
property Component hiddenDelegate : Component {
Component {
id: hiddenDelegate
HiddenDelegate {}
}
property Component emptyDelegate : Component {
Component {
id: emptyDelegate
Item {}
}
}

View File

@@ -1,10 +1,10 @@
// SPDX-FileCopyrightText: 2020 Black Hat <bhat@encom.eu.org>
// SPDX-License-Identifier: GPL-3.0-only
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import Qt.labs.qmlmodels
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents
@@ -175,7 +175,7 @@ MessageDelegateBase {
const menu = Qt.createComponent("org.kde.neochat", "UserMenu").createObject(root, {
window: QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow,
author: root.author,
}) as UserMenu;
});
console.info(Qt.createComponent("org.kde.neochat", "UserMenu").errorString());
menu.popup(root.QQC2.Overlay.overlay);
}

Some files were not shown because too many files have changed in this diff Show More