feat(Communities): implement drag and drop to reorder category channels
Closes: #2776
This commit is contained in:
parent
6561e0ea26
commit
a362efecf4
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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, %*[
|
||||||
{
|
{
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 20363e32ef96d4b5631ef4dd375bdb65252e6416
|
Subproject commit fe086b2fdd998dca50223e4da084eccfc5ab9555
|
Loading…
Reference in New Issue