完成全屏应用界面

This commit is contained in:
hewenfei 2023-03-17 17:25:50 +08:00
parent 12cae14527
commit 5754abb725
10 changed files with 486 additions and 25 deletions

View File

@ -0,0 +1,296 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import QtQml.Models 2.12
import org.ukui.menu.core 1.0
import AppControls2 1.0 as AppControls2
RowLayout {
clip: true
Item {
Layout.preferredWidth: 90
Layout.fillHeight: true
ListView {
id: labelListView
signal labelClicked(string labelId)
anchors.centerIn: parent
width: parent.width
height: contentHeight > parent.height ? parent.height : contentHeight
interactive: contentHeight > parent.height
spacing: 5
model: DelegateModel {
groups: DelegateModelGroup {
name: "disabledItem"
includeByDefault: false
}
items.onChanged: {
for (let i = 0; i < items.count;) {
let item = items.get(i);
if (item.model.isDisable) {
items.setGroups(i, 1, "disabledItem");
continue;
}
++i;
}
}
model: modelManager.getLabelModel()
delegate: MouseArea {
width: ListView.view.width
height: 30
hoverEnabled: true
AppControls2.StyleBackground {
anchors.fill: parent
radius: 4
paletteRole: Palette.Base
alpha: parent.containsPress ? 0.36 : parent.containsMouse ? 0.18 : 0
useStyleTransparent: false
AppControls2.StyleText {
anchors.fill: parent
paletteRole: Palette.Text
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: model.displayName
}
}
onClicked: {
labelListView.labelClicked(model.id)
}
}
}
}
}
Item {
id: contentViewBase
Layout.fillWidth: true
Layout.fillHeight: true
property int maxColumns: 8
property int columns: {
let c = Math.floor(width / cellWidth);
return c > maxColumns ? maxColumns : c;
}
property int cellWidth: 220
// property int cellWidth: Math.min(Math.floor(width / columns), 220)
property int cellHeight: cellWidth
property int headerHeight: 30
Component.onCompleted: {
changeView(modelManager.getLabelGroupModel().containLabel);
modelManager.getLabelGroupModel().containLabelChanged.connect(changeView);
}
Component.onDestruction: {
modelManager.getLabelGroupModel().containLabelChanged.disconnect(changeView);
contentViewLoader.sourceComponent = undefined;
}
function changeView(toLabelView) {
contentViewLoader.sourceComponent = toLabelView ? labelViewComponent : appViewComponent;
}
Loader {
id: contentViewLoader
height: parent.height
width: contentViewBase.cellWidth * contentViewBase.columns + 2
anchors.horizontalCenter: parent.horizontalCenter
}
// view id: 1
Component {
id: appViewComponent
GridView {
ScrollBar.vertical: fullScreenScrollBar
cellWidth: contentViewBase.cellWidth
cellHeight: contentViewBase.cellHeight
model: modelManager.getAppModel()
delegate: Loader {
width: GridView.view.cellWidth
height: width
property int index: model.index
property int type: model.type
property string name: model.name
property string icon: model.icon
sourceComponent: {
if (type === DataType.Normal) {
return appComponent;
}
if (type === DataType.Folder) {
return folderComponent;
}
}
}
Component {
id: appComponent
MouseArea {
anchors.centerIn: parent
width: 100
height: 140
AppControls2.IconLabel {
anchors.fill: parent
iconWidth: 96
iconHeight: 96
appName: name
appIcon: icon
}
onClicked: {
parent.GridView.view.model.appClicked(index);
}
}
}
Component {
id: folderComponent
Item {
MouseArea {
anchors.centerIn: parent
width: 100; height: 140
AppControls2.IconLabel {
anchors.fill: parent
iconWidth: 96
iconHeight: 96
appName: name
appIcon: icon
}
}
}
}
}
}
// view id: 2
Component {
id: labelViewComponent
Flickable {
id: labelViewFlickable
ScrollBar.vertical: fullScreenScrollBar
contentHeight: labelColumn.height
flickableDirection: Flickable.VerticalFlick
interactive: !contentYAnimation.running
Column {
id: labelColumn
width: parent.width
height: childrenRect.height
Repeater {
id: labelRepeater
model: modelManager.getLabelGroupModel()
delegate: GridView {
id: labelAppsGridView
width: parent.width
height: contentHeight
property int labelIndex: index
interactive: false
cacheBuffer: 50
cellWidth: contentViewBase.cellWidth
cellHeight: contentViewBase.cellHeight
header: Row {
width: labelAppsGridView.width
height: contentViewBase.headerHeight
spacing: 15
Text {
id: labelName
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
width: contentWidth
text: name
}
AppControls2.StyleBackground {
anchors.verticalCenter: parent.verticalCenter
paletteRole: Palette.Light
height: 1
width: parent.width - labelName.width - parent.spacing
}
}
model: extraData
delegate: Item {
width: GridView.view.cellWidth
height: GridView.view.cellHeight
MouseArea {
anchors.centerIn: parent
width: 100; height: 140
AppControls2.IconLabel {
anchors.fill: parent
iconWidth: 96
iconHeight: 96
appName: modelData.name
appIcon: modelData.icon
}
onClicked: {
//console.log("clicked", Object.keys(model))
labelRepeater.model.openApp(labelAppsGridView.labelIndex, model.index);
}
}
}
}
}
}
NumberAnimation {
id: contentYAnimation
target: labelViewFlickable
property: "contentY"
duration: 300
onFinished: {
labelViewFlickable.returnToBounds();
}
}
function scrollerView(labelId) {
let labelindex = labelRepeater.model.getLabelIndex(labelId);
if (labelindex < 0 || labelindex >= labelRepeater.count) {
return;
}
let nextY = labelRepeater.itemAt(labelindex).y;
let sh = labelColumn.height - nextY;
if (sh < height) {
nextY -= (height - sh);
}
contentYAnimation.running = false;
if (nextY === contentY) {
return;
}
contentYAnimation.from = contentY;
contentYAnimation.to = nextY;
contentYAnimation.running = true;
}
Component.onCompleted: {
labelListView.labelClicked.connect(scrollerView);
}
Component.onDestruction: {
labelListView.labelClicked.disconnect(scrollerView);
}
}
}
}
Item {
Layout.preferredWidth: 90
Layout.fillHeight: true
AppControls2.ScrollBar {
id: fullScreenScrollBar
anchors.horizontalCenter: parent.horizontalCenter
height: parent.height
width: 20
}
}
}

View File

@ -0,0 +1,8 @@
import QtQuick 2.0
Item {
Text {
anchors.fill: parent
text: qsTr("FullScreenFooter.qml")
}
}

View File

@ -0,0 +1,32 @@
import QtQuick 2.0
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import AppControls2 1.0 as AppControls2
import org.ukui.menu.core 1.0
Item {
clip: true
PluginSelectMenu {
anchors.right: parent.right
anchors.rightMargin: 72 // 48+24
anchors.verticalCenter: parent.verticalCenter
width: 80
height: 48
spacing: 8
}
AppControls2.RoundButton {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: 48
height: 48
buttonIcon: "image://appicon/view-restore-symbolic"
onClicked: {
mainWindow.isFullScreen = false;
}
}
}

View File

@ -1,15 +1,28 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Layouts 1.12
Item { Item {
Rectangle { ColumnLayout {
anchors.fill: parent anchors.fill: parent
color: "yellow" anchors.leftMargin: 35
anchors.rightMargin: 35
MouseArea { FullScreenHeader {
anchors.fill: parent; // full screen header
onClicked: { Layout.preferredHeight: 130
mainWindow.isFullScreen = !mainWindow.isFullScreen; Layout.fillWidth: true
} Layout.maximumHeight: 130
}
FullScreenContent {
// full screen content
Layout.fillHeight: true
Layout.fillWidth: true
}
FullScreenFooter {
// full screen footer
Layout.preferredHeight: 90
Layout.fillWidth: true
} }
} }
} }

View File

@ -40,6 +40,7 @@ Item {
id: extensionListView id: extensionListView
width: parent.width - 34 width: parent.width - 34
height: parent.height height: parent.height
clip: true
orientation: ListView.Horizontal orientation: ListView.Horizontal
model: extensionManager.extensionModel() model: extensionManager.extensionModel()
delegate: headerDelegate delegate: headerDelegate
@ -60,6 +61,19 @@ Item {
Item { Item {
width: 34 width: 34
height: 34 height: 34
Rectangle {
anchors.fill: parent
radius: height / 2
color: "lightblue"
MouseArea {
anchors.fill: parent
onClicked: {
//
console.log("==开始全屏==")
mainWindow.isFullScreen = true;
}
}
}
} }
} }

View File

@ -7,3 +7,6 @@ FullScreenUI 1.0 FullScreenUI.qml
AppPageHeader 1.0 AppPageHeader.qml AppPageHeader 1.0 AppPageHeader.qml
SearchInputBar 1.0 SearchInputBar.qml SearchInputBar 1.0 SearchInputBar.qml
PluginSelectMenu 1.0 PluginSelectMenu.qml PluginSelectMenu 1.0 PluginSelectMenu.qml
FullScreenHeader 1.0 FullScreenHeader.qml
FullScreenContent 1.0 FullScreenContent.qml
FullScreenFooter 1.0 FullScreenFooter.qml

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2023, KylinSoft Co., Ltd. * Copyright (C) 2023, KylinSoft Co., Ltd.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -17,11 +17,98 @@
*/ */
import QtQuick 2.12 import QtQuick 2.12
import QtQml 2.12
import AppUI 1.0 as AppUI import AppUI 1.0 as AppUI
import AppControls2 1.0 as AppControls2
import org.ukui.menu.core 1.0
Item { Item {
AppUI.NormalUI { id: root
anchors.fill: parent clip: true
property int animationDuration: 150
Component.onCompleted: {
loader.reloadUI();
mainWindow.beforeFullScreenChanged.connect(beforeFullScreenSlot);
mainWindow.fullScreenChanged.connect(fullScreenChangedSlot);
}
function fullScreenChangedSlot() {
loader.opacity = 0;
fullScreenAnimation.start();
}
function beforeFullScreenSlot(status) {
if (!status) {
loader.sourceComponent = undefined;
}
backgroundMask.alpha = status ? 0.5 : 0
backgroundMask.enableSizeChange = false;
}
ParallelAnimation {
id: fullScreenAnimation
NumberAnimation { target: backgroundMask; property: "width"; to: root.width; duration: root.animationDuration }
NumberAnimation { target: backgroundMask; property: "height"; to: root.height; duration: root.animationDuration }
onFinished: {
backgroundMask.enableSizeChange = true;
loader.reloadUI();
}
}
AppControls2.StyleBackground {
id: backgroundMask
anchors.left: parent.left
anchors.bottom: parent.bottom
alpha: 0
useStyleTransparent: false
paletteRole: Palette.Dark
property bool enableSizeChange: true
states: [
State {
name: "disableSizeChange"
when: !backgroundMask.enableSizeChange
AnchorChanges {
target: backgroundMask
anchors.top: undefined
anchors.right: undefined
}
},
State {
name: "enableSizeChange"
when: backgroundMask.enableSizeChange
AnchorChanges {
target: backgroundMask
anchors.top: parent.top
anchors.right: parent.right
}
}
]
Loader {
id: loader
anchors.fill: parent
Behavior on opacity {
NumberAnimation { duration: root.animationDuration }
}
function reloadUI() {
loader.sourceComponent = mainWindow.isFullScreen ? fullSceenComponent : normalComponent;
loader.opacity = 1;
}
}
}
Component {
id: fullSceenComponent
AppUI.FullScreenUI {}
}
Component {
id: normalComponent
AppUI.NormalUI {}
} }
} }

View File

@ -10,6 +10,9 @@
<file>AppUI/AppPage.qml</file> <file>AppUI/AppPage.qml</file>
<file>AppUI/Sidebar.qml</file> <file>AppUI/Sidebar.qml</file>
<file>AppUI/AppList.qml</file> <file>AppUI/AppList.qml</file>
<file>AppUI/FullScreenHeader.qml</file>
<file>AppUI/FullScreenContent.qml</file>
<file>AppUI/FullScreenFooter.qml</file>
<file>AppUI/AppPageHeader.qml</file> <file>AppUI/AppPageHeader.qml</file>
<file>AppUI/SearchInputBar.qml</file> <file>AppUI/SearchInputBar.qml</file>
<file>AppControls2/qmldir</file> <file>AppControls2/qmldir</file>

View File

@ -395,6 +395,8 @@ void MenuWindow::init()
QEvent event(QEvent::Move); QEvent event(QEvent::Move);
QCoreApplication::sendEvent(this, &event); QCoreApplication::sendEvent(this, &event);
}); });
updateGeometry();
} }
void MenuWindow::updateGeometry() void MenuWindow::updateGeometry()
@ -412,13 +414,24 @@ bool MenuWindow::isFullScreen() const
return m_isFullScreen; return m_isFullScreen;
} }
/**
* beforeFullScreenChanged -> (qml)onWidthChanged -> fullScreenChanged
* @param isFullScreen
*/
void MenuWindow::setFullScreen(bool isFullScreen) void MenuWindow::setFullScreen(bool isFullScreen)
{ {
if (m_isFullScreen == isFullScreen) { if (m_isFullScreen == isFullScreen) {
return; return;
} }
Q_EMIT beforeFullScreenChanged(isFullScreen);
m_isFullScreen = isFullScreen; m_isFullScreen = isFullScreen;
WindowHelper::windowBlur(this, !m_isFullScreen);
updateGeometry();
// 更新contentItem尺寸
QEvent event(QEvent::Resize); QEvent event(QEvent::Resize);
QCoreApplication::sendEvent(this, &event); QCoreApplication::sendEvent(this, &event);
@ -427,24 +440,17 @@ void MenuWindow::setFullScreen(bool isFullScreen)
void MenuWindow::exposeEvent(QExposeEvent *event) void MenuWindow::exposeEvent(QExposeEvent *event)
{ {
if (isExposed()) {
requestActivate();
}
QQuickWindow::exposeEvent(event); QQuickWindow::exposeEvent(event);
} }
void MenuWindow::resizeEvent(QResizeEvent *event)
{
updateGeometry();
QQuickView::resizeEvent(event);
}
void MenuWindow::showEvent(QShowEvent *event)
{
QQuickWindow::showEvent(event);
}
void MenuWindow::focusOutEvent(QFocusEvent *event) void MenuWindow::focusOutEvent(QFocusEvent *event)
{ {
//setVisible(false); // void QQuickWindow::focusOutEvent(QFocusEvent *ev) { Q_D(QQuickWindow); if (d->contentItem) d->contentItem->setFocus(false, ev->reason()); }
QQuickWindow::focusOutEvent(event); QQuickWindow::focusOutEvent(event);
// setVisible(false);
} }
bool MenuWindow::event(QEvent *event) bool MenuWindow::event(QEvent *event)

View File

@ -115,14 +115,13 @@ public:
Q_SIGNALS: Q_SIGNALS:
void fullScreenChanged(); void fullScreenChanged();
void beforeFullScreenChanged(bool isToFullScreen);
private Q_SLOTS: private Q_SLOTS:
void onActiveFocusItemChanged(); void onActiveFocusItemChanged();
protected: protected:
void exposeEvent(QExposeEvent *event) override; void exposeEvent(QExposeEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void showEvent(QShowEvent *event) override;
void focusOutEvent(QFocusEvent *event) override; void focusOutEvent(QFocusEvent *event) override;
bool event(QEvent *event) override; bool event(QEvent *event) override;