Warning, /graphics/peruse/src/app/qml/PeruseMain.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  *
0020  */
0021 
0022 import QtQuick 2.15
0023 
0024 import org.kde.kirigami 2.14 as Kirigami
0025 import QtQuick.Layouts 1.3
0026 import QtQuick.Controls 2.14 as QQC2
0027 
0028 import org.kde.peruse 0.1 as Peruse
0029 import org.kde.contentlist 0.1
0030 
0031 /**
0032  * @brief main application window.
0033  * 
0034  * This splits the window in two sections:
0035  * - A section where you can select comics.
0036  * - A "global drawer" which can be used to switch between categories
0037  *   and access settings and the open book dialog.
0038  * 
0039  * The global drawer controls which is the main component on the left.
0040  * It initializes on WelcomePage. The category filters are each handled
0041  * by a BookShelf. The store page by Store and the settings by Settings.
0042  * 
0043  * This also controls the bookViewer, which is a Book object where the
0044  * main reading of comics is done.
0045  * 
0046  * There is also the PeruseContextDrawer, which is only accessible on the book
0047  * page and requires flicking in from the right.
0048  */
0049 Kirigami.ApplicationWindow {
0050     id: mainWindow;
0051 
0052     property int animationDuration: 200
0053     property bool isLoading: true
0054     property bool bookOpen: mainWindow.pageStack.layers.currentItem.objectName === "bookViewer"
0055 
0056     title: i18nc("@title:window the generic descriptive title of the application", "Comic Book Reader");
0057 
0058     pageStack {
0059         defaultColumnWidth: Kirigami.Units.gridUnit * 30
0060         initialPage: welcomePage
0061         globalToolBar {
0062             canContainHandles: true
0063             style: Kirigami.ApplicationHeaderStyle.ToolBar
0064             showNavigationButtons: applicationWindow().pageStack.currentIndex > 0 ? Kirigami.ApplicationHeaderStyle.ShowBackButton : 0
0065         }
0066     }
0067 
0068     function showBook(filename, currentPage) {
0069         if(bookOpen) {
0070             mainWindow.pageStack.layers.pop();
0071         }
0072         mainWindow.pageStack.layers.push(bookViewer, {
0073             focus: true,
0074             file: filename,
0075             currentPage: currentPage,
0076         });
0077         peruseConfig.bookOpened(filename);
0078     }
0079 
0080     Peruse.BookListModel {
0081         id: contentList;
0082         contentModel: ContentList {
0083             autoSearch: false
0084 
0085             onSearchStarted: { mainWindow.isLoading = true; }
0086             onSearchCompleted: { mainWindow.isLoading = false; }
0087 
0088             ContentQuery {
0089                 type: ContentQuery.Comics
0090                 locations: peruseConfig.bookLocations
0091             }
0092         }
0093         onCacheLoadedChanged: {
0094             if(!cacheLoaded) {
0095                 return;
0096             }
0097             contentList.contentModel.setKnownFiles(contentList.knownBookFiles());
0098             contentList.contentModel.startSearch()
0099         }
0100     }
0101 
0102     Peruse.Config {
0103         id: peruseConfig;
0104     }
0105     function homeDir() {
0106         return peruseConfig.homeDir();
0107     }
0108 
0109     contextDrawer: PeruseContextDrawer {
0110         id: contextDrawer;
0111     }
0112 
0113     globalDrawer: Kirigami.OverlayDrawer {
0114         edge: Qt.application.layoutDirection === Qt.RightToLeft ? Qt.RightEdge : Qt.LeftEdge
0115         modal: Kirigami.Settings.isMobile || (applicationWindow().width < Kirigami.Units.gridUnit * 50 && !collapsed) // Only modal when not collapsed, otherwise collapsed won't show.
0116         z: modal ? Math.round(position * 10000000) : 100
0117         drawerOpen: !Kirigami.Settings.isMobile && enabled
0118         width: Kirigami.Units.gridUnit * 16
0119         Behavior on width {
0120             NumberAnimation {
0121                 duration: Kirigami.Units.longDuration
0122                 easing.type: Easing.InOutQuad
0123             }
0124         }
0125         Kirigami.Theme.colorSet: Kirigami.Theme.Window
0126 
0127         handleClosedIcon.source: modal ? null : "sidebar-expand-left"
0128         handleOpenIcon.source: modal ? null : "sidebar-collapse-left"
0129         handleVisible: modal
0130         onModalChanged: if (!modal) {
0131             drawerOpen = true;
0132         }
0133 
0134         leftPadding: 0
0135         rightPadding: 0
0136         topPadding: 0
0137         bottomPadding: 0
0138 
0139         contentItem: ColumnLayout {
0140             spacing: 0
0141 
0142             QQC2.ToolBar {
0143                 Layout.fillWidth: true
0144                 Layout.preferredHeight: mainWindow.pageStack.globalToolBar.preferredHeight
0145 
0146                 leftPadding: Kirigami.Units.smallSpacing
0147                 rightPadding: Kirigami.Units.smallSpacing
0148                 topPadding: Kirigami.Units.smallSpacing
0149                 bottomPadding: Kirigami.Units.smallSpacing
0150 
0151                 contentItem: RowLayout {
0152                     Kirigami.Heading {
0153                         text: i18n("Peruse")
0154                         Layout.fillWidth: true
0155                     }
0156 
0157                     QQC2.ToolButton {
0158                         icon.name: "go-home"
0159 
0160                         enabled: mainWindow.currentCategory !== "welcomePage";
0161                         onClicked: if (changeCategory(welcomePage)) {
0162                             pageStack.currentItem.updateRecent();
0163                         }
0164 
0165                         QQC2.ToolTip.text: i18n("Show intro page")
0166                         QQC2.ToolTip.visible: hovered
0167                         QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
0168                     }
0169                 }
0170             }
0171 
0172             QQC2.ButtonGroup {
0173                 id: placeGroup
0174             }
0175 
0176             QQC2.ScrollView {
0177                 id: scrollView
0178 
0179                 Layout.fillHeight: true
0180                 Layout.fillWidth: true
0181 
0182                 contentWidth: availableWidth
0183 
0184                 component PlaceItem : Kirigami.BasicListItem {
0185                     id: item
0186                     signal triggered;
0187                     checkable: true
0188                     Layout.fillWidth: true
0189                     Keys.onDownPressed: nextItemInFocusChain().forceActiveFocus(Qt.TabFocusReason)
0190                     Keys.onUpPressed: nextItemInFocusChain(false).forceActiveFocus(Qt.TabFocusReason)
0191                     Accessible.role: Accessible.MenuItem
0192                     highlighted: checked
0193                     onToggled: if (checked) {
0194                         item.triggered();
0195                     }
0196                 }
0197 
0198                 ColumnLayout {
0199                     spacing: 1
0200                     width: scrollView.width
0201                     PlaceItem {
0202                         text: i18nc("Switch to the listing page showing the most recently read books", "Home");
0203                         icon: "go-home";
0204                         checked: true
0205                         QQC2.ButtonGroup.group: placeGroup
0206                         onTriggered: {
0207                             if (changeCategory(welcomePage)) {
0208                                 pageStack.currentItem.updateRecent();
0209                             }
0210                         }
0211                     }
0212                     PlaceItem {
0213                         text: i18nc("Switch to the listing page showing the most recently discovered books", "Recently Added Books");
0214                         icon: "appointment-new";
0215                         QQC2.ButtonGroup.group: placeGroup
0216                         onTriggered: changeCategory(bookshelfAdded);
0217                     }
0218                     PlaceItem {
0219                         text: i18nc("Open a book from somewhere on disk (uses the open dialog, or a drilldown on touch devices)", "Open Other...");
0220                         icon: "document-open";
0221                         onClicked: openOther();
0222                         QQC2.ButtonGroup.group: undefined
0223                         checkable: false
0224                     }
0225                     Kirigami.ListSectionHeader {
0226                         text: i18nc("Heading for switching to listing page showing items grouped by some properties", "Group By")
0227                     }
0228                     PlaceItem {
0229                         text: i18nc("Switch to the listing page showing items grouped by title", "Title");
0230                         icon: "view-media-title";
0231                         onTriggered: changeCategory(bookshelfTitle);
0232                         QQC2.ButtonGroup.group: placeGroup
0233                     }
0234                     PlaceItem {
0235                         text: i18nc("Switch to the listing page showing items grouped by author", "Author");
0236                         icon: "actor";
0237                         onTriggered: changeCategory(bookshelfAuthor);
0238                         QQC2.ButtonGroup.group: placeGroup
0239                     }
0240                     PlaceItem {
0241                         text: i18nc("Switch to the listing page showing items grouped by series", "Series");
0242                         icon: "edit-group";
0243                         onTriggered: changeCategory(bookshelfSeries);
0244                         QQC2.ButtonGroup.group: placeGroup
0245                     }
0246                     PlaceItem {
0247                         text: i18nc("Switch to the listing page showing items grouped by publisher", "Publisher");
0248                         icon: "view-media-publisher";
0249                         onTriggered: changeCategory(bookshelfPublisher);
0250                         QQC2.ButtonGroup.group: placeGroup
0251                     }
0252                     PlaceItem {
0253                         text: i18nc("Switch to the listing page showing items grouped by keywords, characters or genres", "Keywords");
0254                         icon: "tag";
0255                         onTriggered: changeCategory(bookshelfKeywords);
0256                         QQC2.ButtonGroup.group: placeGroup
0257                     }
0258                     PlaceItem {
0259                         text: i18nc("Switch to the listing page showing items grouped by their filesystem folder", "Folder");
0260                         icon: "tag-folder";
0261                         onTriggered: changeCategory(bookshelfFolder);
0262                         QQC2.ButtonGroup.group: placeGroup
0263                     }
0264 
0265                 }
0266             }
0267 
0268             Item {
0269                 Layout.fillHeight: true
0270             }
0271 
0272             QQC2.Label {
0273                 Layout.fillWidth: true
0274                 horizontalAlignment: Text.AlignHCenter;
0275                 text: i18nc("shown with a throbber when searching for books on the device", "Please wait while we find your books...")
0276                 visible: mainWindow.isLoading
0277             }
0278 
0279             QQC2.BusyIndicator {
0280                 Layout.fillWidth: true
0281                 running: mainWindow.isLoading
0282             }
0283 
0284             PlaceItem {
0285                 text: i18nc("Open the settings page", "Settings");
0286                 icon: "configure"
0287                 onTriggered: changeCategory(settingsPage);
0288                 QQC2.ButtonGroup.group: placeGroup
0289             }
0290 
0291             PlaceItem {
0292                 text: i18nc("Open the about page", "About");
0293                 icon: "help-about"
0294                 onTriggered: changeCategory(aboutPage);
0295                 QQC2.ButtonGroup.group: placeGroup
0296             }
0297         }
0298     }
0299 
0300     Component {
0301         id: welcomePage;
0302         WelcomePage {
0303             onBookSelected: mainWindow.showBook(filename, currentPage);
0304         }
0305     }
0306 
0307     Component {
0308         id: bookViewer;
0309         Book {
0310             id: viewerRoot;
0311             onCurrentPageChanged: {
0312                 contentList.setBookData(viewerRoot.file, "currentPage", viewerRoot.currentPage);
0313             }
0314             onTotalPagesChanged: {
0315                 contentList.setBookData(viewerRoot.file, "totalPages", viewerRoot.totalPages);
0316             }
0317         }
0318     }
0319 
0320     Component {
0321         id: bookshelfTitle;
0322         Bookshelf {
0323             model: contentList.titleCategoryModel;
0324             headerText: i18nc("Title of the page with books grouped by the title start letters", "Group by Title");
0325             onBookSelected: mainWindow.showBook(filename, currentPage);
0326             categoryName: "bookshelfTitle";
0327         }
0328     }
0329 
0330     Component {
0331         id: bookshelfAdded;
0332         Bookshelf {
0333             model: contentList.newlyAddedCategoryModel;
0334             headerText: i18nc("Title of the page with all books ordered by which was added most recently", "Recently Added Books");
0335             sectionRole: "created";
0336             sectionCriteria: ViewSection.FullString;
0337             onBookSelected: mainWindow.showBook(filename, currentPage);
0338             categoryName: "bookshelfAdded";
0339         }
0340     }
0341 
0342     Component {
0343         id: bookshelfSeries;
0344         Bookshelf {
0345             model: contentList.seriesCategoryModel;
0346             headerText: i18nc("Title of the page with books grouped by what series they are in", "Group by Series");
0347             onBookSelected: mainWindow.showBook(filename, currentPage);
0348             categoryName: "bookshelfSeries";
0349         }
0350     }
0351 
0352     Component {
0353         id: bookshelfAuthor;
0354         Bookshelf {
0355             model: contentList.authorCategoryModel;
0356             headerText: i18nc("Title of the page with books grouped by author", "Group by Author");
0357             onBookSelected: mainWindow.showBook(filename, currentPage);
0358             categoryName: "bookshelfAuthor";
0359         }
0360     }
0361 
0362     Component {
0363         id: bookshelfPublisher;
0364         Bookshelf {
0365             model: contentList.publisherCategoryModel;
0366             headerText: i18nc("Title of the page with books grouped by who published them", "Group by Publisher");
0367             onBookSelected: mainWindow.showBook(filename, currentPage);
0368             categoryName: "bookshelfPublisher";
0369         }
0370     }
0371 
0372     Component {
0373         id: bookshelfKeywords;
0374         Bookshelf {
0375             model: contentList.keywordCategoryModel;
0376             headerText: i18nc("Title of the page with books grouped by keywords, character or genres", "Group by Keywords, Characters and Genres");
0377             onBookSelected: mainWindow.showBook(filename, currentPage);
0378             categoryName: "bookshelfKeywords";
0379         }
0380     }
0381 
0382     Component {
0383         id: bookshelfFolder;
0384         Bookshelf {
0385             model: contentList.folderCategoryModel;
0386             headerText: i18nc("Title of the page with books grouped by what folder they are in", "Filter by Folder");
0387             onBookSelected: mainWindow.showBook(filename, currentPage);
0388             categoryName: "bookshelfFolder";
0389         }
0390     }
0391 
0392     Component {
0393         id: bookshelf;
0394         Bookshelf {
0395             onBookSelected: mainWindow.showBook(filename, currentPage);
0396         }
0397     }
0398 
0399     Component {
0400         id: storePage;
0401         Store {
0402         }
0403     }
0404 
0405     Component {
0406         id: settingsPage;
0407         Settings {
0408         }
0409     }
0410 
0411     Component {
0412         id: aboutPage
0413         About {
0414         }
0415     }
0416 
0417     property string currentCategory: "welcomePage";
0418     property Component currentCategoryItem: welcomePage;
0419     function changeCategory(categoryItem) {
0420         if (categoryItem === mainWindow.currentCategoryItem) {
0421             return false;
0422         }
0423         // Clear all the way to the welcome page if we change the category...
0424         mainWindow.pageStack.clear();
0425         mainWindow.pageStack.push(categoryItem);
0426         currentCategory = mainWindow.pageStack.currentItem.categoryName;
0427         currentCategoryItem = categoryItem;
0428         if (PLASMA_PLATFORM.substring(0, 5) === "phone") {
0429             globalDrawer.close();
0430         }
0431         return true;
0432     }
0433 
0434 
0435     Component.onCompleted: {
0436         if (fileToOpen !== "") {
0437             mainWindow.showBook(fileToOpen, 0);
0438         }
0439     }
0440 }
0441