// Copyright (C) 2023 The Qt Company Ltd. // Copyright (C) 2019 Alexey Edelev // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause pragma ComponentBehavior: Bound import QtQml import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts //! [client-qml-1] import QtGrpc import QtGrpcChat import QtGrpcChat.Proto //! [client-qml-1] ApplicationWindow { id: root readonly property color darkColor: Qt.darker(color, 1.4) readonly property color lightColor: Qt.lighter(color, 1.4) Material.theme: Material.Dark Material.accent: Material.Purple width: 460 height: 740 title: qsTr("QtGrpcChat-Client") visible: true function handleStatus(status) : void { switch (status.code) { case QtGrpc.StatusCode.Ok: statusDisplay.text = status.message === "" ? qsTr("OK") : status.message statusDisplay.color = "#4CAF50" break case QtGrpc.StatusCode.Unavailable: statusDisplay.text = qsTr("Server Unavailable") statusDisplay.color = "#F44336" break default: statusDisplay.text = status.message statusDisplay.color = "#F44336" break } statusDisplay.restart() } //! [client-qml-2] Connections { target: ChatEngine function onChatStreamFinished(status) { root.handleStatus(status) loginView.clear() } function onChatStateChanged() { if (ChatEngine.chatState === Backend.ChatState.Connected && mainView.depth === 1) mainView.push("ChatView.qml") else if (ChatEngine.chatState === Backend.ChatState.Disconnected && mainView.depth > 1) mainView.pop() } function onRegisterFinished(status) { root.handleStatus(status) } function onChatError(message) { statusDisplay.text = message statusDisplay.color = "yellow" statusDisplay.restart() } } //! [client-qml-2] // Navigation header containing buttons and information text header: Rectangle { height: 40 color: Qt.darker(root.darkColor, 1.2) RowLayout { anchors.fill: parent anchors.leftMargin: 15 anchors.rightMargin: 15 component NavigationButton: Button { Material.roundedScale: Material.SmallScale Layout.fillHeight: true Layout.preferredWidth: 120 visible: mainView.depth > 1 enabled: mainView.depth > 1 clip: true } NavigationButton { Layout.alignment: Qt.AlignLeft text: "Logout" onPressed: { if (userStatusButton.checked) userStatusButton.animateClick() ChatEngine.logout() } } Text { Layout.alignment: Qt.AlignCenter Layout.fillWidth: true Layout.fillHeight: true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: Material.foreground text: mainView.currentItem.viewInfoText font.pointSize: 16 clip: true } NavigationButton { id: userStatusButton Layout.alignment: Qt.AlignRight checkable: true text: userStatusView.count + " ONLINE" onPressed: userStatus.height = checked ? 0 : userStatusView.contentHeight } } } // Visualize online users Item { id: userStatus width: parent.width * 0.75 anchors.horizontalCenter: parent.horizontalCenter height: 0 z: 1 Behavior on height { NumberAnimation { duration: 250 } } ListView { id: userStatusView anchors.fill: parent model: ChatEngine.userStatusModel interactive: false clip: true delegate: Rectangle { id: userStatusDelegate required property int index required property string username required property int status height: 32 width: userStatusView.width color: root.lightColor topLeftRadius: index === 0 ? 8 : 0 topRightRadius: index === 0 ? 8 : 0 bottomLeftRadius: index === userStatusView.count - 1 ? 8 : 0 bottomRightRadius: index === userStatusView.count - 1 ? 8 : 0 Rectangle { height: 2 width: parent.width anchors.top: parent.top color: Qt.lighter(parent.color, 1.4) visible: userStatusDelegate.index > 0 } Text { text: parent.username font.pointSize: 14 anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: Material.foreground } Rectangle { anchors.right: parent.right anchors.margins: 25 anchors.verticalCenter: parent.verticalCenter height: parent.height - 16 width: height radius: height / 2 color: { switch (parent.status) { case UserStatus.Type.LOGIN: return "#4CAF50" case UserStatus.Type.ACTIVE: return "#4CAF50" case UserStatus.Type.INACTIVE: return "#FF9800" case UserStatus.Type.LOGOUT: return "#F44336" } } } } } } StatusDisplay { id: statusDisplay anchors { top: parent.top left: parent.left right: parent.right leftMargin: 75 rightMargin: 75 topMargin: root.height / 4 } } BusyIndicator { id: busyIndicator z: 2 width: parent.width / 3 height: width anchors.centerIn: parent running: ChatEngine.chatState === Backend.ChatState.Connecting || ChatEngine.chatState === Backend.ChatState.Disconnecting } StackView { id: mainView anchors.fill: parent initialItem: Item { readonly property string viewInfoText: "Login" LoginView { id: loginView anchors { fill: parent leftMargin: 50 rightMargin: 50 topMargin: 100 bottomMargin: 100 } color: root.darkColor border.color: root.lightColor } } } }