diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 4d42a5e..27c2996 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,143 +1,155 @@ - - + + + + + + - android:name="com.example.android.tools.NotificationClient" + + + + + - + + - diff --git a/index.pro b/index.pro index d15db32..9f41b84 100644 --- a/index.pro +++ b/index.pro @@ -1,71 +1,77 @@ QT += qml QT += quick QT += sql CONFIG += c++17 QMAKE_LINK += -nostdlib++ #DESTDIR = $$OUT_PWD/../ linux:unix:!android { } else:android { message(Building helpers for Android) include($$PWD/3rdparty/kirigami/kirigami.pri) include($$PWD/3rdparty/mauikit/mauikit.pri) DEFINES += STATIC_KIRIGAMI } else { message("Unknown configuration") } # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ $$PWD/src/main.cpp \ $$PWD/src/index.cpp \ HEADERS += \ $$PWD/src/index.h \ $$PWD/src/inx.h \ RESOURCES += \ $$PWD/src/qml.qrc \ # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = # Additional import path used to resolve QML modules just for Qt Quick Designer QML_DESIGNER_IMPORT_PATH = # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target include($$PWD/install.pri) DISTFILES += \ $$PWD/org.kde.index.desktop \ 3rdparty/mauikit/src/android/AndroidManifest.xml \ 3rdparty/mauikit/src/android/build.gradle \ + 3rdparty/mauikit/src/android/build.gradle \ + 3rdparty/mauikit/src/android/gradle/wrapper/gradle-wrapper.jar \ 3rdparty/mauikit/src/android/gradle/wrapper/gradle-wrapper.jar \ 3rdparty/mauikit/src/android/gradle/wrapper/gradle-wrapper.properties \ + 3rdparty/mauikit/src/android/gradle/wrapper/gradle-wrapper.properties \ 3rdparty/mauikit/src/android/gradlew \ + 3rdparty/mauikit/src/android/gradlew \ + 3rdparty/mauikit/src/android/gradlew.bat \ 3rdparty/mauikit/src/android/gradlew.bat \ + 3rdparty/mauikit/src/android/res/values/libs.xml \ 3rdparty/mauikit/src/android/res/values/libs.xml contains(ANDROID_TARGET_ARCH,armeabi-v7a) { ANDROID_PACKAGE_SOURCE_DIR = \ $$PWD/3rdparty/mauikit/src/android } diff --git a/src/main.cpp b/src/main.cpp index b4de984..4b59699 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,78 +1,78 @@ #include #include #include #include #include #include "index.h" #include "inx.h" #ifdef Q_OS_ANDROID #include #include #else #include #endif #ifdef STATIC_KIRIGAMI #include "3rdparty/kirigami/src/kirigamiplugin.h" #endif #ifdef STATIC_MAUIKIT #include "3rdparty/mauikit/src/mauikit.h" #endif int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #ifdef Q_OS_ANDROID QGuiApplication app(argc, argv); #else QApplication app(argc, argv); #endif app.setApplicationName(INX::app); app.setApplicationVersion(INX::version); app.setApplicationDisplayName(INX::app); app.setOrganizationName("org.maui.index"); app.setWindowIcon(QIcon(":/index.png")); QCommandLineParser parser; parser.setApplicationDescription(INX::description); const QCommandLineOption versionOption = parser.addVersionOption(); parser.addOption(versionOption); parser.process(app); const QStringList args = parser.positionalArguments(); QStringList paths; if(!args.isEmpty()) paths = args; #ifdef STATIC_KIRIGAMI KirigamiPlugin::getInstance().registerTypes(); #endif #ifdef STATIC_MAUIKIT MauiKit::getInstance().registerTypes(); #endif Index index; QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url, paths, &index](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); if(!paths.isEmpty()) index.openPaths(paths); }, Qt::QueuedConnection); - auto context = engine.rootContext(); + const auto context = engine.rootContext(); context->setContextProperty("inx", &index); engine.load(url); return app.exec(); } diff --git a/src/main.qml b/src/main.qml index 721aa76..a771862 100644 --- a/src/main.qml +++ b/src/main.qml @@ -1,215 +1,349 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui +import QtQml.Models 2.3 import QtQuick.Window 2.0 import "widgets" import "widgets/views" Maui.ApplicationWindow { id: root title: browser.currentPath - property alias browser: browserView.browser showAccounts: false - about.appDescription: qsTr("Index is a file manager that works on desktops, Android and Plasma Mobile. Index lets you browse your system files and applications and preview your music, text, image and video files and share them with external applications.") - about.appIcon: "qrc:/assets/index.svg" + Maui.App.description: qsTr("Index is a file manager that works on desktops, Android and Plasma Mobile. Index lets you browse your system files and applications and preview your music, text, image and video files and share them with external applications.") + Maui.App.iconName: "qrc:/assets/index.svg" - property alias dialog : dialogLoader.item + property bool terminalVisible : true + property alias terminal : terminalLoader.item + property alias browser: _browserList.currentItem + property alias dialog : dialogLoader.item property bool searchBar: false -// accentColor: "#303952" + // accentColor: "#303952" // highlightColor: "#64B5F6" -// altColorText: "#ffffff" + // altColorText: "#ffffff" // headBarBGColor: "#64B5F6" // headBarFGColor: altColorText // headBar.colorScheme.borderColor: Qt.darker(headBarBGColor, 1.4) searchButton.checked: searchBar onSearchButtonClicked: { searchBar = !searchBar if(searchBar) _pathBarLoader.item.forceActiveFocus() } - onGoBackTriggered: browser.goBack() - // headBarBGColor: viewBackgroundColor // headBar.drawBorder: false // footBar.visible: false -// headBar.leftContent: ToolButton -// { -// visible: _drawer.modal -// icon.name: "view-right-new" -// onClicked: _drawer.visible = !_drawer.visible -// checkable: true -// checked: _drawer.visible -// } + // headBar.leftContent: ToolButton + // { + // visible: _drawer.modal + // icon.name: "view-right-new" + // onClicked: _drawer.visible = !_drawer.visible + // checkable: true + // checked: _drawer.visible + // } -// leftIcon.visible: false - // leftIcon.onClicked: _drawer.visible = !_drawer.visible - // leftIcon.checkable: true - // leftIcon.checked: _drawer.visible - // headBar.strech: false Component { id: _pathBarComponent Maui.PathBar { anchors.fill: parent - // colorScheme.backgroundColor: "#fff" - // colorScheme.textColor: "#333" - // colorScheme.borderColor: Qt.darker(headBarBGColor, 1.4) 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: radiusV color: Kirigami.Theme.backgroundColor } } } headBar.implicitHeight: toolBarHeight * 1.2 headBar.middleContent: Loader { id: _pathBarLoader - Layout.fillWidth: true Layout.margins: space.medium Layout.preferredHeight: iconSizes.big sourceComponent: searchBar ? _searchFieldComponent : _pathBarComponent -// onLoaded: -// { -// if(sourceComponent === _pathBarComponent) -// item.url =browser.currentPath -// } } Loader { id: dialogLoader } globalDrawer: Maui.GlobalDrawer { id: _drawer - width: Math.min(Kirigami.Units.gridUnit * 11, root.width) - handleClosedIcon.source: "view-right-new" - handleOpenIcon.source: "view-right-new" -// height: 200 /*- root.header.height - browser.header.height*/ -// y: 0 + property bool collapsed : !root.isWide + + width: collapsed ? placesSidebar.iconSize * 2.5 : Math.min(Kirigami.Units.gridUnit * 11, root.width) + // handleClosedIcon.source: "view-right-new" + // handleOpenIcon.source: "view-right-new" height: root.height - root.header.height - (browser.headBar.position === ToolBar.Footer && _drawer.modal ? browser.footer.height : 0) - modal: !root.isWide - handleVisible: modal + modal: false + handleVisible: false contentItem: Maui.PlacesSidebar { id: placesSidebar + property bool collapsed : !root.isWide + showLabels: !collapsed + section.property: collapsed ? "" : "type" + ScrollBar.vertical.policy: collapsed ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn + // height: _drawer.height anchors.fill: parent onPlaceClicked: { if(_drawer.modal) _drawer.close() browser.openFolder(path) if(searchBar) searchBar = false } list.groups: [ Maui.FMList.PLACES_PATH, Maui.FMList.APPS_PATH, Maui.FMList.CLOUD_PATH, Maui.FMList.REMOTE_PATH, Maui.FMList.REMOVABLE_PATH, Maui.FMList.DRIVES_PATH, Maui.FMList.TAGS_PATH] - // width: isCollapsed ? iconSize*2 : parent.width - // height: parent.height - - } } + ObjectModel { id: tabsObjectModel } - - Browser + ColumnLayout { - id: browserView anchors.fill: parent - } + spacing: 0 + TabBar + { + id: tabsBar + visible: _browserList.count > 1 + Layout.fillWidth: true + Layout.preferredHeight: visible ? Maui.Style.rowHeight : 0 + Kirigami.Theme.colorSet: Kirigami.Theme.View + Kirigami.Theme.inherit: false - // Rectangle - // { - // color: "pink" - // width: iconSizes.big - // height: width * 1.5 + currentIndex : _browserList.currentIndex + clip: true - // anchors.left: parent.left - // anchors.bottom: parent.bottom + ListModel { id: tabsListModel } - // anchors.bottomMargin: toolBarHeight + background: Rectangle + { + color: "transparent" + } - // Maui.ToolButton - // { + Repeater + { + model: tabsListModel + + TabButton + { + id: _tabButton + readonly property int tabWidth: 150 * unit + implicitWidth: Math.min(tabWidth, root.width) + implicitHeight: Maui.Style.rowHeight + checked: index === _browserList.currentIndex + + onClicked: + { + _browserList.currentIndex = index + if(terminal && terminalVisible && !isMobile) + terminal.session.sendText("cd '" + path.replace("file://", "") + "'\n") + } + + background: Rectangle + { + color: checked ? Kirigami.Theme.focusColor : Kirigami.Theme.backgroundColor + opacity: checked ? 0.4 : 1 + + Kirigami.Separator + { + color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) + z: tabsBar.z + 1 + width : 1 + // visible: tabsListModel.count > 1 + anchors + { + bottom: parent.bottom + top: parent.top + right: parent.right + } + } + } + + contentItem: RowLayout + { + spacing: 0 + + Label + { + text: tabsObjectModel.get(index).list.pathName + font.pointSize: fontSizes.default + Layout.fillWidth: true + Layout.fillHeight: true + Layout.margins: space.small + Layout.alignment: Qt.AlignCenter + verticalAlignment: Qt.AlignVCenter + horizontalAlignment: Qt.AlignHCenter + color: Kirigami.Theme.textColor + wrapMode: Text.NoWrap + elide: Text.ElideRight + } + + ToolButton + { + Layout.preferredHeight: iconSizes.medium + Layout.preferredWidth: iconSizes.medium + icon.height: iconSizes.medium + icon.width: iconSizes.width + Layout.margins: space.medium + Layout.alignment: Qt.AlignRight + + icon.name: "dialog-close" + + onClicked: + { + var removedIndex = index + tabsObjectModel.remove(removedIndex) + tabsListModel.remove(removedIndex) + } + } + } + } + } + } + + + Kirigami.Separator + { + visible: tabsBar.visible + color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) + Layout.fillWidth: true + Layout.preferredHeight: 1 + } + + ListView + { + id: _browserList + Layout.fillHeight: true + Layout.fillWidth: true + orientation: ListView.Horizontal + model: tabsObjectModel + snapMode: ListView.SnapOneItem + spacing: 0 + interactive: isMobile && tabsObjectModel.count > 1 + highlightFollowsCurrentItem: true + highlightMoveDuration: 0 + onMovementEnded: _browserList.currentIndex = indexAt(contentX, contentY) + } + + Loader + { + id: terminalLoader + visible: terminalVisible && terminal + focus: true + Layout.fillWidth: true + Layout.minimumHeight: visible && terminal ? 100 : 0 + Layout.maximumHeight: visible && terminal ? 500 : 0 + Layout.preferredHeight : visible && terminal ? 200 : 0 + source: !isMobile ? "widgets/views/Terminal.qml" : undefined + } + } - // } - // } Component { id:fmDialogComponent Maui.FileDialog { onlyDirs: false filterType: Maui.FMList.AUDIO sortBy: Maui.FMList.MODIFIED mode: modes.OPEN } } Connections { target: inx onOpenPath: browser.openFolder(paths[0]) } Component.onCompleted: { if(isAndroid) Maui.Android.statusbarColor(Kirigami.Theme.backgroundColor, true) + openTab(Maui.FM.homePath()) + } + + function openTab(path) + { + var component = Qt.createComponent("widgets/views/Browser.qml"); + if (component.status === Component.Ready) + { + var object = component.createObject(tabsObjectModel); + tabsObjectModel.append(object); + } + + tabsListModel.append({ + title: qsTr("Untitled"), + path: path, + }) + + _browserList.currentIndex = tabsObjectModel.count - 1 + + if(path && Maui.FM.fileExists(path)) + { + setTabMetadata(path) + tabsObjectModel.get(tabsObjectModel.count - 1).openFolder(path) + } + } + + function setTabMetadata(filepath) + { + tabsListModel.setProperty(tabsBar.currentIndex, "path", filepath) } } diff --git a/src/widgets/views/Browser.qml b/src/widgets/views/Browser.qml index 8e01d04..004e1dc 100644 --- a/src/widgets/views/Browser.qml +++ b/src/widgets/views/Browser.qml @@ -1,132 +1,76 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.0 as Kirigami import org.kde.mauikit 1.0 as Maui -//import FMH 1.0 - -ColumnLayout +Maui.FileBrowser { id: control -// orientation: Qt.Vertical - property alias browser : browser - property bool terminalVisible : true - property alias terminal : terminalLoader.item - - Maui.FileBrowser - { - id: browser - Layout.fillWidth: true - Layout.fillHeight: true - headBar.visible: true - headBar.drawBorder: true - headBar.plegable: false - menu:[ - MenuItem - { - visible: !isMobile - text: qsTr("Show terminal") - checkable: true - checked: terminalVisible - onTriggered: - { - terminalVisible = !terminalVisible - Maui.FM.setDirConf(browser.currentPath+"/.directory", "MAUIFM", "ShowTerminal", terminalVisible) - } - } - ] - headBar.rightContent: ToolButton - { - visible: control.terminal - icon.name: "akonadiconsole" - onClicked: control.terminalVisible = !control.terminalVisible - checked : control.terminalVisible - checkable: false - } + height: _browserList.height + width: _browserList.width - onNewBookmark: + headBar.visible: true + itemMenu.contentData: [ + MenuItem { - for(var index in paths) - placesSidebar.list.addPlace(paths[index]) + visible: control.itemMenu.isDir + text: qsTr("Open in tab") + onTriggered: openTab(control.itemMenu.item.path) } + ] - onCurrentPathChanged: + menu: [ + MenuItem { -// if(!isAndroid) -// terminalVisible = Maui.FM.dirConf(currentPath+"/.directory")["showterminal"] === "true" ? true : false - - if(terminalVisible && !isMobile) - terminal.session.sendText("cd '" + currentPath + "'\n") - - for(var i = 0; i < placesSidebar.count; i++) - if(currentPath === placesSidebar.list.get(i).path) - placesSidebar.currentIndex = i + visible: !isMobile + text: qsTr("Show terminal") + checkable: true + checked: terminalVisible + onTriggered: + { + terminalVisible = !terminalVisible + Maui.FM.setDirConf(control.currentPath+"/.directory", "MAUIFM", "ShowTerminal", terminalVisible) + } } + ] - onItemClicked: openItem(index) - - onItemDoubleClicked: - { - var item = list.get(index) - console.log(item.mime) - if(Maui.FM.isDir(item.path) || item.mime === "inode/directory") - browser.openFolder(item.path) - else - browser.openFile(item.path) - } + headBar.rightContent: ToolButton + { + visible: terminal + icon.name: "utilities-terminal" + onClicked: terminalVisible = !terminalVisible + checked : terminalVisible + checkable: false } -// Rectangle -// { -// id: handle -// visible: true - -// Layout.fillWidth: true -// height: 5 -// color: "transparent" - -// Kirigami.Separator -// { -// visible: terminalLoader.visible - -// anchors -// { -// bottom: parent.bottom -// right: parent.right -// left: parent.left -// } -// } + onNewBookmark: + { + for(var index in paths) + placesSidebar.list.addPlace(paths[index]) + } -// MouseArea -// { -// visible: terminalLoader.visible + onCurrentPathChanged: + { + if(terminalVisible && !isMobile) + terminal.session.sendText("cd '" + currentPath.replace("file://", "") + "'\n") -// anchors.fill: parent -// drag.target: parent -// drag.axis: Drag.YAxis -// drag.smoothed: true -// cursorShape: Qt.SizeVerCursor -// } -// } + for(var i = 0; i < placesSidebar.count; i++) + if(currentPath === placesSidebar.list.get(i).path) + placesSidebar.currentIndex = i + } -// handle: Rectangle -// { -// color: "yellow" -// } + onItemClicked: openItem(index) - Loader + onItemDoubleClicked: { - id: terminalLoader - visible: terminalVisible && terminal - focus: true - Layout.fillWidth: true -// Layout.fillHeight: true - Layout.minimumHeight: visible && terminal ? 100 : 0 - Layout.maximumHeight: visible && terminal ? 500 : 0 - Layout.preferredHeight : visible && terminal ? 200 : 0 - source: !isMobile ? "Terminal.qml" : undefined + var item = list.get(index) + console.log(item.mime) + if(Maui.FM.isDir(item.path) || item.mime === "inode/directory") + control.openFolder(item.path) + else + control.openFile(item.path) } - } +