feat: create community categories

This commit is contained in:
Richard Ramos 2021-05-16 11:16:42 -04:00 committed by Iuri Matias
parent a79400e023
commit 0ded790f0d
22 changed files with 689 additions and 9 deletions

View File

@ -0,0 +1,70 @@
import NimQml, Tables
import ../../../status/chat/[chat, message]
import ../../../status/status
import ../../../status/ens
import ../../../status/accounts
import strutils
type
CategoryRoles {.pure.} = enum
Id = UserRole + 1
Name = UserRole + 2
Position = UserRole + 3
QtObject:
type
CategoryList* = ref object of QAbstractListModel
categories*: seq[CommunityCategory]
status: Status
proc setup(self: CategoryList) = self.QAbstractListModel.setup
proc delete(self: CategoryList) =
self.categories = @[]
self.QAbstractListModel.delete
proc newCategoryList*(status: Status): CategoryList =
new(result, delete)
result.categories = @[]
result.status = status
result.setup()
method rowCount*(self: CategoryList, index: QModelIndex = nil): int = self.categories.len
method data(self: CategoryList, index: QModelIndex, role: int): QVariant =
if not index.isValid:
return
if index.row < 0 or index.row >= self.categories.len:
return
let catItem = self.categories[index.row]
let catItemRole = role.CategoryRoles
case catItemRole:
of CategoryRoles.Id: result = newQVariant(catItem.id)
of CategoryRoles.Name: result = newQVariant(catItem.name)
of CategoryRoles.Position: result = newQVariant(catItem.position)
method roleNames(self: CategoryList): Table[int, string] =
{
CategoryRoles.Name.int:"name",
CategoryRoles.Position.int:"position",
CategoryRoles.Id.int: "categoryId"
}.toTable
proc setCategories*(self: CategoryList, categories: seq[CommunityCategory]) =
self.beginResetModel()
self.categories = categories
self.endResetModel()
proc addCategoryToList*(self: CategoryList, category: CommunityCategory): int =
self.beginInsertRows(newQModelIndex(), 0, 0)
self.categories.insert(category, 0)
self.endInsertRows()
result = self.categories.len
proc removeCategoryFromList*(self: CategoryList, categoryId: string): int =
let idx = self.categories.findIndexById(categoryId)
if idx == -1: return
self.beginRemoveRows(newQModelIndex(), idx, idx)
self.categories.delete(idx)
self.endRemoveRows()
result = self.categories.len

View File

@ -19,6 +19,7 @@ type
Muted = UserRole + 10
Id = UserRole + 11
Description = UserRole + 12
CategoryId = UserRole + 13
QtObject:
type
@ -76,6 +77,7 @@ QtObject:
of ChannelsRoles.HasMentions: result = newQVariant(chatItem.hasMentions)
of ChannelsRoles.Muted: result = newQVariant(chatItem.muted.bool)
of ChannelsRoles.Id: result = newQVariant($chatItem.id)
of ChannelsRoles.CategoryId: result = newQVariant(chatItem.categoryId)
of ChannelsRoles.Description: result = newQVariant(chatItem.description)
method roleNames(self: ChannelsList): Table[int, string] =
@ -91,7 +93,8 @@ QtObject:
ChannelsRoles.ContentType.int: "contentType",
ChannelsRoles.Muted.int: "muted",
ChannelsRoles.Id.int: "id",
ChannelsRoles.Description.int: "description"
ChannelsRoles.Description.int: "description",
ChannelsRoles.CategoryId.int: "categoryId"
}.toTable
proc setChats*(self: ChannelsList, chats: seq[Chat]) =

View File

@ -54,8 +54,9 @@ QtObject:
var found = false
for chat in community.chats:
if (chat.id == newChat.id):
# canPost is not available in the newChat so we need to check what we had before
# canPost and categoryId are not available in the newChat so we need to check what we had before
newChat.canPost = community.chats[i].canPost
newChat.categoryId = community.chats[i].categoryId
community.chats[i] = newChat
found = true
i = i + 1
@ -225,7 +226,7 @@ QtObject:
error "Error creating the community", msg = e.msg
result = fmt"Error creating the community: {e.msg}"
proc createCommunityChannel*(self: CommunitiesView, communityId: string, name: string, description: string): string {.slot.} =
proc createCommunityChannel*(self: CommunitiesView, communityId: string, name: string, description: string, categoryId: string): string {.slot.} =
result = ""
try:
let chat = self.status.chat.createCommunityChannel(communityId, name, description)
@ -233,12 +234,38 @@ QtObject:
if (chat.id == ""):
return "Chat was not created. Please try again later"
if categoryId != "":
self.status.chat.reorderCommunityChannel(communityId, categoryId, chat.id.replace(communityId, ""), 0)
chat.categoryId = categoryId
self.joinedCommunityList.addChannelToCommunity(communityId, chat)
self.activeCommunity.addChatItemToList(chat)
except Exception as e:
error "Error creating the channel", msg = e.msg
result = fmt"Error creating the channel: {e.msg}"
proc createCommunityCategory*(self: CommunitiesView, communityId: string, name: string, channels: string): string {.slot.} =
result = ""
try:
let channelSeq = map(parseJson(channels).getElems(), proc(x:JsonNode):string = x.getStr().replace(communityId, ""))
let category = self.status.chat.createCommunityCategory(communityId, name, channelSeq)
self.joinedCommunityList.addCategoryToCommunity(communityId, category)
self.activeCommunity.addCategoryToList(category)
except Exception as e:
error "Error creating the category", msg = e.msg
result = fmt"Error creating the category: {e.msg}"
proc deleteCommunityCategory*(self: CommunitiesView, communityId: string, categoryId: string): string {.slot.} =
result = ""
try:
self.status.chat.deleteCommunityCategory(communityId, categoryId)
self.joinedCommunityList.removeCategoryFromCommunity(communityId, categoryId)
self.activeCommunity.removeCategoryFromList(categoryId)
except Exception as e:
error "Error creating the category", msg = e.msg
result = fmt"Error creating the category: {e.msg}"
proc observedCommunityChanged*(self: CommunitiesView) {.signal.}
proc setObservedCommunity*(self: CommunitiesView, communityId: string) {.slot.} =

View File

@ -3,6 +3,7 @@ import ../../../status/[chat/chat, status]
import channels_list
import ../../../eventemitter
import community_members_list
import category_list
import community_membership_request_list
QtObject:
@ -10,6 +11,7 @@ QtObject:
communityItem*: Community
communityMembershipRequestList*: CommunityMembershipRequestList
chats*: ChannelsList
categories*: CategoryList
members*: CommunityMembersView
status*: Status
active*: bool
@ -19,6 +21,7 @@ QtObject:
proc delete*(self: CommunityItemView) =
if not self.chats.isNil: self.chats.delete
if not self.categories.isNil: self.categories.delete
self.QObject.delete
proc newCommunityItemView*(status: Status): CommunityItemView =
@ -27,6 +30,7 @@ QtObject:
result.status = status
result.active = false
result.chats = newChannelsList(status)
result.categories = newCategoryList(status)
result.communityMembershipRequestList = newCommunityMembershipRequestList()
result.members = newCommunityMembersView(status)
result.setup
@ -36,6 +40,7 @@ QtObject:
proc setCommunityItem*(self: CommunityItemView, communityItem: Community) =
self.communityItem = communityItem
self.chats.setChats(communityItem.chats)
self.categories.setCategories(communityItem.categories)
self.members.setMembers(communityItem.members)
self.nbMembersChanged()
self.communityMembershipRequestList.setNewData(communityItem.membershipRequests)
@ -135,6 +140,9 @@ QtObject:
proc getChats*(self: CommunityItemView): QVariant {.slot.} =
result = newQVariant(self.chats)
proc getCategories*(self: CommunityItemView): QVariant {.slot.} =
result = newQVariant(self.categories)
proc changeChats*(self: CommunityItemView, chats: seq[Chat]) =
self.communityItem.chats = chats
self.chats.setChats(chats)
@ -145,10 +153,26 @@ QtObject:
discard self.chats.addChatItemToList(chat)
self.chatsChanged()
proc addCategoryToList*(self: CommunityItemView, category: CommunityCategory) =
self.communityItem.categories.add(category)
discard self.categories.addCategoryToList(category)
self.chatsChanged()
proc removeCategoryFromList*(self: CommunityItemView, categoryId: string) =
discard self.categories.removeCategoryFromList(categoryId)
let idx = self.communityItem.categories.findIndexById(categoryId)
self.chatsChanged()
if idx == -1: return
self.communityItem.categories.delete(idx)
QtProperty[QVariant] chats:
read = getChats
notify = chatsChanged
QtProperty[QVariant] categories:
read = getCategories
notify = chatsChanged
proc getMembers*(self: CommunityItemView): QVariant {.slot.} =
result = newQVariant(self.members)

View File

@ -129,6 +129,13 @@ QtObject:
let index = self.communities.findIndexById(communityId)
self.communities[index] = community
proc addCategoryToCommunity*(self: CommunityList, communityId: string, category: CommunityCategory) =
var community = self.getCommunityById(communityId)
community.categories.add(category)
let index = self.communities.findIndexById(communityId)
self.communities[index] = community
proc replaceCommunity*(self: CommunityList, community: Community) =
let index = self.communities.findIndexById(community.id)
if (index == -1):
@ -136,4 +143,12 @@ QtObject:
let topLeft = self.createIndex(index, index, nil)
let bottomRight = self.createIndex(index, index, nil)
self.communities[index] = community
self.dataChanged(topLeft, bottomRight, @[CommunityRoles.Name.int, CommunityRoles.Description.int, CommunityRoles.UnviewedMessagesCount.int])
self.dataChanged(topLeft, bottomRight, @[CommunityRoles.Name.int, CommunityRoles.Description.int, CommunityRoles.UnviewedMessagesCount.int])
proc removeCategoryFromCommunity*(self: CommunityList, communityId: string, categoryId:string) =
var community = self.getCommunityById(communityId)
let idx = community.categories.findIndexById(categoryId)
if idx == -1: return
community.categories.delete(idx)
let index = self.communities.findIndexById(communityId)
self.communities[index] = community

View File

@ -447,6 +447,15 @@ proc createCommunity*(self: ChatModel, name: string, description: string, access
proc createCommunityChannel*(self: ChatModel, communityId: string, name: string, description: string): Chat =
result = status_chat.createCommunityChannel(communityId, name, description)
proc createCommunityCategory*(self: ChatModel, communityId: string, name: string, channels: seq[string]): CommunityCategory =
result = status_chat.createCommunityCategory(communityId, name, channels)
proc deleteCommunityCategory*(self: ChatModel, communityId: string, categoryId: string) =
status_chat.deleteCommunityCategory(communityId, categoryId)
proc reorderCommunityChannel*(self: ChatModel, communityId: string, categoryId: string, chatId: string, position: int) =
status_chat.reorderCommunityChat(communityId, categoryId, chatId, position)
proc joinCommunity*(self: ChatModel, communityId: string) =
status_chat.joinCommunity(communityId)

View File

@ -60,6 +60,7 @@ proc toJsonNode*(self: seq[ChatMembershipEvent]): seq[JsonNode] =
type Chat* = ref object
id*: string # ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one is the hex encoded public key and for group chats is a random uuid appended with the hex encoded pk of the creator of the chat
communityId*: string
categoryId*: string
name*: string
description*: string
color*: string
@ -93,12 +94,18 @@ type CommunityMembershipRequest* = object
state*: int
our*: string
type CommunityCategory* = object
id*: string
name*: string
position*: int
type Community* = object
id*: string
name*: string
lastChannelSeen*: string
description*: string
chats*: seq[Chat]
categories*: seq[CommunityCategory]
members*: seq[string]
access*: int
unviewedMessagesCount*: int
@ -164,6 +171,15 @@ proc findIndexById*(self: seq[CommunityMembershipRequest], id: string): int =
result = idx
break
proc findIndexById*(self: seq[CommunityCategory], id: string): int =
result = -1
var idx = -1
for item in self:
inc idx
if(item.id == id):
result = idx
break
proc isMember*(self: Chat, pubKey: string): bool =
for member in self.members:
if member.id == pubKey and member.joined: return true

View File

@ -332,6 +332,42 @@ proc createCommunityChannel*(communityId: string, name: string, description: str
if rpcResult{"result"}.kind != JNull:
result = rpcResult["result"]["chats"][0].toChat()
proc createCommunityCategory*(communityId: string, name: string, channels: seq[string]): CommunityCategory =
let rpcResult = callPrivateRPC("createCommunityCategory".prefix, %*[
{
"communityId": communityId,
"categoryName": name,
"chatIds": channels
}]).parseJSON()
if rpcResult.contains("error"):
raise newException(StatusGoException, rpcResult["error"]["message"].getStr())
else:
for k, v in rpcResult["result"]["communityChanges"].getElems()[0]["categoriesAdded"].pairs():
result.id = v["category_id"].getStr()
result.name = v["name"].getStr()
result.position = v{"position"}.getInt()
proc reorderCommunityChat*(communityId: string, categoryId: string, chatId: string, position: int) =
let rpcResult = callPrivateRPC("reorderCommunityChat".prefix, %*[
{
"communityId": communityId,
"categoryId": categoryId,
"chatId": chatId,
"position": position
}]).parseJSON()
if rpcResult.contains("error"):
raise newException(StatusGoException, rpcResult["error"]["message"].getStr())
proc deleteCommunityCategory*(communityId: string, categoryId: string) =
let rpcResult = callPrivateRPC("deleteCommunityCategory".prefix, %*[
{
"communityId": communityId,
"categoryId": categoryId
}]).parseJSON()
if rpcResult.contains("error"):
raise newException(StatusGoException, rpcResult["error"]["message"].getStr())
proc requestCommunityInfo*(communityId: string) =
discard callPrivateRPC("requestCommunityInfoFromMailserver".prefix, %*[communityId])

View File

@ -201,6 +201,7 @@ proc toCommunity*(jsonCommunity: JsonNode): Community =
for chatId, chat in jsonCommunity{"chats"}:
result.chats.add(Chat(
id: result.id & chatId,
categoryId: chat{"categoryID"}.getStr(),
communityId: result.id,
name: chat{"name"}.getStr,
canPost: chat{"canPost"}.getBool,
@ -209,6 +210,14 @@ proc toCommunity*(jsonCommunity: JsonNode): Community =
#chat{"permissions"}{"access"}.getInt,
))
if jsonCommunity.hasKey("categories") and jsonCommunity["categories"].kind != JNull:
for catId, cat in jsonCommunity{"categories"}:
result.categories.add(CommunityCategory(
id: catId,
name: cat{"name"}.getStr,
position: cat{"position"}.getInt
))
if jsonCommunity.hasKey("members") and jsonCommunity["members"].kind != JNull:
# memberInfo is empty for now
for memberPubKey, memeberInfo in jsonCommunity{"members"}:

View File

@ -26,6 +26,15 @@ Rectangle {
}
}
Component {
id: createCategoryPopup
CreateCategoryPopup {
onClosed: {
destroy()
}
}
}
Component {
id: transferOwnershipPopup
TransferOwnershipPopup {}
@ -82,6 +91,17 @@ Rectangle {
onTriggered: openPopup(createChannelPopup, {communityId: chatsModel.communities.activeCommunity.id})
}
Action {
enabled: chatsModel.communities.activeCommunity.admin
text: qsTr("Create category")
icon.source: "../../img/create-category.svg"
icon.width: 20
icon.height: 20
onTriggered: openPopup(createCategoryPopup, {communityId: chatsModel.communities.activeCommunity.id})
}
Separator {}
Action {
text: qsTr("Invite People")
enabled: chatsModel.communities.activeCommunity.canManageUsers
@ -152,21 +172,28 @@ Rectangle {
leftPadding: Style.current.halfPadding
rightPadding: Style.current.halfPadding
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
contentHeight: channelList.height + emptyViewAndSuggestionsLoader.height + backUpBannerLoader.height + 2 * Style.current.padding
contentHeight: categoryList.height + channelList.height + emptyViewAndSuggestionsLoader.height + backUpBannerLoader.height + 2 * Style.current.padding
clip: true
ChannelList {
id: channelList
searchStr: ""
categoryId: ""
channelModel: chatsModel.communities.activeCommunity.chats
}
CategoryList {
id: categoryList
anchors.top: channelList.bottom
categoryModel: chatsModel.communities.activeCommunity.categories
}
Loader {
id: emptyViewAndSuggestionsLoader
active: chatsModel.communities.activeCommunity.admin && !appSettings.hiddenCommunityWelcomeBanners.includes(chatsModel.communities.activeCommunity.id)
width: parent.width
height: active ? item.height : 0
anchors.top: channelList.bottom
anchors.top: categoryList.bottom
anchors.topMargin: active ? Style.current.padding : 0
sourceComponent: Component {
CommunityWelcomeBanner {}

View File

@ -0,0 +1,193 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import "../../../../shared"
import "../../../../shared/status"
import "../../../../imports"
import "../components"
import "./"
import "../ContactsColumn"
import "../CommunityComponents"
import QtQuick.Dialogs 1.2
Column {
id: categoryListContent
property var categoryModel
property string categoryToDelete: ""
height: childrenRect.height
width: parent.width
spacing: 2
Repeater {
model: categoryListContent.categoryModel
delegate: Item {
id: wrapper
property bool showCategory: true
property color color: {
if (hhandler.hovered) {
return Style.current.menuBackgroundHover
}
return Style.current.transparent
}
height: showCategory ? categoryHeader.height + channelList.height : categoryHeader.height
width: categoryListContent.width
Rectangle {
id: categoryHeader
color: wrapper.color
radius: 8
height: 40
width: categoryListContent.width
StyledText {
text: model.name
elide: Text.ElideRight
color: Style.current.textColor
font.weight: Font.Medium
font.pixelSize: 15
anchors.left: parent.left
anchors.leftMargin: Style.current.halfPadding
anchors.verticalCenter: parent.verticalCenter
}
StatusIconButton {
visible: hhandler.hovered && chatsModel.communities.activeCommunity.admin
id: addBtn
icon.name: "add-category"
width: 20
height: 20
anchors.right: moreBtn.left
anchors.rightMargin: Style.current.halfPadding
anchors.verticalCenter: parent.verticalCenter
iconColor: Style.current.textColor
highlightedIconColor: Style.current.textColor
hoveredIconColor: Style.current.textColor
highlightedBackgroundColor: Style.current.menuBackgroundHover
onClicked: {
openPopup(createChannelPopup, {communityId: chatsModel.communities.activeCommunity.id, categoryId: model.categoryId})
}
StatusToolTip {
visible: addBtn.hovered
text: qsTr("Add channel inside category")
}
}
StatusIconButton {
visible: hhandler.hovered
id: moreBtn
icon.name: "more"
width: 20
height: 20
anchors.right: showBtn.left
anchors.rightMargin: Style.current.halfPadding
anchors.verticalCenter: parent.verticalCenter
iconColor: Style.current.textColor
highlightedIconColor: Style.current.textColor
hoveredIconColor: Style.current.textColor
highlightedBackgroundColor: Style.current.menuBackgroundHover
onClicked: contextMenu.popup()
StatusToolTip {
visible: moreBtn.hovered
text: qsTr("More")
}
PopupMenu {
id: contextMenu
Action {
enabled: chatsModel.communities.activeCommunity.admin
text: qsTr("Edit category")
icon.source: "../../../img/edit.svg"
icon.width: 20
icon.height: 20
}
Separator {
visible: chatsModel.communities.activeCommunity.admin
}
Action {
text: qsTr("Delete category")
enabled: chatsModel.communities.activeCommunity.admin
icon.source: "../../../img/delete.svg"
icon.color: Style.current.red
icon.width: 20
icon.height: 20
onTriggered: {
categoryToDelete = model.categoryId
openPopup(deleteCategoryConfirmationDialogComponent, {
title: qsTr("Delete %1 category").arg(model.name),
confirmationText: qsTr("Are you sure you want to delete %1 category? Channels inside the category wont be deleted.").arg(model.name)
})
}
}
}
}
StatusIconButton {
visible: hhandler.hovered
id: showBtn
icon.name: showCategory ? "hide-category" : "show-category"
width: 20
height: 20
anchors.right: parent.right
anchors.rightMargin: Style.current.halfPadding
anchors.verticalCenter: parent.verticalCenter
iconColor: Style.current.textColor
highlightedIconColor: Style.current.textColor
hoveredIconColor: Style.current.textColor
highlightedBackgroundColor: Style.current.menuBackgroundHover
onClicked: {
showCategory = !showCategory
}
}
HoverHandler {
id: hhandler
}
}
ChannelList {
id: channelList
searchStr: ""
categoryId: model.categoryId
visible: showCategory
height: showCategory ? channelList.childrenRect.height : 0
anchors.top: categoryHeader.bottom
width: categoryListContent.width
channelModel: chatsModel.communities.activeCommunity.chats
}
MessageDialog {
id: deleteError
title: qsTr("Error deleting the category")
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
Component {
id: deleteCategoryConfirmationDialogComponent
ConfirmationDialog {
btnType: "warn"
height: 216
showCancelButton: true
onClosed: {
destroy()
}
onCancelButtonClicked: {
close();
}
onConfirmButtonClicked: function(){
const error = chatsModel.communities.deleteCommunityCategory(chatsModel.communities.activeCommunity.id, categoryToDelete)
if (error) {
creatingError.text = error
return creatingError.open()
}
close();
}
}
}
}
}
}

View File

@ -0,0 +1,73 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import "../../../../imports"
import "../../../../shared"
import "../../../../shared/status"
Rectangle {
property string name: "channel-name"
property string channelId: "channel-id"
property string categoryId: ""
property var onItemChecked
property bool isHovered: false
id: container
visible: categoryId == ""
height: visible ? 52 : 0
width: 425
anchors.right: parent.right
anchors.left: parent.left
anchors.leftMargin: 0
anchors.rightMargin: 0
border.width: 0
radius: Style.current.radius
color: isHovered ? Style.current.backgroundHover : Style.current.transparent
StatusIdenticon {
id: channelImage
height: 36
width: 36
chatId: name
chatName: name
chatType: Constants.chatTypePublic
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
id: channelName
text: "#" + name
elide: Text.ElideRight
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
font.pixelSize: 15
anchors.verticalCenter: parent.verticalCenter
anchors.left: channelImage.right
anchors.leftMargin: Style.current.halfPadding
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
hoverEnabled: true
onEntered: container.isHovered = true
onExited: container.isHovered = false
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
chk.checked = !chk.checked
}
}
StatusCheckBox {
id: chk
anchors.top: channelImage.top
anchors.topMargin: 6
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
onClicked: {
onItemChecked(container.channelId, chk.checked)
}
}
}

View File

@ -0,0 +1,153 @@
import QtQuick 2.12
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.13
import QtQuick.Dialogs 1.3
import "../../../../imports"
import "../../../../shared"
import "../../../../shared/status"
ModalPopup {
property string communityId
readonly property int maxDescChars: 140
property string nameValidationError: ""
property bool isValid: nameInput.isValid
property var channels: []
id: popup
height: 453
onOpened: {
nameInput.text = "";
nameInput.forceActiveFocus(Qt.MouseFocusReason)
}
onClosed: destroy()
function validate() {
nameInput.validate()
return isValid
}
title: qsTr("New category")
ScrollView {
property ScrollBar vScrollBar: ScrollBar.vertical
id: scrollView
anchors.fill: parent
rightPadding: Style.current.padding
anchors.rightMargin: - Style.current.halfPadding
contentHeight: content.height
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
clip: true
function scrollBackUp() {
vScrollBar.setPosition(0)
}
Item {
id: content
height: childrenRect.height
width: parent.width
Input {
id: nameInput
placeholderText: qsTr("Category title")
validationError: popup.nameValidationError
property bool isValid: false
onTextEdited: {
validate()
}
function validate() {
validationError = ""
if (nameInput.text === "") {
//% "You need to enter a name"
validationError = qsTrId("you-need-to-enter-a-name")
} else if (nameInput.text.length > 100) {
//% "Your name needs to be 100 characters or shorter"
validationError = qsTrId("your-name-needs-to-be-100-characters-or-shorter")
}
isValid = validationError === ""
return validationError
}
}
Separator {
id: sep
anchors.left: parent.left
anchors.right: parent.right
anchors.top: nameInput.bottom
anchors.topMargin: Style.current.padding
anchors.leftMargin: -Style.current.padding
anchors.rightMargin: -Style.current.padding
}
StatusSectionHeadline {
id: chatsTitle
text: qsTr("Chats")
anchors.top: sep.bottom
anchors.topMargin: Style.current.smallPadding
}
ListView {
height: childrenRect.height
model: chatsModel.communities.activeCommunity.chats
anchors.top: chatsTitle.bottom
anchors.topMargin: Style.current.smallPadding
anchors.left: parent.left
anchors.right: parent.right
delegate: CommunityChannel {
name: model.name
channelId: model.id
categoryId: model.categoryId
onItemChecked: function(channelId, itemChecked){
var idx = channels.indexOf(channelId)
if(itemChecked){
if(idx === -1){
channels.push(channelId)
}
} else {
if(idx > -1){
channels.splice(idx, 1);
}
}
}
}
}
}
}
footer: StatusButton {
enabled: popup.isValid
//% "Create"
text: qsTrId("create")
anchors.right: parent.right
onClicked: {
if (!validate()) {
scrollView.scrollBackUp()
return
}
const error = chatsModel.communities.createCommunityCategory(communityId, Utils.filterXSS(nameInput.text), JSON.stringify(channels))
if (error) {
creatingError.text = error
return creatingError.open()
}
popup.close()
}
MessageDialog {
id: creatingError
title: qsTr("Error creating the category")
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
}
}

View File

@ -8,6 +8,7 @@ import "../../../../shared/status"
ModalPopup {
property string communityId
property string categoryId: ""
readonly property int maxDescChars: 140
property string nameValidationError: ""
property bool isValid:
@ -177,7 +178,8 @@ ModalPopup {
}
const error = chatsModel.communities.createCommunityChannel(communityId,
Utils.filterXSS(nameInput.text),
Utils.filterXSS(descriptionTextArea.text))
Utils.filterXSS(descriptionTextArea.text),
categoryId)
if (error) {
creatingError.text = error

View File

@ -7,6 +7,7 @@ import "../components"
Item {
property string chatId: ""
property string categoryId: ""
property string name: "channelName"
property string lastMessage: "My latest message\n with a return"
property string timestamp: "1605212622434"
@ -22,6 +23,7 @@ Item {
return chatType
}
property string filterCategory: ""
property string searchStr: ""
property bool isCompact: appSettings.useCompactMode
property int contentType: 1
@ -41,7 +43,7 @@ Item {
property string profileImage: realChatType === Constants.chatTypeOneToOne ? appMain.getProfileImage(chatId) || "" : ""
// Hide the box if it is filtered out
property bool isVisible: searchStr === "" || name.includes(searchStr)
property bool isVisible: categoryId == filterCategory && (searchStr === "" || name.includes(searchStr))
id: wrapper
anchors.right: parent.right

View File

@ -10,6 +10,7 @@ Item {
property var channelModel
property alias channelListCount: chatGroupsListView.count
property string searchStr: ""
property string categoryId: ""
id: channelListContent
width: parent.width
height: childrenRect.height
@ -39,6 +40,8 @@ Item {
hasMentions: model.hasMentions
contentType: model.contentType
searchStr: channelListContent.searchStr
categoryId: model.categoryId
filterCategory: channelListContent.categoryId
chatId: model.id
}
onCountChanged: {

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.9375 5C10.9375 4.48223 10.5178 4.0625 10 4.0625C9.48223 4.0625 9.0625 4.48223 9.0625 5V8.5625C9.0625 8.83864 8.83864 9.0625 8.5625 9.0625H5C4.48223 9.0625 4.0625 9.48223 4.0625 10C4.0625 10.5178 4.48223 10.9375 5 10.9375H8.5625C8.83864 10.9375 9.0625 11.1614 9.0625 11.4375V15C9.0625 15.5178 9.48223 15.9375 10 15.9375C10.5178 15.9375 10.9375 15.5178 10.9375 15V11.4375C10.9375 11.1614 11.1614 10.9375 11.4375 10.9375H15C15.5178 10.9375 15.9375 10.5178 15.9375 10C15.9375 9.48223 15.5178 9.0625 15 9.0625H11.4375C11.1614 9.0625 10.9375 8.83864 10.9375 8.5625V5Z" fill="black" fill-opacity="0.7"/>
</svg>

After

Width:  |  Height:  |  Size: 753 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.00001 13.6667C11.1296 13.6667 13.6667 11.1297 13.6667 8.00004C13.6667 4.87043 11.1296 2.33337 8.00001 2.33337C4.8704 2.33337 2.33334 4.87043 2.33334 8.00004C2.33334 11.1297 4.8704 13.6667 8.00001 13.6667ZM8.00001 14.6667C11.6819 14.6667 14.6667 11.6819 14.6667 8.00004C14.6667 4.31814 11.6819 1.33337 8.00001 1.33337C4.31811 1.33337 1.33334 4.31814 1.33334 8.00004C1.33334 11.6819 4.31811 14.6667 8.00001 14.6667Z" fill="#4360DF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.65987 5.08224C7.70527 4.80985 7.52126 4.55224 7.24887 4.50684C6.97649 4.46144 6.71887 4.64545 6.67348 4.91784L6.51175 5.88817C6.48497 6.0489 6.3459 6.16671 6.18296 6.16671H5.33334C5.0572 6.16671 4.83334 6.39056 4.83334 6.66671C4.83334 6.94285 5.0572 7.16671 5.33334 7.16671H5.90518C6.11116 7.16671 6.26784 7.35166 6.23398 7.55484L6.06731 8.55484C6.04052 8.71557 5.90146 8.83337 5.73851 8.83337H5.00001C4.72387 8.83337 4.50001 9.05723 4.50001 9.33337C4.50001 9.60952 4.72387 9.83337 5.00001 9.83337H5.46073C5.66671 9.83337 5.82339 10.0183 5.78953 10.2215L5.67348 10.9178C5.62808 11.1902 5.81209 11.4478 6.08447 11.4932C6.35686 11.5386 6.61447 11.3546 6.65987 11.0822L6.82159 10.1119C6.84838 9.95118 6.98744 9.83337 7.15039 9.83337H8.1274C8.33338 9.83337 8.49006 10.0183 8.4562 10.2215L8.34014 10.9178C8.29475 11.1902 8.47876 11.4478 8.75114 11.4932C9.02353 11.5386 9.28114 11.3546 9.32654 11.0822L9.48826 10.1119C9.51505 9.95118 9.65411 9.83337 9.81706 9.83337H10.6667C10.9428 9.83337 11.1667 9.60952 11.1667 9.33337C11.1667 9.05723 10.9428 8.83337 10.6667 8.83337H10.0948C9.88885 8.83337 9.73217 8.64842 9.76604 8.44524L9.9327 7.44524C9.95949 7.28451 10.0986 7.16671 10.2615 7.16671H11C11.2762 7.16671 11.5 6.94285 11.5 6.66671C11.5 6.39056 11.2762 6.16671 11 6.16671H10.5393C10.3333 6.16671 10.1766 5.98175 10.2105 5.77857L10.3265 5.08224C10.3719 4.80985 10.1879 4.55224 9.91554 4.50684C9.64316 4.46144 9.38554 4.64545 9.34014 4.91784L9.17842 5.88817C9.15163 6.0489 9.01257 6.16671 8.84962 6.16671H7.87261C7.66663 6.16671 7.50995 5.98175 7.54381 5.77857L7.65987 5.08224ZM8.40518 8.83337C8.56812 8.83337 8.70719 8.71557 8.73398 8.55484L8.90064 7.55484C8.93451 7.35166 8.77782 7.16671 8.57185 7.16671H7.59483C7.43189 7.16671 7.29282 7.28451 7.26604 7.44524L7.09937 8.44524C7.06551 8.64842 7.22219 8.83337 7.42817 8.83337H8.40518Z" fill="#4360DF"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.58709 8.08709C5.9532 7.72097 6.5468 7.72097 6.91291 8.08709L9.64645 10.8206C9.84171 11.0159 10.1583 11.0159 10.3536 10.8206L13.0871 8.08709C13.4532 7.72097 14.0468 7.72097 14.4129 8.08709C14.779 8.4532 14.779 9.0468 14.4129 9.41291L10.6629 13.1629C10.2968 13.529 9.7032 13.529 9.33709 13.1629L5.58709 9.41291C5.22097 9.0468 5.22097 8.4532 5.58709 8.08709Z" fill="black" fill-opacity="0.7"/>
</svg>

After

Width:  |  Height:  |  Size: 546 B

5
ui/app/img/more.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="4.375" cy="10" r="1.875" fill="black" fill-opacity="0.7"/>
<circle cx="15.625" cy="10" r="1.875" fill="black" fill-opacity="0.7"/>
<circle cx="10" cy="10" r="1.875" fill="black" fill-opacity="0.7"/>
</svg>

After

Width:  |  Height:  |  Size: 314 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.46209 6.21209C7.09597 6.5782 7.09597 7.1718 7.46209 7.53791L10.1072 10.1831C10.3513 10.4271 10.3513 10.8229 10.1072 11.0669L7.46209 13.7121C7.09597 14.0782 7.09597 14.6718 7.46209 15.0379C7.8282 15.404 8.4218 15.404 8.78791 15.0379L12.5379 11.2879C12.904 10.9218 12.904 10.3282 12.5379 9.96209L8.78791 6.21209C8.4218 5.84597 7.8282 5.84597 7.46209 6.21209Z" fill="black" fill-opacity="0.7"/>
</svg>

After

Width:  |  Height:  |  Size: 547 B

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 71f66f68064e9897cd17b6bcecba426a91405034
Subproject commit 92032c7158b80908508cd67c08ac6f6c75eee35b