feature(@desktop/communities): add loading state when import community

Toast message is added when user access an existing community using community's private key. Toast
message with message that importing community is in progress is displayed while community is being
imported and once it is imported toast is closed and new one, which will be closed in 4 seconds,
with message that community is imported is displayed.

Fixes: #2467
This commit is contained in:
Sale Djenic 2021-07-16 07:37:07 +02:00 committed by Iuri Matias
parent 9a348e1836
commit e9585e6209
5 changed files with 161 additions and 67 deletions

View File

@ -12,6 +12,12 @@ import ../../../status/types
logScope: logScope:
topics = "communities-view" topics = "communities-view"
type
CommunityImportState {.pure.} = enum
Imported,
InProgress,
Error
QtObject: QtObject:
type CommunitiesView* = ref object of QObject type CommunitiesView* = ref object of QObject
status: Status status: Status
@ -20,6 +26,8 @@ QtObject:
communityList*: CommunityList communityList*: CommunityList
joinedCommunityList*: CommunityList joinedCommunityList*: CommunityList
myCommunityRequests*: seq[CommunityMembershipRequest] myCommunityRequests*: seq[CommunityMembershipRequest]
importingCommunityState: CommunityImportState
communityImportingProcessId: string
proc setup(self: CommunitiesView) = proc setup(self: CommunitiesView) =
self.QObject.setup self.QObject.setup
@ -33,6 +41,7 @@ QtObject:
proc newCommunitiesView*(status: Status): CommunitiesView = proc newCommunitiesView*(status: Status): CommunitiesView =
new(result, delete) new(result, delete)
result.importingCommunityState = CommunityImportState.Imported
result.status = status result.status = status
result.activeCommunity = newCommunityItemView(status) result.activeCommunity = newCommunityItemView(status)
result.observedCommunity = newCommunityItemView(status) result.observedCommunity = newCommunityItemView(status)
@ -40,6 +49,16 @@ QtObject:
result.joinedCommunityList = newCommunityList(status) result.joinedCommunityList = newCommunityList(status)
result.setup result.setup
proc importingCommunityStateChanged*(self: CommunitiesView, state: int, communityImportingProcessId: string) {.signal.}
proc setImportCommunityState(self: CommunitiesView, state: CommunityImportState, communityImportingProcessId: string) =
if (self.importingCommunityState == state):
return
self.communityImportingProcessId = communityImportingProcessId
self.importingCommunityState = state
self.importingCommunityStateChanged(state.int, communityImportingProcessId)
proc calculateUnreadMessages*(self: CommunitiesView, community: var Community) = proc calculateUnreadMessages*(self: CommunitiesView, community: var Community) =
var unreadTotal = 0 var unreadTotal = 0
for chatItem in community.chats: for chatItem in community.chats:
@ -230,6 +249,8 @@ QtObject:
# @cammellos mentioned this would likely changed in Communities Phase 3, so # @cammellos mentioned this would likely changed in Communities Phase 3, so
# no need to polish now. # no need to polish now.
self.setImportCommunityState(CommunityImportState.Imported, self.communityImportingProcessId)
proc isCommunityRequestPending*(self: CommunitiesView, communityId: string): bool {.slot.} = proc isCommunityRequestPending*(self: CommunitiesView, communityId: string): bool {.slot.} =
for communityRequest in self.myCommunityRequests: for communityRequest in self.myCommunityRequests:
if (communityRequest.communityId == communityId): if (communityRequest.communityId == communityId):
@ -369,10 +390,22 @@ QtObject:
error "Error exporting the community", msg = e.msg error "Error exporting the community", msg = e.msg
result = fmt"Error exporting the community: {e.msg}" result = fmt"Error exporting the community: {e.msg}"
proc importCommunity*(self: CommunitiesView, communityKey: string): string {.slot.} = proc importCommunity*(self: CommunitiesView, communityKey: string, communityImportingProcessId: string): string {.slot.} =
try: try:
discard self.status.chat.importCommunity(communityKey) self.setImportCommunityState(CommunityImportState.InProgress, communityImportingProcessId)
let response = self.status.chat.importCommunity(communityKey)
let jsonNode = response.parseJSON()
if (jsonNode.contains("error")):
if (jsonNode["error"].contains("message")):
let msg = jsonNode["error"]["message"].getStr()
result = fmt"Error importing the community: {msg}"
else:
result = fmt"Error importing the community: unknown error"
self.setImportCommunityState(CommunityImportState.Error, communityImportingProcessId)
except Exception as e: except Exception as e:
self.setImportCommunityState(CommunityImportState.Error, communityImportingProcessId)
error "Error importing the community", msg = e.msg error "Error importing the community", msg = e.msg
result = fmt"Error importing the community: {e.msg}" result = fmt"Error importing the community: {e.msg}"

View File

@ -65,7 +65,7 @@ ModalPopup {
communityKey = "0x" + communityKey communityKey = "0x" + communityKey
} }
const error = chatsModel.communities.importCommunity(communityKey) const error = chatsModel.communities.importCommunity(communityKey, Utils.uuid())
if (error) { if (error) {
creatingError.text = error creatingError.text = error

View File

@ -239,10 +239,50 @@ Item {
} }
} }
} }
}
/*##^## Connections {
Designer { target: chatsModel.communities
D{i:0;autoSize:true;formeditorColor:"#ffffff";height:480;width:640} onImportingCommunityStateChanged: {
if (state !== Constants.communityImported &&
state !== Constants.communityImportingInProgress &&
state !== Constants.communityImportingError)
{
return
}
if (state === Constants.communityImported)
{
if (toastMessage.uuid !== communityImportingProcessId)
return
toastMessage.close()
toastMessage.title = qsTr("Community imported")
toastMessage.source = ""
toastMessage.iconRotates = false
toastMessage.dissapearInMs = 4000
}
else if (state === Constants.communityImportingInProgress)
{
toastMessage.uuid = communityImportingProcessId
toastMessage.title = qsTr("Importing community is in progress")
toastMessage.source = "../../img/loading.svg"
toastMessage.iconRotates = true
toastMessage.dissapearInMs = -1
}
else if (state === Constants.communityImportingError)
{
if (toastMessage.uuid !== communityImportingProcessId)
return
toastMessage.close()
return
}
toastMessage.displayCloseButton = false
toastMessage.displayLink = false
toastMessage.iconColor = Style.current.primary
toastMessage.open()
}
}
} }
##^##*/

View File

@ -3,6 +3,10 @@ pragma Singleton
import QtQuick 2.13 import QtQuick 2.13
QtObject { QtObject {
readonly property int communityImported: 0
readonly property int communityImportingInProgress: 1
readonly property int communityImportingError: 2
readonly property int chatTypeOneToOne: 1 readonly property int chatTypeOneToOne: 1
readonly property int chatTypePublic: 2 readonly property int chatTypePublic: 2
readonly property int chatTypePrivateGroupChat: 3 readonly property int chatTypePrivateGroupChat: 3

View File

@ -5,34 +5,52 @@ import "../imports"
import "." import "."
Popup { Popup {
property url source: "../app/img/check-circle.svg"
property color iconColor: Style.current.primary
property bool iconRotates: false
property string title: "Transaction pending..."
//% "View on Etherscan"
readonly property string defaultLinkText: qsTrId("view-on-etherscan")
property string link: "https://etherscan.io/"
property string linkText: defaultLinkText
id: root id: root
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
height: 68 height: 68
padding: 0 padding: 0
margins: 0 margins: 0
width: Math.max(Math.max(titleText.width, linkText.width) + toastImage.width + 12 * 4, 343) width: Math.max(Math.max(titleText.width, linkStyledText.width)
+ (toastImage.visible? toastImage.width + rowId.spacing : 0)
+ rowId.leftPadding + rowId.rightPadding,
343)
x: parent.width - width - Style.current.bigPadding x: parent.width - width - Style.current.bigPadding
y: parent.height - height - Style.current.bigPadding y: parent.height - height - Style.current.bigPadding
//% "View on Etherscan"
readonly property string defaultLinkText: qsTrId("view-on-etherscan")
property string uuid: "" // set this if you want to distinct among multiple toasts
property url source: "../app/img/check-circle.svg"
property color iconColor: Style.current.primary
property bool iconRotates: false
property string title: "Transaction pending..."
property string link: "https://etherscan.io/"
property string linkText: defaultLinkText
property int dissapearInMs: 4000 /* setting this to -1 makes caller responsible to close it */
property bool displayCloseButton: true
property bool displayLink: true
onOpened: { onOpened: {
if(dissapearInMs == -1)
return
timer.setTimeout(function() { timer.setTimeout(function() {
root.close() root.close()
}, 4000); }, dissapearInMs);
} }
onClosed: { onClosed: {
// Reset props // Reset props
source = "../app/img/check-circle.svg"
iconColor = Style.current.primary iconColor = Style.current.primary
iconRotates = false iconRotates = false
root.linkText = defaultLinkText title = "Transaction pending..."
link = "https://etherscan.io/"
linkText = defaultLinkText
dissapearInMs = 4000
displayCloseButton = true
displayLink = true
} }
Timer { Timer {
@ -60,54 +78,58 @@ Popup {
} }
} }
RoundedIcon { Row {
id: toastImage id: rowId
width: 32 anchors.fill: parent
height: 32 leftPadding: 12
iconHeight: 20 rightPadding: 12
iconWidth: 20 topPadding: Style.current.padding
color: Utils.setColorAlpha(root.iconColor, 0.1) bottomPadding: Style.current.padding
anchors.verticalCenter: parent.verticalCenter spacing: 12
anchors.left: parent.left
source: root.source
anchors.leftMargin: 12
iconColor: root.iconColor
rotates: root.iconRotates
}
StyledText { RoundedIcon {
id: titleText id: toastImage
text: root.title visible: root.source != ""
anchors.left: toastImage.right width: 32
anchors.top: parent.top height: 32
font.pixelSize: 13 iconHeight: 20
font.weight: Font.Medium iconWidth: 20
anchors.topMargin: Style.current.padding color: Utils.setColorAlpha(root.iconColor, 0.1)
anchors.leftMargin: 12 anchors.verticalCenter: parent.verticalCenter
} source: root.source
iconColor: root.iconColor
rotates: root.iconRotates
}
StyledText { Column {
id: linkText anchors.verticalCenter: parent.verticalCenter
//% "<a href='%1' style='color:%2;text-decoration:none;'>%3</a>"
text: qsTrId("-a-href---1--style--color--2-text-decoration-none----3--a-") StyledText {
.arg(Style.current.textColorTertiary) id: titleText
.arg(root.link) text: root.title
.arg(root.linkText) font.pixelSize: 13
color: Style.current.textColorTertiary font.weight: Font.Medium
textFormat: Text.RichText }
anchors.left: toastImage.right
anchors.top: titleText.bottom StyledText {
font.pixelSize: 13 id: linkStyledText
font.weight: Font.Medium visible: displayLink
anchors.leftMargin: 12 text: `<a href='${root.link}' style='color:${Style.current.textColorTertiary};text-decoration:none;'>${root.linkText}</a>`
onLinkActivated: { color: Style.current.textColorTertiary
appMain.openLink(root.link) textFormat: Text.RichText
root.close() font.pixelSize: 13
font.weight: Font.Medium
onLinkActivated: {
appMain.openLink(root.link)
root.close()
}
}
} }
} }
SVGImage { SVGImage {
id: closeImage id: closeImage
visible: displayCloseButton
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
source: "../app/img/plusSign.svg" source: "../app/img/plusSign.svg"
@ -126,15 +148,10 @@ Popup {
} }
} }
ColorOverlay { ColorOverlay {
visible: displayCloseButton
anchors.fill: closeImage anchors.fill: closeImage
source: closeImage source: closeImage
rotation: 45 rotation: 45
color: Style.current.textColor color: Style.current.textColor
} }
} }
/*##^##
Designer {
D{i:0;formeditorColor:"#4c4e50";formeditorZoom:1.5;height:68;width:343}
}
##^##*/