diff --git a/qml/AppUI/FullScreenContent.qml b/qml/AppUI/FullScreenContent.qml
new file mode 100644
index 0000000..2e8b685
--- /dev/null
+++ b/qml/AppUI/FullScreenContent.qml
@@ -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
+ }
+ }
+}
diff --git a/qml/AppUI/FullScreenFooter.qml b/qml/AppUI/FullScreenFooter.qml
new file mode 100644
index 0000000..e7aa824
--- /dev/null
+++ b/qml/AppUI/FullScreenFooter.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Item {
+ Text {
+ anchors.fill: parent
+ text: qsTr("FullScreenFooter.qml")
+ }
+}
diff --git a/qml/AppUI/FullScreenHeader.qml b/qml/AppUI/FullScreenHeader.qml
new file mode 100644
index 0000000..51df2f2
--- /dev/null
+++ b/qml/AppUI/FullScreenHeader.qml
@@ -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;
+ }
+ }
+}
+
+
diff --git a/qml/AppUI/FullScreenUI.qml b/qml/AppUI/FullScreenUI.qml
index f59978c..3bde267 100644
--- a/qml/AppUI/FullScreenUI.qml
+++ b/qml/AppUI/FullScreenUI.qml
@@ -1,15 +1,28 @@
import QtQuick 2.0
-
+import QtQuick.Layouts 1.12
Item {
- Rectangle {
+ ColumnLayout {
anchors.fill: parent
- color: "yellow"
+ anchors.leftMargin: 35
+ anchors.rightMargin: 35
- MouseArea {
- anchors.fill: parent;
- onClicked: {
- mainWindow.isFullScreen = !mainWindow.isFullScreen;
- }
+ FullScreenHeader {
+ // full screen header
+ Layout.preferredHeight: 130
+ 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
}
}
}
diff --git a/qml/AppUI/Sidebar.qml b/qml/AppUI/Sidebar.qml
index aadf7a0..663ec34 100644
--- a/qml/AppUI/Sidebar.qml
+++ b/qml/AppUI/Sidebar.qml
@@ -40,6 +40,7 @@ Item {
id: extensionListView
width: parent.width - 34
height: parent.height
+ clip: true
orientation: ListView.Horizontal
model: extensionManager.extensionModel()
delegate: headerDelegate
@@ -60,6 +61,19 @@ Item {
Item {
width: 34
height: 34
+ Rectangle {
+ anchors.fill: parent
+ radius: height / 2
+ color: "lightblue"
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ // 全屏
+ console.log("==开始全屏==")
+ mainWindow.isFullScreen = true;
+ }
+ }
+ }
}
}
diff --git a/qml/AppUI/qmldir b/qml/AppUI/qmldir
index 1263720..d09f024 100644
--- a/qml/AppUI/qmldir
+++ b/qml/AppUI/qmldir
@@ -7,3 +7,6 @@ FullScreenUI 1.0 FullScreenUI.qml
AppPageHeader 1.0 AppPageHeader.qml
SearchInputBar 1.0 SearchInputBar.qml
PluginSelectMenu 1.0 PluginSelectMenu.qml
+FullScreenHeader 1.0 FullScreenHeader.qml
+FullScreenContent 1.0 FullScreenContent.qml
+FullScreenFooter 1.0 FullScreenFooter.qml
diff --git a/qml/main.qml b/qml/main.qml
index f65dcd7..500b917 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
@@ -17,11 +17,98 @@
*/
import QtQuick 2.12
+import QtQml 2.12
import AppUI 1.0 as AppUI
+import AppControls2 1.0 as AppControls2
+import org.ukui.menu.core 1.0
Item {
- AppUI.NormalUI {
- anchors.fill: parent
+ id: root
+ 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 {}
}
}
diff --git a/qml/qml.qrc b/qml/qml.qrc
index d43b85e..91772c6 100644
--- a/qml/qml.qrc
+++ b/qml/qml.qrc
@@ -10,6 +10,9 @@
AppUI/AppPage.qml
AppUI/Sidebar.qml
AppUI/AppList.qml
+ AppUI/FullScreenHeader.qml
+ AppUI/FullScreenContent.qml
+ AppUI/FullScreenFooter.qml
AppUI/AppPageHeader.qml
AppUI/SearchInputBar.qml
AppControls2/qmldir
diff --git a/src/windows/menu-main-window.cpp b/src/windows/menu-main-window.cpp
index 19e758c..43f796e 100644
--- a/src/windows/menu-main-window.cpp
+++ b/src/windows/menu-main-window.cpp
@@ -395,6 +395,8 @@ void MenuWindow::init()
QEvent event(QEvent::Move);
QCoreApplication::sendEvent(this, &event);
});
+
+ updateGeometry();
}
void MenuWindow::updateGeometry()
@@ -412,13 +414,24 @@ bool MenuWindow::isFullScreen() const
return m_isFullScreen;
}
+/**
+ * beforeFullScreenChanged -> (qml)onWidthChanged -> fullScreenChanged
+ * @param isFullScreen
+ */
void MenuWindow::setFullScreen(bool isFullScreen)
{
if (m_isFullScreen == isFullScreen) {
return;
}
+ Q_EMIT beforeFullScreenChanged(isFullScreen);
+
m_isFullScreen = isFullScreen;
+ WindowHelper::windowBlur(this, !m_isFullScreen);
+
+ updateGeometry();
+
+ // 更新contentItem尺寸
QEvent event(QEvent::Resize);
QCoreApplication::sendEvent(this, &event);
@@ -427,24 +440,17 @@ void MenuWindow::setFullScreen(bool isFullScreen)
void MenuWindow::exposeEvent(QExposeEvent *event)
{
+ if (isExposed()) {
+ requestActivate();
+ }
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)
{
- //setVisible(false);
+ // void QQuickWindow::focusOutEvent(QFocusEvent *ev) { Q_D(QQuickWindow); if (d->contentItem) d->contentItem->setFocus(false, ev->reason()); }
QQuickWindow::focusOutEvent(event);
+ // setVisible(false);
}
bool MenuWindow::event(QEvent *event)
diff --git a/src/windows/menu-main-window.h b/src/windows/menu-main-window.h
index 37c649f..ce51749 100644
--- a/src/windows/menu-main-window.h
+++ b/src/windows/menu-main-window.h
@@ -115,14 +115,13 @@ public:
Q_SIGNALS:
void fullScreenChanged();
+ void beforeFullScreenChanged(bool isToFullScreen);
private Q_SLOTS:
void onActiveFocusItemChanged();
protected:
void exposeEvent(QExposeEvent *event) override;
- void resizeEvent(QResizeEvent *event) override;
- void showEvent(QShowEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
bool event(QEvent *event) override;