Compare commits

...

3 Commits

Author SHA1 Message Date
Carl Schwan
8177c1f1bc Port About page to FormCard 2023-08-22 22:03:35 +00:00
Carl Schwan
80171748d8 Port more MobileForm to FormCard
- DevTools
- Network settings
- Push notification
- Permissions
2023-08-22 22:03:35 +00:00
Carl Schwan
6aa2e586de Port to form card 2023-08-22 22:03:35 +00:00
12 changed files with 1104 additions and 1126 deletions

View File

@@ -26,8 +26,7 @@ QVariant StateModel::data(const QModelIndex &index, int role) const
int StateModel::rowCount(const QModelIndex &parent) const int StateModel::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); return !m_room || parent.isValid() ? 0 : m_room->currentState().events().size();
return m_room->currentState().events().size();
} }
NeoChatRoom *StateModel::room() const NeoChatRoom *StateModel::room() const
@@ -37,8 +36,12 @@ NeoChatRoom *StateModel::room() const
void StateModel::setRoom(NeoChatRoom *room) void StateModel::setRoom(NeoChatRoom *room)
{ {
if (m_room == room) {
return;
}
m_room = room; m_room = room;
Q_EMIT roomChanged(); Q_EMIT roomChanged();
beginResetModel(); beginResetModel();
m_stateEvents.clear(); m_stateEvents.clear();
m_stateEvents = m_room->currentState().events().keys(); m_stateEvents = m_room->currentState().events().keys();

View File

@@ -6,107 +6,122 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.kitemmodels 1.0 import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0 import org.kde.neochat 1.0
ColumnLayout { FormCard.FormCardPage {
MobileForm.FormCard { id: root
Layout.fillWidth: true
contentItem: ColumnLayout { required property var room
spacing: 0
MobileForm.FormComboBoxDelegate { FormCard.FormCard {
text: i18n("Room") Layout.topMargin: Kirigami.Units.gridUnit
textRole: "displayName"
valueRole: "id" FormCard.FormComboBoxDelegate {
model: RoomListModel { id: roomChooser
id: roomListModel text: i18n("Room")
connection: Controller.activeConnection textRole: "displayName"
} valueRole: "roomId"
Component.onCompleted: currentIndex = indexOfValue(room.id) model: RoomListModel {
onCurrentValueChanged: room = roomListModel.roomByAliasOrId(currentValue) id: roomListModel
connection: Controller.activeConnection
} }
MobileForm.FormCheckDelegate { onCurrentValueChanged: room = roomListModel.roomByAliasOrId(currentValue)
text: i18n("Show m.room.member events") Component.onCompleted: currentIndex = indexOfValue(room.id)
checked: true }
onToggled: {
if (checked) { FormCard.FormDelegateSeparator { above: showRoomMember }
stateEventFilterModel.removeStateEventTypeFiltered("m.room.member");
} else { FormCard.FormCheckDelegate {
stateEventFilterModel.addStateEventTypeFiltered("m.room.member"); id: showRoomMember
} text: i18n("Show m.room.member events")
checked: true
onToggled: {
if (checked) {
stateEventFilterModel.removeStateEventTypeFiltered("m.room.member");
} else {
stateEventFilterModel.addStateEventTypeFiltered("m.room.member");
} }
} }
MobileForm.FormCheckDelegate { }
id: roomAccoutnDataVisibleCheck
text: i18n("Show room account data") FormCard.FormDelegateSeparator { above: roomAccoutnDataVisibleCheck; below: showRoomMember }
checked: false
} FormCard.FormCheckDelegate {
id: roomAccoutnDataVisibleCheck
text: i18n("Show room account data")
checked: false
}
FormCard.FormDelegateSeparator { below: roomAccoutnDataVisibleCheck }
FormCard.FormTextDelegate {
text: i18n("Room id")
description: room.id
} }
} }
MobileForm.FormCard {
Layout.fillWidth: true FormCard.FormHeader {
title: i18n("Room Account Data for %1", room.displayName)
visible: roomAccoutnDataVisibleCheck.checked visible: roomAccoutnDataVisibleCheck.checked
contentItem: ColumnLayout { }
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Room Account Data for %1 - %2", room.displayName, room.id)
}
Repeater { FormCard.FormCard {
model: room.accountDataEventTypes visible: roomAccoutnDataVisibleCheck.checked
delegate: MobileForm.FormTextDelegate {
text: modelData Repeater {
onClicked: applicationWindow().pageStack.pushDialogLayer("qrc:/MessageSourceSheet.qml", { model: room.accountDataEventTypes
"sourceText": room.roomAcountDataJson(text) delegate: FormCard.FormTextDelegate {
}, { text: modelData
"title": i18n("Event Source"), onClicked: applicationWindow().pageStack.pushDialogLayer("qrc:/MessageSourceSheet.qml", {
"width": Kirigami.Units.gridUnit * 25 "sourceText": room.roomAcountDataJson(text)
}) }, {
} "title": i18n("Event Source"),
"width": Kirigami.Units.gridUnit * 25
})
} }
} }
} }
MobileForm.FormCard {
Layout.fillWidth: true FormCard.FormHeader {
id: stateEventListHeader
title: i18n("Room State for %1", room.displayName)
}
FormCard.FormCard {
Layout.fillHeight: true Layout.fillHeight: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
id: stateEventListHeader
title: i18n("Room State for %1", room.displayName)
subtitle: room.id
}
QQC2.ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
// HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890) QQC2.ScrollView {
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: Kirigami.Units.gridUnit * 20
ListView { // HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
id: stateEventListView QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
clip: true
model: StateFilterModel { ListView {
id: stateEventFilterModel id: stateEventListView
sourceModel: StateModel { clip: true
id: stateModel
room: devtoolsPage.room model: StateFilterModel {
} id: stateEventFilterModel
sourceModel: StateModel {
id: stateModel
room: root.room
} }
}
delegate: MobileForm.FormTextDelegate { delegate: FormCard.FormTextDelegate {
text: model.type text: model.type
description: model.stateKey description: model.stateKey
onClicked: applicationWindow().pageStack.pushDialogLayer('qrc:/MessageSourceSheet.qml', { onClicked: applicationWindow().pageStack.pushDialogLayer('qrc:/MessageSourceSheet.qml', {
sourceText: stateModel.stateEventJson(stateEventFilterModel.mapToSource(stateEventFilterModel.index(model.index, 0))) sourceText: stateModel.stateEventJson(stateEventFilterModel.mapToSource(stateEventFilterModel.index(model.index, 0)))
}, { }, {
title: i18n("Event Source"), title: i18n("Event Source"),
width: Kirigami.Units.gridUnit * 25 width: Kirigami.Units.gridUnit * 25
}); });
}
} }
} }
} }

View File

@@ -6,58 +6,50 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.kitemmodels 1.0 import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0 import org.kde.neochat 1.0
ColumnLayout { FormCard.FormCardPage {
MobileForm.FormCard { id: root
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Server Capabilities")
}
MobileForm.FormTextDelegate {
text: i18n("Can change password")
description: Controller.activeConnection.canChangePassword
}
}
}
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Default Room Version")
}
MobileForm.FormTextDelegate {
text: Controller.activeConnection.defaultRoomVersion
}
}
}
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Available Room Versions")
}
Repeater {
model: Controller.getSupportedRoomVersions(room.connection)
delegate: MobileForm.FormTextDelegate { FormCard.FormHeader {
text: modelData.id title: i18n("Server Capabilities")
contentItem.children: QQC2.Label { }
text: modelData.status
color: Kirigami.Theme.disabledTextColor FormCard.FormCard {
} FormCard.FormTextDelegate {
text: i18n("Can change password")
description: Controller.activeConnection.canChangePassword
}
}
FormCard.FormHeader {
title: i18n("Default Room Version")
}
FormCard.FormCard {
FormCard.FormTextDelegate {
text: Controller.activeConnection.defaultRoomVersion
}
}
FormCard.FormHeader {
title: i18n("Available Room Versions")
}
FormCard.FormCard {
Repeater {
model: Controller.getSupportedRoomVersions(room.connection)
delegate: FormCard.FormTextDelegate {
text: modelData.id
contentItem.children: QQC2.Label {
text: modelData.status
color: Kirigami.Theme.disabledTextColor
} }
} }
} }
} }
Item {
Layout.fillHeight: true
}
} }

View File

@@ -2,41 +2,34 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.settings 1.0 as KirigamiSettings
import org.kde.neochat 1.0 import org.kde.neochat 1.0
Kirigami.Page { KirigamiSettings.CategorizedSettings {
id: devtoolsPage id: root
property NeoChatRoom room property NeoChatRoom room
title: i18n("Developer Tools") actions: [
KirigamiSettings.SettingAction {
leftPadding: 0 actionName: "roomData"
rightPadding: 0 text: i18n("Room Data")
icon.name: "datatype"
header: QQC2.TabBar { page: "qrc:/RoomData.qml"
id: tabBar initialProperties: {
return {
QQC2.TabButton { room: root.room
text: qsTr("Room Data") }
}
},
KirigamiSettings.SettingAction {
actionName: "serverData"
text: i18n("Server Info")
icon.name: "network-server-symbolic"
page: "qrc:/ServerData.qml"
} }
QQC2.TabButton { ]
text: qsTr("Server Info")
}
}
StackLayout {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
RoomData {}
ServerData {}
}
} }

View File

@@ -6,441 +6,439 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.kirigamiaddons.delegates 1.0 as Delegates import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.kitemmodels 1.0 import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0 import org.kde.neochat 1.0
Kirigami.ScrollablePage { FormCard.FormCardPage {
id: root id: root
property NeoChatRoom room property NeoChatRoom room
title: i18nc('@title:window', 'Permissions') title: i18nc("@title:window", "Permissions")
topPadding: 0
leftPadding: 0
rightPadding: 0
UserListModel { readonly property UserListModel userListModel: UserListModel {
id: userListModel id: userListModel
room: root.room room: root.room
} }
ListModel { readonly property ListModel powerLevelModel: ListModel {
id: powerLevelModel id: powerLevelModel
} }
ColumnLayout { FormCard.FormHeader {
spacing: 0 title: i18n("Privileged Users")
MobileForm.FormHeader { }
Layout.fillWidth: true
title: i18n("Privileged Users") FormCard.FormCard {
} Layout.fillWidth: true
MobileForm.FormCard {
Layout.fillWidth: true Repeater {
contentItem: ColumnLayout { model: KSortFilterProxyModel {
spacing: 0 sourceModel: userListModel
Repeater { sortRole: "powerLevel"
model: KSortFilterProxyModel { sortOrder: Qt.DescendingOrder
sourceModel: userListModel filterRowCallback: function(source_row, source_parent) {
sortRole: "powerLevel" let powerLevelRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), UserListModel.PowerLevelRole)
sortOrder: Qt.DescendingOrder return powerLevelRole > 0;
filterRowCallback: function(source_row, source_parent) {
let powerLevelRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), UserListModel.PowerLevelRole)
return powerLevelRole > 0;
}
}
delegate: MobileForm.FormTextDelegate {
text: name
description: userId
contentItem.children: RowLayout {
spacing: Kirigami.Units.largeSpacing
QQC2.Label {
visible: !room.canSendState("m.room.power_levels")
text: powerLevelString
color: Kirigami.Theme.disabledTextColor
}
QQC2.ComboBox {
focusPolicy: Qt.NoFocus // provided by parent
model: powerLevelModel
textRole: "text"
valueRole: "powerLevel"
visible: room.canSendState("m.room.power_levels")
Component.onCompleted: {
/**
* This is very silly but the only way to populate the model with
* translated strings. Done here because the model needs to be filled
* before the first delegate sets it's current index.
*/
if (powerLevelModel.count == 0) {
powerLevelModel.append({"text": i18n("Member (0)"), "powerLevel": 0});
powerLevelModel.append({"text": i18n("Moderator (50)"), "powerLevel": 50});
powerLevelModel.append({"text": i18n("Admin (100)"), "powerLevel": 100});
}
currentIndex = indexOfValue(powerLevel)
}
onActivated: {
room.setUserPowerLevel(userId, currentValue)
}
}
}
}
} }
MobileForm.FormDelegateSeparator { below: userListSearchCard } }
MobileForm.AbstractFormDelegate { delegate: FormCard.FormTextDelegate {
id: userListSearchCard text: name
Layout.fillWidth: true description: userId
visible: room.canSendState("m.room.power_levels") contentItem.children: RowLayout {
spacing: Kirigami.Units.largeSpacing
contentItem: Kirigami.SearchField { QQC2.Label {
id: userListSearchField visible: !room.canSendState("m.room.power_levels")
text: powerLevelString
autoAccept: false color: Kirigami.Theme.disabledTextColor
Layout.fillWidth: true
Keys.onUpPressed: userListView.decrementCurrentIndex()
Keys.onDownPressed: userListView.incrementCurrentIndex()
onAccepted: {
let currentUser = userListView.itemAtIndex(userListView.currentIndex);
currentUser.action.trigger();
}
} }
QQC2.Popup { QQC2.ComboBox {
id: userListSearchPopup focusPolicy: Qt.NoFocus // provided by parent
model: root.powerLevelModel
x: userListSearchField.x textRole: "text"
y: userListSearchField.y - height valueRole: "powerLevel"
width: userListSearchField.width visible: room.canSendState("m.room.power_levels")
height: { Component.onCompleted: {
let maxHeight = userListSearchField.mapToGlobal(userListSearchField.x, userListSearchField.y).y - Kirigami.Units.largeSpacing * 3; /**
let minHeight = Kirigami.Units.gridUnit * 2 + userListSearchPopup.padding * 2; * This is very silly but the only way to populate the model with
let filterContentHeight = userListView.contentHeight + userListSearchPopup.padding * 2; * translated strings. Done here because the model needs to be filled
* before the first delegate sets it's current index.
return Math.max(Math.min(filterContentHeight, maxHeight), minHeight); */
if (root.powerLevelModel.count == 0) {
root.powerLevelModel.append({"text": i18n("Member (0)"), "powerLevel": 0});
root.powerLevelModel.append({"text": i18n("Moderator (50)"), "powerLevel": 50});
root.powerLevelModel.append({"text": i18n("Admin (100)"), "powerLevel": 100});
}
currentIndex = indexOfValue(powerLevel)
} }
padding: Kirigami.Units.smallSpacing onActivated: {
leftPadding: Kirigami.Units.smallSpacing / 2 room.setUserPowerLevel(userId, currentValue)
rightPadding: Kirigami.Units.smallSpacing / 2
modal: false
onClosed: userListSearchField.text = ""
background: Kirigami.ShadowedRectangle {
property color borderColor: Kirigami.Theme.textColor
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
radius: 4
color: Kirigami.Theme.backgroundColor
border {
color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
width: 1
}
shadow {
xOffset: 0
yOffset: 4
color: Qt.rgba(0, 0, 0, 0.3)
size: 8
}
}
contentItem: QQC2.ScrollView {
// HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
ListView {
id: userListView
clip: true
model: UserFilterModel {
id: userListFilterModel
sourceModel: userListModel
filterText: userListSearchField.text
onFilterTextChanged: {
if (filterText.length > 0 && !userListSearchPopup.visible) {
userListSearchPopup.open()
} else if (filterText.length <= 0 && userListSearchPopup.visible) {
userListSearchPopup.close()
}
}
}
delegate: Delegates.RoundedItemDelegate {
id: userListItem
required property string userId
required property string avatar
required property string name
required property int powerLevel
required property string powerLevelString
text: name
contentItem: RowLayout {
KirigamiComponents.Avatar {
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
source: userListItem.avatar ? ("image://" + userListItem.avatar) : ""
name: userListItem.name
}
Delegates.SubtitleContentItem {
itemDelegate: userListItem
subtitle: userListItem.userId
labelItem.textFormat: Text.PlainText
subtitleItem.textFormat: Text.PlainText
Layout.fillWidth: true
}
QQC2.Label {
visible: userListItem.powerLevel > 0
text: userListItem.powerLevelString
color: Kirigami.Theme.disabledTextColor
textFormat: Text.PlainText
wrapMode: Text.NoWrap
}
}
action: Kirigami.Action {
id: editPowerLevelAction
onTriggered: {
userListSearchPopup.close()
let dialog = powerLevelDialog.createObject(applicationWindow().overlay, {
room: root.room,
userId: userListItem.userId,
powerLevel: userListItem.powerLevel
});
dialog.open();
}
}
Component {
id: powerLevelDialog
PowerLevelDialog {
id: powerLevelDialog
}
}
}
}
} }
} }
} }
} }
} }
FormCard.FormDelegateSeparator { below: userListSearchCard }
FormCard.AbstractFormDelegate {
id: userListSearchCard
Layout.fillWidth: true
visible: room.canSendState("m.room.power_levels")
MobileForm.FormHeader { contentItem: Kirigami.SearchField {
Layout.fillWidth: true id: userListSearchField
visible: room.canSendState("m.room.power_levels")
title: i18n("Default permissions") autoAccept: false
}
MobileForm.FormCard { Layout.fillWidth: true
Layout.fillWidth: true
visible: room.canSendState("m.room.power_levels") Keys.onUpPressed: userListView.decrementCurrentIndex()
contentItem: ColumnLayout { Keys.onDownPressed: userListView.incrementCurrentIndex()
spacing: 0
MobileForm.FormComboBoxDelegate { onAccepted: {
text: i18n("Default user power level") let currentUser = userListView.itemAtIndex(userListView.currentIndex);
description: i18n("This is power level for all new users when joining the room") currentUser.action.trigger();
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.defaultUserPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultUserPowerLevel = currentValue
}
MobileForm.FormComboBoxDelegate {
text: i18n("Default power level to set the room state")
description: i18n("This is used for all state events that do not have their own entry here")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.statePowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.statePowerLevel = currentValue
}
MobileForm.FormComboBoxDelegate {
text: i18n("Default power level to send messages")
description: i18n("This is used for all message events that do not have their own entry here")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.defaultEventPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultEventPowerLevel = currentValue
} }
} }
} QQC2.Popup {
id: userListSearchPopup
MobileForm.FormHeader { x: userListSearchField.x
Layout.fillWidth: true y: userListSearchField.y - height
visible: room.canSendState("m.room.power_levels") width: userListSearchField.width
title: i18n("Basic permissions") height: {
} let maxHeight = userListSearchField.mapToGlobal(userListSearchField.x, userListSearchField.y).y - Kirigami.Units.largeSpacing * 3;
MobileForm.FormCard { let minHeight = Kirigami.Units.gridUnit * 2 + userListSearchPopup.padding * 2;
Layout.fillWidth: true let filterContentHeight = userListView.contentHeight + userListSearchPopup.padding * 2;
visible: room.canSendState("m.room.power_levels")
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormComboBoxDelegate {
text: i18n("Invite users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.invitePowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.invitePowerLevel = currentValue
}
MobileForm.FormComboBoxDelegate {
text: i18n("Kick users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.kickPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.kickPowerLevel = currentValue
}
MobileForm.FormComboBoxDelegate {
text: i18n("Ban users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.banPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.banPowerLevel = currentValue
}
MobileForm.FormComboBoxDelegate {
text: i18n("Remove message sent by other users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.redactPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.redactPowerLevel = currentValue
}
}
}
MobileForm.FormHeader { return Math.max(Math.min(filterContentHeight, maxHeight), minHeight);
Layout.fillWidth: true
visible: room.canSendState("m.room.power_levels")
title: i18n("Event permissions")
}
MobileForm.FormCard {
Layout.fillWidth: true
visible: room.canSendState("m.room.power_levels")
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormComboBoxDelegate {
text: i18n("Change user permissions")
description: "m.room.power_levels"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.powerLevelPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.powerLevelPowerLevel = currentValue
} }
MobileForm.FormComboBoxDelegate { padding: Kirigami.Units.smallSpacing
text: i18n("Change the room name") leftPadding: Kirigami.Units.smallSpacing / 2
description: "m.room.name" rightPadding: Kirigami.Units.smallSpacing / 2
textRole: "text" modal: false
valueRole: "powerLevel" onClosed: userListSearchField.text = ""
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.namePowerLevel) background: Kirigami.ShadowedRectangle {
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.namePowerLevel = currentValue property color borderColor: Kirigami.Theme.textColor
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
radius: 4
color: Kirigami.Theme.backgroundColor
border {
color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
width: 1
}
shadow {
xOffset: 0
yOffset: 4
color: Qt.rgba(0, 0, 0, 0.3)
size: 8
}
} }
MobileForm.FormComboBoxDelegate {
text: i18n("Change the room avatar") contentItem: QQC2.ScrollView {
description: "m.room.avatar" // HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
textRole: "text" QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
valueRole: "powerLevel"
model: powerLevelModel ListView {
Component.onCompleted: currentIndex = indexOfValue(room.avatarPowerLevel) id: userListView
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.avatarPowerLevel = currentValue clip: true
}
MobileForm.FormComboBoxDelegate { model: UserFilterModel {
text: i18n("Change the room canonical alias") id: userListFilterModel
description: "m.room.canonical_alias" sourceModel: userListModel
textRole: "text" filterText: userListSearchField.text
valueRole: "powerLevel"
model: powerLevelModel onFilterTextChanged: {
Component.onCompleted: currentIndex = indexOfValue(room.canonicalAliasPowerLevel) if (filterText.length > 0 && !userListSearchPopup.visible) {
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.canonicalAliasPowerLevel = currentValue userListSearchPopup.open()
} } else if (filterText.length <= 0 && userListSearchPopup.visible) {
MobileForm.FormComboBoxDelegate { userListSearchPopup.close()
text: i18n("Change the room topic") }
description: "m.room.topic" }
textRole: "text" }
valueRole: "powerLevel"
model: powerLevelModel delegate: Delegates.RoundedItemDelegate {
Component.onCompleted: currentIndex = indexOfValue(room.topicPowerLevel) id: userListItem
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.topicPowerLevel = currentValue
} required property string userId
MobileForm.FormComboBoxDelegate { required property string avatar
text: i18n("Enable encryption for the room") required property string name
description: "m.room.encryption" required property int powerLevel
textRole: "text" required property string powerLevelString
valueRole: "powerLevel"
model: powerLevelModel text: name
Component.onCompleted: currentIndex = indexOfValue(room.encryptionPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.encryptionPowerLevel = currentValue contentItem: RowLayout {
} KirigamiComponents.Avatar {
MobileForm.FormComboBoxDelegate { Layout.preferredWidth: Kirigami.Units.iconSizes.medium
text: i18n("Change the room history visibility") Layout.preferredHeight: Kirigami.Units.iconSizes.medium
description: "m.room.history_visibility" source: userListItem.avatar ? ("image://" + userListItem.avatar) : ""
textRole: "text" name: userListItem.name
valueRole: "powerLevel" }
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.historyVisibilityPowerLevel) Delegates.SubtitleContentItem {
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.historyVisibilityPowerLevel = currentValue itemDelegate: userListItem
} subtitle: userListItem.userId
MobileForm.FormComboBoxDelegate { labelItem.textFormat: Text.PlainText
text: i18n("Set pinned events") subtitleItem.textFormat: Text.PlainText
description: "m.room.pinned_events" Layout.fillWidth: true
textRole: "text" }
valueRole: "powerLevel"
model: powerLevelModel QQC2.Label {
Component.onCompleted: currentIndex = indexOfValue(room.pinnedEventsPowerLevel) visible: userListItem.powerLevel > 0
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.pinnedEventsPowerLevel = currentValue
} text: userListItem.powerLevelString
MobileForm.FormComboBoxDelegate { color: Kirigami.Theme.disabledTextColor
text: i18n("Upgrade the room") textFormat: Text.PlainText
description: "m.room.tombstone" wrapMode: Text.NoWrap
textRole: "text" }
valueRole: "powerLevel" }
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.tombstonePowerLevel) action: Kirigami.Action {
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.tombstonePowerLevel = currentValue id: editPowerLevelAction
} onTriggered: {
MobileForm.FormComboBoxDelegate { userListSearchPopup.close()
text: i18n("Set the room server access control list (ACL)") let dialog = powerLevelDialog.createObject(applicationWindow().overlay, {
description: "m.room.server_acl" room: root.room,
textRole: "text" userId: userListItem.userId,
valueRole: "powerLevel" powerLevel: userListItem.powerLevel
model: powerLevelModel });
Component.onCompleted: currentIndex = indexOfValue(room.serverAclPowerLevel) dialog.open();
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.serverAclPowerLevel = currentValue }
} }
MobileForm.FormComboBoxDelegate {
visible: room.isSpace Component {
text: i18n("Set the children of this space") id: powerLevelDialog
description: "m.space.child" PowerLevelDialog {
textRole: "text" id: powerLevelDialog
valueRole: "powerLevel" }
model: powerLevelModel }
Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel) }
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceChildPowerLevel = currentValue }
}
MobileForm.FormComboBoxDelegate {
text: i18n("Set the parent space of this room")
description: "m.space.parent"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceParentPowerLevel = currentValue
} }
} }
} }
} }
FormCard.FormHeader {
visible: room.canSendState("m.room.power_levels")
title: i18n("Default permissions")
}
FormCard.FormCard {
visible: room.canSendState("m.room.power_levels")
FormCard.FormComboBoxDelegate {
text: i18n("Default user power level")
description: i18n("This is power level for all new users when joining the room")
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.defaultUserPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultUserPowerLevel = currentValue
}
FormCard.FormDelegateSeparator {}
FormCard.FormComboBoxDelegate {
text: i18n("Default power level to set the room state")
description: i18n("This is used for all state events that do not have their own entry here")
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.statePowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.statePowerLevel = currentValue
}
FormCard.FormDelegateSeparator {}
FormCard.FormComboBoxDelegate {
text: i18n("Default power level to send messages")
description: i18n("This is used for all message events that do not have their own entry here")
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.defaultEventPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultEventPowerLevel = currentValue
}
}
FormCard.FormHeader {
visible: room.canSendState("m.room.power_levels")
title: i18n("Basic permissions")
}
FormCard.FormCard {
visible: room.canSendState("m.room.power_levels")
FormCard.FormComboBoxDelegate {
text: i18n("Invite users")
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.invitePowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.invitePowerLevel = currentValue
}
FormCard.FormDelegateSeparator {}
FormCard.FormComboBoxDelegate {
text: i18n("Kick users")
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.kickPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.kickPowerLevel = currentValue
}
FormCard.FormDelegateSeparator {}
FormCard.FormComboBoxDelegate {
text: i18n("Ban users")
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.banPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.banPowerLevel = currentValue
}
FormCard.FormDelegateSeparator {}
FormCard.FormComboBoxDelegate {
text: i18n("Remove message sent by other users")
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.redactPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.redactPowerLevel = currentValue
}
}
FormCard.FormHeader {
visible: room.canSendState("m.room.power_levels")
title: i18n("Event permissions")
}
FormCard.FormCard {
visible: room.canSendState("m.room.power_levels")
FormCard.FormComboBoxDelegate {
text: i18n("Change user permissions")
description: "m.room.power_levels"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.powerLevelPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.powerLevelPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room name")
description: "m.room.name"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.namePowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.namePowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room avatar")
description: "m.room.avatar"
textRole: "text"
valueRole: "powerLevel"
model: roo.tpowerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.avatarPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.avatarPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room canonical alias")
description: "m.room.canonical_alias"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.canonicalAliasPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.canonicalAliasPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room topic")
description: "m.room.topic"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.topicPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.topicPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Enable encryption for the room")
description: "m.room.encryption"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.encryptionPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.encryptionPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room history visibility")
description: "m.room.history_visibility"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.historyVisibilityPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.historyVisibilityPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Set pinned events")
description: "m.room.pinned_events"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.pinnedEventsPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.pinnedEventsPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Upgrade the room")
description: "m.room.tombstone"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.tombstonePowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.tombstonePowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Set the room server access control list (ACL)")
description: "m.room.server_acl"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.serverAclPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.serverAclPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
visible: room.isSpace
text: i18n("Set the children of this space")
description: "m.space.child"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceChildPowerLevel = currentValue
}
FormCard.FormComboBoxDelegate {
text: i18n("Set the parent space of this room")
description: "m.space.parent"
textRole: "text"
valueRole: "powerLevel"
model: root.powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceParentPowerLevel = currentValue
}
}
} }

View File

@@ -6,138 +6,123 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.kitemmodels 1.0 import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0 import org.kde.neochat 1.0
Kirigami.ScrollablePage { FormCard.FormCardPage {
id: root id: root
property NeoChatRoom room property NeoChatRoom room
title: i18nc('@title:window', 'Notifications') title: i18nc('@title:window', 'Notifications')
topPadding: 0
leftPadding: 0 FormCard.FormHeader {
rightPadding: 0 title: i18n("Room notifications setting")
ColumnLayout { }
spacing: 0
MobileForm.FormHeader { FormCard.FormCard {
Layout.fillWidth: true FormCard.FormRadioDelegate {
title: i18n("Room notifications setting") text: i18n("Follow global setting")
} checked: room.pushNotificationState === PushNotificationState.Default
MobileForm.FormCard { enabled: room.pushNotificationState !== PushNotificationState.Unknown
Layout.fillWidth: true onToggled: {
contentItem: ColumnLayout { room.pushNotificationState = PushNotificationState.Default
spacing: 0
MobileForm.FormRadioDelegate {
text: i18n("Follow global setting")
checked: room.pushNotificationState === PushNotificationState.Default
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
room.pushNotificationState = PushNotificationState.Default
}
}
MobileForm.FormRadioDelegate {
text: i18nc("As in 'notify for all messages'","All")
checked: room.pushNotificationState === PushNotificationState.All
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
room.pushNotificationState = PushNotificationState.All
}
}
MobileForm.FormRadioDelegate {
text: i18nc("As in 'notify when the user is mentioned or the message contains a set keyword'","@Mentions and Keywords")
checked: room.pushNotificationState === PushNotificationState.MentionKeyword
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
room.pushNotificationState = PushNotificationState.MentionKeyword
}
}
MobileForm.FormRadioDelegate {
text: i18nc("As in 'do not notify for any messages'","Off")
checked: room.pushNotificationState === PushNotificationState.Mute
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
room.pushNotificationState = PushNotificationState.Mute
}
}
} }
} }
FormCard.FormRadioDelegate {
text: i18nc("As in 'notify for all messages'","All")
checked: room.pushNotificationState === PushNotificationState.All
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
room.pushNotificationState = PushNotificationState.All
}
}
FormCard.FormRadioDelegate {
text: i18nc("As in 'notify when the user is mentioned or the message contains a set keyword'","@Mentions and Keywords")
checked: room.pushNotificationState === PushNotificationState.MentionKeyword
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
room.pushNotificationState = PushNotificationState.MentionKeyword
}
}
FormCard.FormRadioDelegate {
text: i18nc("As in 'do not notify for any messages'","Off")
checked: room.pushNotificationState === PushNotificationState.Mute
enabled: room.pushNotificationState !== PushNotificationState.Unknown
onToggled: {
room.pushNotificationState = PushNotificationState.Mute
}
}
}
MobileForm.FormCard { FormCard.FormHeader {
title: i18n("Keywords")
}
FormCard.FormCard {
Repeater {
model: KSortFilterProxyModel {
sourceModel: Controller.pushRuleModel
filterRowCallback: function(source_row, source_parent) {
let sectionRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PushRuleModel.SectionRole)
let roomIdRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PushRuleModel.RoomIdRole)
return sectionRole == PushNotificationSection.RoomKeywords && roomIdRole == root.room.id;
}
}
delegate: ruleDelegate
}
FormCard.AbstractFormDelegate {
Layout.fillWidth: true Layout.fillWidth: true
contentItem: ColumnLayout { contentItem : RowLayout {
spacing: 0 Kirigami.ActionTextField {
id: keywordAddField
MobileForm.FormCardHeader {
title: i18n("Keywords")
}
Repeater {
model: KSortFilterProxyModel {
sourceModel: Controller.pushRuleModel
filterRowCallback: function(source_row, source_parent) {
let sectionRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PushRuleModel.SectionRole)
let roomIdRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PushRuleModel.RoomIdRole)
return sectionRole == PushNotificationSection.RoomKeywords && roomIdRole == root.room.id;
}
}
delegate: ruleDelegate
}
MobileForm.AbstractFormDelegate {
Layout.fillWidth: true Layout.fillWidth: true
contentItem : RowLayout { placeholderText: i18n("Keyword…")
Kirigami.ActionTextField { enabled: NotificationsManager.keywordNotificationAction !== PushNotificationAction.Unknown
id: keywordAddField
Layout.fillWidth: true rightActions: Kirigami.Action {
icon.name: "edit-clear"
placeholderText: i18n("Keyword…") visible: keywordAddField.text.length > 0
enabled: NotificationsManager.keywordNotificationAction !== PushNotificationAction.Unknown onTriggered: {
keywordAddField.text = ""
rightActions: Kirigami.Action {
icon.name: "edit-clear"
visible: keywordAddField.text.length > 0
onTriggered: {
keywordAddField.text = ""
}
}
onAccepted: {
Controller.pushRuleModel.addKeyword(keywordAddField.text, root.room.id)
keywordAddField.text = ""
}
}
QQC2.Button {
id: addButton
text: i18n("Add keyword")
Accessible.name: text
icon.name: "list-add"
display: QQC2.AbstractButton.IconOnly
enabled: NotificationsManager.keywordNotificationAction !== PushNotificationAction.Unknown
onClicked: {
Controller.pushRuleModel.addKeyword(keywordAddField.text, root.room.id)
keywordAddField.text = ""
}
QQC2.ToolTip {
text: addButton.text
delay: Kirigami.Units.toolTipDelay
}
} }
} }
onAccepted: {
Controller.pushRuleModel.addKeyword(keywordAddField.text, root.room.id)
keywordAddField.text = ""
}
}
QQC2.Button {
id: addButton
text: i18n("Add keyword")
icon.name: "list-add"
display: QQC2.AbstractButton.IconOnly
enabled: NotificationsManager.keywordNotificationAction !== PushNotificationAction.Unknown
onClicked: {
Controller.pushRuleModel.addKeyword(keywordAddField.text, root.room.id)
keywordAddField.text = ""
}
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
} }
} }
} }
} }
Component { data: Component {
id: ruleDelegate id: ruleDelegate
NotificationRuleItem { NotificationRuleItem {
onDeleteRule: { onDeleteRule: {

View File

@@ -4,10 +4,10 @@
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0 import org.kde.neochat 1.0
MobileForm.AboutPage { FormCard.AboutPage {
title: i18nc("@title:window", "About NeoChat") title: i18nc("@title:window", "About NeoChat")
aboutData: About aboutData: About
} }

View File

@@ -1,8 +1,8 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com> // SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: LGPL-2.0-or-later // SPDX-License-Identifier: LGPL-2.0-or-later
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
MobileForm.AboutKDE { FormCard.AboutKDE {
title: i18nc("@title:window", "About KDE") title: i18nc("@title:window", "About KDE")
} }

View File

@@ -7,344 +7,337 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents import org.kde.kirigamiaddons.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0 import org.kde.neochat 1.0
Kirigami.ScrollablePage { FormCard.FormCardPage {
id: root
title: i18nc("@title:window", "Appearance") title: i18nc("@title:window", "Appearance")
topPadding: 0
leftPadding: 0 FormCard.FormHeader {
rightPadding: 0 Layout.fillWidth: true
ColumnLayout { title: i18n("General theme")
spacing: 0 }
MobileForm.FormHeader {
FormCard.FormCard {
Layout.fillWidth: true
FormCard.AbstractFormDelegate {
id: timelineModeSetting
Layout.fillWidth: true Layout.fillWidth: true
title: i18n("General theme") background: Item {}
} contentItem: RowLayout {
MobileForm.FormCard { Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true spacing: Kirigami.Units.largeSpacing
contentItem: ColumnLayout { Item {
spacing: 0
MobileForm.AbstractFormDelegate {
id: timelineModeSetting
Layout.fillWidth: true Layout.fillWidth: true
background: Item {}
contentItem: RowLayout {
Layout.alignment: Qt.AlignCenter
spacing: Kirigami.Units.largeSpacing
Item {
Layout.fillWidth: true
}
QQC2.ButtonGroup { id: themeGroup }
ThemeRadioButton {
thin: timelineModeSetting.width < Kirigami.Units.gridUnit * 22
innerObject: [
RowLayout {
Layout.fillWidth: true
KirigamiComponents.Avatar {
color: "#4a5bcc"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
QQC2.Control {
Layout.fillWidth: true
contentItem: ColumnLayout {
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Paul Müller"
color: "#4a5bcc"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus facilisis porta mauris, quis finibus sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
}
}
},
RowLayout {
Layout.fillWidth: true
KirigamiComponents.Avatar {
color: "#9f244b"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
QQC2.Control {
Layout.fillWidth: true
contentItem: ColumnLayout {
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Jean Paul"
color: "#9f244b"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus facilisis porta , quis sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
}
}
}
]
text: i18n("Bubbles")
checked: !Config.compactLayout
QQC2.ButtonGroup.group: themeGroup
enabled: !Config.isCompactLayoutImmutable
onToggled: {
Config.compactLayout = !checked;
Config.save();
}
}
ThemeRadioButton {
// Layout.alignment: Qt.AlignRight
thin: timelineModeSetting.width < Kirigami.Units.gridUnit * 22
innerObject: [
RowLayout {
Layout.fillWidth: true
KirigamiComponents.Avatar {
color: "#4a5bcc"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
ColumnLayout {
Layout.fillWidth: true
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Paul Müller"
color: "#4a5bcc"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur elit. Vivamus facilisis porta mauris, finibus sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
},
RowLayout {
Layout.fillWidth: true
KirigamiComponents.Avatar {
color: "#9f244b"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
ColumnLayout {
Layout.fillWidth: true
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Jean Paul"
color: "#9f244b"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus facilisis porta mauris, quis finibus sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
}
]
text: i18n("Compact")
checked: Config.compactLayout
QQC2.ButtonGroup.group: themeGroup
enabled: !Config.isCompactLayoutImmutable
onToggled: {
Config.compactLayout = checked;
Config.save();
}
}
Item {
Layout.fillWidth: true
}
}
} }
QQC2.ButtonGroup { id: themeGroup }
ThemeRadioButton {
thin: timelineModeSetting.width < Kirigami.Units.gridUnit * 22
innerObject: [
RowLayout {
Layout.fillWidth: true
KirigamiComponents.Avatar {
color: "#4a5bcc"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
QQC2.Control {
Layout.fillWidth: true
contentItem: ColumnLayout {
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Paul Müller"
color: "#4a5bcc"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus facilisis porta mauris, quis finibus sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
}
}
},
RowLayout {
Layout.fillWidth: true
KirigamiComponents.Avatar {
color: "#9f244b"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
QQC2.Control {
Layout.fillWidth: true
contentItem: ColumnLayout {
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Jean Paul"
color: "#9f244b"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus facilisis porta , quis sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
}
}
}
]
MobileForm.FormDelegateSeparator { below: compactRoomListDelegate } text: i18n("Bubbles")
checked: !Config.compactLayout
QQC2.ButtonGroup.group: themeGroup
enabled: !Config.isCompactLayoutImmutable
MobileForm.FormCheckDelegate {
id: compactRoomListDelegate
text: i18n("Use compact room list")
checked: Config.compactRoomList
onToggled: { onToggled: {
Config.compactRoomList = checked; Config.compactLayout = !checked;
Config.save(); Config.save();
} }
} }
ThemeRadioButton {
MobileForm.FormDelegateSeparator { above: compactRoomListDelegate ; below: colorSchemeDelegate.item ; visible: colorSchemeDelegate.visible } // Layout.alignment: Qt.AlignRight
thin: timelineModeSetting.width < Kirigami.Units.gridUnit * 22
Loader { innerObject: [
id: colorSchemeDelegate RowLayout {
visible: item !== null && Qt.platform.os !== "android" Layout.fillWidth: true
source: "qrc:/ColorScheme.qml" KirigamiComponents.Avatar {
color: "#4a5bcc"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
ColumnLayout {
Layout.fillWidth: true
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Paul Müller"
color: "#4a5bcc"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur elit. Vivamus facilisis porta mauris, finibus sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
},
RowLayout {
Layout.fillWidth: true
KirigamiComponents.Avatar {
color: "#9f244b"
Layout.alignment: Qt.AlignTop
visible: Config.showAvatarInTimeline
Layout.preferredWidth: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing * 2 : 0
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
ColumnLayout {
Layout.fillWidth: true
QQC2.Label {
Layout.fillWidth: true
font.weight: Font.Bold
font.pixelSize: 7
text: "Jean Paul"
color: "#9f244b"
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus facilisis porta mauris, quis finibus sem suscipit tincidunt."
wrapMode: Text.Wrap
font.pixelSize: 7
}
}
}
]
text: i18n("Compact")
checked: Config.compactLayout
QQC2.ButtonGroup.group: themeGroup
enabled: !Config.isCompactLayoutImmutable
onToggled: {
Config.compactLayout = checked;
Config.save();
}
}
Item {
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
} }
MobileForm.FormCard { FormCard.FormDelegateSeparator { below: compactRoomListDelegate }
Layout.topMargin: Kirigami.Units.largeSpacing
FormCard.FormCheckDelegate {
id: compactRoomListDelegate
text: i18n("Use compact room list")
checked: Config.compactRoomList
onToggled: {
Config.compactRoomList = checked;
Config.save();
}
}
FormCard.FormDelegateSeparator { above: compactRoomListDelegate ; below: colorSchemeDelegate.item ; visible: colorSchemeDelegate.visible }
Loader {
id: colorSchemeDelegate
visible: item !== null && Qt.platform.os !== "android"
source: "qrc:/ColorScheme.qml"
Layout.fillWidth: true Layout.fillWidth: true
}
}
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing * 2
Layout.fillWidth: true
FormCard.FormCheckDelegate {
id: showFancyEffectsDelegate
text: i18n("Show fancy effects in chat")
checked: Config.showFancyEffects
enabled: !Config.isShowFancyEffectsImmutable
onToggled: {
Config.showFancyEffects = checked;
Config.save();
}
}
FormCard.FormDelegateSeparator { above: showFancyEffectsDelegate ; below: hasWindowSystemDelegate }
FormCard.FormCheckDelegate {
id: hasWindowSystemDelegate
visible: Controller.hasWindowSystem
text: i18n("Use transparent chat page")
enabled: !Config.compactLayout && !Config.isBlurImmutable
checked: Config.blur
onToggled: {
Config.blur = checked;
Config.save();
}
}
FormCard.FormDelegateSeparator { above: hasWindowSystemDelegate; below: transparencyDelegate }
FormCard.AbstractFormDelegate {
id: transparencyDelegate
Layout.fillWidth: true
visible: Controller.hasWindowSystem && Config.blur
enabled: !Config.isTransparancyImmutable
background: Item {}
contentItem: ColumnLayout { contentItem: ColumnLayout {
spacing: 0 QQC2.Label {
MobileForm.FormCheckDelegate { text: i18n("Transparency")
id: showFancyEffectsDelegate
text: i18n("Show fancy effects in chat")
checked: Config.showFancyEffects
enabled: !Config.isShowFancyEffectsImmutable
onToggled: {
Config.showFancyEffects = checked;
Config.save();
}
}
MobileForm.FormDelegateSeparator { above: showFancyEffectsDelegate ; below: hasWindowSystemDelegate }
MobileForm.FormCheckDelegate {
id: hasWindowSystemDelegate
visible: Controller.hasWindowSystem
text: i18n("Use transparent chat page")
enabled: !Config.compactLayout && !Config.isBlurImmutable
checked: Config.blur
onToggled: {
Config.blur = checked;
Config.save();
}
}
MobileForm.FormDelegateSeparator { above: hasWindowSystemDelegate; below: transparencyDelegate }
MobileForm.AbstractFormDelegate {
id: transparencyDelegate
Layout.fillWidth: true Layout.fillWidth: true
visible: Controller.hasWindowSystem && Config.blur
enabled: !Config.isTransparancyImmutable
background: Item {}
contentItem: ColumnLayout {
QQC2.Label {
text: i18n("Transparency")
Layout.fillWidth: true
}
QQC2.Slider {
enabled: !Config.compactLayout && Config.blur
from: 0
to: 1
stepSize: 0.05
value: Config.transparency
onMoved: {
Config.transparency = value;
Config.save();
}
Layout.fillWidth: true
HoverHandler { id: sliderHover }
QQC2.ToolTip.visible: sliderHover.hovered && !enabled
QQC2.ToolTip.text: i18n("Only enabled if the transparent chat page is enabled.")
}
QQC2.Label {
text: Math.round(Config.transparency * 100) + "%"
Layout.fillWidth: true
}
}
} }
QQC2.Slider {
MobileForm.FormDelegateSeparator { above: transparencyDelegate; below: showLocalMessagesOnRightDelegate; visible: transparencyDelegate.visible } enabled: !Config.compactLayout && Config.blur
from: 0
MobileForm.FormCheckDelegate { to: 1
id: showLocalMessagesOnRightDelegate stepSize: 0.05
text: i18n("Show your messages on the right") value: Config.transparency
checked: Config.showLocalMessagesOnRight onMoved: {
enabled: !Config.isShowLocalMessagesOnRightImmutable && !Config.compactLayout Config.transparency = value;
onToggled: { Config.save();
Config.showLocalMessagesOnRight = checked
Config.save()
} }
Layout.fillWidth: true
HoverHandler { id: sliderHover }
QQC2.ToolTip.visible: sliderHover.hovered && !enabled
QQC2.ToolTip.text: i18n("Only enabled if the transparent chat page is enabled.")
} }
QQC2.Label {
MobileForm.FormDelegateSeparator { above: showLocalMessagesOnRightDelegate; below: showLinkPreviewDelegate } text: Math.round(Config.transparency * 100) + "%"
Layout.fillWidth: true
MobileForm.FormCheckDelegate {
id: showLinkPreviewDelegate
text: i18n("Show links preview in the chat messages")
checked: Config.showLinkPreview
onToggled: {
Config.showLinkPreview = checked
Config.save()
}
} }
} }
} }
MobileForm.FormHeader {
Layout.fillWidth: true
title: i18n("Show Avatar")
}
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCheckDelegate {
text: i18n("In chat")
checked: Config.showAvatarInTimeline
onToggled: {
Config.showAvatarInTimeline = checked
Config.save()
}
enabled: !Config.isShowAvatarInTimelineImmutable
}
MobileForm.FormCheckDelegate { FormCard.FormDelegateSeparator { above: transparencyDelegate; below: showLocalMessagesOnRightDelegate; visible: transparencyDelegate.visible }
text: i18n("In sidebar")
checked: Config.showAvatarInRoomDrawer FormCard.FormCheckDelegate {
enabled: !Config.isShowAvatarInRoomDrawerImmutable id: showLocalMessagesOnRightDelegate
onToggled: { text: i18n("Show your messages on the right")
Config.showAvatarInRoomDrawer = checked checked: Config.showLocalMessagesOnRight
Config.save() enabled: !Config.isShowLocalMessagesOnRightImmutable && !Config.compactLayout
} onToggled: {
} Config.showLocalMessagesOnRight = checked
Config.save()
}
}
FormCard.FormDelegateSeparator { above: showLocalMessagesOnRightDelegate; below: showLinkPreviewDelegate }
FormCard.FormCheckDelegate {
id: showLinkPreviewDelegate
text: i18n("Show links preview in the chat messages")
checked: Config.showLinkPreview
onToggled: {
Config.showLinkPreview = checked
Config.save()
}
}
}
FormCard.FormHeader {
Layout.fillWidth: true
title: i18n("Show Avatar")
}
FormCard.FormCard {
Layout.fillWidth: true
FormCard.FormCheckDelegate {
text: i18n("In chat")
checked: Config.showAvatarInTimeline
onToggled: {
Config.showAvatarInTimeline = checked
Config.save()
}
enabled: !Config.isShowAvatarInTimelineImmutable
}
FormCard.FormCheckDelegate {
text: i18n("In sidebar")
checked: Config.showAvatarInRoomDrawer
enabled: !Config.isShowAvatarInRoomDrawerImmutable
onToggled: {
Config.showAvatarInRoomDrawer = checked
Config.save()
} }
} }
} }

View File

@@ -7,11 +7,11 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.19 as Kirigami import org.kde.kirigami 2.19 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0 import org.kde.neochat 1.0
MobileForm.AbstractFormDelegate { FormCard.AbstractFormDelegate {
id: deviceDelegate id: deviceDelegate
required property string id required property string id

View File

@@ -7,80 +7,81 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.19 as Kirigami import org.kde.kirigami 2.19 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0 import org.kde.neochat 1.0
Kirigami.ScrollablePage { FormCard.FormCardPage {
id: root
title: i18n("Devices") title: i18n("Devices")
property alias connection: devicesModel.connection property alias connection: devicesModel.connection
leftPadding: 0 DevicesCard {
rightPadding: 0 title: i18n("This Device")
type: DevicesModel.This
DevicesModel { showVerifyButton: false
id: devicesModel }
DevicesCard {
title: i18n("Verified Devices")
type: DevicesModel.Verified
showVerifyButton: true
}
DevicesCard {
title: i18n("Unverified Devices")
type: DevicesModel.Unverified
showVerifyButton: true
}
DevicesCard {
title: i18n("Devices without Encryption Support")
type: DevicesModel.Unencrypted
showVerifyButton: false
} }
ColumnLayout { FormCard.AbstractFormDelegate {
DevicesCard { Layout.fillWidth: true
title: i18n("This Device") visible: Controller.activeConnection && devicesModel.count === 0 // We can assume 0 means loading since there is at least one device
type: DevicesModel.This contentItem: Kirigami.LoadingPlaceholder { }
showVerifyButton: false
}
DevicesCard {
title: i18n("Verified Devices")
type: DevicesModel.Verified
showVerifyButton: true
}
DevicesCard {
title: i18n("Unverified Devices")
type: DevicesModel.Unverified
showVerifyButton: true
}
DevicesCard {
title: i18n("Devices without Encryption Support")
type: DevicesModel.Unencrypted
showVerifyButton: false
}
MobileForm.AbstractFormDelegate {
Layout.fillWidth: true
visible: Controller.activeConnection && devicesModel.count === 0 // We can assume 0 means loading since there is at least one device
contentItem: Kirigami.LoadingPlaceholder { }
}
Kirigami.InlineMessage {
Layout.fillWidth: true
Layout.maximumWidth: Kirigami.Units.gridUnit * 30
Layout.alignment: Qt.AlignHCenter
text: i18n("Please login to view the signed-in devices for your account.")
type: Kirigami.MessageType.Information
visible: !Controller.activeConnection
}
} }
Kirigami.OverlaySheet { Kirigami.InlineMessage {
id: passwordSheet Layout.fillWidth: true
Layout.maximumWidth: Kirigami.Units.gridUnit * 30
Layout.alignment: Qt.AlignHCenter
text: i18n("Please login to view the signed-in devices for your account.")
type: Kirigami.MessageType.Information
visible: !Controller.activeConnection
}
property string deviceId data: [
DevicesModel {
id: devicesModel
},
Kirigami.PromptDialog {
id: passwordSheet
title: i18n("Remove device") property string deviceId
Kirigami.FormLayout {
QQC2.TextField { parent: applicationWindow().overlay
title: i18n("Remove device")
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
onAccepted: {
devicesModel.logout(passwordSheet.deviceId, passwordField.text)
passwordField.text = ""
passwordSheet.close()
}
FormCard.FormTextFieldDelegate {
id: passwordField id: passwordField
Kirigami.FormData.label: i18n("Password:") label: i18n("Password:")
echoMode: TextInput.Password echoMode: TextInput.Password
} }
QQC2.Button {
text: i18n("Confirm")
onClicked: {
devicesModel.logout(passwordSheet.deviceId, passwordField.text)
passwordField.text = ""
passwordSheet.close()
}
}
} }
} ]
} }

View File

@@ -6,104 +6,102 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0 import org.kde.neochat 1.0
Kirigami.ScrollablePage { FormCard.FormCardPage {
title: i18nc("@title:window", "General") id: root
property int currentType property int currentType
property bool proxyConfigChanged: false property bool proxyConfigChanged: false
topPadding: 0 title: i18nc("@title:window", "General")
leftPadding: 0
rightPadding: 0 FormCard.FormHeader {
ColumnLayout { title: i18n("Network Proxy")
spacing: 0 }
MobileForm.FormHeader {
Layout.fillWidth: true FormCard.FormCard {
title: i18n("Network Proxy") FormCard.FormRadioDelegate {
text: i18n("System Default")
checked: currentType === 0
enabled: !Config.isProxyTypeImmutable
onToggled: {
currentType = 0
}
} }
MobileForm.FormCard { FormCard.FormRadioDelegate {
Layout.fillWidth: true text: i18n("HTTP")
contentItem: ColumnLayout { checked: currentType === 1
spacing: 0 enabled: !Config.isProxyTypeImmutable
MobileForm.FormRadioDelegate { onToggled: {
text: i18n("System Default") currentType = 1
checked: currentType === 0 }
enabled: !Config.isProxyTypeImmutable }
onToggled: { FormCard.FormRadioDelegate {
currentType = 0 text: i18n("Socks5")
} checked: currentType === 2
} enabled: !Config.isProxyTypeImmutable
MobileForm.FormRadioDelegate { onToggled: {
text: i18n("HTTP") currentType = 2
checked: currentType === 1 }
enabled: !Config.isProxyTypeImmutable }
onToggled: { }
currentType = 1
} FormCard.FormHeader {
} title: i18n("Proxy Settings")
MobileForm.FormRadioDelegate { }
text: i18n("Socks5")
checked: currentType === 2 FormCard.FormCard {
enabled: !Config.isProxyTypeImmutable FormCard.FormTextFieldDelegate {
onToggled: { id: hostField
currentType = 2 label: i18n("Host")
} text: Config.proxyHost
} inputMethodHints: Qt.ImhUrlCharactersOnly
onEditingFinished: {
proxyConfigChanged = true
} }
} }
MobileForm.FormHeader { FormCard.FormDelegateSeparator {}
Layout.fillWidth: true
title: i18n("Proxy Settings") FormCard.FormSpinBoxDelegate {
id: portField
label: i18n("Port")
value: Config.proxyPort
from: 0
to: 65536
textFromValue: function(value, locale) {
return value // it will add a thousands separator if we don't do this, not sure why
}
onValueChanged: {
proxyConfigChanged = true
}
} }
MobileForm.FormCard {
Layout.fillWidth: true FormCard.FormDelegateSeparator {}
contentItem: ColumnLayout {
spacing: 0 FormCard.FormTextFieldDelegate {
MobileForm.FormTextFieldDelegate { id: userField
id: hostField label: i18n("User")
label: i18n("Host") text: Config.proxyUser
text: Config.proxyHost inputMethodHints: Qt.ImhUrlCharactersOnly
inputMethodHints: Qt.ImhUrlCharactersOnly onEditingFinished: {
onEditingFinished: { proxyConfigChanged = true
proxyConfigChanged = true }
} }
}
MobileForm.FormSpinBoxDelegate { FormCard.FormDelegateSeparator {}
id: portField
label: i18n("Port") FormCard.FormTextFieldDelegate {
value: Config.proxyPort id: passwordField
from: 0 label: i18n("Password")
to: 65536 text: Config.proxyPassword
textFromValue: function(value, locale) { echoMode: TextInput.Password
return value // it will add a thousands separator if we don't do this, not sure why inputMethodHints: Qt.ImhUrlCharactersOnly
} onEditingFinished: {
onValueChanged: { proxyConfigChanged = true
proxyConfigChanged = true
}
}
MobileForm.FormTextFieldDelegate {
id: userField
label: i18n("User")
text: Config.proxyUser
inputMethodHints: Qt.ImhUrlCharactersOnly
onEditingFinished: {
proxyConfigChanged = true
}
}
MobileForm.FormTextFieldDelegate {
id: passwordField
label: i18n("Password")
text: Config.proxyPassword
echoMode: TextInput.Password
inputMethodHints: Qt.ImhUrlCharactersOnly
onEditingFinished: {
proxyConfigChanged = true
}
}
} }
} }
} }