feat(community ownership) Move community control node flow UI

Implement the UI part of the new flow for moving community control nodes
w/o involving private keys

Closes #12088
This commit is contained in:
Lukáš Tinkl 2023-09-12 11:26:57 +02:00 committed by Lukáš Tinkl
parent a072286675
commit 848d3b14f5
26 changed files with 417 additions and 600 deletions

View File

@ -98,11 +98,6 @@ proc init*(self: Controller) =
let args = CommunityArgs(e) let args = CommunityArgs(e)
self.delegate.communityAdded(args.community) self.delegate.communityAdded(args.community)
self.events.on(SIGNAL_COMMUNITY_PRIVATE_KEY_REMOVED) do(e:Args):
let args = CommunityArgs(e)
self.delegate.communityEdited(args.community)
self.delegate.communityPrivateKeyRemoved(args.community.id)
self.events.on(SIGNAL_COMMUNITY_IMPORTED) do(e:Args): self.events.on(SIGNAL_COMMUNITY_IMPORTED) do(e:Args):
let args = CommunityArgs(e) let args = CommunityArgs(e)
if(args.error.len > 0): if(args.error.len > 0):
@ -312,9 +307,6 @@ proc getChatDetailsByIds*(self: Controller, chatIds: seq[string]): seq[ChatDto]
proc requestCommunityInfo*(self: Controller, communityId: string, importing: bool) = proc requestCommunityInfo*(self: Controller, communityId: string, importing: bool) =
self.communityService.requestCommunityInfo(communityId, importing) self.communityService.requestCommunityInfo(communityId, importing)
proc removePrivateKey*(self: Controller, communityId: string) =
self.communityService.removePrivateKey(communityId)
proc importCommunity*(self: Controller, communityKey: string) = proc importCommunity*(self: Controller, communityKey: string) =
self.communityService.asyncImportCommunity(communityKey) self.communityService.asyncImportCommunity(communityKey)

View File

@ -65,9 +65,6 @@ method cancelRequestToJoinCommunity*(self: AccessInterface, communityId: string)
method requestCommunityInfo*(self: AccessInterface, communityId: string, importing: bool) {.base.} = method requestCommunityInfo*(self: AccessInterface, communityId: string, importing: bool) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method removePrivateKey*(self: AccessInterface, communityId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method importCommunity*(self: AccessInterface, communityKey: string) {.base.} = method importCommunity*(self: AccessInterface, communityKey: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
@ -92,9 +89,6 @@ method communityCategoryEdited*(self: AccessInterface) {.base.} =
method communityCategoryDeleted*(self: AccessInterface) {.base.} = method communityCategoryDeleted*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method communityPrivateKeyRemoved*(self: AccessInterface, communityId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method communityEdited*(self: AccessInterface, community: CommunityDto) {.base.} = method communityEdited*(self: AccessInterface, community: CommunityDto) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -243,9 +243,6 @@ method navigateToCommunity*(self: Module, communityId: string) =
else: else:
self.delegate.setActiveSectionById(communityId) self.delegate.setActiveSectionById(communityId)
method communityPrivateKeyRemoved*(self: Module, communityId: string) =
self.view.communityPrivateKeyRemoved(communityId)
method communityEdited*(self: Module, community: CommunityDto) = method communityEdited*(self: Module, community: CommunityDto) =
self.view.model().editItem(self.getCommunityItem(community)) self.view.model().editItem(self.getCommunityItem(community))
self.view.communityChanged(community.id) self.view.communityChanged(community.id)
@ -341,9 +338,6 @@ method communityImported*(self: Module, community: CommunityDto) =
method communityDataImported*(self: Module, community: CommunityDto) = method communityDataImported*(self: Module, community: CommunityDto) =
self.view.addItem(self.getCommunityItem(community)) self.view.addItem(self.getCommunityItem(community))
method removePrivateKey*(self: Module, communityId: string) =
self.controller.removePrivateKey(communityId)
method importCommunity*(self: Module, communityId: string) = method importCommunity*(self: Module, communityId: string) =
self.view.emitImportingCommunityStateChangedSignal(communityId, ImportCommunityState.ImportingInProgress.int, errorMsg = "") self.view.emitImportingCommunityStateChangedSignal(communityId, ImportCommunityState.ImportingInProgress.int, errorMsg = "")
self.controller.importCommunity(communityId) self.controller.importCommunity(communityId)

View File

@ -118,7 +118,6 @@ QtObject:
proc communityAdded*(self: View, communityId: string) {.signal.} proc communityAdded*(self: View, communityId: string) {.signal.}
proc communityChanged*(self: View, communityId: string) {.signal.} proc communityChanged*(self: View, communityId: string) {.signal.}
proc communityPrivateKeyRemoved*(self: View, communityId: string) {.signal.}
proc discordOldestMessageTimestampChanged*(self: View) {.signal.} proc discordOldestMessageTimestampChanged*(self: View) {.signal.}
proc discordImportErrorsCountChanged*(self: View) {.signal.} proc discordImportErrorsCountChanged*(self: View) {.signal.}
proc communityAccessRequested*(self: View, communityId: string) {.signal.} proc communityAccessRequested*(self: View, communityId: string) {.signal.}
@ -540,9 +539,6 @@ QtObject:
proc isCommunityRequestPending*(self: View, communityId: string): bool {.slot.} = proc isCommunityRequestPending*(self: View, communityId: string): bool {.slot.} =
self.delegate.isCommunityRequestPending(communityId) self.delegate.isCommunityRequestPending(communityId)
proc removePrivateKey*(self: View, communityId: string) {.slot.} =
self.delegate.removePrivateKey(communityId)
proc importCommunity*(self: View, communityKey: string) {.slot.} = proc importCommunity*(self: View, communityKey: string) {.slot.} =
self.delegate.importCommunity(communityKey) self.delegate.importCommunity(communityKey)

View File

@ -253,10 +253,6 @@ proc init*(self: Controller) =
let args = CommunityMembersRevealedAccountsArgs(e) let args = CommunityMembersRevealedAccountsArgs(e)
self.delegate.communityMembersRevealedAccountsLoaded(args.communityId, args.membersRevealedAccounts) self.delegate.communityMembersRevealedAccountsLoaded(args.communityId, args.membersRevealedAccounts)
self.events.on(SIGNAL_COMMUNITY_PRIVATE_KEY_REMOVED) do(e:Args):
let args = CommunityArgs(e)
self.delegate.communityEdited(args.community)
self.events.on(SIGNAL_COMMUNITIES_UPDATE) do(e:Args): self.events.on(SIGNAL_COMMUNITIES_UPDATE) do(e:Args):
let args = CommunitiesArgs(e) let args = CommunitiesArgs(e)
for community in args.communities: for community in args.communities:

View File

@ -60,10 +60,6 @@ proc init*(self: Controller) =
let args = CommunityArgs(e) let args = CommunityArgs(e)
self.delegate.editCommunity(args.community) self.delegate.editCommunity(args.community)
self.events.on(SIGNAL_COMMUNITY_PRIVATE_KEY_REMOVED) do(e:Args):
let args = CommunityArgs(e)
self.delegate.editCommunity(args.community)
self.events.on(SIGNAL_COMMUNITIES_UPDATE) do(e:Args): self.events.on(SIGNAL_COMMUNITIES_UPDATE) do(e:Args):
let args = CommunitiesArgs(e) let args = CommunitiesArgs(e)
for community in args.communities: for community in args.communities:

View File

@ -207,8 +207,6 @@ const TOKEN_PERMISSIONS_MODIFIED = "tokenPermissionsModified"
const SIGNAL_CHECK_PERMISSIONS_TO_JOIN_RESPONSE* = "checkPermissionsToJoinResponse" const SIGNAL_CHECK_PERMISSIONS_TO_JOIN_RESPONSE* = "checkPermissionsToJoinResponse"
const SIGNAL_CHECK_PERMISSIONS_TO_JOIN_FAILED* = "checkPermissionsToJoinFailed" const SIGNAL_CHECK_PERMISSIONS_TO_JOIN_FAILED* = "checkPermissionsToJoinFailed"
const SIGNAL_COMMUNITY_PRIVATE_KEY_REMOVED* = "communityPrivateKeyRemoved"
const SIGNAL_COMMUNITY_METRICS_UPDATED* = "communityMetricsUpdated" const SIGNAL_COMMUNITY_METRICS_UPDATED* = "communityMetricsUpdated"
QtObject: QtObject:
@ -1669,20 +1667,6 @@ QtObject:
) )
self.threadpool.start(arg) self.threadpool.start(arg)
proc removePrivateKey*(self: Service, communityId: string) =
try:
let response = status_go.removePrivateKey(communityId)
if (response.error != nil):
let error = Json.decode($response.error, RpcError)
raise newException(RpcException, fmt"err: {error.message}")
var community = self.communities[communityId]
community.isControlNode = false
self.communities[communityId] = community
self.events.emit(SIGNAL_COMMUNITY_PRIVATE_KEY_REMOVED, CommunityArgs(community: community))
except Exception as e:
error "Error removing community private key: ", msg = e.msg
proc asyncImportCommunity*(self: Service, communityKey: string) = proc asyncImportCommunity*(self: Service, communityKey: string) =
let arg = AsyncImportCommunityTaskArg( let arg = AsyncImportCommunityTaskArg(
tptr: cast[ByteAddress](asyncImportCommunityTask), tptr: cast[ByteAddress](asyncImportCommunityTask),

View File

@ -387,9 +387,6 @@ proc collectCommunityMetrics*(communityId: string, metricsType: int, intervals:
proc requestCommunityInfo*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc requestCommunityInfo*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("requestCommunityInfoFromMailserver".prefix, %*[communityId]) result = callPrivateRPC("requestCommunityInfoFromMailserver".prefix, %*[communityId])
proc removePrivateKey*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("removePrivateKey".prefix, %*[communityId])
proc importCommunity*(communityKey: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc importCommunity*(communityKey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("importCommunity".prefix, %*[communityKey]) result = callPrivateRPC("importCommunity".prefix, %*[communityKey])

View File

@ -92,7 +92,9 @@
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?node-id=3132%3A383870&mode=dev" "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?node-id=3132%3A383870&mode=dev"
], ],
"ExportControlNodePopup": [ "ExportControlNodePopup": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31171-627949&mode=design&t=WxK2N6sL8idHBKMZ-0" "https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=36894-685070&mode=design&t=6k1ago8SSQ5Ip9J8-0",
"https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=37275-289960&mode=design&t=6k1ago8SSQ5Ip9J8-0",
"https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=37275-290036&mode=design&t=6k1ago8SSQ5Ip9J8-0"
], ],
"HoldingsDropdown": [ "HoldingsDropdown": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22721%3A499660&t=F5yiYQV2YGPBdrJ8-0", "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22721%3A499660&t=F5yiYQV2YGPBdrJ8-0",
@ -103,7 +105,7 @@
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22734%3A502737&t=7gqqAFbdG5KrPOmn-0" "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22734%3A502737&t=7gqqAFbdG5KrPOmn-0"
], ],
"ImportControlNodePopup": [ "ImportControlNodePopup": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31171-628434&mode=design&t=IFFCNUpRS3oQbzAR-0" "https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=36894-685104&mode=design&t=6k1ago8SSQ5Ip9J8-0"
], ],
"InDropdown": [ "InDropdown": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=2934%3A482182", "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=2934%3A482182",
@ -163,7 +165,8 @@
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31281-635619&mode=design&t=RYpVRgwqCjp8fUEX-0" "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31281-635619&mode=design&t=RYpVRgwqCjp8fUEX-0"
], ],
"OverviewSettingsFooter": [ "OverviewSettingsFooter": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31171-629792&mode=design&t=IAlt2Frp5gx0yPAn-0" "https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=36894-684461&mode=design&t=6k1ago8SSQ5Ip9J8-0",
"https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=36894-684611&mode=design&t=6k1ago8SSQ5Ip9J8-0"
], ],
"OverviewSettingsPanel": [ "OverviewSettingsPanel": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31229-627216&mode=design&t=KoQOW7vmoNc7f41m-0" "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31229-627216&mode=design&t=KoQOW7vmoNc7f41m-0"

View File

@ -45,6 +45,7 @@ SplitView {
Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.".arg(dialog.name) Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.".arg(dialog.name)
loginType: ctrlLoginType.currentIndex loginType: ctrlLoginType.currentIndex
requirementsCheckPending: false
walletAccountsModel: WalletAccountsModel {} walletAccountsModel: WalletAccountsModel {}
permissionsModel: dialog.accessType === Constants.communityChatOnRequestAccess ? PermissionsModel.complexPermissionsModel permissionsModel: dialog.accessType === Constants.communityChatOnRequestAccess ? PermissionsModel.complexPermissionsModel

View File

@ -3,6 +3,8 @@ import QtQuick.Controls 2.15
import AppLayouts.Communities.popups 1.0 import AppLayouts.Communities.popups 1.0
import utils 1.0
import Storybook 1.0 import Storybook 1.0
SplitView { SplitView {
@ -11,22 +13,66 @@ SplitView {
Logs { id: logs } Logs { id: logs }
Item { function openDialog() {
popupComponent.createObject(popupBg)
}
Component.onCompleted: openDialog()
Item {
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.fillHeight: true SplitView.fillHeight: true
PopupBackground { PopupBackground {
id: popupBg
anchors.fill: parent anchors.fill: parent
}
Button { Button {
anchors.centerIn: parent anchors.centerIn: parent
text: "Reopen" text: "Reopen"
onClicked: popupComponent.createObject(parent) onClicked: openDialog()
}
}
}
ListModel {
id: fakeDevicesModel
ListElement {
name: "Device 1 (osx)"
deviceType: "osx"
timestamp: 123456789
isCurrentDevice: true
enabled: true
}
ListElement {
name: "Device 2 (windows)"
deviceType: "windows"
timestamp: 123456789123
isCurrentDevice: false
enabled: false
}
ListElement {
name: "Device 3 (android)"
deviceType: "android"
timestamp: 0
isCurrentDevice: false
enabled: true
}
ListElement {
name: "Device 4 (ios)"
deviceType: "ios"
timestamp: 0
isCurrentDevice: false
enabled: true
}
ListElement {
name: "Device 5 (desktop)"
deviceType: "desktop"
timestamp: 0
isCurrentDevice: false
enabled: true
} }
Component.onCompleted: popupComponent.createObject(parent)
} }
Component { Component {
@ -36,9 +82,27 @@ SplitView {
anchors.centerIn: parent anchors.centerIn: parent
modal: false modal: false
visible: true visible: true
communityName: "Socks" closePolicy: Popup.NoAutoClose
privateKey: "0x0454f2231543ba02583e4c55e513a75092a4f2c86c04d0796b195e964656d6cd94b8237c64ef668eb0fe268387adc3fe699bce97190a631563c82b718c19cf1fb8" destroyOnClose: true
onDeletePrivateKey: logs.logEvent("ExportControlNodePopup::onDeletePrivateKey") community: QtObject {
property string id: "1"
property string name: "Socks"
property var members: { "count": 5 }
property string image: Style.png("tokens/UNI")
property string color: "orchid"
}
devicesStore: QtObject {
function loadDevices() {}
property bool isDeviceSetup: true
property var devicesModule: QtObject {
property bool devicesLoading
property bool devicesLoadingError
}
property var devicesModel: ctrlHasSyncedDevices.checked ? fakeDevicesModel : null
}
} }
} }
@ -49,6 +113,11 @@ SplitView {
SplitView.preferredHeight: 160 SplitView.preferredHeight: 160
logsView.logText: logs.logText logsView.logText: logs.logText
Switch {
id: ctrlHasSyncedDevices
text: "Has synced devices"
}
} }
} }

View File

@ -15,149 +15,25 @@ SplitView {
Logs { id: logs } Logs { id: logs }
SplitView { function openDialog() {
SplitView.fillWidth: true popupComponent.createObject(popupBg)
SplitView.fillHeight: true }
Pane {
id: mainPane Component.onCompleted: openDialog()
Item {
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.fillHeight: true SplitView.fillHeight: true
PopupBackground { PopupBackground {
id: popupBg
anchors.fill: parent anchors.fill: parent
}
Button { Button {
anchors.centerIn: parent anchors.centerIn: parent
text: "Reopen" text: "Reopen"
onClicked: popupComponent.createObject(mainPane) onClicked: openDialog()
}
Component.onCompleted: popupComponent.createObject(mainPane)
}
Pane {
SplitView.preferredWidth: 300
contentItem: ColumnLayout {
Label {
text: "Matching private key"
}
TextEdit {
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: "red"
border.width: 1
}
id: matchingPrivateKey
Layout.fillWidth: true
wrapMode: TextEdit.Wrap
readOnly: true
text: "0x0454f2231543ba02583e4c55e513a75092a4f2c86c04d0796b195e964656d6cd"
}
Button {
text: "Copy"
onClicked: {
matchingPrivateKey.selectAll()
matchingPrivateKey.copy()
matchingPrivateKey.deselect()
}
}
Label {
text: "Mismatching private key"
}
TextEdit {
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: "red"
border.width: 1
}
id: mismatchingPrivateKey
Layout.fillWidth: true
wrapMode: TextEdit.Wrap
readOnly: true
text: "0x0454f2231543ba02583e4c55e513a75092a4f2c86c04d0796b195e964656d6ce"
}
Button {
text: "Copy"
onClicked: {
mismatchingPrivateKey.selectAll()
mismatchingPrivateKey.copy()
mismatchingPrivateKey.deselect()
}
}
Label {
text: "Load in progress private key"
}
TextEdit {
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: "red"
border.width: 1
}
id: loadInProgressPrivateKey
Layout.fillWidth: true
wrapMode: TextEdit.Wrap
readOnly: true
text: "0x0454f2231543ba02583e4c55e513a75092a4f2c86c04d0796b195e964656d6ca"
}
Button {
text: "Copy"
onClicked: {
loadInProgressPrivateKey.selectAll()
loadInProgressPrivateKey.copy()
loadInProgressPrivateKey.deselect()
}
}
Item {
Layout.fillHeight: true
}
}
}
}
QtObject {
id: d
readonly property var community: QtObject {
property string id: "1"
property string name: "Socks"
property var members: { "count": 5 }
property string image: Style.png("tokens/UNI")
property string color: "orchid"
}
readonly property var otherCommunity: QtObject {
property string id: "2"
property string name: "Socks"
property var members: { "count": 5 }
property string image: Style.png("tokens/UNI")
property string color: "orchid"
}
readonly property Timer timer: Timer {
//id: _timer
interval: 1000
repeat: false
function callWithDelay(cb) {
d.timer.triggered.connect(cb);
d.timer.triggered.connect(function release () {
d.timer.triggered.disconnect(cb);
d.timer.triggered.disconnect(release);
});
d.timer.start();
} }
} }
} }
@ -169,16 +45,13 @@ SplitView {
anchors.centerIn: parent anchors.centerIn: parent
modal: false modal: false
visible: true visible: true
community: QtObject {
onRequestCommunityInfo: { property string id: "1"
logs.logEvent("ImportControlNodePopup::onRequestCommunityInfo", ["private key"], [privateKey]) property string name: "Socks"
if(privateKey === matchingPrivateKey.text) property var members: { "count": 5 }
d.timer.callWithDelay(() => popup.setCommunityInfo(d.community)) property string image: Style.png("tokens/UNI")
else if (privateKey === mismatchingPrivateKey.text) property string color: "orchid"
d.timer.callWithDelay(() => popup.setCommunityInfo(d.otherCommunity))
} }
community: d.community
} }
} }

View File

@ -32,27 +32,6 @@ SplitView {
text: "Control node on/off" text: "Control node on/off"
checked: true checked: true
} }
ColumnLayout {
Label {
Layout.fillWidth: true
text: "Login type::"
}
RadioButton {
checked: true
text: qsTr("Password")
onCheckedChanged: if(checked) footer.loginType = Constants.LoginType.Password
}
RadioButton {
text: qsTr("Biometrics")
onCheckedChanged: if(checked) footer.loginType = Constants.LoginType.Biometrics
}
RadioButton {
text: qsTr("Keycard")
onCheckedChanged: if(checked) footer.loginType = Constants.LoginType.Keycard
}
}
} }
} }
} }

View File

@ -2,4 +2,5 @@ import QtQuick 2.15
QtObject { QtObject {
property var chatCommunitySectionModule property var chatCommunitySectionModule
property var contactsStore
} }

View File

@ -54,7 +54,7 @@ StatusBaseText {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: root.leftPadding anchors.leftMargin: root.leftPadding
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
active: root.loading active: root.loading && root.text
sourceComponent: LoadingComponent { sourceComponent: LoadingComponent {
anchors.centerIn: parent anchors.centerIn: parent
radius: textMetrics.font.pixelSize === 15 ? 4 : 8 radius: textMetrics.font.pixelSize === 15 ? 4 : 8

View File

@ -21,7 +21,7 @@ import StatusQ.Controls 0.1
model: someModel model: someModel
// For a vertical list bind the imlicitHeight to contentHeight // For a vertical list bind the implicitHeight to contentHeight
implicitHeight: contentHeight implicitHeight: contentHeight
delegate: DelegateItem { delegate: DelegateItem {

View File

@ -627,10 +627,6 @@ QtObject {
communitiesModuleInst.authenticateWithCallback() communitiesModuleInst.authenticateWithCallback()
} }
function removePrivateKey(communityId) {
root.communitiesModuleInst.removePrivateKey(communityId)
}
readonly property Connections communitiesModuleConnections: Connections { readonly property Connections communitiesModuleConnections: Connections {
target: communitiesModuleInst target: communitiesModuleInst
function onImportingCommunityStateChanged(communityId, state, errorMsg) { function onImportingCommunityStateChanged(communityId, state, errorMsg) {

View File

@ -13,7 +13,6 @@ import utils 1.0
Control { Control {
id: root id: root
property bool isControlNode: true property bool isControlNode: true
property int loginType: Constants.LoginType.Password
property string communityName: "" property string communityName: ""
signal exportControlNodeClicked signal exportControlNodeClicked
@ -29,9 +28,7 @@ Control {
property string paragraphTitle property string paragraphTitle
property string paragraphSubtitle property string paragraphSubtitle
property string primaryButtonText property string primaryButtonText
property string primaryButtonIcon
property string secondaryButtonText property string secondaryButtonText
property string secondaryButtonIcon
property string indicatorBgColor property string indicatorBgColor
property string indicatorColor property string indicatorColor
property var primaryButtonAction: root.exportControlNodeClicked property var primaryButtonAction: root.exportControlNodeClicked
@ -91,15 +88,14 @@ Control {
StatusFlatButton { StatusFlatButton {
size: StatusBaseButton.Size.Small size: StatusBaseButton.Size.Small
text: d.secondaryButtonText text: qsTr("Learn more")
icon.name: d.secondaryButtonIcon icon.name: "external-link"
onClicked: root.learnMoreClicked() onClicked: root.learnMoreClicked()
} }
StatusButton { StatusButton {
size: StatusBaseButton.Size.Small size: StatusBaseButton.Size.Small
text: d.primaryButtonText text: d.primaryButtonText
icon.name: d.primaryButtonIcon
onClicked: d.primaryButtonAction() onClicked: d.primaryButtonAction()
} }
} }
@ -114,10 +110,7 @@ Control {
PropertyChanges { target: d; indicatorColor: Theme.palette.successColor1 } PropertyChanges { target: d; indicatorColor: Theme.palette.successColor1 }
PropertyChanges { target: d; paragraphTitle: qsTr("This device is currently the control node for the %1 Community").arg(root.communityName) } PropertyChanges { target: d; paragraphTitle: qsTr("This device is currently the control node for the %1 Community").arg(root.communityName) }
PropertyChanges { target: d; paragraphSubtitle: qsTr("For your Community to function correctly keep this device online with Status running as much as possible.") } PropertyChanges { target: d; paragraphSubtitle: qsTr("For your Community to function correctly keep this device online with Status running as much as possible.") }
PropertyChanges { target: d; primaryButtonText: qsTr("Move control node") } PropertyChanges { target: d; primaryButtonText: qsTr("How to move control node") }
PropertyChanges { target: d; primaryButtonIcon: Constants.authenticationIconByType[root.loginType] }
PropertyChanges { target: d; secondaryButtonText: qsTr("Learn more") }
PropertyChanges { target: d; secondaryButtonIcon: "external-link" }
PropertyChanges { target: d; primaryButtonAction: root.exportControlNodeClicked } PropertyChanges { target: d; primaryButtonAction: root.exportControlNodeClicked }
}, },
State { State {
@ -126,11 +119,8 @@ Control {
PropertyChanges { target: d; indicatorBgColor: Theme.palette.primaryColor3 } PropertyChanges { target: d; indicatorBgColor: Theme.palette.primaryColor3 }
PropertyChanges { target: d; indicatorColor: Theme.palette.primaryColor1 } PropertyChanges { target: d; indicatorColor: Theme.palette.primaryColor1 }
PropertyChanges { target: d; paragraphTitle: qsTr("Make this device the control node for the %1 Community").arg(root.communityName) } PropertyChanges { target: d; paragraphTitle: qsTr("Make this device the control node for the %1 Community").arg(root.communityName) }
PropertyChanges { target: d; paragraphSubtitle: qsTr("You will need to input the Community private key. Ensure this is a device you can keep online with Status running.") } PropertyChanges { target: d; paragraphSubtitle: qsTr("Ensure this is a device you can keep online with Status running.") }
PropertyChanges { target: d; primaryButtonText: qsTr("Make this device the control node") } PropertyChanges { target: d; primaryButtonText: qsTr("Make this device the control node") }
PropertyChanges { target: d; primaryButtonIcon: "" }
PropertyChanges { target: d; secondaryButtonText: qsTr("Learn more") }
PropertyChanges { target: d; secondaryButtonIcon: "external-link" }
PropertyChanges { target: d; primaryButtonAction: root.importControlNodeClicked } PropertyChanges { target: d; primaryButtonAction: root.importControlNodeClicked }
} }
] ]

View File

@ -148,7 +148,6 @@ StackLayout {
leftPadding: 64 leftPadding: 64
bottomPadding: 64 bottomPadding: 64
topPadding: 0 topPadding: 0
loginType: root.loginType
communityName: root.name communityName: root.name
isControlNode: root.isControlNode isControlNode: root.isControlNode
onExportControlNodeClicked: root.exportControlNodeClicked() onExportControlNodeClicked: root.exportControlNodeClicked()

View File

@ -4,24 +4,276 @@ import QtQuick.Layouts 1.15
import QtQml.Models 2.14 import QtQml.Models 2.14
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import utils 1.0 import utils 1.0
import SortFilterProxyModel 0.2
StatusDialog { StatusDialog {
id: root id: root
property string communityName: "" required property var community
property string privateKey: "" property var devicesStore
signal deletePrivateKey
width: 640 width: 640
title: qsTr("Move %1 community control node").arg(root.communityName)
closePolicy: Popup.NoAutoClose onAboutToShow: {
devicesStore.loadDevices()
}
QtObject {
id: d
readonly property var devices: SortFilterProxyModel {
sourceModel: root.devicesStore.devicesModel
sorters: [
RoleSorter {
roleName: "isCurrentDevice"
sortOrder: Qt.DescendingOrder
priority: 2
},
RoleSorter {
roleName: "isMobile"
priority: 1 // Higher number === higher priority
}
]
proxyRoles: ExpressionRole {
name: "isMobile"
expression: model.deviceType === "ios" || model.deviceType === "android"
}
}
readonly property var syncedDesktopDevices: SortFilterProxyModel {
sourceModel: root.devicesStore.devicesModel
filters: ExpressionFilter {
expression: !model.isCurrentDevice && model.enabled && (model.deviceType !== "ios" && model.deviceType !== "android")
}
}
readonly property bool hasSyncedDesktopDevices: syncedDesktopDevices.count
}
header: StatusDialogHeader {
headline.title: qsTr("How to move the %1 control node to another device").arg(root.community.name)
actions.closeButton.onClicked: root.close()
leftComponent: StatusSmartIdenticon {
asset.name: root.community.image
asset.isImage: !!asset.name
}
}
contentItem: ColumnLayout {
spacing: 20
Paragraph {
text: d.hasSyncedDesktopDevices ? qsTr("Any of your synced <b>desktop</b> devices can be the control node for this Community:")
: qsTr("You dont currently have any <b>synced desktop devices</b>. You will need to sync another desktop device before you can move the %1 control node to it. Does the device you want to use as the control node currently have Status installed?").arg(root.community.name)
}
Loader {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: Style.current.bigPadding
Layout.rightMargin: Style.current.bigPadding
sourceComponent: d.hasSyncedDesktopDevices ? devicesInstructions : noDevicesInstructions
}
}
footer: StatusDialogFooter {
rightButtons: ObjectModel {
StatusButton {
text: qsTr("Close")
onClicked: root.close()
}
}
}
Component {
id: devicesInstructions
ColumnLayout {
spacing: Style.current.padding
Rectangle {
Layout.fillWidth: true
Layout.leftMargin: -40
Layout.rightMargin: -40
Layout.preferredHeight: devicesView.implicitHeight
Layout.fillHeight: true
color: Theme.palette.baseColor2
Rectangle {
anchors.fill: parent
anchors.leftMargin: -parent.Layout.leftMargin
anchors.rightMargin: -parent.Layout.rightMargin
anchors.topMargin: 28
anchors.bottomMargin: 28
color: Theme.palette.indirectColor4
radius: Style.current.radius
clip: true
StatusListView {
id: devicesView
width: parent.width
implicitHeight: contentHeight
height: parent.height
spacing: 0
visible: !root.devicesStore.devicesModule.devicesLoading &&
!root.devicesStore.devicesModule.devicesLoadingError &&
root.devicesStore.isDeviceSetup
model: d.devices
delegate: ItemDelegate {
id: deviceDelegate
width: ListView.view.width
implicitHeight: 64
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
horizontalPadding: Style.current.padding
verticalPadding: 12
text: model.name
enabled: model.enabled && !model.isMobile
background: null
contentItem: RowLayout {
spacing: Style.current.padding
StatusRoundIcon {
Layout.alignment: Qt.AlignLeading
asset.name: SQUtils.Utils.deviceIcon(model.deviceType)
asset.color: model.isCurrentDevice ? Theme.palette.successColor1 : enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
asset.bgColor: model.isCurrentDevice ? Theme.palette.successColor3 : enabled ? Theme.palette.primaryColor3 : Theme.palette.baseColor2
}
StatusBaseText {
Layout.fillWidth: true
color: enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
text: deviceDelegate.text
}
StatusBaseText {
Layout.alignment: Qt.AlignTrailing
visible: model.isCurrentDevice
color: Theme.palette.successColor1
text: qsTr("Control node (this device)")
}
StatusBaseText {
Layout.alignment: Qt.AlignTrailing
visible: model.isMobile
color: Theme.palette.baseColor1
text: qsTr("Not eligible (desktop only)")
}
}
}
}
}
}
Instruction {
text: qsTr("1. On the device you want to make the control node <font color='%1'>login using this profile</font>").arg(Theme.palette.directColor1)
}
Row {
Layout.fillWidth: true
spacing: 4
Instruction {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("2. Go to")
}
StatusRoundIcon {
anchors.verticalCenter: parent.verticalCenter
asset.name: "show"
}
Paragraph {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("%1 Admin Overview").arg(root.community.name)
}
}
Instruction {
text: qsTr("3. Click <font color='%1'>Make this device the control node</font>").arg(Theme.palette.directColor1)
}
}
}
Component {
id: noDevicesInstructions
ColumnLayout {
spacing: Style.current.padding
StatusSwitchTabBar {
id: switchBar
Layout.fillWidth: true
StatusSwitchTabButton {
text: qsTr("Status installed on other device")
}
StatusSwitchTabButton {
text: qsTr("Status not installed on other device")
}
}
StackLayout {
Layout.fillWidth: true
Layout.fillHeight: true
currentIndex: switchBar.currentIndex
ColumnLayout {
Instruction {
text: qsTr("On this device...")
}
Row {
Layout.fillWidth: true
spacing: 4
Instruction {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("1. Go to")
}
StatusRoundIcon {
anchors.verticalCenter: parent.verticalCenter
asset.name: "settings"
}
Paragraph {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Settings")
}
}
Row {
Layout.fillWidth: true
spacing: 4
Instruction {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("2. Go to")
}
StatusRoundIcon {
anchors.verticalCenter: parent.verticalCenter
asset.name: "rotate"
}
Paragraph {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Syncing")
}
}
Instruction {
text: qsTr("3. Click <font color='%1'>Setup Syncing</font> and sync your other devices").arg(Theme.palette.directColor1)
}
Instruction {
text: qsTr("4. Click <font color='%1'>How to move control node</font> again for next instructions").arg(Theme.palette.directColor1)
}
}
ColumnLayout {
Instruction {
text: qsTr("1. Install and launch Status on the device you want to use as the control node")
}
Instruction {
text: qsTr("2. On that device, click <font color='%1'>I already use Status</font>").arg(Theme.palette.directColor1)
}
Instruction {
text: qsTr("3. Click <font color='%1'>Scan or enter sync code</font> and sync your new device").arg(Theme.palette.directColor1)
}
Instruction {
text: qsTr("4. Click <font color='%1'>How to move control node</font> again for next instructions").arg(Theme.palette.directColor1)
}
}
}
}
}
component Paragraph: StatusBaseText { component Paragraph: StatusBaseText {
Layout.fillWidth: true Layout.fillWidth: true
@ -33,118 +285,7 @@ StatusDialog {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
component CopyButton: StatusButton { component Instruction: Paragraph {
id: copyButton color: Theme.palette.baseColor1
borderColor: textColor
disabledTextColor: textColor
disabledColor: normalColor
text: qsTr("Copy")
size: StatusButton.Size.Tiny
states: [
State {
name: "success"
PropertyChanges {
target: copyButton
text: ""
icon.name: "checkmark"
normalColor: Theme.palette.successColor2
textColor: Theme.palette.successColor1
enabled: false
}
}
]
onClicked: {
width = width // break the biding to prevent the button from shrinking
copyButton.state = "success"
Backpressure.debounce(root, 2000, function () {
copyButton.state = ""
})()
}
}
StatusScrollView {
id: scroll
anchors.fill: parent
contentWidth: availableWidth
ColumnLayout {
id: layout
width: scroll.availableWidth
spacing: 20
Paragraph {
text: qsTr("For a Status Community to function, it needs to have a single control node running. This installation of Status Desktop is currently the %1 community control node. To move the %1 control node to another device: ").arg(root.communityName)
}
ColumnLayout {
Layout.fillWidth: true
spacing: 4
Paragraph {
text: qsTr("1. Copy your Communitys private key:")
}
StatusBaseInput {
id: privateKeyTextArea
Layout.fillWidth: true
multiline: true
edit.readOnly: true
text: root.privateKey
rightComponent: CopyButton {
onClicked: {
privateKeyTextArea.edit.selectAll()
privateKeyTextArea.edit.copy()
privateKeyTextArea.edit.deselect()
}
}
}
Paragraph {
text: qsTr("2. Stop using this computer as a control node")
}
Paragraph {
text: qsTr("3. Import this Community via private key on another installation of Status desktop")
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
StatusDialogDivider { Layout.fillWidth: true }
Item { Layout.fillHeight: true }
Paragraph {
text: qsTr("I acknowledge that...")
}
StatusCheckBox {
id: agreeToStopControl
Layout.fillWidth: true
font.pixelSize: Style.current.primaryTextFontSize
text: qsTr("%1 will stop working without a control node").arg(root.communityName)
}
StatusCheckBox {
id: agreeToSavePrivateKey
Layout.fillWidth: true
Layout.minimumHeight: 40
font.pixelSize: Style.current.primaryTextFontSize
text: qsTr("I have saved the %1 private key").arg(root.communityName)
}
StatusCheckBox {
id: agreeToDeletePrivateKey
Layout.fillWidth: true
Layout.minimumHeight: 40
font.pixelSize: Style.current.primaryTextFontSize
text: qsTr("If I lose the private key, %1 will be unrecoverable").arg(root.communityName)
}
}
}
}
footer: StatusDialogFooter {
rightButtons: ObjectModel {
StatusButton {
text: qsTr("Delete private key and stop control node")
enabled: agreeToStopControl.checked && agreeToSavePrivateKey.checked && agreeToDeletePrivateKey.checked
type: StatusBaseButton.Type.Danger
onClicked: {
root.deletePrivateKey()
root.close()
}
}
}
} }
} }

View File

@ -5,6 +5,7 @@ import QtQml 2.15
import QtQml.Models 2.14 import QtQml.Models 2.14
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
@ -16,25 +17,23 @@ StatusDialog {
required property var community required property var community
signal importControlNode(string privateKey) signal importControlNode(var community)
signal requestCommunityInfo(string privateKey)
function setCommunityInfo(communityInfo) {
d.requestedCommunityInfo = communityInfo
d.privateKeyCheckInProgress = false
}
onRequestCommunityInfo: d.privateKeyCheckInProgress = true
width: 640 width: 640
height: Math.max(552, implicitHeight)
title: qsTr("Make this device the control node for %1").arg(root.community.name) header: StatusDialogHeader {
headline.title: qsTr("Make this device the control node for %1").arg(root.community.name)
actions.closeButton.onClicked: root.close()
leftComponent: StatusSmartIdenticon {
asset.name: root.community.image
asset.isImage: !!asset.name
}
}
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
component Paragraph: StatusBaseText { component Paragraph: StatusBaseText {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 40
font.pixelSize: Style.current.primaryTextFontSize font.pixelSize: Style.current.primaryTextFontSize
lineHeightMode: Text.FixedHeight lineHeightMode: Text.FixedHeight
lineHeight: 22 lineHeight: 22
@ -42,163 +41,42 @@ StatusDialog {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
component PasteButton: StatusButton { contentItem: ColumnLayout {
id: pasteButton spacing: Style.current.padding
borderColor: textColor
text: qsTr("Paste")
size: StatusButton.Size.Tiny
}
component ChatDetails: Control {
verticalPadding: 6
horizontalPadding: 4
contentItem: RowLayout {
StatusChatInfoButton {
id: communityInfoButton
Layout.alignment: Qt.AlignVCenter
title: community.name
subTitle: qsTr("%n member(s)", "", community.members.count || 0)
asset.name: community.image
asset.color: community.color
asset.isImage: true
type: StatusChatInfoButton.Type.OneToOneChat
hoverEnabled: false
visible: false
}
Item { Layout.fillWidth: true }
StatusBaseText {
id: detectionLabel
Layout.alignment: Qt.AlignVCenter
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
font.pixelSize: Style.current.additionalTextSize
visible: !!text
}
}
states: [
State {
name: "matchingPrivateKey"
when: d.isPrivateKeyMatching
PropertyChanges { target: detectionLabel; text: qsTr("Private key is valid") }
PropertyChanges { target: detectionLabel; color: Theme.palette.successColor1 }
PropertyChanges { target: communityInfoButton; visible: true }
},
State {
name: "mismatchingPrivateKey"
when: !d.isPrivateKeyMatching && d.isPrivateKey && !d.privateKeyCheckInProgress
PropertyChanges { target: detectionLabel; text: qsTr("This is not the correct private key for %1").arg(root.community.name) }
PropertyChanges { target: detectionLabel; color: Theme.palette.dangerColor1 }
},
State {
name: "checking"
when: d.privateKeyCheckInProgress
PropertyChanges { target: detectionLabel; text: qsTr("Checking private key...") }
PropertyChanges { target: detectionLabel; color: Theme.palette.baseColor1 }
},
State {
name: "invalidPrivateKey"
when: !d.isPrivateKey && d.isPrivateKeyInserted
PropertyChanges { target: detectionLabel; text: qsTr("This is not a private key") }
PropertyChanges { target: detectionLabel; color: Theme.palette.dangerColor1 }
}
]
}
QtObject {
id: d
readonly property bool isPrivateKey: Utils.isPrivateKey(privateKeyTextArea.text)
readonly property bool isPrivateKeyMatching: d.requestedCommunityInfo ? d.requestedCommunityInfo.id === community.id : false
readonly property bool isPrivateKeyInserted: privateKeyTextArea.text.length > 0
property bool privateKeyCheckInProgress: false
property var requestedCommunityInfo: undefined
onIsPrivateKeyChanged: {
if(!isPrivateKey) {
requestedCommunityInfo = undefined
privateKeyCheckInProgress = false
return
}
privateKeyCheckInProgress = true
requestedCommunityInfo = undefined
requestCommunityInfo(privateKeyTextArea.text)
}
}
ColumnLayout {
id: mainLayout
anchors.fill: parent
spacing: 0
Paragraph { Paragraph {
Layout.preferredHeight: 22 text: qsTr("Are you sure you want to make this device the control node for %1? This device should be one that you are able to keep online and running Status at all times to enable the Community to function correctly.").arg(root.community.name)
Layout.bottomMargin: Style.current.halfPadding
text: qsTr("To move the %1 control node to this device: ").arg(root.community.name)
} }
Paragraph {
text: qsTr("1. Stop using any other devices as the control node for this Community")
}
Paragraph {
text: qsTr("2. Paste the Communitys private key below:")
}
StatusBaseInput {
id: privateKeyTextArea
Layout.fillWidth: true
Layout.preferredHeight: 86
rightPadding: Style.current.padding
multiline: true
valid: d.isPrivateKey || !d.isPrivateKeyInserted
placeholderText: qsTr("e.g. %1").arg("0x0454f2231543ba02583e4c55e513a75092a4f2c86c04d0796b195e964656d6cd94b8237c64ef668eb0fe268387adc3fe699bce97190a631563c82b718c19cf1fb8")
rightComponent: PasteButton {
onClicked: {
privateKeyTextArea.edit.clear()
privateKeyTextArea.edit.paste()
}
}
}
ChatDetails {
Layout.topMargin: Style.current.halfPadding
Layout.fillWidth: true
Layout.minimumHeight: 46
}
Item {
Layout.fillHeight: true
Layout.minimumHeight: Style.current.xlPadding
}
ColumnLayout {
id: agreementLayout
Layout.fillWidth: true
Layout.fillHeight: true
spacing: mainLayout.spacing
visible: d.isPrivateKeyMatching
StatusDialogDivider { StatusDialogDivider {
Layout.fillWidth: true Layout.fillWidth: true
} }
Paragraph { Paragraph {
Layout.topMargin: Style.current.padding
text: qsTr("I acknowledge that...") text: qsTr("I acknowledge that...")
} }
StatusCheckBox { StatusCheckBox {
id: agreementCheckBox id: agreementCheckBox
Layout.fillWidth: true Layout.fillWidth: true
font.pixelSize: Style.current.primaryTextFontSize font.pixelSize: Style.current.primaryTextFontSize
text: qsTr("I must keep this device online and running Status for the Community to function") text: qsTr("I must keep this device online and running Status")
} }
StatusCheckBox {
id: agreementCheckBox2
Layout.fillWidth: true
font.pixelSize: Style.current.primaryTextFontSize
text: qsTr("My other synced device will cease to be the control node for this Community")
} }
} }
footer: StatusDialogFooter { footer: StatusDialogFooter {
rightButtons: ObjectModel { rightButtons: ObjectModel {
StatusFlatButton {
text: qsTr("Cancel")
onClicked: root.close()
}
StatusButton { StatusButton {
text: qsTr("Make this device the control node for %1").arg(root.community.name) text: qsTr("Make this device the control node for %1").arg(root.community.name)
enabled: d.isPrivateKeyMatching && agreementCheckBox.checked enabled: agreementCheckBox.checked && agreementCheckBox2.checked
onClicked: { onClicked: {
root.importControlNode(privateKeyTextArea.text) root.importControlNode(root.community)
root.close() root.close()
} }
} }

View File

@ -60,8 +60,6 @@ QtObject {
signal importingCommunityStateChanged(string communityId, int state, string errorMsg) signal importingCommunityStateChanged(string communityId, int state, string errorMsg)
signal communityPrivateKeyRemoved(string communityId)
signal communityInfoAlreadyRequested() signal communityInfoAlreadyRequested()
function createCommunity(args = { function createCommunity(args = {
@ -253,9 +251,5 @@ QtObject {
function onCommunityInfoAlreadyRequested() { function onCommunityInfoAlreadyRequested() {
root.communityInfoAlreadyRequested() root.communityInfoAlreadyRequested()
} }
function onCommunityPrivateKeyRemoved(communityId) {
root.communityPrivateKeyRemoved(communityId)
}
} }
} }

View File

@ -218,23 +218,14 @@ StatusSectionLayout {
if(!root.isControlNode) if(!root.isControlNode)
return return
root.rootStore.authenticateWithCallback((authenticated) => { Global.openExportControlNodePopup(root.community)
if(!authenticated)
return
Global.openExportControlNodePopup(root.community.name, root.chatCommunitySectionModule.exportCommunity(root.community.id), (popup) => {
popup.onDeletePrivateKey.connect(() => {
root.rootStore.removePrivateKey(root.community.id)
})
})
})
} }
onImportControlNodeClicked: { onImportControlNodeClicked: {
if(root.isControlNode) if(root.isControlNode)
return return
Global.openImportControlNodePopup(root.community, d.importControlNodePopupOpened) Global.openImportControlNodePopup(root.community)
} }
} }
@ -532,44 +523,6 @@ StatusSectionLayout {
} }
} }
} }
function requestCommunityInfoWithCallback(privateKey, callback) {
if(!callback) return
//success
root.rootStore.communityAdded.connect(function communityAddedHandler(communityId) {
root.rootStore.communityAdded.disconnect(communityAddedHandler)
let community = null
try {
const communityJson = root.rootStore.getSectionByIdJson(communityId)
community = JSON.parse(communityJson)
} catch (e) {
console.warn("Error parsing community json: ", communityJson, " error: ", e.message)
}
callback(community)
})
//error
root.rootStore.importingCommunityStateChanged.connect(function communityImportingStateChangedHandler(communityId, status) {
root.rootStore.importingCommunityStateChanged.disconnect(communityImportingStateChangedHandler)
if(status === Constants.communityImportingError) {
callback(null)
}
})
root.rootStore.requestCommunityInfo(privateKey, false)
}
function importControlNodePopupOpened(popup) {
popup.requestCommunityInfo.connect((privateKey) => {
requestCommunityInfoWithCallback(privateKey, popup.setCommunityInfo)
})
popup.importControlNode.connect((privateKey) => {
root.rootStore.importCommunity(privateKey)
})
}
} }
StatusQUtils.ModelChangeTracker { StatusQUtils.ModelChangeTracker {

View File

@ -205,6 +205,7 @@ Item {
popupParent: appMain popupParent: appMain
rootStore: appMain.rootStore rootStore: appMain.rootStore
communitiesStore: appMain.communitiesStore communitiesStore: appMain.communitiesStore
devicesStore: appMain.rootStore.profileSectionStore.devicesStore
isDevBuild: !production isDevBuild: !production
} }
@ -342,16 +343,6 @@ Item {
Constants.ephemeralNotificationType.normal, Constants.ephemeralNotificationType.normal,
"") "")
} }
function onCommunityPrivateKeyRemoved(communityId) {
const community = appMain.communitiesStore.getCommunityDetailsAsJson(communityId)
Global.displayToastMessage(qsTr("This device is no longer the control node for the %1 Community").arg(community.name),
"",
"info",
false,
Constants.ephemeralNotificationType.normal,
"")
}
} }
Connections { Connections {

View File

@ -28,6 +28,7 @@ QtObject {
required property var popupParent required property var popupParent
required property var rootStore required property var rootStore
property var communitiesStore property var communitiesStore
property var devicesStore
property bool isDevBuild property bool isDevBuild
property var activePopupComponents: [] property var activePopupComponents: []
@ -276,15 +277,12 @@ QtObject {
openPopup(testnetModal) openPopup(testnetModal)
} }
function openExportControlNodePopup(communityName, privateKey, cb) { function openExportControlNodePopup(community) {
openPopup(exportControlNodePopup, { openPopup(exportControlNodePopup, { community })
communityName: communityName,
privateKey: privateKey
}, cb)
} }
function openImportControlNodePopup(community, cb) { function openImportControlNodePopup(community) {
openPopup(importControlNodePopup, {community: community}, cb) openPopup(importControlNodePopup, { community })
} }
readonly property list<Component> _components: [ readonly property list<Component> _components: [
@ -680,6 +678,7 @@ QtObject {
Component { Component {
id: exportControlNodePopup id: exportControlNodePopup
ExportControlNodePopup { ExportControlNodePopup {
devicesStore: root.devicesStore
onClosed: destroy() onClosed: destroy()
} }
}, },
@ -688,6 +687,7 @@ QtObject {
id: importControlNodePopup id: importControlNodePopup
ImportControlNodePopup { ImportControlNodePopup {
onClosed: destroy() onClosed: destroy()
onImportControlNode: console.warn("!!! TODO importControlNode for community:", community.name) // FIXME implement moving (importing) the control node
} }
}, },

View File

@ -46,8 +46,8 @@ QtObject {
signal openOutgoingIDRequestPopup(string publicKey, var cb) signal openOutgoingIDRequestPopup(string publicKey, var cb)
signal openDeleteMessagePopup(string messageId, var messageStore) signal openDeleteMessagePopup(string messageId, var messageStore)
signal openDownloadImageDialog(string imageSource) signal openDownloadImageDialog(string imageSource)
signal openExportControlNodePopup(string communityName, string privateKey, var cb) signal openExportControlNodePopup(var community)
signal openImportControlNodePopup(var community, var cb) signal openImportControlNodePopup(var community)
signal contactRenamed(string publicKey) signal contactRenamed(string publicKey)
signal openLink(string link) signal openLink(string link)