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
This commit is contained in:
Pascal Precht 2021-06-15 16:27:39 +02:00
parent 4577551873
commit 7bca27455f
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
4 changed files with 163 additions and 45 deletions

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,10 +228,16 @@ Rectangle {
StatusAppTwoPanelLayout {
leftPanel: Item {
anchors.fill: parent
StatusChatInfoToolBar {
id: statusChatInfoToolBar
anchors.top: parent.top
chatInfoButton.title: "Cryptokitties"
chatInfoButton.subTitle: "128 Members"
chatInfoButton.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
@ -265,41 +266,22 @@ Rectangle {
}
}
Column {
anchors.top: parent.top
anchors.topMargin: 64
anchors.horizontalCenter: parent.horizontalCenter
spacing: 4
StatusChatListAndCategories {
anchors.top: statusChatInfoToolBar.bottom
anchors.topMargin: 8
anchors.bottom: parent.bottom
width: parent.width
StatusChatList {
id: statusChatList
anchors.horizontalCenter: parent.horizontalCenter
chatListItems.model: demoCommunityChatListItems
}
chatList.model: demoCommunityChatListItems
categoryList.model: demoCommunityCategoryItems
StatusChatListCategory {
name: "Public"
showActionButtons: true
chatList.chatListItems.model: demoCommunityChatListItems
chatList.selectedChatId: "0"
chatList.onChatItemSelected: chatList.selectedChatId = id
popupMenu: categoryPopupCmp
}
showCategoryActionButtons: true
onChatItemSelected: selectedChatId = id
StatusChatListCategory {
name: "Development"
categoryPopupMenu: StatusPopupMenu {
showActionButtons: true
chatList.chatListItems.model: demoCommunityChatListItems
chatList.onChatItemSelected: chatList.selectedChatId = id
popupMenu: categoryPopupCmp
}
}
property string categoryId
Component {
id: categoryPopupCmp
StatusPopupMenu {
StatusMenuItem {
text: "Mute Category"
icon.name: "notification"
@ -323,8 +305,29 @@ Rectangle {
type: StatusMenuItem.Type.Danger
}
}
popupMenu: StatusPopupMenu {
StatusMenuItem {
text: "Create channel"
icon.name: "channel"
}
StatusMenuItem {
text: "Create category"
icon.name: "channel-category"
}
StatusMenuSeparator {}
StatusMenuItem {
text: "Invite people"
icon.name: "share-ios"
}
}
}
}
rightPanel: Item {
anchors.fill: parent
@ -413,6 +416,7 @@ Rectangle {
hasMention: false
unreadMessagesCount: 0
iconColor: "orange"
categoryId: "public"
}
ListElement {
chatId: "2"
@ -423,6 +427,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"
}
}
}

View File

@ -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
}
}

View File

@ -6,6 +6,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

View File

@ -18,6 +18,7 @@
<file>src/StatusQ/Popups/StatusMenuItem.qml</file>
<file>src/StatusQ/Components/qmldir</file>
<file>src/StatusQ/Components/StatusChatListItem.qml</file>
<file>src/StatusQ/Components/StatusChatListAndCategories.qml</file>
<file>src/StatusQ/Components/StatusChatInfoToolBar.qml</file>
<file>src/StatusQ/Components/StatusNavigationListItem.qml</file>
<file>src/StatusQ/Components/StatusChatToolBar.qml</file>