feat: Single discord channel import UI flow

Closes #12039
This commit is contained in:
Lukáš Tinkl 2023-09-01 09:58:48 +02:00 committed by Lukáš Tinkl
parent b22b632b2d
commit e106be9b12
15 changed files with 835 additions and 344 deletions

View File

@ -107,3 +107,10 @@ QtObject:
let index = self.createIndex(idx, 0, nil)
self.items[idx].selected = true
self.dataChanged(index, index, @[ModelRole.Selected.int])
proc selectOneItem*(self: DiscordCategoriesModel, id: string) =
for i in 0 ..< self.items.len:
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.items[i].selected = self.items[i].getId() == id
self.dataChanged(index, index, @[ModelRole.Selected.int])

View File

@ -214,3 +214,11 @@ QtObject:
self.items[idx].selected = true
self.dataChanged(index, index, @[ModelRole.Selected.int])
self.hasSelectedItemsChanged()
proc selectOneItem*(self: DiscordChannelsModel, id: string) =
for i in 0 ..< self.items.len:
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.items[i].selected = self.items[i].getId() == id
self.dataChanged(index, index, @[ModelRole.Selected.int])
self.hasSelectedItemsChanged()

View File

@ -47,6 +47,8 @@ QtObject:
discordDataExtractionInProgress: bool
discordImportCommunityId: string
discordImportCommunityName: string
discordImportChannelId: string
discordImportChannelName: string
discordImportCommunityImage: string
discordImportHasCommunityImage: bool
downloadingCommunityHistoryArchives: bool
@ -481,6 +483,8 @@ QtObject:
self.setDiscordImportWarningsCount(0)
self.setDiscordImportCommunityId("")
self.setDiscordImportCommunityName("")
self.discordImportChannelId = ""
self.discordImportChannelName = ""
self.setDiscordImportCommunityImage("")
self.setDiscordImportHasCommunityImage(false)
self.setDiscordImportInProgress(false)
@ -609,6 +613,30 @@ QtObject:
if self.discordChannelsModel.allChannelsByCategoryUnselected(item.getCategoryId()):
self.discordCategoriesModel.unselectItem(item.getCategoryId())
proc discordImportChannelChanged*(self: View) {.signal.}
proc toggleOneDiscordChannel*(self: View, id: string) {.slot.} =
let item = self.discordChannelsModel.getItem(id)
self.discordChannelsModel.selectOneItem(id)
self.discordCategoriesModel.selectOneItem(item.getCategoryId())
self.discordImportChannelId = id
self.discordImportChannelName = item.getName()
self.discordImportChannelChanged()
proc getDiscordImportChannelId(self: View): string {.slot.} =
return self.discordImportChannelId
QtProperty[string] discordImportChannelId:
read = getDiscordImportChannelId
notify = discordImportChannelChanged
proc getDiscordImportChannelName(self: View): string {.slot.} =
return self.discordImportChannelName
QtProperty[string] discordImportChannelName:
read = getDiscordImportChannelName
notify = discordImportChannelChanged
proc tokenListModel*(self: View): TokenListModel =
result = self.tokenListModel

View File

@ -724,7 +724,7 @@ QtObject:
return
if not self.communities.hasKey(communityId):
error "requested community doesn't exists", communityId
error "requested community doesn't exist", communityId
return
return self.communities[communityId]
@ -1004,10 +1004,10 @@ QtObject:
if response.error != nil:
let error = Json.decode($response.error, RpcError)
raise newException(RpcException, "Error creating community: " & error.message)
raise newException(RpcException, "Error importing discord community: " & error.message)
except Exception as e:
error "Error creating community", msg = e.msg
error "Error importing discord community", msg = e.msg
proc createCommunity*(
self: Service,
@ -1941,7 +1941,7 @@ QtObject:
try:
discard status_go.requestCancelDiscordCommunityImport(communityId)
except Exception as e:
error "Error extracting discord channels and categories", msg = e.msg
error "Error canceling discord community import", msg = e.msg
proc createOrEditCommunityTokenPermission*(self: Service, communityId: string, tokenPermission: CommunityTokenPermissionDto) =
try:

View File

@ -1,6 +1,7 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15
import Storybook 1.0
@ -13,56 +14,161 @@ SplitView {
orientation: Qt.Vertical
property var dialog
function createAndOpenDialog() {
dialog = dlgComponent.createObject(popupBg)
dialog.open()
}
Component.onCompleted: createAndOpenDialog()
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
PopupBackground {
id: popupBg
anchors.fill: parent
Button {
anchors.centerIn: parent
text: "Reopen"
onClicked: createAndOpenDialog()
}
}
CreateChannelPopup {
anchors.centerIn: parent
modal: false
closePolicy: Popup.NoAutoClose
Component {
id: dlgComponent
CreateChannelPopup {
id: dialog
anchors.centerIn: parent
modal: false
closePolicy: Popup.NoAutoClose
destroyOnClose: true
isEdit: isEditCheckBox.checked
isDeleteable: isDeleteableCheckBox.checked
isEdit: isEditCheckBox.checked
isDeleteable: isDeleteableCheckBox.checked
isDiscordImport: isDiscordCheckBox.checked
emojiPopup: Popup {
id: emojiPopup
Binding on channelName {
value: "test-channel"
when: dialog.isEdit
restoreMode: Binding.RestoreBindingOrValue
}
parent: root
Binding on channelDescription {
value: "TEST TEST TEST"
when: dialog.isEdit
restoreMode: Binding.RestoreBindingOrValue
}
property var emojiSize
Binding on channelColor {
value: "pink"
when: dialog.isEdit
restoreMode: Binding.RestoreBindingOrValue
}
Button {
text: "😃"
onClicked: {
emojiPopup.emojiSelected(text, false)
emojiPopup.close()
communitiesStore: QtObject {
property string discordImportChannelName
readonly property bool discordImportInProgress: false
readonly property bool discordDataExtractionInProgress: false
readonly property int discordImportErrorsCount: 0
readonly property int discordImportWarningsCount: 0
readonly property int discordOldestMessageTimestamp: 0
property var discordFileList: ListModel {
readonly property int selectedCount: count
property bool selectedFilesValid
}
property var discordCategoriesModel: ListModel {}
property var discordChannelsModel: ListModel {
property bool hasSelectedItems
readonly property int count: 32 // hide the parsing/loading spinner
}
function setFileListItems(filePaths) {
for (const filePath of filePaths) {
discordFileList.append({"filePath": filePath, errorMessage: ""})
}
}
function removeFileListItem(path) {
for (let i = 0; i < discordFileList.count; i++) {
const item = discordFileList.get(i)
if (item.filePath === path)
discordFileList.remove(i)
}
}
function clearFileList() {
discordFileList.clear()
discordFileList.selectedFilesValid = false
}
function clearDiscordCategoriesAndChannels() {
discordCategoriesModel.clear()
discordChannelsModel.clear()
discordChannelsModel.hasSelectedItems = false
}
function requestExtractChannelsAndCategories() {
discordFileList.selectedFilesValid = true
}
function toggleOneDiscordChannel(id) {
logs.logEvent("toggleOneDiscordChannel", ["id"], arguments)
}
function resetDiscordImport() {
logs.logEvent("resetDiscordImport")
}
function requestCancelDiscordChannelImport(id) {
logs.logEvent("requestCancelDiscordChannelImport", ["id"], arguments)
}
function requestImportDiscordChannel(args, timestamp) {
logs.logEvent("requestImportDiscordChannel", ["args", "timestamp"], arguments)
}
}
signal emojiSelected(string emoji, bool atCu)
emojiPopup: Popup {
id: inner_emojiPopup
parent: root
property var emojiSize
Button {
text: "😃"
onClicked: {
emojiPopup.emojiSelected(text, false)
emojiPopup.close()
}
}
signal emojiSelected(string emoji, bool atCu)
}
onCreateCommunityChannel: function(chName, chDescription, chEmoji, chColor, chCategoryId) {
logs.logEvent("onCreateCommunityChannel",
["chName", "chDescription", "chEmoji", "chColor", "chCategoryId"], arguments)
}
onEditCommunityChannel: function(chName, chDescription, chEmoji, chColor, chCategoryId) {
logs.logEvent("onEditCommunityChannel",
["chName", "chDescription", "chEmoji", "chColor", "chCategoryId"], arguments)
}
onDeleteCommunityChannel: () => {
logs.logEvent("onDeleteCommunityChannel")
}
}
onCreateCommunityChannel: function(chName, chDescription, chEmoji, chColor, chCategoryId) {
logs.logEvent("onCreateCommunityChannel",
["chName", "chDescription", "chEmoji", "chColor", "chCategoryId"], arguments)
}
onEditCommunityChannel: function(chName, chDescription, chEmoji, chColor, chCategoryId) {
logs.logEvent("onEditCommunityChannel",
["chName", "chDescription", "chEmoji", "chColor", "chCategoryId"], arguments)
}
onDeleteCommunityChannel: () => {
logs.logEvent("onDeleteCommunityChannel")
}
Component.onCompleted: open()
}
}
@ -75,15 +181,23 @@ SplitView {
RowLayout {
CheckBox {
id: isEditCheckBox
text: "isEdit"
onToggled: if (checked) isDiscordCheckBox.checked = false
}
CheckBox {
id: isDeleteableCheckBox
enabled: isEditCheckBox.checked
text: "isDeleteable"
}
CheckBox {
id: isDiscordCheckBox
enabled: !isEditCheckBox.checked
text: "isDiscordImport"
onToggled: {
if (!!dialog && dialog.opened)
dialog.close()
}
}
}
}
}

View File

@ -20,6 +20,7 @@ StackLayout {
property var createChatPropertiesStore
readonly property var contactsStore: rootStore.contactsStore
readonly property var permissionsStore: rootStore.permissionsStore
property var communitiesStore
property var sectionItemModel
@ -118,6 +119,7 @@ StackLayout {
contactsStore: root.contactsStore
rootStore: root.rootStore
createChatPropertiesStore: root.createChatPropertiesStore
communitiesStore: root.communitiesStore
sectionItemModel: root.sectionItemModel
amIMember: chatItem.amIMember
amISectionAdmin: root.sectionItemModel.memberRole === Constants.memberRole.owner ||

View File

@ -30,6 +30,7 @@ StatusSectionLayout {
property RootStore rootStore
property var createChatPropertiesStore
property var communitiesStore
property var sectionItemModel
property var emojiPopup
@ -238,6 +239,7 @@ StatusSectionLayout {
communitySectionModule: root.rootStore.chatCommunitySectionModule
communityData: sectionItemModel
store: root.rootStore
communitiesStore: root.communitiesStore
emojiPopup: root.emojiPopup
hasAddedContacts: root.hasAddedContacts
onInfoButtonClicked: root.communityInfoButtonClicked()

View File

@ -14,15 +14,18 @@ import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
StatusDialog {
import AppLayouts.Communities.controls 1.0
StatusStackModal {
id: root
width: 480
height: 509
property var communitiesStore
property bool isDiscordImport // creating new or importing from discord?
property bool isEdit: false
property bool isDeleteable: false
property string chatId: ""
property string categoryId: ""
property string channelName: ""
@ -41,8 +44,15 @@ StatusDialog {
signal editCommunityChannel(string chName, string chDescription, string chEmoji, string chColor, string chCategoryId)
signal deleteCommunityChannel()
width: 640
QtObject {
id: d
function isFormValid() {
return nameInput.valid && descriptionTextArea.valid &&
Utils.validateAndReturnError(colorDialog.color.toString().toUpperCase(), communityColorValidator) === ""
}
function openEmojiPopup(leftSide = false) {
root.emojiPopupOpened = true;
root.emojiPopup.open();
@ -50,17 +60,117 @@ StatusDialog {
root.emojiPopup.x = leftSide ? root.x + Style.current.padding : (root.x + (root.width - root.emojiPopup.width - Style.current.padding));
root.emojiPopup.y = root.y + root.header.height + root.topPadding + nameInput.height + Style.current.smallPadding;
}
function _getChannelConfig() {
return {
discordChannelId: root.communitiesStore.discordImportChannelId,
categoryId: root.categoryId,
name: StatusQUtils.Utils.filterXSS(nameInput.input.text),
description: StatusQUtils.Utils.filterXSS(descriptionTextArea.text),
color: colorDialog.color.toString().toUpperCase(),
emoji: StatusQUtils.Emoji.deparse(nameInput.input.asset.emoji),
options: {
// TODO
}
}
}
function requestImportDiscordChannel() {
const error = root.communitiesStore.requestImportDiscordChannel(_getChannelConfig(), datePicker.selectedDate.valueOf()/1000)
if (error) {
creatingError.text = error.error
creatingError.open()
}
}
}
title: qsTr("New channel")
padding: 0
stackTitle: isDiscordImport ? qsTr("New Channel With Imported Chat History") :
isEdit ? qsTr("Edit #%1").arg(root.channelName)
: qsTr("New channel")
nextButton: StatusButton {
objectName: "createChannelNextBtn"
font.weight: Font.Medium
text: typeof currentItem.nextButtonText !== "undefined" ? currentItem.nextButtonText : qsTr("Import chat history")
enabled: typeof(currentItem.canGoNext) == "undefined" || currentItem.canGoNext
loading: root.communitiesStore.discordDataExtractionInProgress
onClicked: {
const nextAction = currentItem.nextAction
if (typeof(nextAction) == "function") {
return nextAction()
}
root.currentIndex++
}
}
finishButton: StatusButton {
objectName: "createOrEditCommunityChannelBtn"
font.weight: Font.Medium
text: isDiscordImport ? qsTr("Import chat history") : isEdit ? qsTr("Save changes") : qsTr("Create channel")
enabled: typeof(currentItem.canGoNext) == "undefined" || currentItem.canGoNext
onClicked: {
let nextAction = currentItem.nextAction
if (typeof (nextAction) == "function") {
return nextAction()
}
if (!root.isDiscordImport) {
if (!d.isFormValid()) {
scrollView.scrollBackUp()
return
}
let emoji = StatusQUtils.Emoji.deparse(nameInput.input.asset.emoji)
if (!isEdit) {
root.createCommunityChannel(StatusQUtils.Utils.filterXSS(nameInput.input.text),
StatusQUtils.Utils.filterXSS(descriptionTextArea.text),
emoji,
colorDialog.color.toString().toUpperCase(),
root.categoryId)
} else {
root.editCommunityChannel(StatusQUtils.Utils.filterXSS(nameInput.input.text),
StatusQUtils.Utils.filterXSS(descriptionTextArea.text),
emoji,
colorDialog.color.toString().toUpperCase(),
root.categoryId)
}
// TODO Open the channel once we have designs for it
root.close()
}
}
}
readonly property StatusButton clearFilesButton: StatusButton {
font.weight: Font.Medium
text: qsTr("Clear all")
type: StatusBaseButton.Type.Danger
visible: typeof currentItem.isFileListView !== "undefined" && currentItem.isFileListView
enabled: !fileListView.fileListModelEmpty && !root.communitiesStore.discordDataExtractionInProgress
onClicked: root.communitiesStore.clearFileList()
}
readonly property StatusButton deleteChannelButton: StatusButton {
objectName: "deleteCommunityChannelBtn"
visible: isEdit && isDeleteable && !isDiscordImport
text: qsTr("Delete channel")
type: StatusBaseButton.Type.Danger
onClicked: root.deleteCommunityChannel()
}
rightButtons: [clearFilesButton, deleteChannelButton, nextButton, finishButton]
onAboutToShow: {
if (root.isDiscordImport) {
if (!root.communitiesStore.discordImportInProgress) {
root.communitiesStore.clearFileList()
root.communitiesStore.clearDiscordCategoriesAndChannels()
}
for (let i = 0; i < discordPages.length; i++) {
stackItems.push(discordPages[i])
}
}
onOpened: {
nameInput.text = ""
nameInput.input.asset.emoji = ""
nameInput.input.edit.forceActiveFocus(Qt.MouseFocusReason)
if (isEdit) {
root.title = qsTr("Edit #%1").arg(root.channelName);
nameInput.text = root.channelName
descriptionTextArea.text = root.channelDescription
if (root.channelEmoji) {
@ -70,8 +180,300 @@ StatusDialog {
} else {
nameInput.input.asset.isLetterIdenticon = true;
}
updateRightButtons()
}
readonly property list<Item> discordPages: [
ColumnLayout {
id: fileListView
spacing: 24
readonly property bool isFileListView: true
readonly property var fileListModel: root.communitiesStore.discordFileList
readonly property bool fileListModelEmpty: !fileListModel.count
readonly property bool canGoNext: fileListModel.selectedCount
|| (fileListModel.selectedCount && fileListModel.selectedFilesValid)
readonly property string nextButtonText: fileListModel.selectedCount && fileListModel.selectedFilesValid ?
qsTr("Proceed with (%1/%2) files").arg(fileListModel.selectedCount).arg(fileListModel.count) :
fileListModel.selectedCount && fileListModel.selectedCount === fileListModel.count ? qsTr("Validate %n file(s)", "", fileListModel.selectedCount)
: fileListModel.selectedCount ? qsTr("Validate (%1/%2) files").arg(fileListModel.selectedCount).arg(fileListModel.count)
: qsTr("Start channel import")
readonly property var nextAction: function () {
if (!fileListView.fileListModel.selectedFilesValid)
return root.communitiesStore.requestExtractChannelsAndCategories()
root.currentIndex++
}
RowLayout {
Layout.fillWidth: true
spacing: 12
StatusBaseText {
Layout.fillWidth: true
maximumLineCount: 2
wrapMode: Text.Wrap
elide: Text.ElideRight
text: fileListView.fileListModelEmpty ? qsTr("Select Discord channel JSON files to import") :
root.communitiesStore.discordImportErrorsCount ? qsTr("Some of your community files cannot be used") :
qsTr("Uncheck any files you would like to exclude from the import")
}
StatusBaseText {
visible: fileListView.fileListModelEmpty && !issuePill.visible
font.pixelSize: 12
color: Theme.palette.baseColor1
text: qsTr("(JSON file format only)")
}
IssuePill {
id: issuePill
type: root.communitiesStore.discordImportErrorsCount ? IssuePill.Type.Error : IssuePill.Type.Warning
count: root.communitiesStore.discordImportErrorsCount || root.communitiesStore.discordImportWarningsCount || 0
visible: !!count && !fileListView.fileListModelEmpty
}
StatusButton {
Layout.alignment: Qt.AlignRight
text: qsTr("Browse files")
type: StatusBaseButton.Type.Primary
onClicked: fileDialog.open()
enabled: !root.communitiesStore.discordDataExtractionInProgress
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: Theme.palette.baseColor4
ColumnLayout {
visible: fileListView.fileListModelEmpty
anchors.top: parent.top
anchors.topMargin: 60
anchors.horizontalCenter: parent.horizontalCenter
spacing: 8
StatusRoundIcon {
Layout.alignment: Qt.AlignHCenter
asset.name: "info"
}
StatusBaseText {
Layout.topMargin: 8
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Qt.AlignHCenter
text: qsTr("Export the Discord channels chat history data using %1").arg("<a href='https://github.com/Tyrrrz/DiscordChatExporter/releases/tag/2.40.4'>DiscordChatExporter</a>")
onLinkActivated: Global.openLink(link)
HoverHandler {
id: handler1
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: handler1.hovered && parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Qt.AlignHCenter
text: qsTr("Refer to this <a href='https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Readme.md'>documentation</a> if you have any queries")
onLinkActivated: Global.openLink(link)
HoverHandler {
id: handler2
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: handler2.hovered && parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
}
Component {
id: floatingDivComp
Rectangle {
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
width: ListView.view ? ListView.view.width : 0
height: 4
color: Theme.palette.directColor8
}
}
StatusListView {
visible: !fileListView.fileListModelEmpty
enabled: !root.communitiesStore.discordDataExtractionInProgress
anchors.fill: parent
leftMargin: 8
rightMargin: 8
model: fileListView.fileListModel
header: !atYBeginning ? floatingDivComp : null
headerPositioning: ListView.OverlayHeader
footer: !atYEnd ? floatingDivComp : null
footerPositioning: ListView.OverlayHeader
delegate: ColumnLayout {
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
RowLayout {
spacing: 20
Layout.fillWidth: true
Layout.topMargin: 8
StatusBaseText {
Layout.fillWidth: true
text: model.filePath
font.pixelSize: 13
elide: Text.ElideRight
wrapMode: Text.WordWrap
maximumLineCount: 2
}
StatusFlatRoundButton {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
type: StatusFlatRoundButton.Type.Secondary
icon.name: "close"
icon.color: Theme.palette.directColor1
icon.width: 24
icon.height: 24
onClicked: root.communitiesStore.removeFileListItem(model.filePath)
}
}
StatusBaseText {
Layout.fillWidth: true
text: "%1 %2".arg("⚠").arg(model.errorMessage)
visible: model.errorMessage
font.pixelSize: 13
font.weight: Font.Medium
elide: Text.ElideMiddle
color: Theme.palette.dangerColor1
verticalAlignment: Qt.AlignTop
}
}
}
}
FileDialog {
id: fileDialog
title: qsTr("Choose files to import")
selectMultiple: true
nameFilters: [qsTr("JSON files (%1)").arg("*.json *.JSON")]
onAccepted: {
if (fileDialog.fileUrls.length > 0) {
const files = []
for (let i = 0; i < fileDialog.fileUrls.length; i++)
files.push(decodeURI(fileDialog.fileUrls[i].toString()))
root.communitiesStore.setFileListItems(files)
}
}
}
},
ColumnLayout {
id: categoriesAndChannelsView
spacing: 24
readonly property bool canGoNext: root.communitiesStore.discordChannelsModel.hasSelectedItems
readonly property var nextAction: function () {
d.requestImportDiscordChannel()
// replace ourselves with the progress dialog, no way back
root.leftButtons[0].visible = false
root.backgroundColor = Theme.palette.baseColor4
root.replace(progressComponent)
}
Component {
id: progressComponent
DiscordImportProgressContents {
width: root.availableWidth
store: root.communitiesStore
importingSingleChannel: true
onClose: root.close()
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
visible: !root.communitiesStore.discordChannelsModel.count
Loader {
anchors.centerIn: parent
active: parent.visible
sourceComponent: StatusLoadingIndicator {
width: 50
height: 50
}
}
}
ColumnLayout {
spacing: 12
visible: root.communitiesStore.discordChannelsModel.count
StatusBaseText {
Layout.fillWidth: true
text: qsTr("Select the chat history you would like to import into #%1...").arg(StatusQUtils.Utils.filterXSS(nameInput.input.text))
wrapMode: Text.WordWrap
}
RowLayout {
spacing: 20
Layout.fillWidth: true
StatusRadioButton {
text: qsTr("Import all history")
checked: true
}
StatusRadioButton {
id: startDateRadio
text: qsTr("Start date")
}
StatusDatePicker {
id: datePicker
Layout.fillWidth: true
selectedDate: new Date(root.communitiesStore.discordOldestMessageTimestamp * 1000)
enabled: startDateRadio.checked
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: Theme.palette.baseColor4
StatusListView {
anchors.fill: parent
anchors.margins: 16
model: root.communitiesStore.discordCategoriesModel
delegate: ColumnLayout {
width: ListView.view.width
spacing: 8
StatusBaseText {
readonly property string categoryId: model.id
id: categoryCheckbox
text: model.name
}
ColumnLayout {
spacing: 8
Layout.fillWidth: true
Layout.leftMargin: 24
Repeater {
Layout.fillWidth: true
model: root.communitiesStore.discordChannelsModel
delegate: StatusRadioButton {
width: parent.width
text: model.name
checked: model.selected
visible: model.categoryId === categoryCheckbox.categoryId
onToggled: root.communitiesStore.toggleOneDiscordChannel(model.id)
}
}
}
}
}
}
}
}
]
Connections {
enabled: root.opened && root.emojiPopupOpened
target: emojiPopup
@ -85,278 +487,157 @@ StatusDialog {
}
}
function isFormValid() {
return (nameInput.valid &&
descriptionTextArea.valid) &&
Utils.validateAndReturnError(colorDialog.color.toString().toUpperCase(),
communityColorValidator) === ""
}
stackItems: [
StatusScrollView {
id: scrollView
StatusScrollView {
id: scrollView
readonly property bool canGoNext: d.isFormValid()
property ScrollBar vScrollBar: ScrollBar.vertical
property ScrollBar vScrollBar: ScrollBar.vertical
anchors.fill: parent
contentWidth: availableWidth
padding: 16
contentWidth: availableWidth
padding: 0
function scrollBackUp() {
vScrollBar.setPosition(0)
}
ColumnLayout {
id: content
width: scrollView.availableWidth
spacing: 0
StatusInput {
id: nameInput
Layout.fillWidth: true
input.edit.objectName: "createOrEditCommunityChannelNameInput"
label: qsTr("Channel name")
charLimit: root.maxChannelNameLength
placeholderText: qsTr("# Name the channel")
input.onTextChanged: {
const cursorPosition = input.cursorPosition
input.text = Utils.convertSpacesToDashes(input.text)
input.cursorPosition = cursorPosition
if (root.channelEmoji === "") {
input.letterIconName = text;
}
}
input.asset.color: colorDialog.color.toString()
input.rightComponent: StatusRoundButton {
objectName: "StatusChannelPopup_emojiButton"
implicitWidth: 32
implicitHeight: 32
icon.width: 20
icon.height: 20
icon.name: "smiley"
onClicked: {
d.openEmojiPopup();
}
}
onIconClicked: {
d.openEmojiPopup(true);
}
validators: [
StatusMinLengthValidator {
minLength: 1
errorMessage: Utils.getErrorMessage(nameInput.errors, qsTr("channel name"))
},
StatusRegularExpressionValidator {
regularExpression: Constants.regularExpressions.alphanumericalExpanded
errorMessage: Constants.errorMessages.alphanumericalExpandedRegExp
}
]
function scrollBackUp() {
vScrollBar.setPosition(0)
}
Item {
id: spacer1
height: 16
Layout.fillWidth: true
}
ColumnLayout {
id: content
StatusBaseText {
Layout.fillWidth: true
text: qsTr("Channel colour")
font.pixelSize: 15
color: Theme.palette.directColor1
}
width: scrollView.availableWidth
spacing: 0
Item {
id: spacer2
height: 8
Layout.fillWidth: true
}
StatusInput {
id: nameInput
Layout.fillWidth: true
input.edit.objectName: "createOrEditCommunityChannelNameInput"
label: qsTr("Channel name")
charLimit: root.maxChannelNameLength
placeholderText: qsTr("# Name the channel")
Item {
height: colorSelectorButton.height + 16
Layout.fillWidth: true
StatusPickerButton {
id: colorSelectorButton
property string validationError: ""
bgColor: colorDialog.colorSelected ? colorDialog.color : Theme.palette.baseColor2
contentColor: colorDialog.colorSelected ? Theme.palette.white : Theme.palette.baseColor1
text: colorDialog.colorSelected ?
colorDialog.color.toString().toUpperCase() :
qsTr("Pick a colour")
onClicked: colorDialog.open();
onTextChanged: {
if (colorDialog.colorSelected) {
validationError = Utils.validateAndReturnError(text, communityColorValidator)
input.onTextChanged: {
const cursorPosition = input.cursorPosition
input.text = Utils.convertSpacesToDashes(input.text)
input.cursorPosition = cursorPosition
if (root.channelEmoji === "") {
input.letterIconName = text
}
}
input.asset.color: colorDialog.color.toString()
input.rightComponent: StatusRoundButton {
objectName: "StatusChannelPopup_emojiButton"
implicitWidth: 32
implicitHeight: 32
icon.width: 20
icon.height: 20
icon.name: "smiley"
onClicked: d.openEmojiPopup()
}
onIconClicked: {
d.openEmojiPopup(true);
}
validators: [
StatusMinLengthValidator {
minLength: 1
errorMessage: Utils.getErrorMessage(nameInput.errors, qsTr("channel name"))
},
StatusRegularExpressionValidator {
regularExpression: Constants.regularExpressions.alphanumericalExpanded
errorMessage: Constants.errorMessages.alphanumericalExpandedRegExp
}
]
}
StatusColorDialog {
id: colorDialog
anchors.centerIn: parent
property bool colorSelected: root.isEdit && root.channelColor
headerSettings.title: qsTr("Channel Colour")
standardColors: Theme.palette.communityColorsArray
color: root.isEdit && root.channelColor ? root.channelColor :
Theme.palette.primaryColor1
onAccepted: colorSelected = true
Item {
Layout.preferredHeight: 16
Layout.fillWidth: true
}
StatusBaseText {
text: colorSelectorButton.validationError
visible: !!text
color: Theme.palette.dangerColor1
anchors.top: colorSelectorButton.bottom
anchors.topMargin: 4
anchors.right: colorSelectorButton.right
Layout.fillWidth: true
text: qsTr("Channel colour")
}
}
StatusInput {
id: descriptionTextArea
Layout.fillWidth: true
input.edit.objectName: "createOrEditCommunityChannelDescriptionInput"
input.verticalAlignment: TextEdit.AlignTop
label: qsTr("Description")
charLimit: 140
placeholderText: qsTr("Describe the channel")
input.multiline: true
minimumHeight: 88
maximumHeight: 88
validators: [
StatusMinLengthValidator {
minLength: 1
errorMessage: Utils.getErrorMessage(descriptionTextArea.errors, qsTr("channel description"))
},
StatusRegularExpressionValidator {
regularExpression: Constants.regularExpressions.alphanumericalExpanded
errorMessage: Constants.errorMessages.alphanumericalExpandedRegExp
}
]
}
/* TODO: use the code below to enable private channels and message limit */
/* StatusListItem { */
/* width: parent.width */
/* height: 56 */
/* sensor.enabled: false */
/* title: qsTr("Private channel") */
/* components: [ */
/* StatusSwitch { */
/* id: privateSwitch */
/* } */
/* ] */
/* } */
/* StatusBaseText { */
/* width: parent.width - 32 */
/* anchors.left: parent.left */
/* anchors.right: parent.right */
/* anchors.rightMargin: 121 */
/* anchors.leftMargin: 16 */
/* color: Theme.palette.baseColor1 */
/* wrapMode: Text.WordWrap */
/* text: qsTr("By making a channel private, only members with selected permission will be able to access it") */
/* } */
/* StatusModalDivider { */
/* topPadding: 8 */
/* bottomPadding: 8 */
/* } */
/* StatusListItem { */
/* width: parent.width */
/* height: 56 */
/* sensor.enabled: false */
/* title: qsTr("Message limit") */
/* components: [ */
/* StatusSwitch {} */
/* ] */
/* } */
/* StatusBaseText { */
/* width: parent.width - 32 */
/* anchors.left: parent.left */
/* anchors.right: parent.right */
/* anchors.rightMargin: 121 */
/* anchors.leftMargin: 16 */
/* color: Theme.palette.baseColor1 */
/* wrapMode: Text.WordWrap */
/* text: qsTr("Limit channel members to sending one message per chose time interval") */
/* } */
Item {
Layout.fillWidth: true
height: 8
}
}
}
footer: StatusDialogFooter {
rightButtons: ObjectModel {
StatusButton {
objectName: "deleteCommunityChannelBtn"
visible: isEdit && isDeleteable
text: qsTr("Delete channel")
type: StatusBaseButton.Type.Danger
onClicked: {
root.deleteCommunityChannel()
Item {
Layout.preferredHeight: 8
Layout.fillWidth: true
}
}
StatusButton {
objectName: "createOrEditCommunityChannelBtn"
enabled: isFormValid()
text: isEdit ?
qsTr("Save changes") :
qsTr("Create channel")
onClicked: {
if (!isFormValid()) {
scrollView.scrollBackUp()
return
}
let error = "";
let emoji = StatusQUtils.Emoji.deparse(nameInput.input.asset.emoji)
if (!isEdit) {
//scrollView.communityColor.color.toString().toUpperCase()
root.createCommunityChannel(StatusQUtils.Utils.filterXSS(nameInput.input.text),
StatusQUtils.Utils.filterXSS(descriptionTextArea.text),
emoji,
colorDialog.color.toString().toUpperCase(),
root.categoryId)
} else {
root.editCommunityChannel(StatusQUtils.Utils.filterXSS(nameInput.input.text),
StatusQUtils.Utils.filterXSS(descriptionTextArea.text),
emoji,
colorDialog.color.toString().toUpperCase(),
root.categoryId)
Item {
height: colorSelectorButton.height + 16
Layout.fillWidth: true
StatusPickerButton {
id: colorSelectorButton
property string validationError: ""
width: parent.width
bgColor: colorDialog.colorSelected ? colorDialog.color : Theme.palette.baseColor2
contentColor: colorDialog.colorSelected ? Theme.palette.white : Theme.palette.baseColor1
text: colorDialog.colorSelected ? colorDialog.color.toString().toUpperCase() : qsTr("Pick a colour")
onClicked: colorDialog.open()
onTextChanged: {
if (colorDialog.colorSelected) {
validationError = Utils.validateAndReturnError(text, communityColorValidator)
}
}
}
if (error) {
const errorJson = JSON.parse(error)
creatingError.text = errorJson.error
return creatingError.open()
StatusColorDialog {
id: colorDialog
anchors.centerIn: parent
property bool colorSelected: root.isEdit && root.channelColor
headerSettings.title: qsTr("Channel Colour")
standardColors: Theme.palette.communityColorsArray
color: root.isEdit && root.channelColor ? root.channelColor : Theme.palette.primaryColor1
onAccepted: colorSelected = true
}
// TODO Open the community once we have designs for it
root.close()
StatusBaseText {
text: colorSelectorButton.validationError
visible: !!text
color: Theme.palette.dangerColor1
anchors.top: colorSelectorButton.bottom
anchors.topMargin: 4
anchors.right: colorSelectorButton.right
}
}
StatusInput {
id: descriptionTextArea
Layout.fillWidth: true
input.edit.objectName: "createOrEditCommunityChannelDescriptionInput"
input.verticalAlignment: TextEdit.AlignTop
label: qsTr("Description")
charLimit: 140
placeholderText: qsTr("Describe the channel")
input.multiline: true
minimumHeight: 88
maximumHeight: 88
validators: [
StatusMinLengthValidator {
minLength: 1
errorMessage: Utils.getErrorMessage(descriptionTextArea.errors, qsTr("channel description"))
},
StatusRegularExpressionValidator {
regularExpression: Constants.regularExpressions.alphanumericalExpanded
errorMessage: Constants.errorMessages.alphanumericalExpandedRegExp
}
]
}
}
}
}
]
MessageDialog {
id: creatingError
title: qsTr("Error creating the community")
title: qsTr("Error creating the channel")
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
}

View File

@ -107,32 +107,28 @@ StatusStackModal {
Layout.fillWidth: true
spacing: 12
StatusBaseText {
font.pixelSize: 15
Layout.fillWidth: true
maximumLineCount: 2
wrapMode: Text.Wrap
elide: Text.ElideRight
text: fileListView.fileListModelEmpty ? qsTr("Select Discord JSON files to import") :
root.store.discordImportErrorsCount ? qsTr("Some of your community files cannot be used") :
qsTr("Uncheck any files you would like to exclude from the import")
}
StatusBaseText {
visible: fileListView.fileListModelEmpty
visible: fileListView.fileListModelEmpty && !issuePill.visible
font.pixelSize: 12
color: Theme.palette.baseColor1
text: qsTr("(JSON file format only)")
}
IssuePill {
type: root.store.discordImportErrorsCount ? IssuePill.Type.Error : IssuePill.Type.Warning
count: {
if (root.store.discordImportErrorsCount > 0) {
return root.store.discordImportErrorsCount
}
if (root.store.discordImportWarningsCount > 0) {
return root.store.discordImportWarningsCount
}
return 0
}
visible: !!count
id: issuePill
type: root.communitiesStore.discordImportErrorsCount ? IssuePill.Type.Error : IssuePill.Type.Warning
count: root.communitiesStore.discordImportErrorsCount || root.communitiesStore.discordImportWarningsCount || 0
visible: !!count && !fileListView.fileListModelEmpty
}
Item { Layout.fillWidth: true }
StatusButton {
Layout.alignment: Qt.AlignRight
text: qsTr("Browse files")
type: StatusBaseButton.Type.Primary
onClicked: fileDialog.open()
@ -160,8 +156,7 @@ StatusStackModal {
Layout.topMargin: 8
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Qt.AlignHCenter
text: qsTr("Export your Discord JSON data using %1")
.arg("<a href='https://github.com/Tyrrrz/DiscordChatExporter'>DiscordChatExporter</a>")
text: qsTr("Export your Discord JSON data using %1").arg("<a href='https://github.com/Tyrrrz/DiscordChatExporter/releases/tag/2.40.4'>DiscordChatExporter</a>")
onLinkActivated: Global.openLink(link)
HoverHandler {
id: handler1
@ -175,7 +170,7 @@ StatusStackModal {
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Qt.AlignHCenter
text: qsTr("Refer to this <a href='https://github.com/Tyrrrz/DiscordChatExporter/wiki'>wiki</a> if you have any queries")
text: qsTr("Refer to this <a href='https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Readme.md'>documentation</a> if you have any queries")
onLinkActivated: Global.openLink(link)
HoverHandler {
id: handler2

View File

@ -20,6 +20,8 @@ StatusScrollView {
property var store
property bool importingSingleChannel
signal close()
enum ImportStatus {
@ -36,9 +38,9 @@ StatusScrollView {
visible: d.status === DiscordImportProgressContents.ImportStatus.CompletedWithWarnings ||
d.status === DiscordImportProgressContents.ImportStatus.StoppedWithErrors
type: StatusButton.Danger
text: qsTr("Delete community & restart import")
text: root.importingSingleChannel ? qsTr("Delete channel & restart import") : qsTr("Delete community & restart import")
onClicked: {
// TODO display a confirmation and open CreateCommunityPopup again
// TODO display a confirmation and restart the whole flow
root.close()
}
},
@ -68,10 +70,11 @@ StatusScrollView {
StatusButton {
visible: d.status === DiscordImportProgressContents.ImportStatus.CompletedSuccessfully ||
d.status === DiscordImportProgressContents.ImportStatus.CompletedWithWarnings
text: qsTr("Visit your new community")
text: root.importingSingleChannel ? qsTr("Visit your new channel") : qsTr("Visit your new community")
onClicked: {
root.close()
root.store.setActiveCommunity(root.store.discordImportCommunityId)
if (!root.importingSingleChannel)
root.store.setActiveCommunity(root.store.discordImportCommunityId)
}
}
]
@ -85,11 +88,11 @@ StatusScrollView {
readonly property var helperInfo: {
"import.communityCreation": {
icon: "network",
text: qsTr("Setting up your community")
text: root.importingSingleChannel ? qsTr("Setting up your new channel") : qsTr("Setting up your community")
},
"import.channelsCreation": {
icon: "channel",
text: qsTr("Importing channels")
text: root.importingSingleChannel ? qsTr("Importing Discord channel") : qsTr("Importing channels")
},
"import.importMessages": {
icon: "receive",
@ -101,7 +104,7 @@ StatusScrollView {
},
"import.initializeCommunity": {
icon: "communities",
text: qsTr("Initializing community")
text: root.importingSingleChannel ? qsTr("Initializing channel") : qsTr("Initializing community")
}
}
@ -137,7 +140,7 @@ StatusScrollView {
if (importStopped)
return ""
if (progress <= 0.0)
return qsTr("Pending...")
return qsTr("Pending...")
return qsTr("Importing from file %1 of %2...").arg(currentChunk).arg(totalChunksCount)
}
@ -279,17 +282,18 @@ StatusScrollView {
text: {
switch (d.status) {
case DiscordImportProgressContents.ImportStatus.InProgress:
return qsTr("Importing %1 from Discord...").arg(root.store.discordImportCommunityName)
return qsTr("Importing %1 from Discord...").arg(root.importingSingleChannel ? root.store.discordImportChannelName : root.store.discordImportCommunityName)
case DiscordImportProgressContents.ImportStatus.Stopped:
return qsTr("Importing %1 from Discord stopped...").arg(root.store.discordImportCommunityName)
return qsTr("Importing %1 from Discord stopped...").arg(root.importingSingleChannel ? root.store.discordImportChannelName : root.store.discordImportCommunityName)
case DiscordImportProgressContents.ImportStatus.StoppedWithErrors:
return qsTr("Importing %1 stopped due to a critical issue...").arg(root.store.discordImportCommunityName)
return qsTr("Importing %1 stopped due to a critical issue...").arg(root.importingSingleChannel ? root.store.discordImportChannelName : root.store.discordImportCommunityName)
case DiscordImportProgressContents.ImportStatus.CompletedWithWarnings:
return qsTr("%1 was imported with %n issue(s).", "", root.store.discordImportWarningsCount).arg(root.store.discordImportCommunityName)
return qsTr("%1 was imported with %n issue(s).", "", root.store.discordImportWarningsCount)
.arg(root.importingSingleChannel ? root.store.discordImportChannelName : root.store.discordImportCommunityName)
case DiscordImportProgressContents.ImportStatus.CompletedSuccessfully:
return qsTr("%1 was successfully imported from Discord.").arg(root.store.discordImportCommunityName)
return qsTr("%1 was successfully imported from Discord.").arg(root.importingSingleChannel ? root.store.discordImportChannelName : root.store.discordImportCommunityName)
default:
return qsTr("Your Discord community import is in progress...")
return qsTr("Your Discord import is in progress...")
}
}
}
@ -329,7 +333,7 @@ StatusScrollView {
wrapMode: Text.WordWrap
font.pixelSize: 13
text: d.status === DiscordImportProgressContents.ImportStatus.InProgress ?
qsTr("This process can take a while. Feel free to hide this window and use Status normally in the meantime. Well notify you when the Community is ready for you.") :
qsTr("This process can take a while. Feel free to hide this window and use Status normally in the meantime. Well notify you when the %1 is ready for you.").arg(root.importingSingleChannel ? qsTr("Channel") : qsTr("Community")) :
qsTr("If there were any issues with your import you can upload new JSON files via the community page at any time.")
}
}
@ -339,13 +343,16 @@ StatusScrollView {
ConfirmationDialog {
id: cancelConfirmationPopup
headerSettings.title: qsTr("Are you sure you want to cancel the import?")
confirmationText: qsTr("Your new Status community will be deleted and all information entered will be lost.")
confirmationText: qsTr("Your new Status %1 will be deleted and all information entered will be lost.").arg(root.importingSingleChannel ? qsTr("channel") : qsTr("community"))
showCancelButton: true
cancelBtnType: "default"
confirmButtonLabel: qsTr("Delete community")
cancelButtonLabel: qsTr("Continue importing")
confirmButtonLabel: root.importingSingleChannel ? qsTr("Delete channel & cancel import") : qsTr("Delete community")
cancelButtonLabel: root.importingSingleChannel ? qsTr("Cancel") : qsTr("Continue importing")
onConfirmButtonClicked: {
root.store.requestCancelDiscordCommunityImport(root.store.discordImportCommunityId)
if (root.importingSingleChannel)
root.store.requestCancelDiscordChannelImport(root.store.discordImportChannelName)
else
root.store.requestCancelDiscordCommunityImport(root.store.discordImportCommunityId)
cancelConfirmationPopup.close()
root.close()
}

View File

@ -10,7 +10,10 @@ StatusDialog {
property var store
title: qsTr("Import a community from Discord into Status")
property bool importingSingleChannel
title: importingSingleChannel ? qsTr("Import a channel from Discord into Status") :
qsTr("Import a community from Discord into Status")
horizontalPadding: 16
verticalPadding: 20
@ -38,6 +41,7 @@ StatusDialog {
id: contents
anchors.fill: parent
store: root.store
importingSingleChannel: root.importingSingleChannel
onClose: root.close()
}
}

View File

@ -27,6 +27,8 @@ QtObject {
property int discordImportProgressCurrentChunk: root.communitiesModuleInst.discordImportProgressCurrentChunk
property string discordImportCommunityId: root.communitiesModuleInst.discordImportCommunityId
property string discordImportCommunityName: root.communitiesModuleInst.discordImportCommunityName
property string discordImportChannelId: root.communitiesModuleInst.discordImportChannelId
property string discordImportChannelName: root.communitiesModuleInst.discordImportChannelName
property url discordImportCommunityImage: root.communitiesModuleInst.discordImportCommunityImage
property bool discordImportHasCommunityImage: root.communitiesModuleInst.discordImportHasCommunityImage
property var discordImportTasks: root.communitiesModuleInst.discordImportTasks
@ -161,6 +163,7 @@ QtObject {
function removeFileListItem(filePath) {
root.communitiesModuleInst.removeFileListItem(filePath)
}
function setFileListItems(filePaths) {
root.communitiesModuleInst.setFileListItems(filePaths)
}
@ -183,12 +186,20 @@ QtObject {
function toggleDiscordChannel(id, selected) {
root.communitiesModuleInst.toggleDiscordChannel(id, selected)
}
}
function toggleOneDiscordChannel(id) {
root.communitiesModuleInst.toggleOneDiscordChannel(id)
}
function requestCancelDiscordCommunityImport(id) {
root.communitiesModuleInst.requestCancelDiscordCommunityImport(id)
}
function requestCancelDiscordChannelImport(id) {
console.warn("!!! IMPLEMENT ME requestCancelDiscordChannelImport(id)") // FIXME
}
function resetDiscordImport() {
root.communitiesModuleInst.resetDiscordImport(false)
}
@ -220,6 +231,18 @@ QtObject {
args.options.historyArchiveSupportEnabled, args.options.pinMessagesAllowedForMembers, from);
}
function requestImportDiscordChannel(args = {
discordChannelId: "",
name: "",
description: "",
color: "",
emoji: "",
options: {
// TODO
}
}, from = 0) {
console.warn("!!! IMPLEMENT ME requestImportDiscordChannel") // FIXME
}
readonly property Connections connections: Connections {
target: communitiesModuleInst

View File

@ -36,6 +36,7 @@ Item {
property var emojiPopup
property var store
property var communitiesStore
property bool hasAddedContacts: false
property var communityData
@ -173,6 +174,13 @@ Item {
onTriggered: Global.openPopup(createChannelPopup)
}
StatusAction {
objectName: "importCommunityChannelBtn"
text: qsTr("Create channel via Discord import")
icon.name: "download"
onTriggered: Global.openPopup(createChannelPopup, {isDiscordImport: true})
}
StatusAction {
objectName: "createCommunityCategoryBtn"
text: qsTr("Create category")
@ -248,6 +256,13 @@ Item {
onTriggered: Global.openPopup(createChannelPopup)
}
StatusAction {
objectName: "importCommunityChannelBtn"
text: qsTr("Create channel via Discord import")
icon.name: "download"
onTriggered: Global.openPopup(createChannelPopup, {isDiscordImport: true})
}
StatusAction {
text: qsTr("Create category")
icon.name: "channel-category"
@ -523,7 +538,7 @@ Item {
Component {
id: createChannelPopup
CreateChannelPopup {
anchors.centerIn: parent
communitiesStore: root.communitiesStore
emojiPopup: root.emojiPopup
onCreateCommunityChannel: function (chName, chDescription, chEmoji, chColor,
chCategoryId) {

View File

@ -742,15 +742,18 @@ Item {
readonly property int warnings: appMain.communitiesStore.discordImportWarningsCount
readonly property string communityId: appMain.communitiesStore.discordImportCommunityId
readonly property string communityName: appMain.communitiesStore.discordImportCommunityName
readonly property string channelId: appMain.communitiesStore.discordImportChannelId
readonly property string channelName: appMain.communitiesStore.discordImportChannelName
readonly property string channelOrCommunityName: channelName || communityName
active: !cancelled && (inProgress || finished || stopped)
type: errors ? ModuleWarning.Type.Danger : ModuleWarning.Type.Success
text: {
if (finished || stopped) {
if (errors)
return qsTr("The import of %1 from Discord to Status was stopped: <a href='#'>Critical issues found</a>").arg(communityName)
return qsTr("The import of %1 from Discord to Status was stopped: <a href='#'>Critical issues found</a>").arg(channelOrCommunityName)
let result = qsTr("%1 was successfully imported from Discord to Status").arg(communityName) + " <a href='#'>"
let result = qsTr("%1 was successfully imported from Discord to Status").arg(channelOrCommunityName) + " <a href='#'>"
if (warnings)
result += qsTr("Details (%1)").arg(qsTr("%n issue(s)", "", warnings))
else
@ -759,7 +762,7 @@ Item {
return result
}
if (inProgress) {
let result = qsTr("Importing %1 from Discord to Status").arg(communityName) + " <a href='#'>"
let result = qsTr("Importing %1 from Discord to Status").arg(channelOrCommunityName) + " <a href='#'>"
if (warnings)
result += qsTr("Check progress (%1)").arg(qsTr("%n issue(s)", "", warnings))
else
@ -770,16 +773,17 @@ Item {
return ""
}
onLinkActivated: popups.openDiscordImportProgressPopup()
onLinkActivated: popups.openDiscordImportProgressPopup(!!channelId)
progressValue: progress
closeBtnVisible: finished || stopped
buttonText: finished && !errors ? qsTr("Visit your Community") : ""
buttonText: finished && !errors ? !!channelId ? qsTr("Visit your new channel") : qsTr("Visit your Community") : ""
onClicked: function() {
appMain.communitiesStore.setActiveCommunity(communityId)
}
onCloseClicked: {
hide();
if (!!channelId)
rootStore.setActiveSectionChat(communityId, channelId)
else
appMain.communitiesStore.setActiveCommunity(communityId)
}
onCloseClicked: hide()
}
ModuleWarning {
@ -1247,6 +1251,7 @@ Item {
stickersPopup: statusStickersPopupLoader.item
sectionItemModel: model
createChatPropertiesStore: appMain.createChatPropertiesStore
communitiesStore: appMain.communitiesStore
communitySettingsDisabled: production && appMain.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled
rootStore: ChatStores.RootStore {

View File

@ -244,8 +244,8 @@ QtObject {
openPopup(editSharedAddressesPopupComponent, {communityId: communityId, isEditMode: true})
}
function openDiscordImportProgressPopup() {
openPopup(discordImportProgressDialog)
function openDiscordImportProgressPopup(importingSingleChannel) {
openPopup(discordImportProgressDialog, {importingSingleChannel: importingSingleChannel})
}
function openRemoveContactConfirmationPopup(displayName, publicKey) {