Files
amnezia-client/client/ui/qml/Pages2/PageShare.qml
T

1004 lines
39 KiB
QML
Raw Normal View History

import QtQuick
2023-06-13 20:03:20 +09:00
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
2023-06-13 20:03:20 +09:00
import SortFilterProxyModel 0.2
2023-06-13 20:03:20 +09:00
import PageEnum 1.0
import ContainerProps 1.0
2024-07-07 13:42:38 +03:00
import Style 1.0
2023-06-13 20:03:20 +09:00
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Components"
import "../Config"
2023-06-13 20:03:20 +09:00
PageType {
id: root
defaultActiveFocusItem: clientNameTextField.textField
enum ConfigType {
AmneziaConnection,
OpenVpn,
WireGuard,
2024-02-23 19:55:59 +02:00
Awg,
ShadowSocks,
2024-03-27 11:02:34 +00:00
Cloak,
Xray
}
2023-11-21 20:13:51 +07:00
signal revokeConfig(int index)
onRevokeConfig: function(index) {
PageController.showBusyIndicator(true)
ExportController.revokeConfig(index,
ContainersModel.getProcessedContainerIndex(),
2024-02-19 19:54:15 +05:00
ServersModel.getProcessedServerCredentials())
2023-11-21 20:13:51 +07:00
PageController.showBusyIndicator(false)
2023-12-14 11:03:27 +07:00
PageController.showNotificationMessage(qsTr("Config revoked"))
2023-11-21 20:13:51 +07:00
}
2023-06-13 20:03:20 +09:00
Connections {
target: ExportController
function onGenerateConfig(type) {
2023-11-21 20:13:51 +07:00
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
2023-07-04 09:58:19 +09:00
shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true)
switch (type) {
2024-02-23 19:55:59 +02:00
case PageShare.ConfigType.AmneziaConnection: {
ExportController.generateConnectionConfig(clientNameTextField.textFieldText);
break;
}
2023-08-22 14:37:29 +05:00
case PageShare.ConfigType.OpenVpn: {
2023-11-23 00:03:43 +07:00
ExportController.generateOpenVpnConfig(clientNameTextField.textFieldText)
2023-08-22 14:37:29 +05:00
shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config")
shareConnectionDrawer.configExtension = ".ovpn"
shareConnectionDrawer.configFileName = "amnezia_for_openvpn"
break
2023-08-22 14:37:29 +05:00
}
case PageShare.ConfigType.WireGuard: {
2023-11-23 00:03:43 +07:00
ExportController.generateWireGuardConfig(clientNameTextField.textFieldText)
2023-08-22 14:37:29 +05:00
shareConnectionDrawer.configCaption = qsTr("Save WireGuard config")
shareConnectionDrawer.configExtension = ".conf"
shareConnectionDrawer.configFileName = "amnezia_for_wireguard"
break
}
2024-02-23 19:55:59 +02:00
case PageShare.ConfigType.Awg: {
ExportController.generateAwgConfig(clientNameTextField.textFieldText)
shareConnectionDrawer.configCaption = qsTr("Save AmneziaWG config")
shareConnectionDrawer.configExtension = ".conf"
shareConnectionDrawer.configFileName = "amnezia_for_awg"
break
}
case PageShare.ConfigType.ShadowSocks: {
ExportController.generateShadowSocksConfig()
2024-06-19 02:14:22 +03:00
shareConnectionDrawer.configCaption = qsTr("Save Shadowsocks config")
shareConnectionDrawer.configExtension = ".json"
shareConnectionDrawer.configFileName = "amnezia_for_shadowsocks"
break
}
case PageShare.ConfigType.Cloak: {
ExportController.generateCloakConfig()
shareConnectionDrawer.configCaption = qsTr("Save Cloak config")
shareConnectionDrawer.configExtension = ".json"
shareConnectionDrawer.configFileName = "amnezia_for_cloak"
break
2023-08-22 14:37:29 +05:00
}
2024-03-27 11:02:34 +00:00
case PageShare.ConfigType.Xray: {
ExportController.generateXrayConfig()
shareConnectionDrawer.configCaption = qsTr("Save XRay config")
shareConnectionDrawer.configExtension = ".json"
shareConnectionDrawer.configFileName = "amnezia_for_xray"
break
}
2023-06-13 20:03:20 +09:00
}
2023-07-04 09:58:19 +09:00
PageController.showBusyIndicator(false)
}
2024-05-25 13:00:51 +03:00
function onExportErrorOccurred(error) {
2023-07-04 09:58:19 +09:00
shareConnectionDrawer.close()
2024-05-25 13:00:51 +03:00
PageController.showErrorMessage(error)
2023-06-13 20:03:20 +09:00
}
}
2023-11-23 14:32:16 +07:00
property bool isSearchBarVisible: false
2023-06-13 20:03:20 +09:00
property bool showContent: false
property bool shareButtonEnabled: true
2023-06-13 20:03:20 +09:00
property list<QtObject> connectionTypesModel: [
amneziaConnectionFormat
]
QtObject {
id: amneziaConnectionFormat
property string name: qsTr("For the AmneziaVPN app")
property var type: PageShare.ConfigType.AmneziaConnection
2023-06-13 20:03:20 +09:00
}
QtObject {
id: openVpnConnectionFormat
2024-04-29 23:33:35 +02:00
property string name: qsTr("OpenVPN native format")
property var type: PageShare.ConfigType.OpenVpn
2023-06-13 20:03:20 +09:00
}
QtObject {
id: wireGuardConnectionFormat
property string name: qsTr("WireGuard native format")
property var type: PageShare.ConfigType.WireGuard
2023-06-13 20:03:20 +09:00
}
2024-02-23 19:55:59 +02:00
QtObject {
id: awgConnectionFormat
property string name: qsTr("AmneziaWG native format")
property var type: PageShare.ConfigType.Awg
}
QtObject {
id: shadowSocksConnectionFormat
2024-06-19 02:14:22 +03:00
property string name: qsTr("Shadowsocks native format")
property var type: PageShare.ConfigType.ShadowSocks
}
QtObject {
id: cloakConnectionFormat
property string name: qsTr("Cloak native format")
property var type: PageShare.ConfigType.Cloak
}
2024-03-27 11:02:34 +00:00
QtObject {
id: xrayConnectionFormat
property string name: qsTr("XRay native format")
property var type: PageShare.ConfigType.Xray
}
2023-06-13 20:03:20 +09:00
FlickableType {
2024-04-18 17:54:55 +04:00
id: a
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height + 10
2023-06-13 20:03:20 +09:00
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
2023-08-26 10:08:50 +03:00
spacing: 0
2024-04-18 17:54:55 +04:00
Item {
id: focusItem
KeyNavigation.tab: header.actionButton
onFocusChanged: {
if (focusItem.activeFocus) {
a.contentY = 0
}
}
}
2023-06-13 20:03:20 +09:00
HeaderType {
2024-04-18 17:54:55 +04:00
id: header
2023-06-13 20:03:20 +09:00
Layout.fillWidth: true
2023-08-26 10:08:50 +03:00
Layout.topMargin: 24
2023-06-13 20:03:20 +09:00
2023-10-21 18:32:30 +01:00
headerText: qsTr("Share VPN Access")
2023-11-23 00:03:43 +07:00
actionButtonImage: "qrc:/images/controls/more-vertical.svg"
actionButtonFunction: function() {
shareFullAccessDrawer.open()
}
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: connectionRadioButton
2024-02-16 15:24:06 +05:00
DrawerType2 {
2023-11-23 00:03:43 +07:00
id: shareFullAccessDrawer
2024-02-16 15:24:06 +05:00
parent: root
2023-11-23 00:03:43 +07:00
2024-02-16 15:24:06 +05:00
anchors.fill: parent
expandedHeight: root.height
2024-04-18 17:54:55 +04:00
onClosed: {
if (!GC.isMobile()) {
clientNameTextField.textField.forceActiveFocus()
}
}
2023-11-23 00:03:43 +07:00
2024-02-16 15:24:06 +05:00
expandedContent: ColumnLayout {
id: shareFullAccessDrawerContent
2023-11-23 00:03:43 +07:00
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
spacing: 0
onImplicitHeightChanged: {
shareFullAccessDrawer.expandedHeight = shareFullAccessDrawerContent.implicitHeight + 32
}
2024-04-18 17:54:55 +04:00
Connections {
target: shareFullAccessDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
2023-11-23 00:03:43 +07:00
Header2Type {
Layout.fillWidth: true
Layout.bottomMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Share full access to the server and VPN")
descriptionText: qsTr("Use for your own devices, or share with those you trust to manage the server.")
}
2024-04-18 17:54:55 +04:00
Item {
id: focusItem
KeyNavigation.tab: shareFullAccessButton.rightButton
}
2023-11-23 00:03:43 +07:00
LabelWithButtonType {
2024-04-18 17:54:55 +04:00
id: shareFullAccessButton
2023-11-23 00:03:43 +07:00
Layout.fillWidth: true
text: qsTr("Share")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: focusItem
2023-11-23 00:03:43 +07:00
clickedFunction: function() {
PageController.goToPage(PageEnum.PageShareFullAccess)
shareFullAccessDrawer.close()
}
2024-04-18 17:54:55 +04:00
2023-11-23 00:03:43 +07:00
}
}
}
2023-06-13 20:03:20 +09:00
}
Rectangle {
id: accessTypeSelector
property int currentIndex
Layout.topMargin: 32
implicitWidth: accessTypeSelectorContent.implicitWidth
implicitHeight: accessTypeSelectorContent.implicitHeight
2024-07-07 13:42:38 +03:00
color: AmneziaStyle.color.blackLight
2023-06-13 20:03:20 +09:00
radius: 16
RowLayout {
id: accessTypeSelectorContent
spacing: 0
HorizontalRadioButton {
2024-04-18 17:54:55 +04:00
id: connectionRadioButton
2023-06-13 20:03:20 +09:00
checked: accessTypeSelector.currentIndex === 0
implicitWidth: (root.width - 32) / 2
text: qsTr("Connection")
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: usersRadioButton
2023-06-13 20:03:20 +09:00
onClicked: {
accessTypeSelector.currentIndex = 0
2024-04-18 17:54:55 +04:00
if (!GC.isMobile()) {
clientNameTextField.textField.forceActiveFocus()
}
2023-06-13 20:03:20 +09:00
}
}
HorizontalRadioButton {
2024-04-18 17:54:55 +04:00
id: usersRadioButton
2023-11-21 20:13:51 +07:00
checked: accessTypeSelector.currentIndex === 1
2023-06-13 20:03:20 +09:00
implicitWidth: (root.width - 32) / 2
2023-11-21 20:13:51 +07:00
text: qsTr("Users")
2023-06-13 20:03:20 +09:00
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? clientNameTextField.textField : serverSelector
2023-06-13 20:03:20 +09:00
onClicked: {
accessTypeSelector.currentIndex = 1
2023-11-21 20:13:51 +07:00
PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getProcessedContainerIndex(),
2024-02-19 19:54:15 +05:00
ServersModel.getProcessedServerCredentials())
2023-11-21 20:13:51 +07:00
PageController.showBusyIndicator(false)
2024-04-18 17:54:55 +04:00
focusItem.forceActiveFocus()
2023-06-13 20:03:20 +09:00
}
}
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 24
2023-08-26 10:08:50 +03:00
Layout.bottomMargin: 24
2023-06-13 20:03:20 +09:00
2023-11-21 20:13:51 +07:00
visible: accessTypeSelector.currentIndex === 0
text: qsTr("Share VPN access without the ability to manage the server")
2024-07-07 13:42:38 +03:00
color: AmneziaStyle.color.grey
2023-06-13 20:03:20 +09:00
}
2023-11-21 20:13:51 +07:00
TextFieldWithHeaderType {
2023-11-23 00:03:43 +07:00
id: clientNameTextField
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
Layout.topMargin: 16
visible: accessTypeSelector.currentIndex === 0
headerText: qsTr("User name")
textFieldText: "New client"
textField.maximumLength: 20
2023-11-21 20:13:51 +07:00
checkEmptyText: true
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: serverSelector
2023-11-21 20:13:51 +07:00
}
2023-06-13 20:03:20 +09:00
DropDownType {
id: serverSelector
signal severSelectorIndexChanged
property int currentIndex: -1
2023-06-13 20:03:20 +09:00
Layout.fillWidth: true
2023-08-26 10:08:50 +03:00
Layout.topMargin: 16
2023-06-13 20:03:20 +09:00
drawerHeight: 0.4375
2024-02-16 15:24:06 +05:00
drawerParent: root
2023-06-13 20:03:20 +09:00
descriptionText: qsTr("Server")
2023-06-13 20:03:20 +09:00
headerText: qsTr("Server")
listView: ListViewWithRadioButtonType {
id: serverSelectorListView
rootWidth: root.width
imageSource: "qrc:/images/controls/check.svg"
2023-06-13 20:03:20 +09:00
model: SortFilterProxyModel {
id: proxyServersModel
sourceModel: ServersModel
filters: [
ValueFilter {
roleName: "hasWriteAccess"
value: true
},
ValueFilter {
roleName: "hasInstalledContainers"
value: true
}
]
}
2023-06-13 20:03:20 +09:00
clickedFunction: function() {
handler()
if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) {
serverSelector.currentIndex = serverSelectorListView.currentIndex
serverSelector.severSelectorIndexChanged()
}
2024-02-16 15:24:06 +05:00
serverSelector.close()
2023-06-13 20:03:20 +09:00
}
Component.onCompleted: {
if (ServersModel.isDefaultServerHasWriteAccess() && ServersModel.getDefaultServerData("hasInstalledContainers")) {
serverSelectorListView.currentIndex = proxyServersModel.mapFromSource(ServersModel.defaultIndex)
} else {
serverSelectorListView.currentIndex = 0
}
serverSelectorListView.triggerCurrentItem()
}
function handler() {
2023-06-13 20:03:20 +09:00
serverSelector.text = selectedText
2024-02-19 19:54:15 +05:00
ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
2023-06-13 20:03:20 +09:00
}
}
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: protocolSelector
}
DropDownType {
id: protocolSelector
2023-06-13 20:03:20 +09:00
Layout.fillWidth: true
Layout.topMargin: 16
drawerHeight: 0.5
2024-02-16 15:24:06 +05:00
drawerParent: root
2023-06-13 20:03:20 +09:00
2023-10-03 23:28:44 +05:00
descriptionText: qsTr("Protocol")
headerText: qsTr("Protocol")
2023-06-13 20:03:20 +09:00
listView: ListViewWithRadioButtonType {
id: protocolSelectorListView
2023-06-13 20:03:20 +09:00
rootWidth: root.width
imageSource: "qrc:/images/controls/check.svg"
2023-06-13 20:03:20 +09:00
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
filters: [
ValueFilter {
roleName: "isInstalled"
value: true
},
ValueFilter {
roleName: "isShareable"
value: true
2023-06-13 20:03:20 +09:00
}
]
}
currentIndex: 0
clickedFunction: function() {
handler()
2024-02-16 15:24:06 +05:00
protocolSelector.close()
}
Connections {
target: serverSelector
2023-06-13 20:03:20 +09:00
function onSeverSelectorIndexChanged() {
2024-02-19 19:54:15 +05:00
var defaultContainer = proxyContainersModel.mapFromSource(ServersModel.getProcessedServerData("defaultContainer"))
2024-02-13 20:20:13 +05:00
protocolSelectorListView.currentIndex = defaultContainer
protocolSelectorListView.triggerCurrentItem()
}
}
2023-06-13 20:03:20 +09:00
function handler() {
if (!proxyContainersModel.count) {
root.shareButtonEnabled = false
return
} else {
root.shareButtonEnabled = true
}
2023-06-13 20:03:20 +09:00
protocolSelector.text = selectedText
2023-06-13 20:03:20 +09:00
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex))
2023-06-13 20:03:20 +09:00
2023-11-23 14:32:16 +07:00
fillConnectionTypeModel()
if (accessTypeSelector.currentIndex === 1) {
2023-11-21 20:13:51 +07:00
PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getProcessedContainerIndex(),
2024-02-19 19:54:15 +05:00
ServersModel.getProcessedServerCredentials())
2023-11-21 20:13:51 +07:00
PageController.showBusyIndicator(false)
}
}
function fillConnectionTypeModel() {
root.connectionTypesModel = [amneziaConnectionFormat]
var index = proxyContainersModel.mapToSource(currentIndex)
if (index === ContainerProps.containerFromString("amnezia-openvpn")) {
root.connectionTypesModel.push(openVpnConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-wireguard")) {
root.connectionTypesModel.push(wireGuardConnectionFormat)
2024-02-23 19:55:59 +02:00
} else if (index === ContainerProps.containerFromString("amnezia-awg")) {
root.connectionTypesModel.push(awgConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-shadowsocks")) {
root.connectionTypesModel.push(openVpnConnectionFormat)
root.connectionTypesModel.push(shadowSocksConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-openvpn-cloak")) {
root.connectionTypesModel.push(openVpnConnectionFormat)
root.connectionTypesModel.push(shadowSocksConnectionFormat)
root.connectionTypesModel.push(cloakConnectionFormat)
2024-03-27 11:02:34 +00:00
} else if (index === ContainerProps.containerFromString("amnezia-xray")) {
root.connectionTypesModel.push(xrayConnectionFormat)
2023-06-13 20:03:20 +09:00
}
}
}
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ?
exportTypeSelector :
isSearchBarVisible ?
searchTextField.textField :
usersHeader.actionButton
2023-06-13 20:03:20 +09:00
}
DropDownType {
id: exportTypeSelector
2023-06-13 20:03:20 +09:00
property int currentIndex: 0
2023-06-13 20:03:20 +09:00
Layout.fillWidth: true
Layout.topMargin: 16
drawerHeight: 0.4375
2024-02-16 15:24:06 +05:00
drawerParent: root
2023-06-13 20:03:20 +09:00
visible: accessTypeSelector.currentIndex === 0
enabled: root.connectionTypesModel.length > 1
2023-06-13 20:03:20 +09:00
descriptionText: qsTr("Connection format")
headerText: qsTr("Connection format")
2023-08-16 22:45:05 +05:00
listView: ListViewWithRadioButtonType {
onCurrentIndexChanged: {
exportTypeSelector.currentIndex = currentIndex
exportTypeSelector.text = selectedText
}
2023-06-13 20:03:20 +09:00
rootWidth: root.width
imageSource: "qrc:/images/controls/check.svg"
2023-06-13 20:03:20 +09:00
model: root.connectionTypesModel
currentIndex: 0
2023-06-13 20:03:20 +09:00
clickedFunction: function() {
exportTypeSelector.text = selectedText
exportTypeSelector.currentIndex = currentIndex
2024-02-16 15:24:06 +05:00
exportTypeSelector.close()
2023-06-13 20:03:20 +09:00
}
Component.onCompleted: {
exportTypeSelector.text = selectedText
exportTypeSelector.currentIndex = currentIndex
2023-06-13 20:03:20 +09:00
}
}
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: shareButton
2023-06-13 20:03:20 +09:00
}
BasicButtonType {
id: shareButton
2023-06-13 20:03:20 +09:00
Layout.fillWidth: true
2023-08-26 10:08:50 +03:00
Layout.topMargin: 40
Layout.bottomMargin: 32
2023-06-13 20:03:20 +09:00
enabled: shareButtonEnabled
2023-11-21 20:13:51 +07:00
visible: accessTypeSelector.currentIndex === 0
2023-06-13 20:03:20 +09:00
text: qsTr("Share")
2024-04-18 17:54:55 +04:00
imageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
parentFlickable: a
2023-06-13 20:03:20 +09:00
clickedFunc: function(){
if (clientNameTextField.textFieldText !== "") {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
}
2023-11-21 20:13:51 +07:00
}
2024-04-18 17:54:55 +04:00
2023-11-21 20:13:51 +07:00
}
Header2Type {
2024-04-18 17:54:55 +04:00
id: usersHeader
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 16
2023-11-23 14:32:16 +07:00
visible: accessTypeSelector.currentIndex === 1 && !root.isSearchBarVisible
2023-11-21 20:13:51 +07:00
headerText: qsTr("Users")
2023-11-23 14:32:16 +07:00
actionButtonImage: "qrc:/images/controls/search.svg"
actionButtonFunction: function() {
root.isSearchBarVisible = true
}
2024-04-18 17:54:55 +04:00
Keys.onTabPressed: clientsListView.model.count > 0 ?
clientsListView.forceActiveFocus() :
lastItemTabClicked(focusItem)
2023-11-23 14:32:16 +07:00
}
RowLayout {
Layout.topMargin: 24
Layout.bottomMargin: 16
visible: accessTypeSelector.currentIndex === 1 && root.isSearchBarVisible
TextFieldWithHeaderType {
id: searchTextField
Layout.fillWidth: true
textFieldPlaceholderText: qsTr("Search")
2024-04-18 17:54:55 +04:00
Connections {
target: root
function onIsSearchBarVisibleChanged() {
if (root.isSearchBarVisible) {
searchTextField.textField.forceActiveFocus()
} else {
searchTextField.textFieldText = ""
if (!GC.isMobile()) {
usersHeader.actionButton.forceActiveFocus()
}
}
}
}
Keys.onEscapePressed: {
root.isSearchBarVisible = false
}
function navigateTo() {
if (GC.isMobile()) {
focusItem.forceActiveFocus()
return;
}
if (searchTextField.textFieldText === "") {
root.isSearchBarVisible = false
usersHeader.actionButton.forceActiveFocus()
} else {
closeSearchButton.forceActiveFocus()
}
}
Keys.onTabPressed: { navigateTo() }
Keys.onEnterPressed: { navigateTo() }
Keys.onReturnPressed: { navigateTo() }
2023-11-23 14:32:16 +07:00
}
ImageButtonType {
2024-04-18 17:54:55 +04:00
id: closeSearchButton
2023-11-23 14:32:16 +07:00
image: "qrc:/images/controls/close.svg"
2024-07-07 13:42:38 +03:00
imageColor: AmneziaStyle.color.white
2023-11-23 14:32:16 +07:00
2024-04-18 17:54:55 +04:00
Keys.onTabPressed: {
if (!GC.isMobile()) {
if (clientsListView.model.count > 0) {
clientsListView.forceActiveFocus()
} else {
lastItemTabClicked(focusItem)
}
}
}
function clickedFunc() {
2023-11-23 14:32:16 +07:00
root.isSearchBarVisible = false
}
2024-04-18 17:54:55 +04:00
onClicked: clickedFunc()
Keys.onEnterPressed: clickedFunc()
Keys.onReturnPressed: clickedFunc()
2023-11-23 14:32:16 +07:00
}
2023-11-21 20:13:51 +07:00
}
ListView {
2023-11-23 00:03:43 +07:00
id: clientsListView
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
visible: accessTypeSelector.currentIndex === 1
2023-11-23 14:32:16 +07:00
model: SortFilterProxyModel {
id: proxyClientManagementModel
sourceModel: ClientManagementModel
filters: RegExpFilter {
roleName: "clientName"
pattern: ".*" + searchTextField.textFieldText + ".*"
caseSensitivity: Qt.CaseInsensitive
}
}
2023-11-21 20:13:51 +07:00
clip: true
interactive: false
2024-04-18 17:54:55 +04:00
activeFocusOnTab: true
focus: true
Keys.onTabPressed: {
if (!GC.isMobile()) {
if (currentIndex < this.count - 1) {
this.incrementCurrentIndex()
currentItem.focusItem.forceActiveFocus()
} else {
this.currentIndex = 0
lastItemTabClicked(focusItem)
}
}
}
onActiveFocusChanged: {
if (focus && !GC.isMobile()) {
currentIndex = 0
currentItem.focusItem.forceActiveFocus()
}
}
onCurrentIndexChanged: {
if (currentItem) {
if (currentItem.y < a.contentY) {
a.contentY = currentItem.y
} else if (currentItem.y + currentItem.height + clientsListView.y > a.contentY + a.height) {
a.contentY = currentItem.y + clientsListView.y + currentItem.height - a.height
}
}
}
2023-11-21 20:13:51 +07:00
delegate: Item {
2023-11-23 00:03:43 +07:00
implicitWidth: clientsListView.width
2023-11-21 20:13:51 +07:00
implicitHeight: delegateContent.implicitHeight
2024-04-18 17:54:55 +04:00
property alias focusItem: clientFocusItem.rightButton
2023-11-21 20:13:51 +07:00
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: -16
anchors.leftMargin: -16
LabelWithButtonType {
2024-04-18 17:54:55 +04:00
id: clientFocusItem
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
2023-11-23 00:03:43 +07:00
text: clientName
2023-11-21 20:13:51 +07:00
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
2023-11-23 00:03:43 +07:00
clientInfoDrawer.open()
2023-11-21 20:13:51 +07:00
}
}
DividerType {}
2024-02-16 15:24:06 +05:00
DrawerType2 {
2023-11-23 00:03:43 +07:00
id: clientInfoDrawer
2023-11-21 20:13:51 +07:00
2024-02-16 15:24:06 +05:00
parent: root
2024-04-18 17:54:55 +04:00
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
2024-02-16 15:24:06 +05:00
anchors.fill: parent
2023-11-21 20:13:51 +07:00
2024-02-16 15:24:06 +05:00
expandedContent: ColumnLayout {
2024-04-28 16:03:41 +03:00
id: expandedContent
2023-11-21 20:13:51 +07:00
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 8
2024-04-28 16:03:41 +03:00
onImplicitHeightChanged: {
clientInfoDrawer.expandedHeight = expandedContent.implicitHeight + 32
}
2024-04-18 17:54:55 +04:00
Connections {
target: clientInfoDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem1.forceActiveFocus()
}
}
2023-11-21 20:13:51 +07:00
Header2Type {
Layout.fillWidth: true
2023-11-23 00:03:43 +07:00
headerText: clientName
2024-04-28 16:03:41 +03:00
}
ColumnLayout
{
id: textColumn
2024-07-07 13:42:38 +03:00
property string textColor: AmneziaStyle.color.grey
2024-04-28 16:03:41 +03:00
Layout.bottomMargin: 24
ParagraphTextType {
color: textColumn.textColor
visible: creationDate
Layout.fillWidth: true
text: qsTr("Creation date: %1").arg(creationDate)
}
ParagraphTextType {
color: textColumn.textColor
visible: latestHandshake
Layout.fillWidth: true
text: qsTr("Latest handshake: %1").arg(latestHandshake)
}
ParagraphTextType {
color: textColumn.textColor
visible: dataReceived
Layout.fillWidth: true
text: qsTr("Data received: %1").arg(dataReceived)
}
ParagraphTextType {
color: textColumn.textColor
visible: dataSent
Layout.fillWidth: true
text: qsTr("Data sent: %1").arg(dataSent)
}
2023-11-21 20:13:51 +07:00
}
2024-04-18 17:54:55 +04:00
Item {
id: focusItem1
KeyNavigation.tab: renameButton
}
2023-11-21 20:13:51 +07:00
BasicButtonType {
2024-04-18 17:54:55 +04:00
id: renameButton
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
Layout.topMargin: 24
2024-07-07 13:42:38 +03:00
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.blackHovered
pressedColor: AmneziaStyle.color.blackPressed
disabledColor: AmneziaStyle.color.grey
textColor: AmneziaStyle.color.white
2023-11-21 20:13:51 +07:00
borderWidth: 1
text: qsTr("Rename")
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: revokeButton
clickedFunc: function() {
2023-11-21 20:13:51 +07:00
clientNameEditDrawer.open()
}
2024-02-16 15:24:06 +05:00
DrawerType2 {
2023-11-21 20:13:51 +07:00
id: clientNameEditDrawer
2024-02-16 15:24:06 +05:00
parent: root
2023-11-21 20:13:51 +07:00
2024-02-16 15:24:06 +05:00
anchors.fill: parent
expandedHeight: root.height * 0.35
2023-11-21 20:13:51 +07:00
2024-04-18 17:54:55 +04:00
onClosed: {
if (!GC.isMobile()) {
focusItem1.forceActiveFocus()
}
}
2024-02-16 15:24:06 +05:00
expandedContent: ColumnLayout {
2023-11-21 20:13:51 +07:00
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
2024-02-16 15:24:06 +05:00
anchors.topMargin: 32
2023-11-21 20:13:51 +07:00
anchors.leftMargin: 16
anchors.rightMargin: 16
2024-02-16 15:24:06 +05:00
Connections {
target: clientNameEditDrawer
enabled: !GC.isMobile()
2024-02-16 15:24:06 +05:00
function onOpened() {
clientNameEditor.textField.forceActiveFocus()
}
}
2024-04-18 17:54:55 +04:00
Item {
id: focusItem2
KeyNavigation.tab: clientNameEditor.textField
}
2023-11-21 20:13:51 +07:00
TextFieldWithHeaderType {
2023-11-23 00:03:43 +07:00
id: clientNameEditor
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
headerText: qsTr("Client name")
2023-11-23 00:03:43 +07:00
textFieldText: clientName
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: saveButton
2023-11-21 20:13:51 +07:00
}
BasicButtonType {
id: saveButton
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
text: qsTr("Save")
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: focusItem2
2023-11-21 20:13:51 +07:00
clickedFunc: function() {
if (clientNameEditor.textFieldText === "") {
return
}
2023-11-23 00:03:43 +07:00
if (clientNameEditor.textFieldText !== clientName) {
2023-11-21 20:13:51 +07:00
PageController.showBusyIndicator(true)
ExportController.renameClient(index,
2023-11-23 00:03:43 +07:00
clientNameEditor.textFieldText,
ContainersModel.getProcessedContainerIndex(),
2024-02-19 19:54:15 +05:00
ServersModel.getProcessedServerCredentials())
2023-11-21 20:13:51 +07:00
PageController.showBusyIndicator(false)
clientNameEditDrawer.close()
}
}
}
}
}
}
BasicButtonType {
2024-04-18 17:54:55 +04:00
id: revokeButton
2023-11-21 20:13:51 +07:00
Layout.fillWidth: true
2024-07-07 13:42:38 +03:00
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.blackHovered
pressedColor: AmneziaStyle.color.blackPressed
disabledColor: AmneziaStyle.color.grey
textColor: AmneziaStyle.color.white
2023-11-21 20:13:51 +07:00
borderWidth: 1
text: qsTr("Revoke")
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: focusItem1
2023-11-21 20:13:51 +07:00
clickedFunc: function() {
2024-02-16 15:24:06 +05:00
var headerText = qsTr("Revoke the config for a user - %1?").arg(clientName)
var descriptionText = qsTr("The user will no longer be able to connect to your server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
2023-11-21 20:13:51 +07:00
2024-02-16 15:24:06 +05:00
var yesButtonFunction = function() {
2023-11-23 00:03:43 +07:00
clientInfoDrawer.close()
2023-11-21 20:13:51 +07:00
root.revokeConfig(index)
}
2024-02-16 15:24:06 +05:00
var noButtonFunction = function() {
2024-04-18 17:54:55 +04:00
if (!GC.isMobile()) {
focusItem1.forceActiveFocus()
}
2023-11-21 20:13:51 +07:00
}
2024-02-16 15:24:06 +05:00
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
2023-11-21 20:13:51 +07:00
}
}
}
}
2023-06-13 20:03:20 +09:00
}
}
}
}
}
2024-02-16 15:24:06 +05:00
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
2024-04-18 17:54:55 +04:00
onClosed: {
if (!GC.isMobile()) {
clientNameTextField.textField.forceActiveFocus()
}
}
2024-02-16 15:24:06 +05:00
}
2023-11-23 14:32:16 +07:00
MouseArea {
anchors.fill: parent
onPressed: function(mouse) {
forceActiveFocus()
mouse.accepted = false
}
}
}