diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml index 352df33..7351e65 100644 --- a/src/controls/ApplicationWindow.qml +++ b/src/controls/ApplicationWindow.qml @@ -1,568 +1,569 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Window 2.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Controls.Material 2.1 import "private" Kirigami.AbstractApplicationWindow { id: root visible: true width: Screen.width * (Kirigami.Settings.isMobile ? 1 : 0.4) height: Screen.height * (Kirigami.Settings.isMobile ? 1 : 0.4) contentItem.anchors.leftMargin: root.sideBar && !root.globalDrawer ? ((root.sideBar.collapsible && root.sideBar.collapsed) ? root.sideBar.collapsedSize : (root.sideBar.modal ? 0 : root.sideBar.width * root.sideBar.position)) : (!root.sideBar && root.globalDrawer && (root.globalDrawer.modal === false) ? root.globalDrawer.width * root.globalDrawer.position : 0) property Maui.AbstractSideBar sideBar /***************************************************/ /******************** ALIASES *********************/ /*************************************************/ property alias headBar : _headBar property alias footBar: _footBar property alias dialog: dialogLoader.item property alias leftIcon : menuBtn property alias menuButton : menuBtn property alias mainMenu : mainMenu.contentData property alias about : aboutDialog property alias accounts: _accountsDialogLoader.item property var currentAccount: Maui.App.accounts.currentAccount property alias notifyDialog: _notify wideScreen: isWide /***************************************************/ /*********************** UI ***********************/ /*************************************************/ property bool isWide : root.width >= Kirigami.Units.gridUnit * 30 property Flickable flickable : null onFlickableChanged: returnToBounds() property int footerPositioning : Kirigami.Settings.isMobile && flickable ? ListView.PullBackHeader : ListView.InlineFooter property int headerPositioning : Kirigami.Settings.isMobile && flickable ? ListView.PullBackHeader : ListView.InlineHeader /***************************************************/ /********************* COLORS *********************/ /*************************************************/ property color headBarBGColor: Kirigami.Theme.backgroundColor property color headBarFGColor: Kirigami.Theme.textColor /***************************************************/ /**************** READONLY PROPS ******************/ /*************************************************/ readonly property bool isMobile : Kirigami.Settings.isMobile readonly property bool isAndroid: Maui.Handy.isAndroid readonly property bool isTouch: Maui.Handy.isTouch readonly property real screenWidth : Screen.width readonly property real screenHeight : Screen.height /***************************************************/ /******************** SIGNALS *********************/ /*************************************************/ signal menuButtonClicked(); onClosing: { if(!Kirigami.Settings.isMobile) { const height = root.height const width = root.width const x = root.x const y = root.y Maui.FM.saveSettings("GEOMETRY", Qt.rect(x, y, width, height), "WINDOW") } } property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientation || Screen.primaryOrientation === Qt.InvertedPortraitOrientation onIsPortraitChanged: { if(isPortrait) { console.log("PORTARIT MODE CHANGED") width: Screen.width height: Screen.height } } // onHeadBarBGColorChanged: // { // if(!isMobile && colorSchemeName.length > 0) // Maui.KDE.setColorScheme(colorSchemeName, headBarBGColor, headBarFGColor) // else if(isAndroid && headBar.position === ToolBar.Header) // Maui.Android.statusbarColor(headBarBGColor, false) // else if(isAndroid && headBar.position === ToolBar.Footer) // Maui.Android.statusbarColor(Kirigami.Theme.viewBackgroundColor, true) // // } // // onHeadBarFGColorChanged: // { // if(!isAndroid && !isMobile && colorSchemeName.length > 0 && headBar.position === ToolBar.Header) // Maui.KDE.setColorScheme(colorSchemeName, headBarBGColor, headBarFGColor) // else if(isAndroid && headBar.position === ToolBar.Header) // Maui.Android.statusbarColor(headBarBGColor, false) // else if(isAndroid && headBar.position === ToolBar.Footer) // Maui.Android.statusbarColor(Kirigami.Theme.viewBackgroundColor, true) // } /* * background: Rectangle * { * color: bgColor } */ Component { id: _accountsComponent ColumnLayout { visible: Maui.App.handleAccounts spacing: Maui.Style.space.medium Kirigami.Icon { visible: Maui.App.accounts.currentAccountIndex >= 0 source: "user-identity" Layout.preferredHeight: Maui.Style.iconSizes.large Layout.preferredWidth: Maui.Style.iconSizes.large Layout.alignment: Qt.AlignCenter Layout.margins: Maui.Style.space.medium } Label { visible: Maui.App.accounts.currentAccountIndex >= 0 text: currentAccount.user Layout.fillWidth: true horizontalAlignment: Qt.AlignHCenter elide: Text.ElideMiddle wrapMode: Text.NoWrap font.bold: true font.weight: Font.Bold } Kirigami.Separator { visible: _accountsListing.count > 0 Layout.fillWidth: true } ListBrowser { id: _accountsListing visible: _accountsListing.count > 0 Layout.fillWidth: true - Layout.preferredHeight: Math.min(listView.contentHeight, 300) - listView.spacing: Maui.Style.space.medium + Layout.preferredHeight: Math.min(contentHeight, 300) + spacing: Maui.Style.space.medium Kirigami.Theme.backgroundColor: "transparent" currentIndex: Maui.App.accounts.currentAccountIndex model: Maui.BaseModel { list: Maui.App.accounts } delegate: Maui.ListBrowserDelegate { iconSource: "amarok_artist" iconSizeHint: Maui.Style.iconSizes.medium label1.text: model.user label2.text: model.server width: _accountsListing.width height: Maui.Style.rowHeight * 1.2 leftPadding: Maui.Style.space.tiny rightPadding: Maui.Style.space.tiny onClicked: Maui.App.accounts.currentAccountIndex = index } Component.onCompleted: { if(_accountsListing.count > 0) Maui.App.accounts.currentAccountIndex = 0 } } Kirigami.Separator { visible: _accountsListing.count > 0 Layout.fillWidth: true } Button { Layout.margins: Maui.Style.space.small Layout.preferredHeight: implicitHeight Layout.alignment: Qt.AlignCenter text: qsTr("Manage accounts") icon.name: "list-add-user" onClicked: { if(root.accounts) accounts.open() mainMenu.close() } Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.1) Kirigami.Theme.textColor: Kirigami.Theme.textColor } Kirigami.Separator { Layout.fillWidth: true } } } Connections { target: root.flickable ? root.flickable : null - enabled: root.flickable && (root.header || root.footer) + enabled: root.flickable && ((root.header && root.headerPositioning === ListView.PullBackHeader) || (root.footer && root.footerPositioning === ListView.PullBackFooter)) property int oldContentY property bool updatingContentY: false - - onContentHeightChanged: returnToBounds() onContentYChanged: { + if(!root.flickable.dragging && root.flickable.atYBeginning) + root.returnToBounds() + if (updatingContentY || !root.flickable || !root.flickable.dragging) { - oldContentY = root.flickable.contentY; + oldContentY = root.flickable.contentY return; //TODO: merge //if moves but not dragging, just update oldContentY } if(root.flickable.contentHeight < root.height) return var oldFHeight var oldHHeight if (root.footer && root.footerPositioning === ListView.PullBackFooter) { oldFHeight = root.footer.height root.footer.height = Math.max(0, Math.min(root.footer.implicitHeight, root.footer.height + oldContentY - root.flickable.contentY)); } if (root.header && root.headerPositioning === ListView.PullBackHeader) { oldHHeight = root.header.height root.header.height = Math.max(0, Math.min(root.header.implicitHeight, root.header.height + oldContentY - root.flickable.contentY)); } //if the implicitHeight is changed, use that to simulate scroll if ((root.footer && oldFHeight !== root.footer.height)|| ( root.header && oldHHeight !== root.header.height)) { updatingContentY = true; if(root.header && oldHHeight !== root.header.height) root.flickable.contentY -= (oldHHeight - root.header.height) updatingContentY = false; } else { oldContentY = root.flickable.contentY } } onMovementEnded: { if (root.headerPositioning === ListView.PullBackHeader && root.header) { if (root.header.height >= (root.header.implicitHeight/2) || root.flickable.atYBeginning ) { root.header.height = root.header.implicitHeight } else { root.header.height = 0 } } if (root.footerPositioning === ListView.PullBackFooter && root.footer) { if (root.footer.height >= (root.footer.implicitHeight/2) || root.flickable.atYEnd) { if(root.flickable.atYEnd) { root.footer.height = root.footer.implicitHeight root.flickable.contentY = root.flickable.contentHeight - root.flickable.height oldContentY = root.flickable.contentY }else { root.footer.height = root.footer.implicitHeight } } else { root.footer.height = 0 } } } } property Maui.ToolBar mheadBar : Maui.ToolBar { id: _headBar visible: count > 1 position: ToolBar.Header width: root.width height: implicitHeight // Kirigami.Theme.backgroundColor: headBarBGColor // Kirigami.Theme.textColor: headBarFGColor // Kirigami.Theme.inherit: true leftContent: [ ToolButton { id: menuBtn icon.name: "application-menu" icon.color: headBarFGColor icon.width: Maui.Style.iconSizes.medium icon.height: Maui.Style.iconSizes.medium checked: mainMenu.visible onClicked: { menuButtonClicked() mainMenu.visible ? mainMenu.close() : mainMenu.popup(parent, parent.x , parent.height+ Maui.Style.space.medium) } Menu { id: mainMenu modal: true z: 999 width: Maui.Style.unit * 250 Loader { id: _accountsMenuLoader width: parent.width * 0.9 anchors.horizontalCenter: parent.horizontalCenter active: Maui.App.handleAccounts sourceComponent: Maui.App.handleAccounts ? _accountsComponent : null } MenuItem { text: qsTr("About") icon.name: "documentinfo" onTriggered: aboutDialog.open() } } } ] } property Maui.ToolBar mfootBar : Maui.ToolBar { id: _footBar visible: count position: ToolBar.Footer width: root.width height: implicitHeight } header: headBar.count && headBar.position === ToolBar.Header ? headBar : null footer: Column { id: _footer visible : children onImplicitHeightChanged: height = implicitHeight children: { if(headBar.position === ToolBar.Footer && headBar.count && footBar.count) return [footBar , headBar] else if(headBar.position === ToolBar.Footer && headBar.count) return [headBar] else if(footBar.count) return [footBar] else return null } } Maui.AboutDialog { id: aboutDialog } Loader { id: _accountsDialogLoader source: Maui.App.handleAccounts ? "private/AccountsHelper.qml" : "" } Maui.Dialog { id: _notify property var cb : ({}) property alias iconName : _notifyTemplate.iconSource property alias title : _notifyTemplate.label1 property alias body: _notifyTemplate.label2 verticalAlignment: Qt.AlignTop defaultButtons: _notify.cb !== null rejectButton.visible: false onAccepted: { if(_notify.cb) { _notify.cb() _notify.close() } } page.padding: Maui.Style.space.medium footBar.background: null maxHeight: Math.max(Maui.Style.iconSizes.large + Maui.Style.space.huge, (_notifyTemplate.implicitHeight)) + Maui.Style.space.big + footBar.height maxWidth: Kirigami.Settings.isMobile ? parent.width * 0.9 : Maui.Style.unit * 500 widthHint: 0.8 Timer { id: _notifyTimer onTriggered: { if(_mouseArea.containsPress || _mouseArea.containsMouse) return; _notify.close() } } onClosed: _notifyTimer.stop() Maui.ListItemTemplate { id: _notifyTemplate anchors.fill: parent iconSizeHint: Maui.Style.iconSizes.huge label1.font.bold: true label1.font.weight: Font.Bold label1.font.pointSize: Maui.Style.fontSizes.big iconSource: "dialog-warning" } MouseArea { id: _mouseArea height: parent.height width: parent.width anchors.centerIn: parent hoverEnabled: true } function show(callback) { _notify.cb = callback || null _notifyTimer.start() _notify.open() } } Loader { id: dialogLoader } Component.onCompleted: { if(isAndroid) { if(headBar.position === ToolBar.Footer) Maui.Android.statusbarColor(Kirigami.Theme.backgroundColor, true) else Maui.Android.statusbarColor(headBar.Kirigami.Theme.backgroundColor, true) } if(!Kirigami.Settings.isMobile) { const rect = Maui.FM.loadSettings("GEOMETRY", "WINDOW", Qt.rect(root.x, root.y, root.width, root.height)) root.x = rect.x root.y = rect.y root.width = rect.width root.height = rect.height } } Connections { target: Maui.App onSendNotification: notify(icon, title, body, callback, timeout, buttonText) } function notify(icon, title, body, callback, timeout, buttonText) { _notify.iconName = icon || "emblem-warning" _notify.title.text = title _notify.body.text = body _notifyTimer.interval = timeout ? timeout : 2500 _notify.acceptButton.text = buttonText || qsTr ("Accept") _notify.show(callback) } function returnToBounds() { if(root.header) root.header.height = root.header.implicitHeight if(root.footer) root.footer.height = root.footer.implicitHeight } } diff --git a/src/controls/FileDialog.qml b/src/controls/FileDialog.qml index 9fbf687..dcf79cb 100644 --- a/src/controls/FileDialog.qml +++ b/src/controls/FileDialog.qml @@ -1,271 +1,271 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Layouts 1.3 Maui.Dialog { id: control maxHeight: Kirigami.Settings.isMobile ? parent.height * 0.95 : Maui.Style.unit * 500 maxWidth: Maui.Style.unit * 700 page.padding: 0 property alias currentPath : browser.currentPath property alias browser : browser property string suggestedFileName : "" property alias settings : browser.settings property bool searchBar : false readonly property var modes : ({OPEN: 0, SAVE: 1}) property int mode : modes.OPEN property var callback : ({}) property alias textField: _textField rejectButton.visible: false acceptButton.text: control.mode === modes.SAVE ? qsTr("Save") : qsTr("Open") footBar.leftSretch: false footBar.middleContent: Maui.TextField { id: _textField visible: control.mode === modes.SAVE Layout.fillWidth: true placeholderText: qsTr("File name") text: suggestedFileName } onAccepted: { console.log("CURRENT PATHb", browser.currentPath+"/"+textField.text) if(control.mode === modes.SAVE && Maui.FM.fileExists(browser.currentPath+"/"+textField.text)) { _confirmationDialog.open() }else { done() } } Maui.Dialog { id: _confirmationDialog acceptButton.text: qsTr("Accept") rejectButton.text: qsTr("Cancel") title: qsTr(textField.text+" already exists!") message: qsTr("If you are sure you want to replace the existing file click on Accept, otherwise click on cancel and change the name of the file to something different...") onAccepted: control.done() onRejected: close() } Maui.Page { id: page anchors.fill: parent leftPadding: 0 rightPadding: leftPadding topPadding: leftPadding bottomPadding: leftPadding headBar.implicitHeight: Maui.Style.toolBarHeight + Maui.Style.space.medium Component { id: _pathBarComponent Maui.PathBar { anchors.fill: parent onPathChanged: browser.openFolder(path) url: browser.currentPath onHomeClicked: browser.openFolder(Maui.FM.homePath()) onPlaceClicked: browser.openFolder(path) } } Component { id: _searchFieldComponent Maui.TextField { anchors.fill: parent placeholderText: qsTr("Search for files... ") onAccepted: browser.openFolder("search://"+text) // onCleared: browser.goBack() onGoBackTriggered: { searchBar = false clear() // browser.goBack() } background: Rectangle { border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) radius: Maui.Style.radiusV color: Kirigami.Theme.backgroundColor } } } headBar.leftContent: ToolButton { icon.name: "application-menu" checked: pageRow.currentIndex === 0 onClicked: pageRow.currentIndex = !pageRow.currentIndex } headBar.middleContent: Item { id: _pathBarLoader Layout.fillWidth: true Layout.margins: Maui.Style.space.medium height: Maui.Style.iconSizes.big Loader { anchors.fill: parent sourceComponent: searchBar ? _searchFieldComponent : _pathBarComponent } } headBar.rightContent: ToolButton { id: searchButton icon.name: "edit-find" onClicked: searchBar = !searchBar checked: searchBar } Kirigami.PageRow { id: pageRow anchors.fill: parent clip: true separatorVisible: wideMode initialPage: [sidebar, browser] defaultColumnWidth: Kirigami.Units.gridUnit * (Kirigami.Settings.isMobile? 15 : 8) Maui.PlacesListBrowser { id: sidebar onPlaceClicked: { pageRow.currentIndex = 1 browser.openFolder(path) } list.groups: control.mode === modes.OPEN ? [ Maui.FMList.PLACES_PATH, Maui.FMList.CLOUD_PATH, Maui.FMList.REMOTE_PATH, Maui.FMList.DRIVES_PATH, Maui.FMList.TAGS_PATH] : [Maui.FMList.PLACES_PATH, Maui.FMList.REMOTE_PATH, Maui.FMList.CLOUD_PATH, Maui.FMList.DRIVES_PATH] } Maui.FileBrowser { id: browser previewer.parent: ApplicationWindow.overlay settings.selectionMode: control.mode === modes.OPEN onNewBookmark: { for(var index in paths) sidebar.list.addPlace(paths[index]) } onItemClicked: { switch(control.mode) { case modes.OPEN : { openItem(index) break } case modes.SAVE: { if(Maui.FM.isDir(currentFMList.get(index).path)) openItem(index) else textField.text = currentFMList.get(index).label break } } } onCurrentPathChanged: { sidebar.currentIndex = -1 for(var i = 0; i < sidebar.count; i++) if(String(browser.currentPath) === sidebar.list.get(i).path) { sidebar.currentIndex = i return; } } } } } function show(cb) { if(cb) callback = cb - browser.openFolder(browser.currentPath) +// browser.openFolder(browser.currentPath) open() } function closeIt() { browser.clearSelection() close() } function done() { var paths = browser.selectionBar && browser.selectionBar.visible ? browser.selectionBar.uris : [browser.currentPath] if(control.mode === modes.SAVE) { for(var i in paths) paths[i] = paths[i] + "/" + textField.text } if(callback) callback(paths) control.closeIt() } } diff --git a/src/controls/Page.qml b/src/controls/Page.qml index d604eef..73ac94c 100644 --- a/src/controls/Page.qml +++ b/src/controls/Page.qml @@ -1,253 +1,253 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.10 import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import QtQuick.Layouts 1.3 Page { id: control focus: true leftPadding: control.padding rightPadding: control.padding topPadding: control.padding bottomPadding: control.padding Kirigami.Theme.colorSet: Kirigami.Theme.View property bool showTitle : true property Flickable flickable : null property int footerPositioning : Kirigami.Settings.isMobile && flickable ? ListView.PullBackHeader : ListView.InlineFooter property int headerPositioning : Kirigami.Settings.isMobile && flickable ? ListView.PullBackHeader : ListView.InlineHeader signal goBackTriggered() signal goForwardTriggered() background: Rectangle { color: Kirigami.Theme.backgroundColor } onFlickableChanged: returnToBounds() Connections { target: control.flickable ? control.flickable : null - enabled: control.flickable && (control.header || control.footer) + enabled: control.flickable && ((control.header && control.headerPositioning === ListView.PullBackHeader) || (control.footer && control.footerPositioning === ListView.PullBackFooter)) property int oldContentY property bool updatingContentY: false - onContentHeightChanged: returnToBounds() - - onContentYChanged: - { + onContentYChanged: + { + if(!control.flickable.dragging && control.flickable.atYBeginning) + control.returnToBounds() + if (updatingContentY || !control.flickable || !control.flickable.dragging) { oldContentY = control.flickable.contentY; return; //TODO: merge //if moves but not dragging, just update oldContentY } if(control.flickable.contentHeight < control.height) return var oldFHeight var oldHHeight if (control.footer && control.footerPositioning === ListView.PullBackFooter) { oldFHeight = control.footer.height control.footer.height = Math.max(0, Math.min(control.footer.implicitHeight, control.footer.height + oldContentY - control.flickable.contentY)); + + } if (control.header && control.headerPositioning === ListView.PullBackHeader) { oldHHeight = control.header.height control.header.height = Math.max(0, Math.min(control.header.implicitHeight, control.header.height + oldContentY - control.flickable.contentY)); } //if the implicitHeight is changed, use that to simulate scroll if ((control.footer && oldFHeight !== control.footer.height) || ( control.header && oldHHeight !== control.header.height)) { updatingContentY = true if(control.header && oldHHeight !== control.header.height) control.flickable.contentY -= (oldHHeight - control.header.height) updatingContentY = false } else { oldContentY = control.flickable.contentY } } onMovementEnded: { - - - if (control.headerPositioning === ListView.PullBackHeader && control.header) { if (control.header.height >= (control.header.implicitHeight/2) || control.flickable.atYBeginning ) { control.header.height = control.header.implicitHeight } else { control.header.height = 0 } } if (control.footerPositioning === ListView.PullBackFooter && control.footer) { if (control.footer.height >= (control.footer.implicitHeight/2) || control.flickable.atYEnd) { if(control.flickable.atYEnd) { control.footer.height = control.footer.implicitHeight control.flickable.contentY = control.flickable.contentHeight - control.flickable.height oldContentY = control.flickable.contentY }else { control.footer.height = control.footer.implicitHeight } } else { control.footer.height = 0 } } } } property alias headBar : _headBar property alias footBar: _footBar property Maui.ToolBar mheadBar : Maui.ToolBar { id: _headBar visible: count > 1 width: control.width height: implicitHeight position: ToolBar.Header Component { id: _titleComponent Label { text: control.title elide : Text.ElideRight font.bold : false font.weight: Font.Bold color : Kirigami.Theme.textColor font.pointSize: Maui.Style.fontSizes.big horizontalAlignment : Text.AlignHCenter verticalAlignment : Text.AlignVCenter } } middleContent: Loader { Layout.fillWidth: sourceComponent === _titleComponent Layout.fillHeight: sourceComponent === _titleComponent sourceComponent: control.title && control.showTitle ? _titleComponent : undefined } } property Maui.ToolBar mfootBar : Maui.ToolBar { id: _footBar visible: count position: ToolBar.Footer width: control.width height: implicitHeight } header: headBar.count && headBar.position === ToolBar.Header ? headBar : null footer: Column { id: _footer visible : children onImplicitHeightChanged: height = implicitHeight children: { if(headBar.position === ToolBar.Footer && headBar.count && footBar.count) return [footBar , headBar] else if(headBar.position === ToolBar.Footer && headBar.count) return [headBar] else if(footBar.count) return [footBar] else return [] } } Keys.onBackPressed: { control.goBackTriggered(); event.accepted = true } Shortcut { sequence: "Forward" onActivated: control.goForwardTriggered(); } Shortcut { sequence: StandardKey.Forward onActivated: control.goForwardTriggered(); } Shortcut { sequence: StandardKey.Back onActivated: control.goBackTriggered(); } function returnToBounds() { if(control.header) control.header.height = control.header.implicitHeight if(control.footer) control.footer.height = control.footer.implicitHeight } } diff --git a/src/controls/ToolBar.qml b/src/controls/ToolBar.qml index e658d28..63e00de 100644 --- a/src/controls/ToolBar.qml +++ b/src/controls/ToolBar.qml @@ -1,301 +1,308 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.6 import QtQuick.Controls 2.2 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import "private" ToolBar { id: control implicitHeight: Maui.Style.toolBarHeight implicitWidth: mainFlickable.contentWidth spacing: Maui.Style.space.small padding: 0 property alias stickyRightContent : rightRowContent.sticky property alias stickyLeftContent : leftRowContent.sticky property alias stickyMiddleContent : middleRowContent.sticky property alias leftContent : leftRowContent.data property alias middleContent : middleRowContent.data property alias rightContent : rightRowContent.data property alias middleLayout : middleRowContent property alias leftLayout : leftRowContent property alias rightLayout : rightRowContent property alias layout : layout readonly property alias fits : mainFlickable.fits property int margins: Maui.Style.space.medium property int count : leftContent.length + middleContent.length + rightContent.length property bool flickable: true property bool strech : true property bool leftSretch: strech property bool rightSretch: strech property bool middleStrech: strech // leftPadding: Kirigami.Units.smallSpacing*2 // rightPadding: Kirigami.Units.smallSpacing*2 // background: Rectangle // { // id: headBarBG // color: colorScheme.backgroundColor // implicitHeight: Maui.Style.toolBarHeightAlt // radius: floating ? Maui.Style.radiusV : 0 // border.color: floating ? colorScheme.borderColor : "transparent" // // SequentialAnimation on radius // { // ColorAnimation { to: colorScheme.backgroundColor ; duration: 1000 } // } // // Kirigami.Separator // { // visible: drawBorder // color: colorScheme.borderColor // height: Maui.Style.unit // anchors // { // left: parent.left // right: parent.right // bottom: control.position == ToolBar.Footer ? undefined : parent.bottom // top: control.position == ToolBar.Footer ? parent.top : undefined // } // } // // layer.enabled: dropShadow // layer.effect: DropShadow // { // anchors.fill: headBarBG // horizontalOffset: 0 // verticalOffset: Maui.Style.unit * (altToolBars ? -1 : 1) // radius: 8 // samples: 25 // color: Qt.darker(colorScheme.backgroundColor, 1.4) // source: headBarBG // } // } MouseArea { id: _rightFlickRec width: Maui.Style.iconSizes.medium height: parent.height visible: !mainFlickable.atXEnd && !mainFlickable.fits && control.flickable hoverEnabled: true anchors { top: parent.top bottom: parent.bottom right: parent.right } z: 999 EdgeShadow { visible: true parent: parent edge: Qt.RightEdge anchors { right: parent.right top: parent.top bottom: parent.bottom } opacity: 1 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration easing.type: Easing.InOutQuad } } } Kirigami.Icon { visible: !Kirigami.Settings.isMobile anchors.centerIn: parent source: "qrc:/assets/arrow-right.svg" isMask: true width: Maui.Style.iconSizes.small height: Maui.Style.iconSizes.small color: _rightFlickRec.hovered ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor } enabled: !mainFlickable.atXEnd opacity: enabled ? 1 : 0.4 onClicked: { if(!mainFlickable.atXEnd) mainFlickable.contentX += control.height if(mainFlickable.atXEnd) mainFlickable.returnToBounds() } } MouseArea { id: _leftFlickRec width: Maui.Style.iconSizes.medium height: parent.height visible: !mainFlickable.atXBeginning && !mainFlickable.fits && control.flickable hoverEnabled: true anchors { top: parent.top bottom: parent.bottom left: parent.left } z: 999 EdgeShadow { visible: true parent: parent edge: Qt.LeftEdge anchors { left: parent.left top: parent.top bottom: parent.bottom } opacity: 1 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration easing.type: Easing.InOutQuad } } } Kirigami.Icon { anchors.centerIn: parent visible: !Kirigami.Settings.isMobile source: "qrc:/assets/arrow-left.svg" isMask: true width: Maui.Style.iconSizes.small height: Maui.Style.iconSizes.small color: _leftFlickRec.hovered ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor } enabled: !mainFlickable.atXBeginning opacity: enabled ? 1 : 0.4 onClicked: { if(!mainFlickable.atXBeginning) mainFlickable.contentX -= control.height if(mainFlickable.atXBeginning) mainFlickable.returnToBounds() } } Flickable { id: mainFlickable property bool fits : contentWidth < control.width onFitsChanged: returnToBounds() - anchors.fill: parent + height: control.implicitHeight + anchors { + left: parent.left + right: parent.right + bottom: control.position === ToolBar.Header ? parent.bottom : undefined + top: control.position === ToolBar.Footer ? parent.top : undefined + } + anchors.leftMargin: !fits && _leftFlickRec.visible && control.flickable && !Kirigami.Settings.isMobile ? _leftFlickRec.width : margins anchors.rightMargin: !fits && _rightFlickRec.visible && control.flickable && !Kirigami.Settings.isMobile ? _rightFlickRec.width : margins flickableDirection: Flickable.HorizontalFlick interactive: !fits && Maui.Handy.isTouch contentWidth: ((control.margins) + Maui.Style.space.medium) + (control.stickyLeftContent ? leftRowContent.implicitWidth : leftRowContent.width) + (control.stickyMiddleContent ? middleRowContent.implicitWidth : middleRowContent.width) + (control.stickyRightContent ? rightRowContent.implicitWidth : rightRowContent.width) boundsBehavior: Kirigami.Settings.isMobile ? Flickable.DragOverBounds : Flickable.StopAtBounds clip: true RowLayout { id: layout width: control.width - control.margins - Maui.Style.space.medium height: control.height RowLayout { id: leftRowContent // visible: control.leftSretch && implicitWidth property bool sticky : false Layout.leftMargin: rightRowContent.implicitWidth && implicitWidth === 0 && middleRowContent.implicitWidth && control.leftSretch ? rightRowContent.implicitWidth : undefined Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft spacing: leftContent.length > 0 ? control.spacing : 0 Layout.minimumWidth: !sticky ? undefined : implicitWidth Layout.fillWidth: control.leftSretch && implicitWidth Layout.fillHeight: true } RowLayout { id: middleRowContent property bool sticky : false // visible: control.middleStrech && implicitWidth Layout.alignment: Qt.AlignCenter spacing: middleContent.length === 1 ? 0 : control.spacing Layout.minimumWidth: !sticky ? undefined : implicitWidth // Layout.maximumWidth: control.width - leftRowContent.implicitWidth - rightRowContent.implicitWidth Layout.fillWidth: control.middleStrech Layout.fillHeight: true } RowLayout { id: rightRowContent // visible: control.rightSretch && implicitWidth property bool sticky : false Layout.rightMargin: leftRowContent.implicitWidth && implicitWidth === 0 && middleRowContent.implicitWidth && control.rightSretch ? leftRowContent.implicitWidth : undefined Layout.alignment: Qt.AlignVCenter | Qt.AlignRight spacing: rightContent.length > 0 ? control.spacing : 0 Layout.minimumWidth: !sticky ? undefined : implicitWidth // Layout.maximumWidth: !sticky ? rightRowContent.width : implicitWidth Layout.fillWidth: control.rightSretch && implicitWidth Layout.fillHeight: true } } // ScrollBar.horizontal: ScrollBar { visible: false} } } diff --git a/src/controls/private/BrowserView.qml b/src/controls/private/BrowserView.qml index fdf5cbd..f2746cb 100644 --- a/src/controls/private/BrowserView.qml +++ b/src/controls/private/BrowserView.qml @@ -1,668 +1,663 @@ import QtQuick 2.9 import QtQuick.Controls 2.9 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Page { id: control property url path - onPathChanged: control.currentView.currentIndex = 0 + onPathChanged: if(control.currentView) control.currentView.currentIndex = 0 property Maui.FMList currentFMList property Maui.BaseModel currentFMModel property alias currentView : viewLoader.item property int viewType property string filter height: _browserList.height width: _browserList.width function setCurrentFMList() { control.currentFMList = currentView.currentFMList control.currentFMModel = currentView.currentFMModel currentView.forceActiveFocus() } Menu { id: _dropMenu property string urls property url target enabled: Maui.FM.getFileInfo(target).isdir == "true" && !urls.includes(target.toString()) MenuItem { text: qsTr("Copy here") onTriggered: { const urls = _dropMenu.urls.split(",") for(var i in urls) Maui.FM.copy(urls[i], _dropMenu.target, false) } } MenuItem { text: qsTr("Move here") onTriggered: { const urls = _dropMenu.urls.split(",") for(var i in urls) Maui.FM.cut(urls[i], _dropMenu.target) } } MenuItem { text: qsTr("Link here") onTriggered: { const urls = _dropMenu.urls.split(",") for(var i in urls) Maui.FM.createSymlink(_dropMenu.source[i], urls.target) } } } Loader { id: viewLoader anchors.fill: parent focus: true - sourceComponent: switch(control.viewType) - { - case Maui.FMList.ICON_VIEW: return gridViewBrowser - case Maui.FMList.LIST_VIEW: return listViewBrowser - case Maui.FMList.MILLERS_VIEW: return millerViewBrowser - } + sourceComponent: listViewBrowser onLoaded: setCurrentFMList() } Maui.FMList { id: _commonFMList path: control.path onSortByChanged: if(group) groupBy() onlyDirs: settings.onlyDirs filterType: settings.filterType filters: settings.filters sortBy: settings.sortBy } Component { id: listViewBrowser Maui.ListBrowser { id: _listViewBrowser property alias currentFMList : _browserModel.list property alias currentFMModel : _browserModel topMargin: Maui.Style.contentMargins showPreviewThumbnails: settings.showThumbnails keepEmblemOverlay: settings.selectionMode showDetailsInfo: true - supportsRefreshing: true + BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize model: Maui.BaseModel { id: _browserModel list: _commonFMList filter: control.filter recursiveFilteringEnabled: true sortCaseSensitivity: Qt.CaseInsensitive filterCaseSensitivity: Qt.CaseInsensitive } section.delegate: Maui.LabelDelegate { id: delegate width: parent.width height: Maui.Style.toolBarHeightAlt label: String(section).toUpperCase() labelTxt.font.pointSize: Maui.Style.fontSizes.big isSection: true } delegate: Maui.ListBrowserDelegate { id: delegate width: parent.width height: _listViewBrowser.itemSize + Maui.Style.space.big leftPadding: Maui.Style.space.small rightPadding: leftPadding padding: 0 showDetailsInfo: _listViewBrowser.showDetailsInfo folderSize : _listViewBrowser.itemSize showTooltip: true showEmblem: _listViewBrowser.showEmblem keepEmblemOverlay : _listViewBrowser.keepEmblemOverlay showThumbnails: _listViewBrowser.showPreviewThumbnails rightEmblem: _listViewBrowser.rightEmblem isSelected: selectionBar ? selectionBar.contains(model.path) : false leftEmblem: isSelected ? "list-remove" : "list-add" draggable: true Maui.Badge { iconName: "link" anchors.left: parent.left anchors.bottom: parent.bottom visible: (model.issymlink == true) || (model.issymlink == "true") } Connections { target: selectionBar onUriRemoved: { if(uri === model.path) delegate.isSelected = false } onUriAdded: { if(uri === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemClicked(index) } onDoubleClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemDoubleClicked(index) } onPressAndHold: { _listViewBrowser.currentIndex = index _listViewBrowser.itemRightClicked(index) } onRightClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemRightClicked(index) } onRightEmblemClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.rightEmblemClicked(index) } onLeftEmblemClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.leftEmblemClicked(index) } onContentDropped: { _dropMenu.urls = drop.urls.join(",") _dropMenu.target = model.path _dropMenu.popup() } } } } } Component { id: gridViewBrowser Maui.GridBrowser { id: _gridViewBrowser property alias currentFMList : _browserModel.list property alias currentFMModel : _browserModel itemSize : thumbnailsSize + Maui.Style.fontSizes.default cellHeight: itemSize * 1.5 keepEmblemOverlay: settings.selectionMode showPreviewThumbnails: settings.showThumbnails supportsRefreshing: true BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize model: Maui.BaseModel { id: _browserModel list: _commonFMList filter: control.filter recursiveFilteringEnabled: true sortCaseSensitivity: Qt.CaseInsensitive filterCaseSensitivity: Qt.CaseInsensitive } delegate: Maui.GridBrowserDelegate { id: delegate folderSize: height * 0.5 height: _gridViewBrowser.cellHeight width: _gridViewBrowser.cellWidth padding: Maui.Style.space.tiny showTooltip: true showEmblem: _gridViewBrowser.showEmblem keepEmblemOverlay: _gridViewBrowser.keepEmblemOverlay showThumbnails: _gridViewBrowser.showPreviewThumbnails rightEmblem: _gridViewBrowser.rightEmblem isSelected: selectionBar ? selectionBar.contains(model.path) : false leftEmblem: isSelected ? "list-remove" : "list-add" draggable: true Maui.Badge { iconName: "link" anchors.left: parent.left anchors.bottom: parent.bottom anchors.bottomMargin: Maui.Style.space.big visible: (model.issymlink == true) || (model.issymlink == "true") } Connections { target: selectionBar onUriRemoved: { if(uri === model.path) delegate.isSelected = false } onUriAdded: { if(uri === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemClicked(index) } onDoubleClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemDoubleClicked(index) } onPressAndHold: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemRightClicked(index) } onRightClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemRightClicked(index) } onRightEmblemClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.rightEmblemClicked(index) } onLeftEmblemClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.leftEmblemClicked(index) } onContentDropped: { _dropMenu.urls = drop.urls.join(",") _dropMenu.target = model.path _dropMenu.popup() } } } } } Component { id: millerViewBrowser Item { id: _millerControl property Maui.FMList currentFMList property Maui.BaseModel currentFMModel property int currentIndex signal itemClicked(int index) signal itemDoubleClicked(int index) signal itemRightClicked(int index) signal keyPress(var event) signal rightEmblemClicked(int index) signal leftEmblemClicked(int index) signal areaClicked(var mouse) signal areaRightClicked() ListView { id: _millerColumns anchors.fill: parent boundsBehavior: !Maui.Handy.isTouch? Flickable.StopAtBounds : Flickable.OvershootBounds keyNavigationEnabled: true interactive: Maui.Handy.isTouch orientation: ListView.Horizontal snapMode: ListView.SnapToItem ScrollBar.horizontal: ScrollBar { id: _scrollBar snapMode: ScrollBar.SnapAlways policy: ScrollBar.AlwaysOn contentItem: Rectangle { implicitWidth: _scrollBar.interactive ? 13 : 4 implicitHeight: _scrollBar.interactive ? 13 : 4 color: "#333" opacity: _scrollBar.pressed ? 0.7 : _scrollBar.interactive && _scrollBar.hovered ? 0.5 : 0.2 radius: 0 } background: Rectangle { implicitWidth: _scrollBar.interactive ? 16 : 4 implicitHeight: _scrollBar.interactive ? 16 : 4 color: "#0e000000" opacity: 0.0 visible: _scrollBar.interactive radius: 0 } } onCurrentItemChanged: { _millerControl.currentFMList = currentItem.currentFMList _millerControl.currentFMModel = currentItem.currentFMModel control.setCurrentFMList() currentItem.forceActiveFocus() } onCountChanged: { _millerColumns.currentIndex = _millerColumns.count-1 _millerColumns.positionViewAtEnd() } Maui.PathList { id: _millerList path: control.path onPathChanged: { _millerColumns.currentIndex = _millerColumns.count-1 _millerColumns.positionViewAtEnd() } } model: Maui.BaseModel { id: _millerModel list: _millerList } delegate: Item { property alias currentFMList : _millersFMList property alias currentFMModel : _millersFMModel property int _index : index width: Math.min(Kirigami.Units.gridUnit * 22, control.width) height: parent.height focus: true function forceActiveFocus() { _millerListView.forceActiveFocus() } Kirigami.Separator { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right width: 1 z: 999 } Maui.FMList { id: _millersFMList path: model.path onlyDirs: settings.onlyDirs filterType: settings.filterType filters: settings.filters sortBy: settings.sortBy } Maui.ListBrowser { id: _millerListView anchors.fill: parent topMargin: Maui.Style.contentMargins showPreviewThumbnails: settings.showThumbnails keepEmblemOverlay: settings.selectionMode showDetailsInfo: true onKeyPress: _millerControl.keyPress(event) currentIndex : 0 onCurrentIndexChanged: _millerControl.currentIndex = currentIndex BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize section.delegate: Maui.LabelDelegate { id: delegate width: parent.width height: Maui.Style.toolBarHeightAlt label: String(section).toUpperCase() labelTxt.font.pointSize: Maui.Style.fontSizes.big isSection: true } onAreaClicked: { _millerColumns.currentIndex = _index _millerControl.areaClicked(mouse) } onAreaRightClicked: { _millerColumns.currentIndex = _index _millerControl.areaRightClicked() } model: Maui.BaseModel { id: _millersFMModel list: _millersFMList filter: control.filter recursiveFilteringEnabled: true sortCaseSensitivity: Qt.CaseInsensitive filterCaseSensitivity: Qt.CaseInsensitive } delegate: Maui.ListBrowserDelegate { id: delegate width: parent.width height: _millerListView.itemSize + Maui.Style.space.big leftPadding: Maui.Style.space.small rightPadding: leftPadding padding: 0 showDetailsInfo: _millerListView.showDetailsInfo folderSize : _millerListView.itemSize showTooltip: true showEmblem: _millerListView.showEmblem keepEmblemOverlay : _millerListView.keepEmblemOverlay showThumbnails: _millerListView.showPreviewThumbnails rightEmblem: _millerListView.rightEmblem isSelected: selectionBar ? selectionBar.contains(model.path) : false leftEmblem: isSelected ? "list-remove" : "list-add" draggable: true Maui.Badge { iconName: "link" anchors.left: parent.left anchors.bottom: parent.bottom visible: (model.issymlink == true) || (model.issymlink == "true") } Connections { target: selectionBar onUriRemoved: { if(uri === model.path) delegate.isSelected = false } onUriAdded: { if(uri === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemClicked(index) } onDoubleClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemDoubleClicked(index) } onPressAndHold: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemRightClicked(index) } onRightClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemRightClicked(index) } onRightEmblemClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.rightEmblemClicked(index) } onLeftEmblemClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.leftEmblemClicked(index) } onContentDropped: { _dropMenu.urls = drop.urls.join(",") _dropMenu.target = model.path _dropMenu.popup() } } } } } } } } }