feat(Communities): implement drag and drop to reorder category channels

Closes: #2776
This commit is contained in:
B.Melnik 2021-07-28 15:40:51 +03:00 committed by Pascal Precht
parent 6561e0ea26
commit a362efecf4
11 changed files with 89 additions and 8 deletions

View File

@ -1,4 +1,5 @@
import NimQml, Tables import NimQml, Tables
import algorithm
import ../../../status/chat/[chat, message] import ../../../status/chat/[chat, message]
import ../../../status/status import ../../../status/status
import ../../../status/accounts import ../../../status/accounts
@ -19,6 +20,7 @@ type
Id = UserRole + 11 Id = UserRole + 11
Description = UserRole + 12 Description = UserRole + 12
CategoryId = UserRole + 13 CategoryId = UserRole + 13
Position = UserRole + 14
QtObject: QtObject:
type type
@ -65,6 +67,7 @@ QtObject:
of ChannelsRoles.Id: result = newQVariant($chatItem.id) of ChannelsRoles.Id: result = newQVariant($chatItem.id)
of ChannelsRoles.CategoryId: result = newQVariant(chatItem.categoryId) of ChannelsRoles.CategoryId: result = newQVariant(chatItem.categoryId)
of ChannelsRoles.Description: result = newQVariant(chatItem.description) of ChannelsRoles.Description: result = newQVariant(chatItem.description)
of ChannelsRoles.Position: result = newQVariant(chatItem.position)
method roleNames(self: ChannelsList): Table[int, string] = method roleNames(self: ChannelsList): Table[int, string] =
{ {
@ -80,12 +83,20 @@ QtObject:
ChannelsRoles.Muted.int: "muted", ChannelsRoles.Muted.int: "muted",
ChannelsRoles.Id.int: "id", ChannelsRoles.Id.int: "id",
ChannelsRoles.Description.int: "description", ChannelsRoles.Description.int: "description",
ChannelsRoles.CategoryId.int: "categoryId" ChannelsRoles.CategoryId.int: "categoryId",
ChannelsRoles.Position.int: "position"
}.toTable }.toTable
proc sortChats(x, y: Chat): int =
if x.position < y.position: -1
elif x.position == y.position: 0
else: 1
proc setChats*(self: ChannelsList, chats: seq[Chat]) = proc setChats*(self: ChannelsList, chats: seq[Chat]) =
self.beginResetModel() self.beginResetModel()
self.chats = chats var copy = chats
copy.sort(sortChats)
self.chats = copy
self.endResetModel() self.endResetModel()
proc addChatItemToList*(self: ChannelsList, channel: Chat): int = proc addChatItemToList*(self: ChannelsList, channel: Chat): int =
@ -165,7 +176,19 @@ QtObject:
self.chats[idx] = channel self.chats[idx] = channel
self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.Description.int, ChannelsRoles.ContentType.int, ChannelsRoles.LastMessage.int, ChannelsRoles.Timestamp.int, ChannelsRoles.UnreadMessages.int, ChannelsRoles.Identicon.int, ChannelsRoles.ChatType.int, ChannelsRoles.Color.int, ChannelsRoles.MentionsCount.int, ChannelsRoles.Muted.int]) self.dataChanged(topLeft, bottomRight,
@[ChannelsRoles.Name.int,
ChannelsRoles.Description.int,
ChannelsRoles.ContentType.int,
ChannelsRoles.LastMessage.int,
ChannelsRoles.Timestamp.int,
ChannelsRoles.UnreadMessages.int,
ChannelsRoles.Identicon.int,
ChannelsRoles.ChatType.int,
ChannelsRoles.Color.int,
ChannelsRoles.MentionsCount.int,
ChannelsRoles.Muted.int,
ChannelsRoles.Position.int])
proc clearUnreadMessages*(self: ChannelsList, channelId: string) = proc clearUnreadMessages*(self: ChannelsList, channelId: string) =
let idx = self.chats.findIndexById(channelId) let idx = self.chats.findIndexById(channelId)

View File

@ -186,6 +186,13 @@ QtObject:
read = muted read = muted
notify = mutedChanged notify = mutedChanged
proc position*(self: ChatItemView): int {.slot.} = result = ?.self.chatItem.position
proc positionChanged*(self: ChatItemView) {.signal.}
QtProperty[int] position:
read = position
notify = positionChanged
proc contains*(self: ChatItemView, pubKey: string): bool {.slot.} = proc contains*(self: ChatItemView, pubKey: string): bool {.slot.} =
if self.chatItem.isNil: return false if self.chatItem.isNil: return false
return self.chatItem.contains(pubKey) return self.chatItem.contains(pubKey)

View File

@ -23,6 +23,7 @@ proc mergeChat(community: var Community, chat: Chat): bool =
if (c.id == chat.id): if (c.id == chat.id):
chat.canPost = community.chats[i].canPost chat.canPost = community.chats[i].canPost
chat.categoryId = community.chats[i].categoryId chat.categoryId = community.chats[i].categoryId
chat.position = community.chats[i].position
community.chats[i] = chat community.chats[i] = chat
return true return true
@ -342,6 +343,24 @@ QtObject:
error "Error creating the category", msg = e.msg error "Error creating the category", msg = e.msg
result = fmt"Error creating the category: {e.msg}" result = fmt"Error creating the category: {e.msg}"
proc reorderCommunityCategory*(self: CommunitiesView, communityId: string, categoryId: string, position: int): string {.slot} =
result = ""
try:
self.status.chat.reorderCommunityCategory(communityId, categoryId, position)
except Exception as e:
error "Error reorder the category", msg = e.msg
result = fmt"Error reorder the category: {e.msg}"
proc reorderCommunityChannel*(self: CommunitiesView, communityId: string, categoryId: string, chatId: string, position: int): string {.slot} =
result = ""
try:
self.status.chat.reorderCommunityChannel(communityId, categoryId, chatId, position)
except Exception as e:
error "Error reorder the channel", msg = e.msg
result = fmt"Error reorder the channel: {e.msg}"
proc setObservedCommunity*(self: CommunitiesView, communityId: string) {.slot.} = proc setObservedCommunity*(self: CommunitiesView, communityId: string) {.slot.} =
if(communityId == ""): return if(communityId == ""): return
var community = self.communityList.getCommunityById(communityId) var community = self.communityList.getCommunityById(communityId)

View File

@ -486,6 +486,9 @@ QtObject:
proc deleteCommunityChat*(self: ChatModel, communityId: string, channelId: string) = proc deleteCommunityChat*(self: ChatModel, communityId: string, channelId: string) =
status_chat.deleteCommunityChat(communityId, channelId) status_chat.deleteCommunityChat(communityId, channelId)
proc reorderCommunityCategory*(self: ChatModel, communityId: string, categoryId: string, position: int) =
status_chat.reorderCommunityCategory(communityId, categoryId, position)
proc createCommunityCategory*(self: ChatModel, communityId: string, name: string, channels: seq[string]): CommunityCategory = proc createCommunityCategory*(self: ChatModel, communityId: string, name: string, channels: seq[string]): CommunityCategory =
result = status_chat.createCommunityCategory(communityId, name, channels) result = status_chat.createCommunityCategory(communityId, name, channels)

View File

@ -88,6 +88,7 @@ type Chat* = ref object
muted*: bool muted*: bool
canPost*: bool canPost*: bool
ensName*: string ensName*: string
position*: int
type RemovedMessage* = object type RemovedMessage* = object
chatId*: string chatId*: string
@ -180,7 +181,8 @@ proc toJsonNode*(self: Chat): JsonNode =
"name": (if self.ensName != "": self.ensName else: self.name), "name": (if self.ensName != "": self.ensName else: self.name),
"timestamp": self.timestamp, "timestamp": self.timestamp,
"unviewedMessagesCount": self.unviewedMessagesCount, "unviewedMessagesCount": self.unviewedMessagesCount,
"joined": self.joined "joined": self.joined,
"position": self.position
} }
proc findIndexById*(self: seq[Chat], id: string): int = proc findIndexById*(self: seq[Chat], id: string): int =

View File

@ -425,6 +425,17 @@ proc reorderCommunityChat*(communityId: string, categoryId: string, chatId: stri
if rpcResult.contains("error"): if rpcResult.contains("error"):
raise newException(StatusGoException, rpcResult["error"]["message"].getStr()) raise newException(StatusGoException, rpcResult["error"]["message"].getStr())
proc reorderCommunityCategory*(communityId: string, categoryId: string, position: int) =
let rpcResult = callPrivateRPC("reorderCommunityCategory".prefix, %*[
{
"communityId": communityId,
"categoryId": categoryId,
"position": position
}]).parseJSON()
if rpcResult.contains("error"):
raise newException(StatusGoException, rpcResult["error"]["message"].getStr())
proc deleteCommunityCategory*(communityId: string, categoryId: string) = proc deleteCommunityCategory*(communityId: string, categoryId: string) =
let rpcResult = callPrivateRPC("deleteCommunityCategory".prefix, %*[ let rpcResult = callPrivateRPC("deleteCommunityCategory".prefix, %*[
{ {

View File

@ -259,7 +259,8 @@ proc toCommunity*(jsonCommunity: JsonNode): Community =
description: chat{"description"}.getStr, description: chat{"description"}.getStr,
canPost: chat{"canPost"}.getBool, canPost: chat{"canPost"}.getBool,
chatType: ChatType.CommunityChat, chatType: ChatType.CommunityChat,
private: chat{"permissions"}{"private"}.getBool private: chat{"permissions"}{"private"}.getBool,
position: chat{"position"}.getInt
)) ))
if jsonCommunity.hasKey("categories") and jsonCommunity["categories"].kind != JNull: if jsonCommunity.hasKey("categories") and jsonCommunity["categories"].kind != JNull:

View File

@ -124,7 +124,9 @@ Item {
return implicitHeight return implicitHeight
} }
draggableItems: true
chatList.model: chatsModel.communities.activeCommunity.chats chatList.model: chatsModel.communities.activeCommunity.chats
categoryList.model: chatsModel.communities.activeCommunity.categories categoryList.model: chatsModel.communities.activeCommunity.categories
showCategoryActionButtons: chatsModel.communities.activeCommunity.admin showCategoryActionButtons: chatsModel.communities.activeCommunity.admin
@ -133,6 +135,10 @@ Item {
onChatItemSelected: chatsModel.channelView.setActiveChannel(id) onChatItemSelected: chatsModel.channelView.setActiveChannel(id)
onChatItemUnmuted: chatsModel.channelView.unmuteChatItem(id) onChatItemUnmuted: chatsModel.channelView.unmuteChatItem(id)
onChatItemReordered: function (categoryId, chatId, from, to) {
chatsModel.communities.reorderCommunityChannel(chatsModel.communities.activeCommunity.id, categoryId, chatId, to);
}
onCategoryAddButtonClicked: openPopup(createChannelPopup, { onCategoryAddButtonClicked: openPopup(createChannelPopup, {
communityId: chatsModel.communities.activeCommunity.id, communityId: chatsModel.communities.activeCommunity.id,
categoryId: id categoryId: id

View File

@ -299,7 +299,7 @@ StatusWindow {
property alias droppedUrls: rptDraggedPreviews.model property alias droppedUrls: rptDraggedPreviews.model
readonly property int chatView: Utils.getAppSectionIndex(Constants.chat) readonly property int chatView: Utils.getAppSectionIndex(Constants.chat)
readonly property int timelineView: Utils.getAppSectionIndex(Constants.timeline) readonly property int timelineView: Utils.getAppSectionIndex(Constants.timeline)
property bool enabled: containsDrag && loader.item && property bool enabled: containsDrag && drag.source.objectName !== "chatItem" && loader.item &&
( (
// in chat view // in chat view
(loader.item.currentView === chatView && (loader.item.currentView === chatView &&
@ -326,10 +326,17 @@ StatusWindow {
onDropped: (drop) => { onDropped: (drop) => {
if (enabled) { if (enabled) {
droppedOnValidScreen(drop) droppedOnValidScreen(drop)
} else {
drop.accepted = false
} }
cleanup() cleanup()
} }
onEntered: { onEntered: {
if (!enabled) {
drag.accepted = false
return
}
// needed because drag.urls is not a normal js array // needed because drag.urls is not a normal js array
rptDraggedPreviews.model = drag.urls.filter(img => Utils.hasDragNDropImageExtension(img)) rptDraggedPreviews.model = drag.urls.filter(img => Utils.hasDragNDropImageExtension(img))
} }

View File

@ -430,3 +430,5 @@ DISTFILES += \
shared/status/StatusRadioButtonRow.qml \ shared/status/StatusRadioButtonRow.qml \
shared/status/StatusSettingsLineButton.qml \ shared/status/StatusSettingsLineButton.qml \
sounds/ErrorSound.qml sounds/ErrorSound.qml
DISTFILES += $$files("StatusQ/*", true)

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 20363e32ef96d4b5631ef4dd375bdb65252e6416 Subproject commit fe086b2fdd998dca50223e4da084eccfc5ab9555