feat(Layout): introduce StatusAppNavBar

This commit introduces a new `StatusAppNavBar` component that can be used
to create a Status application's tab bar for dedicated tab sections such as
chat, profile, wallet etc.

The component is build in a way that it support declarative and imperative usage
where necessary.

In its most simple form, a `StatusAppNavBar` comes with a single tab button
for the chat section. Such button has to be of type `StatusNavBarTabButton`:

```qml
import StatusQ.Layout 0.1

StatusAppNavBar {
    navBarChatButton: StatusNavBarTabButton {
        icon.name: "chat"
        badge.value: 33
        badge.visible: true
        tooltip.text: "Chat"
    }
}
```

In addition, it's possible to specify a list of `StatusNavBarTabButton` for
other sections of the application using the `navBarTabButtons` property:

```qml

StatusAppNavBar {
    ...
    navBarTabButtons: [
        StatusNavBarTabButton {
            icon.name: "wallet"
            tooltip.text: "Wallet"
        },
        StatusNavBarTabButton {
            icon.name: "browser"
            tooltip.text: "Browser"
        },
        StatusNavBarTabButton {
            icon.name: "status-update"
            tooltip.text: "Timeline"
        }
    ]
}
```

Lastly, when desired to render tabs for Status community, which can grow
in size, `StatusAppNavBar` exposes a list via the `navBarCommunityTabButtons`
property that can have a `model` and a `delegate`. The `delegate` should also
be a `StatusNavBarTabButton`:

```qml

StatusAppNavBar {
    ...
    navBarCommunityTabButtons.model: someModel.communities

    navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
        name: model.name
        tooltip.text: model.name
        anchors.horizontalCenter: parent.horizontalCenter
    }
}
```

The amount of community tab buttons can grow as they need until their dedicated
area becomes scrollable, at which point all `navBarTabButtons` will stick to the
bottom of `StatusAppNavBar`.

Closes #18
This commit is contained in:
Pascal Precht 2021-05-11 16:25:46 +02:00 committed by Michał Cieślak
parent a3c3091c5d
commit a1e721bfc3
7 changed files with 427 additions and 0 deletions

View File

@ -0,0 +1,259 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Layout 0.1
GridLayout {
columns: 6
columnSpacing: 5
rowSpacing: 5
property ThemePalette theme
Button {
id: btn
text: "Append"
onClicked: {
buttons.append({
name: "Test community",
tooltipText: "Test Community"
})
}
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
tooltip.text: "Chat"
}
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
tooltip.text: "Chat"
}
navBarCommunityTabButtons.model: ListModel {
id: buttons
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
anchors.horizontalCenter: parent.horizontalCenter
}
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
},
StatusNavBarTabButton {
icon.name: "status-update"
tooltip.text: "Timeline"
},
StatusNavBarTabButton {
icon.name: "profile"
badge.visible: true
badge.anchors.rightMargin: 4
badge.anchors.topMargin: 5
badge.border.color: Theme.palette.statusAppNavBar.backgroundColor
badge.border.width: 2
tooltip.text: "Profile"
}
]
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
tooltip.text: "Chat"
}
navBarCommunityTabButtons.model: ListModel {
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
anchors.horizontalCenter: parent.horizontalCenter
}
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
}
]
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
tooltip.text: "Chat"
}
navBarCommunityTabButtons.model: ListModel {
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
anchors.horizontalCenter: parent.horizontalCenter
}
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
},
StatusNavBarTabButton {
icon.name: "status-update"
tooltip.text: "Timeline"
},
StatusNavBarTabButton {
icon.name: "profile"
badge.visible: true
badge.anchors.rightMargin: 4
badge.anchors.topMargin: 5
badge.border.color: Theme.palette.statusAppNavBar.backgroundColor
badge.border.width: 2
tooltip.text: "Profile"
}
]
}
StatusAppNavBar {
id: test
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
tooltip.text: "Chat"
}
navBarCommunityTabButtons.model: ListModel {
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
anchors.horizontalCenter: parent.horizontalCenter
}
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
},
StatusNavBarTabButton {
icon.name: "status-update"
tooltip.text: "Timeline"
},
StatusNavBarTabButton {
icon.name: "profile"
badge.visible: true
badge.anchors.rightMargin: 4
badge.anchors.topMargin: 5
badge.border.color: Theme.palette.statusAppNavBar.backgroundColor
badge.border.width: 2
tooltip.text: "Profile"
}
]
}
}

View File

@ -44,6 +44,11 @@ Window {
checkable: true
text: "Controls"
}
Button {
id: layoutTab
checkable: true
text: "Layout"
}
Button {
id: otherTab
checkable: true
@ -87,6 +92,8 @@ Window {
return iconsComponent;
case controlsTab:
return controlsComponent;
case layoutTab:
return layoutComponent;
case otherTab:
return othersComponent;
case buttonsTab:
@ -96,6 +103,7 @@ Window {
}
}
}
Row {
id: switchRow
scale: 0.8
@ -169,6 +177,14 @@ Window {
}
}
Component {
id: layoutComponent
Layout {
anchors.centerIn: parent
theme: Theme.palette
}
}
Component {
id: othersComponent
Others {

View File

@ -116,5 +116,9 @@ ThemePalette {
miscColor9: getColor('moss2')
miscColor10: getColor('brown3')
miscColor11: getColor('yellow2')
property QtObject statusAppNavBar: QtObject {
property color backgroundColor: baseColor5
}
}

View File

@ -116,5 +116,9 @@ ThemePalette {
miscColor9: getColor('moss')
miscColor10: getColor('brown')
miscColor11: getColor('brown2')
property QtObject statusAppNavBar: QtObject {
property color backgroundColor: baseColor4
}
}

View File

@ -76,6 +76,10 @@ QtObject {
property color miscColor10
property color miscColor11
property QtObject statusAppNavBar: QtObject {
property color backgroundColor
}
function alphaColor(color, alpha) {
let actualColor = Qt.darker(color, 1)
actualColor.a = alpha

View File

@ -0,0 +1,135 @@
import QtQuick 2.13
import QtQuick.Layouts 1.13
import QtQuick.Controls 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
Rectangle {
id: statusAppNavBar
property StatusNavBarTabButton navBarChatButton
property list<StatusNavBarTabButton> navBarTabButtons
property alias navBarCommunityTabButtons: navBarCommunityTabButtons
property int navBarContentHeight: 0
property int navBarContentHeightWithoutCommunityButtons: 0
width: 78
implicitHeight: 600
color: Theme.palette.statusAppNavBar.backgroundColor
Component.onCompleted: {
navBarContentHeightWithoutCommunityButtons = (navBarChatButtonSlot.anchors.topMargin + navBarChatButtonSlot.height) +
(separator.anchors.topMargin + separator.height) +
(navBarTabButtonsSlot.height + navBarTabButtonsSlot.anchors.topMargin + navBarTabButtonsSlot.anchors.bottomMargin)
navBarContentHeight = navBarContentHeightWithoutCommunityButtons +
(navBarCommunityTabButtonsSlot.height + navBarScrollSection.anchors.topMargin)
}
onNavBarChatButtonChanged: {
if (!!navBarChatButton) {
navBarChatButton.parent = navBarChatButtonSlot
}
}
onNavBarTabButtonsChanged: {
if (navBarTabButtons.length) {
for (let idx in navBarTabButtons) {
navBarTabButtons[idx].parent = navBarTabButtonsSlot
}
}
}
Item {
id: navBarChatButtonSlot
anchors.top: parent.top
anchors.topMargin: 48
anchors.horizontalCenter: parent.horizontalCenter
height: statusAppNavBar.navBarChatButton.height
width: statusAppNavBar.navBarChatButton.width
}
Rectangle {
id: separatorTop
height: 1
width: 30
color: Theme.palette.directColor7
anchors.top: navBarChatButtonSlot.bottom
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
visible: separator.anchors.topMargin === 0
}
ScrollView {
id: navBarScrollSection
anchors.top: separatorTop.visible ? separatorTop.bottom : navBarChatButtonSlot.bottom
anchors.topMargin: separatorTop.visible ? 0 : 12
anchors.horizontalCenter: statusAppNavBar.horizontalCenter
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
clip: true
Component.onCompleted: {
if (navBarContentHeight > statusAppNavBar.height) {
height = statusAppNavBar.height -
statusAppNavBar.navBarContentHeightWithoutCommunityButtons -
(!!navBarTabButtonsSlot.anchors.bottom ? navBarTabButtonsSlot.anchors.bottomMargin : navBarTabButtonsSlot.anchors.topMargin)
bottomPadding = 16
topPadding = 16
} else {
height = navBarCommunityTabButtonsSlot.implicitHeight
}
}
Column {
id: navBarCommunityTabButtonsSlot
width: navBarScrollSection.width
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
spacing: 12
onImplicitHeightChanged: {
statusAppNavBar.Component.onCompleted()
navBarTabButtonsSlot.Component.onCompleted()
navBarScrollSection.Component.onCompleted()
}
Repeater {
id: navBarCommunityTabButtons
}
}
}
Rectangle {
id: separator
height: 1
width: 30
color: Theme.palette.directColor7
anchors.top: navBarCommunityTabButtons.model && navBarCommunityTabButtons.model.count > 0 ? navBarScrollSection.bottom : navBarChatButtonSlot.bottom
anchors.topMargin: navBarScrollSection.height < navBarCommunityTabButtonsSlot.implicitHeight ? 0 : 16
anchors.horizontalCenter: parent.horizontalCenter
visible: navBarChatButton !== null && navBarTabButtons.length > 0
}
Column {
id: navBarTabButtonsSlot
anchors.horizontalCenter: parent.horizontalCenter
spacing: 12
Component.onCompleted: {
if (navBarContentHeight > statusAppNavBar.height) {
anchors.top = undefined
anchors.topMargin = 0
anchors.bottom = statusAppNavBar.bottom
anchors.bottomMargin = 32
} else {
anchors.bottom = undefined
anchors.bottomMargin = 0
anchors.top = separator.visible ? separator.bottom : parent.top
anchors.topMargin = separator.visible ? 16 : navBarChatButtonSlot.anchors.topMargin
}
}
}
}

View File

@ -0,0 +1,5 @@
module StatusQ.Layout
StatusAppNavBar 0.1 StatusAppNavBar.qml