Compare commits

...
Author SHA1 Message Date
Pascal Precht de1282b40e feat(Components): introduce StatusChatListAndCategories component
This is a wrapping component that can be used to render community chat
lists and categories. It takes care of rendering categories, the top
chat list, as well as becominng scrollable in case the content outgrows
the available space.

Usage:

```qml
import StatusQ.Components 0.1

StatusChatListAndCategories {

    chatList.model: ... // non-categorized chat items, pass all chat items here, the component will take care of filtering categorized items out
    categoryListModel: ... // available categories (need to have `id` and `name`)

    selectedChatId: ...

    showCategoryActionButtons: true // default `false` - useful when only admin users can create and mutate categories/channels

    onChatItemSelected: ... // `id` is available for selected chat id

    categoryPopupMenu: StatusPopupMenu { // optional popup menu for category items

        property string categoryId // define this property to have it hydrated with correct id and make it available inside menu items
        ...
    }

    popupMenu: StatusPopupMenu { ... } // optional popup menu for whole list, will be triggered with right-click
}
```

Closes #133
2021-06-15 16:27:39 +02:00
Pascal Precht 9c76688929 feat(StatusChatListCategory): apply chat list filter and expose category id in popup menu
This uses the newly introduced `filterFn` in `StatusChatList` to hide chat items
that don't belong to a given category.

It also optionally exposes the `categoryId` on the provided popup menu, so it has
access to it inside menu item triggers.
2021-06-15 16:10:43 +02:00
Pascal Precht e3d6c7a4fc feat(StatusChatList): introduce filterFn and categoryId
Chat lists can belong to a category inside of communities, so they should
hold a property `categoryId` that represents that. In addition,
this commit introduces a `filterFn` function that can be used to conditionally
show/hide chat list items.

Closes #154
2021-06-15 16:07:24 +02:00
Pascal Precht ef7a75195e feat(StatusPopupMenu): introduce openHandler
Similar to `closeHandler`, StatusPopupMenu can now have a customized `openHandler`
to run custom logic on open.
2021-06-15 16:04:41 +02:00
Pascal Precht 2db3c30a26 feat(StatusChatListCategory): introduce flag to show/hide buttons
This commit introduces a `showActionButtons` flag that defaults to `false`
and can be used to render the action buttons provided in the chat list category.

This is useful for cases where only admin users should have the right to
create channels inside categories or mutate a category's state.

Settings `showActionButtons: true` will then render the buttons.

Closes #150
2021-06-15 12:17:51 +02:00
8 changed files with 205 additions and 62 deletions
+76 -59
View File
@@ -157,23 +157,18 @@ Rectangle {
StatusAppTwoPanelLayout {
leftPanel: Item {
leftPanel: StatusChatListAndCategories {
anchors.fill: parent
anchors.topMargin: 64
StatusChatList {
anchors.top: parent.top
anchors.topMargin: 64
anchors.horizontalCenter: parent.horizontalCenter
selectedChatId: "0"
chatListItems.model: demoChatListItems
onChatItemSelected: selectedChatId = id
onChatItemUnmuted: {
for (var i = 0; i < demoChatListItems.count; i++) {
let item = demoChatListItems.get(i);
if (item.chatId === id) {
demoChatListItems.setProperty(i, "muted", false)
}
chatList.model: demoChatListItems
selectedChatId: "0"
onChatItemSelected: selectedChatId = id
onChatItemUnmuted: {
for (var i = 0; i < demoChatListItems.count; i++) {
let item = demoChatListItems.get(i);
if (item.chatId === id) {
demoChatListItems.setProperty(i, "muted", false)
}
}
}
@@ -233,68 +228,65 @@ Rectangle {
StatusAppTwoPanelLayout {
leftPanel: Item {
leftPanel: StatusChatListAndCategories {
anchors.topMargin: 64
anchors.fill: parent
Column {
anchors.top: parent.top
anchors.topMargin: 64
anchors.horizontalCenter: parent.horizontalCenter
spacing: 4
chatList.model: demoCommunityChatListItems
categoryList.model: demoCommunityCategoryItems
StatusChatList {
id: statusChatList
anchors.horizontalCenter: parent.horizontalCenter
chatListItems.model: demoCommunityChatListItems
showCategoryActionButtons: true
onChatItemSelected: selectedChatId = id
categoryPopupMenu: StatusPopupMenu {
property string categoryId
StatusMenuItem {
text: "Mute Category"
icon.name: "notification"
}
StatusChatListCategory {
name: "Public"
chatList.chatListItems.model: demoCommunityChatListItems
chatList.selectedChatId: "0"
chatList.onChatItemSelected: chatList.selectedChatId = id
popupMenu: categoryPopupCmp
StatusMenuItem {
text: "Mark as Read"
icon.name: "checkmark-circle"
}
StatusChatListCategory {
name: "Development"
StatusMenuItem {
text: "Edit Category"
icon.name: "edit"
}
chatList.chatListItems.model: demoCommunityChatListItems
chatList.onChatItemSelected: chatList.selectedChatId = id
popupMenu: categoryPopupCmp
StatusMenuSeparator {}
StatusMenuItem {
text: "Delete Category"
icon.name: "delete"
type: StatusMenuItem.Type.Danger
}
}
Component {
id: categoryPopupCmp
StatusPopupMenu {
StatusMenuItem {
text: "Mute Category"
icon.name: "notification"
}
popupMenu: StatusPopupMenu {
StatusMenuItem {
text: "Create channel"
icon.name: "channel"
}
StatusMenuItem {
text: "Mark as Read"
icon.name: "checkmark-circle"
}
StatusMenuItem {
text: "Create category"
icon.name: "channel-category"
}
StatusMenuItem {
text: "Edit Category"
icon.name: "edit"
}
StatusMenuSeparator {}
StatusMenuSeparator {}
StatusMenuItem {
text: "Delete Category"
icon.name: "delete"
type: StatusMenuItem.Type.Danger
}
StatusMenuItem {
text: "Invite people"
icon.name: "share-ios"
}
}
}
rightPanel: Item {
anchors.fill: parent
@@ -383,6 +375,7 @@ Rectangle {
hasMention: false
unreadMessagesCount: 0
iconColor: "orange"
categoryId: "public"
}
ListElement {
chatId: "2"
@@ -393,6 +386,30 @@ Rectangle {
hasMention: false
unreadMessagesCount: 0
iconColor: "orange"
categoryId: "public"
}
ListElement {
chatId: "3"
name: "language-design"
chatType: StatusChatListItem.Type.CommunityChat
muted: false
hasUnreadMessages: false
hasMention: false
unreadMessagesCount: 0
iconColor: "orange"
categoryId: "dev"
}
}
ListModel {
id: demoCommunityCategoryItems
ListElement {
categoryId: "public"
name: "Public"
}
ListElement {
categoryId: "dev"
name: "Development"
}
}
}
+7
View File
@@ -40,11 +40,18 @@ GridLayout {
StatusChatListCategoryItem {
title: "Chat list category"
opened: false
showActionButtons: true
}
StatusChatListCategoryItem {
title: "Chat list category (opened)"
opened: true
showActionButtons: true
}
StatusChatListCategoryItem {
title: "Chat list category (no buttons)"
opened: true
}
StatusChatListItem {
@@ -10,9 +10,12 @@ Column {
spacing: 4
property string categoryId: ""
property string selectedChatId: ""
property alias chatListItems: statusChatListItems
property var filterFn
signal chatItemSelected(string id)
signal chatItemUnmuted(string id)
@@ -33,6 +36,12 @@ Column {
onClicked: statusChatList.chatItemSelected(model.chatId)
onUnmute: statusChatList.chatItemUnmuted(model.chatId)
visible: {
if (!!statusChatList.filterFn) {
return statusChatList.filterFn(model, statusChatList.categoryId)
}
return true
}
}
}
}
@@ -0,0 +1,88 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
ScrollView {
id: statusChatListAndCategories
clip: true
contentHeight: chatListsAndCategories.height + 8
property string selectedChatId: ""
property bool showCategoryActionButtons: false
property alias chatList: statusChatList.chatListItems
property alias categoryList: statusChatListCategories
property alias sensor: sensor
property Component categoryPopupMenu
property Component popupMenu
signal chatItemSelected(string id)
signal chatItemUnmuted(string id)
signal categoryAddButtonClicked(string id)
onPopupMenuChanged: {
if (!!popupMenu) {
popupMenuSlot.sourceComponent = popupMenu
}
}
MouseArea {
id: sensor
anchors.top: parent.top
width: parent.width
height: statusChatListAndCategories.height
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton && !!statusChatListAndCategories.popupMenu) {
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6)
return
}
}
Column {
id: chatListsAndCategories
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
spacing: 4
StatusChatList {
id: statusChatList
anchors.horizontalCenter: parent.horizontalCenter
visible: !!chatListItems.model && chatListItems.model.count > 0
selectedChatId: statusChatListAndCategories.selectedChatId
onChatItemSelected: statusChatListAndCategories.chatItemSelected(id)
onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
filterFn: function (model) {
return !!!model.categoryId
}
}
Repeater {
id: statusChatListCategories
visible: !!model && model.count > 0
delegate: StatusChatListCategory {
categoryId: model.categoryId
name: model.name
showActionButtons: statusChatListAndCategories.showCategoryActionButtons
addButton.onClicked: statusChatListAndCategories.categoryAddButtonClicked(model.categoryId)
chatList.chatListItems.model: statusChatListAndCategories.chatList.model
chatList.selectedChatId: statusChatListAndCategories.selectedChatId
chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(id)
popupMenu: statusChatListAndCategories.categoryPopupMenu
}
}
}
}
Loader {
id: popupMenuSlot
active: !!statusChatListAndCategories.popupMenu
}
}
@@ -12,6 +12,7 @@ Column {
property string name: ""
property bool opened: true
property alias showActionButtons: statusChatListCategoryItem.showActionButtons
property alias addButton: statusChatListCategoryItem.addButton
property alias menuButton: statusChatListCategoryItem.menuButton
property alias toggleButton: statusChatListCategoryItem.toggleButton
@@ -50,15 +51,23 @@ Column {
StatusChatList {
id: statusChatList
anchors.horizontalCenter: parent.horizontalCenter
visible: statusChatListCategory.opened
categoryId: statusChatListCategory.categoryId
filterFn: function (model) {
return !!model.categoryId && model.categoryId == statusChatList.categoryId
}
}
Loader {
id: popupMenuSlot
active: !!statusChatListCategory.popupMenu
onLoaded: {
popupMenuSlot.item.openHandler = function () {
if (popupMenuSlot.item.hasOwnProperty('categoryId')) {
popupMenuSlot.item.categoryId = statusChatListCategory.categoryId
}
}
popupMenuSlot.item.closeHandler = function () {
statusChatListCategoryItem.highlighted = false
statusChatListCategoryItem.menuButton.highlighted = false
@@ -16,6 +16,7 @@ StatusListItem {
property bool opened: true
property bool highlighted: false
property bool showActionButtons: false
property alias addButton: addButton
property alias menuButton: menuButton
property alias toggleButton: toggleButton
@@ -39,7 +40,9 @@ StatusListItem {
id: addButton
icon.name: "add"
icon.width: 20
visible: statusChatListCategoryItem.sensor.containsMouse || statusChatListCategoryItem.highlighted
visible: statusChatListCategoryItem.showActionButtons &&
(statusChatListCategoryItem.highlighted ||
statusChatListCategoryItem.sensor.containsMouse)
onClicked: statusChatListCategoryItem.addButtonClicked(mouse)
tooltip.text: "Add channel inside category"
},
@@ -47,7 +50,9 @@ StatusListItem {
id: menuButton
icon.name: "more"
icon.width: 21
visible: statusChatListCategoryItem.sensor.containsMouse || statusChatListCategoryItem.highlighted
visible: statusChatListCategoryItem.showActionButtons &&
(statusChatListCategoryItem.highlighted ||
statusChatListCategoryItem.sensor.containsMouse)
onClicked: statusChatListCategoryItem.menuButtonClicked(mouse)
tooltip.text: "More"
},
+1
View File
@@ -5,6 +5,7 @@ StatusChatList 0.1 StatusChatList.qml
StatusChatListItem 0.1 StatusChatListItem.qml
StatusChatListCategory 0.1 StatusChatListCategory.qml
StatusChatListCategoryItem 0.1 StatusChatListCategoryItem.qml
StatusChatListAndCategories 0.1 StatusChatListAndCategories.qml
StatusChatToolBar 0.1 StatusChatToolBar.qml
StatusDescriptionListItem 0.1 StatusDescriptionListItem.qml
StatusLetterIdenticon 0.1 StatusLetterIdenticon.qml
+7
View File
@@ -16,8 +16,15 @@ Menu {
property int menuItemCount: 0
property var subMenuItemIcons: []
property var openHandler
property var closeHandler
onOpened: {
if (typeof openHandler === "function") {
openHandler()
}
}
onClosed: {
if (typeof closeHandler === "function") {
closeHandler()