diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 0a9a890..998eab1 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -85,7 +85,7 @@ qt_add_qml_module(${PROJECT_NAME} URI ${PROJECT_NAME} VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} RESOURCE_PREFIX "/qt/qml/" - QML_FILES example.qml + QML_FILES example.qml components/RibbonMessageListViewExample.qml RESOURCES resources/imgs/heart.png resources/imgs/search.png ) diff --git a/example/components/RibbonMessageListViewExample.qml b/example/components/RibbonMessageListViewExample.qml new file mode 100644 index 0000000..a4560c1 --- /dev/null +++ b/example/components/RibbonMessageListViewExample.qml @@ -0,0 +1,72 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import RibbonUI + +Item { + id: root + implicitHeight: layout.height + layout.anchors.margins * 2 + implicitWidth: 500 + RibbonButton{ + anchors{ + top:parent.top + topMargin: 8 + right: parent.right + rightMargin: anchors.topMargin + } + show_bg: false + show_hovered_bg: false + icon_source: RibbonIcons.Dismiss + onClicked: close_popup() + } + ColumnLayout{ + id: layout + width: parent.width - anchors.margins * 2 + anchors.centerIn: parent + anchors.margins: 30 + RibbonText{ + Layout.alignment: Qt.AlignHCenter + text: qsTr("Message List View Example") + font.pixelSize: 20 + } + RibbonMessageListView{ + id: view + auto_scroll_to_bottom: true + Layout.preferredHeight: 500 + Layout.preferredWidth: parent.width + delegate: RibbonMessage{ + id: msg + sender_text: `${model.time} ${model.recieved ? qsTr('Recieved') : qsTr('Sent')}` + RibbonText{ + font.pixelSize: msg.font_size + color: RibbonTheme.dark_mode ? "white" : !model.recieved ? "white" : "black" + text: model.text ? model.text : "" + visible: model.text ? true : false + Layout.preferredWidth: implicitWidth < (view.width / 2 - padding) ? implicitWidth : (view.width / 2 - padding) + wrapMode: RibbonText.Wrap + } + } + } + RowLayout{ + Layout.alignment: Qt.AlignHCenter + RibbonButton{ + icon_source: RibbonIcons.AddCircle + text: qsTr('Add Message') + onClicked: { + view.message_model.append({ + time: Qt.formatDateTime(new Date(), "yyyy-MM-dd hh:mm:ss.zzz"), + text: String(Math.random()*10), + recieved: (Math.floor(Math.random()*10))%2===0, + }) + } + } + RibbonButton{ + icon_source: RibbonIcons.DismissCircle + text: qsTr('Clear Message') + onClicked: { + view.message_model.clear() + } + } + } + } +} diff --git a/example/example.qml b/example/example.qml index 68ae068..a9a21bd 100644 --- a/example/example.qml +++ b/example/example.qml @@ -1,10 +1,7 @@ import QtQuick import QtQuick.Layouts import QtQuick.Controls -import QtQuick.Controls.Material -import QtQuick.Window import RibbonUI -import org.wangwenx190.FramelessHelper RibbonWindow { id:root @@ -422,6 +419,24 @@ RibbonWindow { } } } + RibbonTabPage{ + title: qsTr("Views") + RibbonTabGroup{ + width: message_list_view_layout.width + 30 + text: qsTr("MessageListView") + RowLayout{ + id: message_list_view_layout + anchors.centerIn: parent + height: parent.height + spacing: 10 + RibbonButton{ + text: qsTr('Open Message List View') + icon_source: RibbonIcons.Open + onClicked: root.show_popup("qrc:/qt/qml/RibbonUIAPP/components/RibbonMessageListViewExample.qml") + } + } + } + } RibbonTabPage{ title: qsTr("Others") RibbonTabGroup{ @@ -555,10 +570,7 @@ RibbonWindow { RibbonPaperView{ id: view - anchors{ - top: parent.top - bottom: parent.bottom - } + anchors.fill: parent top_padding: tab_bar.height bottom_padding: bottom_bar.height page_width: (page_slider.value / 100.0) * width diff --git a/lib_source/CMakeLists.txt b/lib_source/CMakeLists.txt index 2afa181..64efbbe 100644 --- a/lib_source/CMakeLists.txt +++ b/lib_source/CMakeLists.txt @@ -52,7 +52,8 @@ set( qml/RibbonText.qml qml/RibbonTextBoxMenu.qml qml/RibbonPopup.qml qml/RibbonPopupDialog.qml qml/RibbonLineEdit.qml qml/RibbonTextEdit.qml qml/RibbonComboBox.qml qml/RibbonSpinBox.qml qml/RibbonScrollIndicator.qml - qml/RibbonScrollBar.qml qml/RibbonWindow.qml + qml/RibbonScrollBar.qml qml/RibbonWindow.qml qml/RibbonMessage.qml + qml/RibbonMessageListView.qml ) foreach(qmlfile ${qml_files}) diff --git a/lib_source/qml/RibbonMessage.qml b/lib_source/qml/RibbonMessage.qml new file mode 100644 index 0000000..088c3b9 --- /dev/null +++ b/lib_source/qml/RibbonMessage.qml @@ -0,0 +1,55 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import RibbonUI + +Rectangle{ + id: bubble + color: "transparent" + property double padding: 10 + default property alias content: message_layout.data + property var data_model: model + property int font_size: 13 + property string sender_text: "sender" + width: ListView.view.width + height: bubble_layout.height + padding*2 + + ColumnLayout{ + id: bubble_layout + anchors{ + top: parent.top + topMargin: parent.padding + } + layoutDirection: data_model.recieved ? Qt.LeftToRight : Qt.RightToLeft + Component.onCompleted: { + if (data_model.recieved) + { + anchors.left = parent.left + anchors.leftMargin = parent.padding + } + else{ + anchors.right = parent.right + anchors.rightMargin = parent.padding + } + } + RibbonText{ + id: sender_text + text: bubble.sender_text + padding: bubble.padding + color: RibbonTheme.dark_mode ? "white" : "black" + } + RibbonRectangle{ + id: bubble_bg + color: data_model.recieved ? RibbonTheme.dark_mode ? "#202020" : "#FFFFFF" : RibbonTheme.dark_mode ? "#2F2F2F" : "#4397F7" + height: message_layout.height + bubble.padding*2 + width: message_layout.width + bubble.padding*2 + radius: 10 + topLeftRadius: data_model.recieved ? 2 : bubble.padding + topRightRadius: !data_model.recieved ? 2 : bubble.padding + ColumnLayout{ + id: message_layout + anchors.centerIn: parent + } + } + } +} diff --git a/lib_source/qml/RibbonMessageListView.qml b/lib_source/qml/RibbonMessageListView.qml new file mode 100644 index 0000000..d44b3c8 --- /dev/null +++ b/lib_source/qml/RibbonMessageListView.qml @@ -0,0 +1,60 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import RibbonUI + +RibbonView{ + id: view + spacing: 0 + + property int max_msg_num: 10 + property bool auto_scroll_to_bottom: false + property int animation_time: 200 + property alias delegate: message_list.delegate + property alias message_model: message_model + property alias view: message_list + + ListModel{ + id: message_model + onCountChanged: auto_scroll_btn_timer.restart() + } + + Timer{ + id: auto_scroll_btn_timer + interval: animation_time + repeat: false + onTriggered: { + if(view.auto_scroll_to_bottom) + view.scroll_to_bottom() + } + } + + ListView{ + id: message_list + cacheBuffer: message_list.height * 2 + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: parent.height + Layout.preferredWidth: parent.width + model: message_model + add: Transition { + NumberAnimation { + properties: "y" + from: message_list.height + duration: animation_time + } + } + ScrollBar.vertical: RibbonScrollBar { + anchors.right: message_list.right + anchors.rightMargin: 2 + } + } + + function scroll_to_up(){ + message_list.positionViewAtBeginning() + } + + function scroll_to_bottom(){ + message_list.positionViewAtEnd() + } + +}