Warning, /graphics/peruse/src/app/qml/listcomponents/BookTile.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.12
0023 import QtQuick.Controls 2.12 as QtControls
0024 
0025 import org.kde.kirigami 2.14 as Kirigami
0026 
0027 /**
0028  * @brief small window with book information.
0029  * 
0030  * This shows a bit of information about the book and gives a
0031  * selector with the other books in the series.
0032  * 
0033  * It pops up after finishing a book in Book, and when pressing long
0034  * on a BookTileTall item in BookShelf.
0035  * 
0036  */
0037 Item {
0038     id: root;
0039     property bool selected: false;
0040     property alias title: bookTitle.text;
0041     property var author: [];
0042     property string publisher;
0043     property alias filename: bookFile.text;
0044     property alias thumbnail: coverImage.source;
0045     property int categoryEntriesCount;
0046     property string currentPage;
0047     property string totalPages;
0048     property var description: [];
0049     property string comment: peruseConfig.getFilesystemProperty(root.filename, "comment");
0050     property var tags: peruseConfig.getFilesystemProperty(root.filename, "tags").split(",");
0051     property int rating: peruseConfig.getFilesystemProperty(root.filename, "rating");
0052     signal bookSelected(string fileSelected, int currentPage);
0053     signal bookDeleteRequested(string fileSelected);
0054 
0055     property int neededHeight: bookCover.height;// + bookAuthorLabel.height + bookFile.height + Kirigami.Units.smallSpacing * 4;
0056     property bool showCommentTags: neededHeight > bookTitle.height + bookAuthorLabel.height
0057                                    + bookPublisherLabel.height + ratingContainer.height
0058                                    + tagsContainer.height + commentContainer.height + deleteButton.height + Kirigami.Units.smallSpacing * 7;
0059     visible: height > 1;
0060     enabled: visible;
0061     clip: true;
0062 
0063     onRatingChanged: {
0064         if (peruseConfig.getFilesystemProperty(root.filename, "rating") !== rating) {
0065             contentList.setBookData(root.filename, "rating", rating);
0066             peruseConfig.setFilesystemProperty(root.filename, "rating", rating);
0067         }
0068     }
0069     onTagsChanged: {
0070         if (tags.join(",") !== peruseConfig.getFilesystemProperty(root.filename, "tags")) {
0071             contentList.setBookData(root.filename, "tags", tags.join(","));
0072             peruseConfig.setFilesystemProperty(root.filename, "tags", tags.join(","));
0073         }
0074     }
0075     onCommentChanged: {
0076         contentList.setBookData(root.filename, "comment", comment);
0077         peruseConfig.setFilesystemProperty(root.filename, "comment", comment);
0078     }
0079 
0080     onFilenameChanged: {
0081         comment = peruseConfig.getFilesystemProperty(root.filename, "comment");
0082         tags = peruseConfig.getFilesystemProperty(root.filename, "tags").split(",");
0083         rating = peruseConfig.getFilesystemProperty(root.filename, "rating");
0084         ratingRow.potentialRating = rating;
0085     }
0086 
0087     Rectangle {
0088         anchors.fill: parent;
0089         color: Kirigami.Theme.highlightColor;
0090         opacity: root.selected ? 1 : 0;
0091         Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; } }
0092     }
0093     Item {
0094         id: bookCover;
0095         anchors {
0096             top: parent.top;
0097             left: parent.left;
0098         }
0099         width: root.width / 3;
0100         height: width * 1.5;
0101         Kirigami.Icon {
0102             id: coverImage;
0103             anchors {
0104                 fill: parent;
0105                 margins: Kirigami.Units.largeSpacing;
0106             }
0107             source: root.thumbnail === "Unknown role" ? "" : root.thumbnail;
0108             placeholder: "application-vnd.oasis.opendocument.text";
0109             fallback: "paint-unknown"
0110         }
0111         MouseArea {
0112             anchors.fill: parent;
0113             onClicked: root.bookSelected(root.filename, root.currentPage);
0114         }
0115     }
0116     Kirigami.Heading {
0117         id: bookTitle;
0118         anchors {
0119             top: parent.top;
0120             leftMargin: Kirigami.Units.smallSpacing;
0121             left: bookCover.right;
0122             right: parent.right;
0123         }
0124         maximumLineCount: 1;
0125         elide: Text.ElideMiddle;
0126         font.weight: Font.Bold;
0127         MouseArea {
0128             anchors.fill: parent;
0129             onClicked: root.bookSelected(root.filename, root.currentPage);
0130         }
0131         Rectangle {
0132             anchors {
0133                 left: parent.left;
0134                 top: parent.baseline;
0135                 topMargin: 2;
0136             }
0137             height: 2;
0138             width: parent.paintedWidth;
0139             color: Kirigami.Theme.linkColor;
0140         }
0141     }
0142     QtControls.Label {
0143         id: bookAuthorLabel;
0144         anchors {
0145             top: bookTitle.bottom;
0146             left: bookCover.right;
0147             leftMargin: Kirigami.Units.smallSpacing;
0148         }
0149         width: paintedWidth;
0150         text: i18nc("Label for authors", "Author(s)");
0151         font.weight: Font.Bold;
0152     }
0153     QtControls.Label {
0154         id: bookAuthor;
0155         anchors {
0156             top: bookTitle.bottom;
0157             left: bookAuthorLabel.right;
0158             leftMargin: Kirigami.Units.smallSpacing;
0159             right: parent.right;
0160         }
0161         elide: Text.ElideRight;
0162         text: (typeof root.author !== "undefined" && root.author.length > 0) ? root.author.join(", ") : "(unknown)";
0163         opacity: (text === "(unknown)" || text === "") ? 0.3 : 1;
0164     }
0165     QtControls.Label {
0166         id: bookPublisherLabel;
0167         anchors {
0168             top: bookAuthorLabel.bottom;
0169             left: bookCover.right;
0170             leftMargin: Kirigami.Units.smallSpacing;
0171         }
0172         width: paintedWidth;
0173         text: i18nc("Label for publisher", "Publisher");
0174         font.weight: Font.Bold;
0175     }
0176     QtControls.Label {
0177         id: bookPublisher;
0178         anchors {
0179             top: bookAuthor.bottom;
0180             left: bookPublisherLabel.right;
0181             leftMargin: Kirigami.Units.smallSpacing;
0182             right: parent.right;
0183         }
0184         elide: Text.ElideRight;
0185         text: root.publisher === "" ? "(unknown)" : root.publisher;
0186         opacity: (text === "(unknown)" || text === "") ? 0.3 : 1;
0187     }
0188     QtControls.Label {
0189         id: bookFile;
0190         anchors {
0191             top: bookPublisherLabel.bottom;
0192             left: bookCover.right;
0193             leftMargin: Kirigami.Units.smallSpacing;
0194             right: parent.right;
0195         }
0196         elide: Text.ElideMiddle;
0197         opacity: 0.3;
0198         font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.8;
0199         maximumLineCount: 1;
0200     }
0201     Item {
0202         id: ratingContainer;
0203         anchors {
0204             top: bookFile.bottom;
0205             left: bookCover.right;
0206             right: parent.right;
0207             margins: Kirigami.Units.smallSpacing;
0208         }
0209         Row {
0210             id: ratingRow;
0211             QtControls.Label {
0212                 width: paintedWidth;
0213                 text: i18nc("label for rating widget","Rating");
0214                 height: Kirigami.Units.iconSizes.medium;
0215                 font.weight: Font.Bold;
0216                 anchors.rightMargin: Kirigami.Units.smallSpacing;
0217             }
0218             property int potentialRating: root.rating;
0219             Repeater{
0220                 model: 5;
0221                 Item {
0222 
0223                     height: Kirigami.Units.iconSizes.medium;
0224                     width: Kirigami.Units.iconSizes.medium;
0225 
0226                 Kirigami.Icon {
0227                     source: "rating";
0228                     opacity: (ratingRow.potentialRating-2)/2 >= index? 1.0: 0.3;
0229                     anchors.fill:parent;
0230 
0231                     MouseArea {
0232                         anchors.fill: parent;
0233                         hoverEnabled: true;
0234                         onEntered: {
0235                             if (ratingRow.potentialRating === (index+1)*2) {
0236                                 ratingRow.potentialRating = ratingRow.potentialRating-1;
0237                             } else {
0238                                 ratingRow.potentialRating = (index+1)*2;
0239                             }
0240                         }
0241                         onExited: {
0242                             ratingRow.potentialRating = root.rating;
0243                         }
0244                         onClicked: root.rating === ratingRow.potentialRating?
0245                                        root.rating = ratingRow.potentialRating-1 :
0246                                        root.rating = ratingRow.potentialRating;
0247                     }
0248 
0249                 }
0250                 Kirigami.Icon {
0251                     source: "rating";
0252                     height: parent.height/2;
0253                     clip: true;
0254                     anchors.centerIn: parent;
0255                     width: height;
0256                     visible: ratingRow.potentialRating === (index*2)+1;
0257                 }
0258                 }
0259             }
0260         }
0261 
0262         height: childrenRect.height;
0263     }
0264     Item {
0265         id: tagsContainer;
0266         height: childrenRect.height;
0267         visible: root.showCommentTags;
0268         anchors {
0269             top: ratingContainer.bottom;
0270             left: bookCover.right;
0271             right: parent.right;
0272             margins: Kirigami.Units.smallSpacing;
0273         }
0274         QtControls.Label {
0275             text: i18nc("label for tags field","Tags");
0276             height: tagField.height;
0277             font.weight: Font.Bold;
0278             id: tagsLabel;
0279         }
0280         QtControls.TextField {
0281             id: tagField;
0282             anchors{
0283                 leftMargin: Kirigami.Units.smallSpacing;
0284                 left: tagsLabel.right;
0285                 top: parent.top;
0286                 right: parent.right;
0287             }
0288             width: {parent.width - tagsLabel.width - Kirigami.Units.smallSpacing;}
0289 
0290             text: root.tags.length !== 0? root.tags.join(", "): "";
0291             placeholderText: i18nc("Placeholder tag field", "(No tags)");
0292             onEditingFinished: {
0293                 var tags = text.split(",");
0294                 for (var i in tags) {
0295                     tags[i] = tags[i].trim();
0296                 }
0297                 root.tags = tags;
0298             }
0299         }
0300     }
0301     Item {
0302         id: commentContainer;
0303         height: childrenRect.height;
0304         visible: root.showCommentTags;
0305         anchors {
0306             top: tagsContainer.bottom;
0307             left: bookCover.right;
0308             right: parent.right;
0309             margins: Kirigami.Units.smallSpacing;
0310         }
0311         QtControls.Label {
0312             text: i18nc("label for comment field","Comment");
0313             height: tagField.height;
0314             font.weight: Font.Bold;
0315             id: commentLabel;
0316         }
0317         QtControls.TextField {
0318             id: commentField;
0319             anchors{
0320                 leftMargin: Kirigami.Units.smallSpacing;
0321                 left: commentLabel.right;
0322                 top: parent.top;
0323                 right: parent.right;
0324             }
0325             width: parent.width - commentLabel.width - Kirigami.Units.smallSpacing;
0326 
0327             text: root.comment !== ""? root.comment: "";
0328             placeholderText: i18nc("Placeholder comment field", "(No comment)");
0329             onEditingFinished: {
0330                 root.comment = text;
0331             }
0332         }
0333     }
0334     Item {
0335         id: descriptionContainer;
0336         anchors {
0337             top: root.showCommentTags ? commentContainer.bottom : ratingContainer.bottom;
0338             left: bookCover.right;
0339             right: parent.right;
0340             bottom: deleteBase.top;
0341             margins: Kirigami.Units.smallSpacing;
0342         }
0343         QtControls.Label {
0344             anchors.fill: parent;
0345             verticalAlignment: Text.AlignTop;
0346             text: (typeof root.description !== "undefined" && root.description.length !== 0) ?
0347                       root.description.join("\n\n"):
0348                       i18nc("Placeholder text for the book description field when no description is set", "(no description available for this book)");
0349             wrapMode: Text.WrapAtWordBoundaryOrAnywhere
0350             opacity: (typeof root.description !== "undefined" && root.description.length !== 0) ? 1.0: 0.3;
0351         }
0352     }
0353     Item {
0354         id: deleteBase;
0355         anchors {
0356             left: bookCover.right;
0357             leftMargin: Kirigami.Units.smallSpacing;
0358             right: parent.right;
0359             bottom: parent.bottom;
0360         }
0361         height: deleteButton.height + Kirigami.Units.smallSpacing * 2;
0362         Behavior on height { NumberAnimation { duration: applicationWindow().animationDuration; easing.type: Easing.InOutQuad; } }
0363         states: [
0364             State {
0365                 name: "confirmDelete";
0366                 PropertyChanges { target: deleteButton; opacity: 0; }
0367                 PropertyChanges { target: deleteConfirmBase; opacity: 1; }
0368                 PropertyChanges { target: deleteBase; height: deleteConfirmBase.height; }
0369             }
0370         ]
0371         QtControls.Button {
0372             id: deleteButton;
0373             text: i18nc("Spawn inline dialog box to confirm permanent removal of this book", "Delete from Device");
0374             anchors {
0375                 bottom: parent.bottom;
0376                 right: parent.right;
0377                 margins: Kirigami.Units.smallSpacing;
0378             }
0379 //             iconName: "edit-delete";
0380             onClicked: deleteBase.state = "confirmDelete";
0381             Behavior on opacity { NumberAnimation { duration: applicationWindow().animationDuration; easing.type: Easing.InOutQuad; } }
0382         }
0383         Rectangle {
0384             id: deleteConfirmBase;
0385             opacity: 0;
0386             width: parent.width;
0387             Behavior on opacity { NumberAnimation { duration: applicationWindow().animationDuration; easing.type: Easing.InOutQuad; } }
0388             height: yesDelete.height + confirmDeleteLabel.height + Kirigami.Units.largeSpacing * 2 + Kirigami.Units.smallSpacing;
0389             color: Kirigami.Theme.backgroundColor;
0390             QtControls.Label {
0391                 id: confirmDeleteLabel;
0392                 anchors {
0393                     top: parent.top;
0394                     topMargin: Kirigami.Units.largeSpacing;
0395                     left: parent.left;
0396                     right: parent.right;
0397                 }
0398                 height: paintedHeight;
0399                 wrapMode: Text.WordWrap;
0400                 horizontalAlignment: Text.AlignHCenter;
0401                 text: i18nc("Dialog text for delete book dialog", "Are you sure you want to delete this from your device?");
0402             }
0403             QtControls.Button {
0404                 id: yesDelete;
0405                 anchors {
0406                     top: confirmDeleteLabel.bottom;
0407                     topMargin: Kirigami.Units.smallSpacing;
0408                     right: parent.horizontalCenter;
0409                     rightMargin: (Kirigami.Units.smallSpacing) / 2;
0410                 }
0411                 text: i18nc("Confirmation button for book delete dialog", "Yes, Really Delete");
0412 //                 iconName: "dialog-ok";
0413                 onClicked: {root.bookDeleteRequested(root.filename); deleteBase.state = "";}
0414             }
0415             QtControls.Button {
0416                 anchors {
0417                     top: confirmDeleteLabel.bottom;
0418                     topMargin: Kirigami.Units.smallSpacing;
0419                     left: parent.horizontalCenter;
0420                     leftMargin: (Kirigami.Units.smallSpacing) / 2;
0421                 }
0422                 text: i18nc("Cancellation button or book delete dialog", "No, Cancel Delete");
0423 //                 iconName: "dialog-cancel";
0424                 onClicked: deleteBase.state = "";
0425             }
0426         }
0427     }
0428 }