Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
5fadb582c9 | |||
6b54401371 | |||
28b65e2f33 | |||
0689c3b9d9 | |||
9c121c6ba9 | |||
f2a66221e6 | |||
2de9d78f41 | |||
96355b0a97 | |||
47597471dd | |||
184f52c896 | |||
31b2b0b004 |
23
README.md
@ -57,12 +57,21 @@
|
||||
|FluTooltip|tooltip提示框||
|
||||
|FluTreeView|树控件||
|
||||
|FluTheme|主题设置|支持主题颜色切换,夜间模式|
|
||||
|FluCarousel|轮播图组件|支持无限轮播|
|
||||
|FluTimePicker|时间选择器||
|
||||
|FluDatePicker|日期选择器||
|
||||
|FluMenu|菜单Popup||
|
||||
|FluNavigationView|响应式导航布局||
|
||||
|
||||
# 部分效果预览
|
||||
|
||||
## 主页
|
||||
## 一个聊天Demo,调用了ChatGPT的接口
|
||||
|
||||

|
||||

|
||||
|
||||
## 各种Button按钮
|
||||
|
||||

|
||||
|
||||
## 主题颜色切换、夜间模式
|
||||
|
||||
@ -72,10 +81,14 @@
|
||||
|
||||

|
||||
|
||||
## Toast组件
|
||||
## 轮播图组件
|
||||
|
||||

|
||||
|
||||
## InfoBar提示框组件
|
||||
|
||||

|
||||
|
||||
## Rectangle组件
|
||||
## 多窗口路由跳转
|
||||
|
||||

|
||||

|
BIN
doc/preview/buttons.png
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
doc/preview/carousel.png
Normal file
After Width: | Height: | Size: 383 KiB |
BIN
doc/preview/chatgpt.png
Normal file
After Width: | Height: | Size: 382 KiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 119 KiB |
BIN
doc/preview/multiwindow.png
Normal file
After Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 703 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 101 KiB |
@ -15,6 +15,7 @@ Window {
|
||||
"/":"qrc:/page/MainPage.qml",
|
||||
"/about":"qrc:/page/AboutPage.qml",
|
||||
"/login":"qrc:/page/LoginPage.qml",
|
||||
"/chat":"qrc:/page/ChatPage.qml",
|
||||
}
|
||||
FluApp.initialRoute = "/"
|
||||
FluApp.run()
|
||||
|
40
example/ChatController.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "ChatController.h"
|
||||
|
||||
ChatController::ChatController(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
isLoading(false);
|
||||
networkManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
|
||||
void ChatController::sendMessage(const QString& text){
|
||||
isLoading(true);
|
||||
QUrl apiUrl("https://api.openai.com/v1/engines/text-davinci-003/completions");
|
||||
QNetworkRequest request(apiUrl);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization", QString::fromStdString("Bearer %1").arg(QString::fromUtf8(QByteArray::fromBase64(baseKey.toUtf8()))).toUtf8());
|
||||
QJsonObject requestData;
|
||||
requestData.insert("prompt", text);
|
||||
requestData.insert("max_tokens", 1000);
|
||||
requestData.insert("temperature", 0.5);
|
||||
QJsonDocument requestDoc(requestData);
|
||||
QByteArray requestDataBytes = requestDoc.toJson();
|
||||
QNetworkReply* reply = networkManager->post(request, requestDataBytes);
|
||||
connect(reply, &QNetworkReply::finished,this, [=]() {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QString responseString = QString::fromUtf8(reply->readAll());
|
||||
qDebug() << responseString;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(responseString.toUtf8());
|
||||
QJsonObject jsonObj = doc.object();
|
||||
QString text = jsonObj.value("choices").toArray().at(0).toObject().value("text").toString();
|
||||
if(text.isEmpty()){
|
||||
text = "不好意思,我似乎听不懂您的意思";
|
||||
}
|
||||
responseData(text);
|
||||
} else {
|
||||
responseData("网络错误:"+reply->errorString());
|
||||
}
|
||||
isLoading(false);
|
||||
reply->deleteLater();
|
||||
});
|
||||
}
|
28
example/ChatController.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef CHATCONTROLLER_H
|
||||
#define CHATCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QByteArray>
|
||||
#include "stdafx.h"
|
||||
|
||||
class ChatController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(bool,isLoading)
|
||||
Q_PROPERTY_AUTO(QString,responseData);
|
||||
public:
|
||||
explicit ChatController(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void sendMessage(const QString& text);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager* networkManager;
|
||||
QString baseKey = "c2stbXgxWm5MQkZ5TzhNYzNmRWl6eDZUM0JsYmtGSnNBWjNiakJjSXB6WGN3QW9KSk11";
|
||||
};
|
||||
|
||||
#endif // CHATCONTROLLER_H
|
@ -115,6 +115,49 @@ FluScrollablePage{
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
width: parent.width
|
||||
height: 68
|
||||
paddings: 10
|
||||
|
||||
FluDropDownButton{
|
||||
disabled:drop_down_button_switch.selected
|
||||
text:"DropDownButton"
|
||||
anchors{
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
}
|
||||
items:[
|
||||
FluMenuItem{
|
||||
text:"Menu_1"
|
||||
},
|
||||
FluMenuItem{
|
||||
text:"Menu_2"
|
||||
},
|
||||
FluMenuItem{
|
||||
text:"Menu_3"
|
||||
},
|
||||
FluMenuItem{
|
||||
text:"Menu_4"
|
||||
}
|
||||
]
|
||||
}
|
||||
Row{
|
||||
spacing: 5
|
||||
anchors{
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
}
|
||||
FluToggleSwitch{
|
||||
id:drop_down_button_switch
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
FluText{
|
||||
text:"Disabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
width: parent.width
|
||||
height: 100
|
||||
@ -189,4 +232,6 @@ FluScrollablePage{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -9,13 +9,11 @@ FluScrollablePage{
|
||||
|
||||
title:"Carousel"
|
||||
|
||||
|
||||
FluArea{
|
||||
width: parent.width
|
||||
height: 370
|
||||
paddings: 10
|
||||
Layout.topMargin: 20
|
||||
|
||||
Column{
|
||||
spacing: 15
|
||||
anchors{
|
||||
@ -23,7 +21,6 @@ FluScrollablePage{
|
||||
left:parent.left
|
||||
}
|
||||
FluText{
|
||||
|
||||
text:"轮播图,支持无限轮播,无限滑动,用ListView实现的组件"
|
||||
}
|
||||
FluCarousel{
|
||||
@ -33,12 +30,7 @@ FluScrollablePage{
|
||||
Component.onCompleted: {
|
||||
carousel.setData([{url:"qrc:/res/image/banner_1.jpg"},{url:"qrc:/res/image/banner_2.jpg"},{url:"qrc:/res/image/banner_3.jpg"}])
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
QT += quick concurrent
|
||||
QT += quick concurrent network
|
||||
CONFIG += c++11
|
||||
|
||||
DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT
|
||||
|
||||
SOURCES += \
|
||||
ChatController.cpp \
|
||||
main.cpp
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
|
||||
RC_ICONS = favicon.ico
|
||||
|
||||
#qnx: target.path = /tmp/$${TARGET}/bin
|
||||
#else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
#!isEmpty(target.path): INSTALLS += target
|
||||
@ -22,3 +25,6 @@ CONFIG(debug,debug|release) {
|
||||
} else {
|
||||
DESTDIR = $$absolute_path($${_PRO_FILE_PWD_}/../bin/release)
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
ChatController.h
|
||||
|
BIN
example/favicon.ico
Normal file
After Width: | Height: | Size: 272 KiB |
@ -4,6 +4,7 @@
|
||||
#include <QDir>
|
||||
#include <QQuickWindow>
|
||||
#include <QProcess>
|
||||
#include "ChatController.h"
|
||||
|
||||
QMap<QString, QVariant> properties(){
|
||||
QMap<QString, QVariant> map;
|
||||
@ -20,6 +21,9 @@ int main(int argc, char *argv[])
|
||||
// QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
|
||||
QGuiApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
qmlRegisterType<ChatController>("Controller",1,0,"ChatController");
|
||||
|
||||
QMapIterator<QString, QVariant> iterator(properties());
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
|
@ -34,7 +34,7 @@ FluWindow {
|
||||
fontStyle: FluText.Title
|
||||
}
|
||||
FluText{
|
||||
text:"v1.0.8"
|
||||
text:"v1.0.10"
|
||||
fontStyle: FluText.Body
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
}
|
||||
|
230
example/page/ChatPage.qml
Normal file
@ -0,0 +1,230 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import FluentUI 1.0
|
||||
import Controller 1.0
|
||||
|
||||
FluWindow {
|
||||
|
||||
width: 680
|
||||
height: 600
|
||||
minimumWidth: 500
|
||||
minimumHeight: 600
|
||||
|
||||
title:"ChatGPT"
|
||||
|
||||
ChatController{
|
||||
id:controller
|
||||
|
||||
onResponseDataChanged: {
|
||||
appendMessage(false,responseData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ListModel{
|
||||
id:model_message
|
||||
ListElement{
|
||||
isMy:false
|
||||
text:"欢迎使用ChatGPT"
|
||||
}
|
||||
ListElement{
|
||||
isMy:true
|
||||
text:"好的,3Q"
|
||||
}
|
||||
}
|
||||
|
||||
FluAppBar{
|
||||
id:appbar
|
||||
title:"ChatGPT"
|
||||
}
|
||||
|
||||
Component{
|
||||
id:com_text
|
||||
TextEdit {
|
||||
text: modelData.text
|
||||
wrapMode: Text.WrapAnywhere
|
||||
readOnly: true
|
||||
textFormat: Text.RichText
|
||||
selectByMouse: true
|
||||
selectByKeyboard: true
|
||||
selectedTextColor: color
|
||||
color:FluColors.Black
|
||||
selectionColor: {
|
||||
if(FluTheme.isDark){
|
||||
return FluTheme.primaryColor.lighter
|
||||
}else{
|
||||
return FluTheme.primaryColor.dark
|
||||
}
|
||||
}
|
||||
width: Math.min(list_message.width-200,600,implicitWidth)
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
id:layout_content
|
||||
anchors{
|
||||
top: appbar.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: layout_bottom.top
|
||||
margins: 10
|
||||
}
|
||||
color: FluTheme.isDark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(245/255,245/255,245/255,1)
|
||||
|
||||
ListView{
|
||||
id:list_message
|
||||
anchors.fill: parent
|
||||
model:model_message
|
||||
clip: true
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
header:Item{
|
||||
width: list_message.width
|
||||
height:20
|
||||
}
|
||||
footer:Item{
|
||||
width: list_message.width
|
||||
height:20
|
||||
}
|
||||
delegate: Item{
|
||||
width: ListView.view.width
|
||||
height: childrenRect.height
|
||||
|
||||
FluRectangle{
|
||||
id:item_avatar
|
||||
width: 30
|
||||
height: 30
|
||||
radius:[15,15,15,15]
|
||||
anchors{
|
||||
right: isMy ? parent.right : undefined
|
||||
rightMargin: isMy ? 20 : undefined
|
||||
left: isMy ? undefined : parent.left
|
||||
leftMargin: isMy ? undefined : 20
|
||||
top:parent.top
|
||||
}
|
||||
Image {
|
||||
asynchronous: true
|
||||
anchors.fill: parent
|
||||
sourceSize: Qt.size(100,100)
|
||||
source: isMy ? "qrc:/res/svg/avatar_2.svg" : "qrc:/res/image/logo_openai.png"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
id:item_layout_content
|
||||
color: isMy ? "#FF95EC69" : "#FFFFFF"
|
||||
width: item_msg_loader.width+10
|
||||
height: item_msg_loader.height+10
|
||||
radius: 3
|
||||
anchors{
|
||||
top: item_avatar.top
|
||||
right: isMy ? item_avatar.left : undefined
|
||||
rightMargin: isMy ? 10 : undefined
|
||||
left: isMy ? undefined : item_avatar.right
|
||||
leftMargin: isMy ? undefined : 10
|
||||
|
||||
}
|
||||
|
||||
Loader{
|
||||
id:item_msg_loader
|
||||
property var modelData: model
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: com_text
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Item{
|
||||
id:item_layout_bottom
|
||||
width: parent.width
|
||||
anchors.top: item_layout_content.bottom
|
||||
height: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
id:layout_bottom
|
||||
height: 90
|
||||
anchors{
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 10
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: 10
|
||||
rightMargin: 10
|
||||
}
|
||||
|
||||
|
||||
ScrollView{
|
||||
anchors{
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: button_send.left
|
||||
bottomMargin: 10
|
||||
leftMargin: 10
|
||||
rightMargin: 10
|
||||
}
|
||||
height: Math.min(textbox.implicitHeight,64)
|
||||
FluMultiLineTextBox{
|
||||
id:textbox
|
||||
}
|
||||
}
|
||||
|
||||
FluFilledButton{
|
||||
id:button_send
|
||||
text:controller.isLoading ? timer_loading.loadingText :"发送"
|
||||
anchors{
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
bottomMargin: 10
|
||||
rightMargin: 10
|
||||
}
|
||||
width: 60
|
||||
disabled: controller.isLoading
|
||||
onClicked:{
|
||||
var text = textbox.text
|
||||
appendMessage(true,text)
|
||||
controller.sendMessage(text)
|
||||
textbox.clear()
|
||||
}
|
||||
|
||||
Timer{
|
||||
id:timer_loading
|
||||
property int count : 0
|
||||
property string loadingText : ""
|
||||
interval: 500
|
||||
running: controller.isLoading
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
switch(count%3){
|
||||
case 0:
|
||||
loadingText = "."
|
||||
break
|
||||
case 1:
|
||||
loadingText = ".."
|
||||
break
|
||||
case 2:
|
||||
loadingText = "..."
|
||||
break
|
||||
default:
|
||||
loadingText = ""
|
||||
break
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function appendMessage(isMy,text){
|
||||
model_message.append({isMy:isMy,text:text})
|
||||
list_message.positionViewAtEnd()
|
||||
}
|
||||
|
||||
}
|
@ -58,13 +58,6 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
FluPaneItem{
|
||||
title:"Menu"
|
||||
onTap:{
|
||||
nav_view.push("qrc:/T_Menu.qml")
|
||||
}
|
||||
}
|
||||
|
||||
FluPaneItem{
|
||||
title:"TimePicker"
|
||||
onTap:{
|
||||
@ -123,7 +116,6 @@ FluWindow {
|
||||
title:"Popus"
|
||||
}
|
||||
|
||||
|
||||
FluPaneItem{
|
||||
title:"Dialog"
|
||||
onTap:{
|
||||
@ -131,6 +123,13 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
FluPaneItem{
|
||||
title:"Menu"
|
||||
onTap:{
|
||||
nav_view.push("qrc:/T_Menu.qml")
|
||||
}
|
||||
}
|
||||
|
||||
FluPaneItemHeader{
|
||||
title:"Navigation"
|
||||
}
|
||||
@ -205,6 +204,35 @@ FluWindow {
|
||||
items:original_items
|
||||
footerItems:footer_items
|
||||
|
||||
actions:[
|
||||
Image {
|
||||
width: 30
|
||||
height: 30
|
||||
Layout.preferredWidth: 30
|
||||
Layout.preferredHeight: 30
|
||||
sourceSize: Qt.size(60,60)
|
||||
source: "qrc:/res/image/logo_openai.png"
|
||||
Layout.rightMargin: 5
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
FluApp.navigate("/chat")
|
||||
}
|
||||
}
|
||||
},
|
||||
FluText{
|
||||
text:"夜间模式"
|
||||
fontStyle: FluText.Body
|
||||
},
|
||||
FluToggleSwitch{
|
||||
selected: FluTheme.isDark
|
||||
clickFunc:function(){
|
||||
FluTheme.isDark = !FluTheme.isDark
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: {
|
||||
nav_view.setCurrentIndex(1)
|
||||
nav_view.push("qrc:/T_Buttons.qml")
|
||||
|
@ -38,5 +38,7 @@
|
||||
<file>res/image/banner_1.jpg</file>
|
||||
<file>res/image/banner_2.jpg</file>
|
||||
<file>res/image/banner_3.jpg</file>
|
||||
<file>res/image/logo_openai.png</file>
|
||||
<file>page/ChatPage.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
BIN
example/res/image/logo_openai.png
Normal file
After Width: | Height: | Size: 22 KiB |
@ -36,7 +36,6 @@ Button {
|
||||
}
|
||||
contentItem: FluText {
|
||||
text: control.text
|
||||
anchors.centerIn: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: {
|
||||
|
@ -4,22 +4,17 @@ import FluentUI 1.0
|
||||
|
||||
Item {
|
||||
|
||||
|
||||
id:control
|
||||
|
||||
property bool flagXChanged: true
|
||||
property int radius : 5
|
||||
property int loopTime: 2000
|
||||
property bool showIndicator: true
|
||||
|
||||
|
||||
id:control
|
||||
width: 400
|
||||
height: 300
|
||||
|
||||
ListModel{
|
||||
id:content_model
|
||||
}
|
||||
|
||||
FluRectangle{
|
||||
anchors.fill: parent
|
||||
radius: [control.radius,control.radius,control.radius,control.radius]
|
||||
@ -33,12 +28,14 @@ Item {
|
||||
clip: true
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
model:content_model
|
||||
maximumFlickVelocity: 4 * (list_view.orientation ===
|
||||
Qt.Horizontal ? width : height)
|
||||
maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height)
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
orientation : ListView.Horizontal
|
||||
delegate: Item{
|
||||
width: ListView.view.width
|
||||
height: ListView.view.height
|
||||
|
||||
property int displayIndex: {
|
||||
if(index === 0)
|
||||
return content_model.count-3
|
||||
@ -46,19 +43,12 @@ Item {
|
||||
return 0
|
||||
return index-1
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: model.url
|
||||
fillMode:Image.PreserveAspectCrop
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
|
||||
onMovementEnded:{
|
||||
currentIndex = list_view.contentX/list_view.width
|
||||
if(currentIndex === 0){
|
||||
@ -69,15 +59,11 @@ Item {
|
||||
flagXChanged = false
|
||||
timer_run.start()
|
||||
}
|
||||
|
||||
onMovementStarted: {
|
||||
flagXChanged = true
|
||||
timer_run.stop()
|
||||
}
|
||||
|
||||
onContentXChanged: {
|
||||
|
||||
|
||||
if(flagXChanged){
|
||||
var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width)
|
||||
var minY = Math.max(0,(list_view.width*(currentIndex-1)))
|
||||
@ -89,11 +75,8 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
orientation : ListView.Horizontal
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setData(data){
|
||||
content_model.clear()
|
||||
content_model.append(data[data.length-1])
|
||||
@ -102,7 +85,6 @@ Item {
|
||||
list_view.currentIndex = 1
|
||||
timer_run.restart()
|
||||
}
|
||||
|
||||
Row{
|
||||
spacing: 10
|
||||
anchors{
|
||||
@ -131,9 +113,6 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Timer{
|
||||
id:timer_anim
|
||||
interval: 250
|
||||
@ -144,7 +123,6 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer{
|
||||
id:timer_run
|
||||
interval: control.loopTime
|
||||
@ -153,9 +131,6 @@ Item {
|
||||
list_view.highlightMoveDuration = 250
|
||||
list_view.currentIndex = list_view.currentIndex+1
|
||||
timer_anim.start()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -205,6 +205,9 @@ Rectangle {
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
model: generateYearArray(1924,2048)
|
||||
clip: true
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
visible: showYear
|
||||
delegate: Loader{
|
||||
property var model: modelData
|
||||
@ -212,11 +215,6 @@ Rectangle {
|
||||
property int position:index
|
||||
sourceComponent: list_delegate
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
if(currentIndex!==-1){
|
||||
list_view_1.positionViewAtIndex(currentIndex, ListView.NoPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
width: 1
|
||||
@ -229,6 +227,9 @@ Rectangle {
|
||||
height: parent.height
|
||||
clip: true
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
delegate: Loader{
|
||||
property var model: modelData
|
||||
@ -236,11 +237,6 @@ Rectangle {
|
||||
property int position:index
|
||||
sourceComponent: list_delegate
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
if(currentIndex!==-1){
|
||||
list_view_2.positionViewAtIndex(currentIndex, ListView.NoPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
width: 1
|
||||
@ -252,6 +248,9 @@ Rectangle {
|
||||
width: showYear ? 100 : 150
|
||||
height: parent.height
|
||||
clip: true
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
@ -261,9 +260,6 @@ Rectangle {
|
||||
property int position:index
|
||||
sourceComponent: list_delegate
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
list_view_3.positionViewAtIndex(currentIndex, ListView.NoPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,10 +344,12 @@ Rectangle {
|
||||
text_day.text = day
|
||||
|
||||
var pos = root.mapToItem(null, 0, 0)
|
||||
if(window.height>pos.y+35+340){
|
||||
popup.y = 35
|
||||
}else{
|
||||
popup.y = window.height-(pos.y+340)
|
||||
if(window.height>pos.y+root.height+popup.height){
|
||||
popup.y = root.height
|
||||
} else if(pos.y>popup.height){
|
||||
popup.y = -popup.height
|
||||
} else {
|
||||
popup.y = window.height-(pos.y+popup.height)
|
||||
}
|
||||
popup.open()
|
||||
}
|
||||
|
@ -1,6 +1,89 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Window 2.15
|
||||
import FluentUI 1.0
|
||||
|
||||
Item {
|
||||
Button {
|
||||
|
||||
property bool disabled: false
|
||||
property color normalColor: FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
|
||||
property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
|
||||
property color disableColor: FluTheme.isDark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
|
||||
|
||||
id: control
|
||||
topPadding:5
|
||||
bottomPadding:5
|
||||
leftPadding:15
|
||||
rightPadding:35
|
||||
enabled: !disabled
|
||||
focusPolicy:Qt.TabFocus
|
||||
property var window : Window.window
|
||||
|
||||
property alias items: menu.content
|
||||
|
||||
Keys.onSpacePressed: control.visualFocus&&clicked()
|
||||
|
||||
background: Rectangle{
|
||||
border.color: FluTheme.isDark ? "#505050" : "#DFDFDF"
|
||||
border.width: 1
|
||||
radius: 4
|
||||
FluFocusRectangle{
|
||||
visible: control.visualFocus
|
||||
radius:8
|
||||
}
|
||||
color:{
|
||||
if(disabled){
|
||||
return disableColor
|
||||
}
|
||||
return hovered ? hoverColor :normalColor
|
||||
}
|
||||
FluIcon{
|
||||
iconSource:FluentIcons.ChevronDown
|
||||
iconSize: 15
|
||||
anchors{
|
||||
right: parent.right
|
||||
rightMargin: 10
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
color:title.color
|
||||
}
|
||||
|
||||
}
|
||||
contentItem: FluText {
|
||||
id:title
|
||||
text: control.text
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: {
|
||||
if(FluTheme.isDark){
|
||||
if(disabled){
|
||||
return Qt.rgba(131/255,131/255,131/255,1)
|
||||
}
|
||||
return Qt.rgba(1,1,1,1)
|
||||
}else{
|
||||
if(disabled){
|
||||
return Qt.rgba(160/255,160/255,160/255,1)
|
||||
}
|
||||
return Qt.rgba(0,0,0,1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var pos = control.mapToItem(null, 0, 0)
|
||||
if(window.height>pos.y+control.height+menu.height){
|
||||
menu.y = control.height
|
||||
}else if(pos.y>menu.height){
|
||||
menu.y = -menu.height
|
||||
}else{
|
||||
popup.y = window.height-(pos.y+menu.height)
|
||||
}
|
||||
menu.open()
|
||||
}
|
||||
|
||||
FluMenu{
|
||||
id:menu
|
||||
width: control.width
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,16 +1,27 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
Menu {
|
||||
id: popup
|
||||
default property alias content: container.data
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 140
|
||||
implicitHeight: container.height
|
||||
color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(237/255,237/255,237/255,1)
|
||||
radius: 5
|
||||
width: 140
|
||||
height: container.height
|
||||
|
||||
background: Item {
|
||||
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,0.97) : Qt.rgba(237/255,237/255,237/255,0.97)
|
||||
radius: 5
|
||||
layer.enabled: true
|
||||
layer.effect: GaussianBlur {
|
||||
radius: 8
|
||||
samples: 16
|
||||
}
|
||||
}
|
||||
|
||||
FluShadow{
|
||||
radius: 5
|
||||
@ -19,6 +30,7 @@ Menu {
|
||||
spacing: 5
|
||||
topPadding: 5
|
||||
bottomPadding: 5
|
||||
width: popup.width
|
||||
id:container
|
||||
function closePopup(){
|
||||
popup.close()
|
||||
|
@ -4,7 +4,12 @@ import QtQuick.Controls 2.15
|
||||
Item {
|
||||
|
||||
id:root
|
||||
width: 140
|
||||
width: {
|
||||
if(root.parent){
|
||||
return root.parent.width
|
||||
}
|
||||
return 140
|
||||
}
|
||||
height: 32
|
||||
|
||||
property string text: "MenuItem"
|
||||
@ -12,14 +17,21 @@ Item {
|
||||
|
||||
Rectangle{
|
||||
anchors.centerIn: parent
|
||||
width: 100
|
||||
width: root.width-40
|
||||
height: 32
|
||||
radius: 4
|
||||
color:{
|
||||
if(mouse_area.containsMouse){
|
||||
return FluTheme.isDark ? Qt.rgba(56/255,56/255,56/255,1) : Qt.rgba(230/255,230/255,230/255,1)
|
||||
if(FluTheme.isDark){
|
||||
if(mouse_area.containsMouse){
|
||||
return Qt.rgba(1,1,1,0.05)
|
||||
}
|
||||
return Qt.rgba(0,0,0,0)
|
||||
}else{
|
||||
if(mouse_area.containsMouse){
|
||||
return Qt.rgba(0,0,0,0.05)
|
||||
}
|
||||
return Qt.rgba(0,0,0,0)
|
||||
}
|
||||
return FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(237/255,237/255,237/255,1)
|
||||
}
|
||||
|
||||
FluText{
|
||||
|
@ -16,6 +16,8 @@ Item {
|
||||
|
||||
property bool displaMinimalNav : false
|
||||
|
||||
property alias actions: layout_actions.data
|
||||
|
||||
onDisplayModeChanged: {
|
||||
if(displayMode === FluNavigationView.Minimal){
|
||||
anim_navi.enabled = false
|
||||
@ -172,22 +174,13 @@ Item {
|
||||
|
||||
|
||||
RowLayout{
|
||||
id:layout_actions
|
||||
anchors{
|
||||
right: parent.right
|
||||
rightMargin: 14
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
spacing: 5
|
||||
FluText{
|
||||
text:"夜间模式"
|
||||
fontStyle: FluText.Body
|
||||
}
|
||||
FluToggleSwitch{
|
||||
selected: FluTheme.isDark
|
||||
clickFunc:function(){
|
||||
FluTheme.isDark = !FluTheme.isDark
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,11 +370,8 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function push(url){
|
||||
nav_swipe.push(url)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ Button {
|
||||
if(selected&&disabled){
|
||||
return 3
|
||||
}
|
||||
if(hovered){
|
||||
if(pressed){
|
||||
if(selected){
|
||||
return 5
|
||||
}
|
||||
@ -48,7 +48,7 @@ Button {
|
||||
}
|
||||
Behavior on border.width {
|
||||
NumberAnimation{
|
||||
duration: 100
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
border.color: {
|
||||
|
@ -6,8 +6,6 @@ Item{
|
||||
id:root
|
||||
property var radius:[0,0,0,0]
|
||||
property color color : "#FFFFFF"
|
||||
property color borderColor:"red"
|
||||
property int borderWidth: 1
|
||||
property bool shadow: true
|
||||
default property alias contentItem: container.data
|
||||
|
||||
|
@ -202,6 +202,9 @@ Rectangle {
|
||||
height: parent.height
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
model: isH ? generateArray(1,12) : generateArray(0,23)
|
||||
clip: true
|
||||
delegate: Loader{
|
||||
@ -210,9 +213,6 @@ Rectangle {
|
||||
property int position:index
|
||||
sourceComponent: list_delegate
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
list_view_1.positionViewAtIndex(currentIndex, ListView.NoPosition)
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
width: 1
|
||||
@ -225,6 +225,9 @@ Rectangle {
|
||||
height: parent.height
|
||||
model: generateArray(0,59)
|
||||
clip: true
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
delegate: Loader{
|
||||
@ -233,9 +236,6 @@ Rectangle {
|
||||
property int position:index
|
||||
sourceComponent: list_delegate
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
list_view_2.positionViewAtIndex(currentIndex, ListView.NoPosition)
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
width: 1
|
||||
@ -250,6 +250,9 @@ Rectangle {
|
||||
model: ["上午","下午"]
|
||||
clip: true
|
||||
visible: isH
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: 0
|
||||
highlightMoveDuration: 0
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
@ -259,9 +262,6 @@ Rectangle {
|
||||
property int position:index
|
||||
sourceComponent: list_delegate
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
list_view_3.positionViewAtIndex(currentIndex, ListView.NoPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,10 +358,12 @@ Rectangle {
|
||||
}
|
||||
|
||||
var pos = root.mapToItem(null, 0, 0)
|
||||
if(window.height>pos.y+35+340){
|
||||
popup.y = 35
|
||||
}else{
|
||||
popup.y = window.height-(pos.y+340)
|
||||
if(window.height>pos.y+root.height+popup.height){
|
||||
popup.y = root.height
|
||||
} else if(pos.y>popup.height){
|
||||
popup.y = -popup.height
|
||||
} else {
|
||||
popup.y = window.height-(pos.y+popup.height)
|
||||
}
|
||||
popup.open()
|
||||
}
|
||||
|
@ -61,6 +61,9 @@ Button {
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|