diff --git a/harbour-sailfin.pro b/harbour-sailfin.pro index 0187e82..a665637 100644 --- a/harbour-sailfin.pro +++ b/harbour-sailfin.pro @@ -41,31 +41,32 @@ DISTFILES += \ qml/components/LibraryItemDelegate.qml \ qml/components/MoreSection.qml \ qml/components/PlainLabel.qml \ + qml/components/PlayToolbar.qml \ qml/components/RemoteImage.qml \ qml/components/Shim.qml \ qml/components/UserGridDelegate.qml \ qml/components/VideoPlayer.qml \ - qml/components/itemdetails/CollectionFolder.qml \ - qml/components/itemdetails/EpisodeDetails.qml \ - qml/components/itemdetails/FilmDetails.qml \ - qml/components/itemdetails/PlayToolbar.qml \ + qml/components/VideoTrackSelector.qml \ qml/components/itemdetails/SeasonDetails.qml \ - qml/components/itemdetails/SeriesDetails.qml \ - qml/components/itemdetails/UnsupportedDetails.qml \ - qml/components/itemdetails/VideoTrackSelector.qml \ qml/components/videoplayer/VideoError.qml \ qml/components/videoplayer/VideoHud.qml \ qml/cover/CoverPage.qml \ qml/cover/PosterCover.qml \ qml/cover/VideoCover.qml \ - qml/pages/CollectionPage.qml \ - qml/pages/DetailPage.qml \ qml/pages/LegalPage.qml \ qml/pages/MainPage.qml \ qml/pages/AboutPage.qml \ qml/harbour-sailfin.qml \ qml/pages/SettingsPage.qml \ qml/pages/VideoPage.qml \ + qml/pages/itemdetails/BaseDetailPage.qml \ + qml/pages/itemdetails/CollectionPage.qml \ + qml/pages/itemdetails/EpisodePage.qml \ + qml/pages/itemdetails/FilmPage.qml \ + qml/pages/itemdetails/MusicAlbumPage.qml \ + qml/pages/itemdetails/SeasonPage.qml \ + qml/pages/itemdetails/SeriesPage.qml \ + qml/pages/itemdetails/UnsupportedPage.qml \ qml/pages/setup/AddServerConnectingPage.qml \ qml/pages/setup/LoginDialog.qml \ qml/qmldir diff --git a/qml/Utils.js b/qml/Utils.js index 4f67621..efbe310 100644 --- a/qml/Utils.js +++ b/qml/Utils.js @@ -40,7 +40,7 @@ function ticksToText(ticks) { function itemImageUrl(baseUrl, item, type, options) { if (!item.ImageTags[type]) { return "" } return itemModelImageUrl(baseUrl, item.Id, item.ImageTags[type], type, options) - } +} function itemModelImageUrl(baseUrl, itemId, tag, type, options) { if (tag == undefined) return "" @@ -56,3 +56,23 @@ function itemModelImageUrl(baseUrl, itemId, tag, type, options) { function usePortraitCover(itemType) { return ["Series", "Movie", "tvshows", "movies"].indexOf(itemType) >= 0 } + +/** + * Returns the page url for a certain item type. + */ +function getPageUrl(itemType) { + switch (itemType.toLowerCase()) { + case "series": + return Qt.resolvedUrl("pages/itemdetails/SeriesPage.qml") + case "movie": + return Qt.resolvedUrl("pages/itemdetails/FilmPage.qml") + case "collection": + return Qt.resolvedUrl("pages/itemdetails/ColectionPage.qml") + case "season": + return Qt.resolvedUrl("pages/itemdetails/SeasonPage.qml") + case "episode": + return Qt.resolvedUrl("pages/itemdetails/EpisodePage.qml") + default: + return Qt.resolvedUrl("pages/itemdetails/UnsupportedPage.qml") + } +} diff --git a/qml/components/PlayToolbar.qml b/qml/components/PlayToolbar.qml new file mode 100644 index 0000000..d1b6e1f --- /dev/null +++ b/qml/components/PlayToolbar.qml @@ -0,0 +1,61 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2020 Chris Josten + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +import QtQuick 2.6 +import Sailfish.Silica 1.0 + +Column { + property alias imageSource : playImage.source + property real imageAspectRatio: 1.0 + signal playPressed() + spacing: Theme.paddingLarge + + BackgroundItem { + width: parent.width + height: width / imageAspectRatio + HighlightImage { + id: playImage + anchors.fill: parent + fillMode: Image.PreserveAspectCrop + color: Theme.overlayBackgroundColor + clip: true + } + Icon { + id: playButton + source: "image://theme/icon-l-play" + anchors.centerIn: parent + highlighted: parent.highlighted + } + onClicked: playPressed() + } + Row { + anchors { + //left: parent.left + right: parent.right + leftMargin: Theme.horizontalPageMargin + rightMargin: Theme.horizontalPageMargin + } + spacing: Theme.paddingMedium + IconButton { + id: favouriteButton + icon.source: "image://theme/icon-m-favorite" + } + + } +} diff --git a/qml/components/itemdetails/VideoTrackSelector.qml b/qml/components/VideoTrackSelector.qml similarity index 100% rename from qml/components/itemdetails/VideoTrackSelector.qml rename to qml/components/VideoTrackSelector.qml diff --git a/qml/components/itemdetails/CollectionFolder.qml b/qml/components/itemdetails/CollectionFolder.qml deleted file mode 100644 index 4f0aa37..0000000 --- a/qml/components/itemdetails/CollectionFolder.qml +++ /dev/null @@ -1,24 +0,0 @@ -/* -Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -import QtQuick 2.6 - -Item { - -} diff --git a/qml/components/itemdetails/EpisodeDetails.qml b/qml/components/itemdetails/EpisodeDetails.qml deleted file mode 100644 index 8331545..0000000 --- a/qml/components/itemdetails/EpisodeDetails.qml +++ /dev/null @@ -1,62 +0,0 @@ -/* -Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -import QtQuick 2.6 -import Sailfish.Silica 1.0 -import nl.netsoj.chris.Jellyfin 1.0 - -import ".." -import "../../Utils.js" as Utils - -Column { - property var itemData - spacing: Theme.paddingMedium - - PlayToolbar { - onPlayPressed: pageStack.push(Qt.resolvedUrl("../../pages/VideoPage.qml"), - {"itemId": itemId, "itemData": itemData, "audioTrack": trackSelector.audioTrack, - "subtitleTrack": trackSelector.subtitleTrack }) - } - - VideoTrackSelector { - id: trackSelector - width: parent.width - tracks: itemData.MediaStreams - } - - PlainLabel { - id: tinyDetails - text: { - if (typeof itemData.IndexNumberEnd !== "undefined") { - qsTr("Episode %1–%2 Season %3").arg(itemData.IndexNumber) - .arg(itemData.IndexNumberEnd) - .arg(itemData.ParentIndexNumber) - } else { - qsTr("Episode %1 Season %2").arg(itemData.IndexNumber).arg(itemData.ParentIndexNumber) - } - } - } - - PlainLabel { - id: overviewText - text: itemData.Overview - font.pixelSize: Theme.fontSizeSmall - color: Theme.secondaryHighlightColor - } -} diff --git a/qml/components/itemdetails/FilmDetails.qml b/qml/components/itemdetails/FilmDetails.qml deleted file mode 100644 index bc4850a..0000000 --- a/qml/components/itemdetails/FilmDetails.qml +++ /dev/null @@ -1,53 +0,0 @@ -/* -Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -import QtQuick 2.6 -import Sailfish.Silica 1.0 - -import "../" -import "../../Utils.js" as Utils - -Column { - property var itemData - spacing: Theme.paddingMedium - - PlayToolbar { - onPlayPressed: pageStack.push(Qt.resolvedUrl("../../pages/VideoPage.qml"), - {"itemId": itemId, "itemData": itemData, "audioTrack": trackSelector.audioTrack, - "subtitleTrack": trackSelector.subtitleTrack }) - } - - VideoTrackSelector { - id: trackSelector - width: parent.width - tracks: itemData.MediaStreams - } - - PlainLabel { - id: tinyDetails - text: qsTr("Released: %1 — Run time: %2").arg(itemData.ProductionYear).arg(Utils.ticksToText(itemData.RunTimeTicks)) - } - - PlainLabel { - id: overviewText - text: itemData.Overview - font.pixelSize: Theme.fontSizeSmall - color: Theme.secondaryHighlightColor - } -} diff --git a/qml/components/itemdetails/PlayToolbar.qml b/qml/components/itemdetails/PlayToolbar.qml deleted file mode 100644 index 7262294..0000000 --- a/qml/components/itemdetails/PlayToolbar.qml +++ /dev/null @@ -1,43 +0,0 @@ -/* -Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -import QtQuick 2.6 -import Sailfish.Silica 1.0 - -Row { - signal playPressed() - - anchors { - //left: parent.left - right: parent.right - leftMargin: Theme.horizontalPageMargin - rightMargin: Theme.horizontalPageMargin - } - spacing: Theme.paddingMedium - IconButton { - id: favouriteButton - icon.source: "image://theme/icon-m-favorite" - } - IconButton { - id: playButton - icon.source: "image://theme/icon-l-play" - onPressed: playPressed() - } - -} diff --git a/qml/components/itemdetails/SeasonDetails.qml b/qml/components/itemdetails/SeasonDetails.qml index 7353b34..8b13789 100644 --- a/qml/components/itemdetails/SeasonDetails.qml +++ b/qml/components/itemdetails/SeasonDetails.qml @@ -1,123 +1 @@ -/* -Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -import QtQuick 2.6 -import Sailfish.Silica 1.0 -import nl.netsoj.chris.Jellyfin 1.0 - -import "../../Utils.js" as Utils -import "../.." -import ".." - -Column { - property var itemData - - ShowEpisodesModel { - id: episodeModel - apiClient: ApiClient - show: itemData.SeriesId - seasonId: itemData.Id - fields: ["Overview"] - } - - ColumnView { - model: episodeModel - itemHeight: Constants.libraryDelegateHeight - delegate: BackgroundItem { - height: Constants.libraryDelegateHeight - RemoteImage { - id: episodeImage - anchors { - top: parent.top - left: parent.left - bottom: parent.bottom - } - width: Constants.libraryDelegateWidth - height: Constants.libraryDelegateHeight - source: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": height}) - fillMode: Image.PreserveAspectCrop - clip: true - - // Makes the progress bar stand out more - Shim { - anchors { - left: parent.left - bottom: parent.bottom - right: parent.right - } - height: parent.height / 3 - shimColor: Theme.overlayBackgroundColor - shimOpacity: Theme.opacityOverlay - //width: model.userData.PlayedPercentage * parent.width / 100 - visible: episodeProgress.width > 0 // It doesn't look nice when it's visible on every image - } - - Rectangle { - id: episodeProgress - anchors { - left: parent.left - bottom: parent.bottom - } - height: Theme.paddingMedium - width: model.userData.PlayedPercentage * parent.width / 100 - color: Theme.highlightColor - } - } - - Label { - id: episodeTitle - anchors { - left: episodeImage.right - leftMargin: Theme.paddingLarge - top: parent.top - right: parent.right - rightMargin: Theme.horizontalPageMargin - } - text: model.name - truncationMode: TruncationMode.Fade - horizontalAlignment: Text.AlignLeft - } - - Label { - id: episodeOverview - anchors { - left: episodeImage.right - leftMargin: Theme.paddingLarge - right: parent.right - rightMargin: Theme.horizontalPageMargin - top: episodeTitle.bottom - bottom: parent.bottom - } - color: highlighted ? Theme.secondaryHighlightColor: Theme.secondaryColor - font.pixelSize: Theme.fontSizeExtraSmall - //: No overview/summary text of an episode available - text: model.overview || qsTr("No overview available") - wrapMode: Text.WordWrap - elide: Text.ElideRight - } - onClicked: pageStack.push(Qt.resolvedUrl("../../pages/DetailPage.qml"), {"itemId": model.id}) - } - } - onItemDataChanged: { - console.log(JSON.stringify(itemData)) - episodeModel.show = itemData.SeriesId - episodeModel.seasonId = itemData.Id - episodeModel.reload() - } -} diff --git a/qml/components/itemdetails/SeriesDetails.qml b/qml/components/itemdetails/SeriesDetails.qml deleted file mode 100644 index f5e24fa..0000000 --- a/qml/components/itemdetails/SeriesDetails.qml +++ /dev/null @@ -1,68 +0,0 @@ -/* -Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -import QtQuick 2.6 -import Sailfish.Silica 1.0 -import nl.netsoj.chris.Jellyfin 1.0 - -import "../" -import "../../Utils.js" as Utils - -Column { - property var itemData - - PlainLabel { - id: overviewText - text: itemData.Overview - font.pixelSize: Theme.fontSizeSmall - color: Theme.secondaryHighlightColor - } - - SectionHeader { - //: Seasons of a (TV) show - text: qsTr("Seasons") - } - - ShowSeasonsModel { - id: showSeasonsModel - apiClient: ApiClient - show: itemData.Id - } - - SilicaListView { - model: showSeasonsModel - clip: true - width: parent.width - height: Screen.width / 2 - orientation: ListView.Horizontal - spacing: Theme.paddingLarge - leftMargin: Theme.horizontalPageMargin - rightMargin: Theme.horizontalPageMargin - delegate: LibraryItemDelegate { - poster: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": height}) - title: model.name - onClicked: pageStack.push(Qt.resolvedUrl("../../pages/DetailPage.qml"), {"itemId": model.id}) - } - } - - onItemDataChanged: { - showSeasonsModel.show = itemData.Id - showSeasonsModel.reload() - } -} diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml index 8645b84..afd82ab 100644 --- a/qml/pages/MainPage.qml +++ b/qml/pages/MainPage.qml @@ -94,7 +94,7 @@ Page { text: model.name busy: userItemModel.status != ApiModel.Ready - onHeaderClicked: pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {"itemId": model.id}) + onHeaderClicked: pageStack.push(Qt.resolvedUrl("itemdetails/CollectionPage.qml"), {"itemId": model.id}) Loader { width: parent.width sourceComponent: carrouselView @@ -202,7 +202,7 @@ Page { progress: model.userData.PlayedPercentage / 100 onClicked: { - pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id}) + pageStack.push(Utils.getPageUrl(model.type), {"itemId": model.id}) } } } diff --git a/qml/pages/DetailPage.qml b/qml/pages/itemdetails/BaseDetailPage.qml similarity index 57% rename from qml/pages/DetailPage.qml rename to qml/pages/itemdetails/BaseDetailPage.qml index c85070b..7ce36df 100644 --- a/qml/pages/DetailPage.qml +++ b/qml/pages/itemdetails/BaseDetailPage.qml @@ -21,8 +21,7 @@ import Sailfish.Silica 1.0 import nl.netsoj.chris.Jellyfin 1.0 -import "../components" -import "../components/itemdetails" +import "../../components" /** * This page displays details about a film, show, season, episode, and so on. @@ -35,11 +34,11 @@ Page { property string itemId: "" property var itemData: ({}) property bool _loading: true - readonly property bool _hasLogo: itemData.ImageTags.Logo !== undefined - readonly property string _logo: itemData.ImageTags.Logo + readonly property bool hasLogo: (typeof itemData.ImageTags !== "undefined") && (typeof itemData.ImageTags["Logo"] !== "undefined") readonly property var _backdropImages: itemData.BackdropImageTags readonly property var _parentBackdropImages: itemData.ParentBackdropImageTags readonly property string parentId: itemData.ParentId || "" + property alias backdrop: backdrop on_BackdropImagesChanged: updateBackdrop() on_ParentBackdropImagesChanged: updateBackdrop() @@ -62,72 +61,6 @@ Page { anchors.fill: parent } - SilicaFlickable { - anchors.fill: parent - contentHeight: content.height - - Column { - id: content - width: parent.width - - PageHeader { - title: itemData.Name || qsTr("Loading") - visible: !_hasLogo - } - - Column { - width: parent.width - Item { - width: 1 - height: Theme.paddingLarge - } - RemoteImage { - anchors { - horizontalCenter: parent.horizontalCenter - } - source: _hasLogo ? ApiClient.baseUrl + "/Items/" + itemId + "/Images/Logo?tag=" + _logo : "" - } - Item { - width: 1 - height: Theme.paddingLarge - } - visible: _hasLogo - } - - Item { - width: 1 - height: Theme.paddingLarge - } - - Loader { - active: itemData != undefined - asynchronous: true - width: parent.width - source: { - switch (itemData.Type){ - case "Movie": - return Qt.resolvedUrl("../components/itemdetails/FilmDetails.qml") - case "Series": - return Qt.resolvedUrl("../components/itemdetails/SeriesDetails.qml") - case "Season": - return Qt.resolvedUrl("../components/itemdetails/SeasonDetails.qml") - case "Episode": - return Qt.resolvedUrl("../components/itemdetails/EpisodeDetails.qml") - case undefined: - return "" - default: - return Qt.resolvedUrl("../components/itemdetails/UnsupportedDetails.qml") - } - } - onLoaded: { - item.itemData = Qt.binding(function() { return pageRoot.itemData; }) - } - } - - - } - } - PageBusyIndicator { running: pageRoot._loading } @@ -160,8 +93,13 @@ Page { //console.log(JSON.stringify(result)) pageRoot.itemData = result pageRoot._loading = false - if (status == PageStatus.Active) - appWindow.itemData = result + if (status == PageStatus.Active) { + if (itemData.Type === "CollectionFolder") { + appWindow.collectionId = itemData.Id + } else { + appWindow.itemData = result + } + } } } } diff --git a/qml/pages/CollectionPage.qml b/qml/pages/itemdetails/CollectionPage.qml similarity index 79% rename from qml/pages/CollectionPage.qml rename to qml/pages/itemdetails/CollectionPage.qml index 2585608..50d82e1 100644 --- a/qml/pages/CollectionPage.qml +++ b/qml/pages/itemdetails/CollectionPage.qml @@ -21,21 +21,18 @@ import Sailfish.Silica 1.0 import nl.netsoj.chris.Jellyfin 1.0 -import ".." -import "../components" -import "../Utils.js" as Utils +import "../.." +import "../../components" -Page { +BaseDetailPage { id: pageRoot - property var itemId - property var itemData - property bool _loading: true UserItemModel { id: collectionModel apiClient: ApiClient parentId: itemData.Id || "" sortBy: ["SortName"] + onParentIdChanged: reload() } SilicaGridView { @@ -99,7 +96,7 @@ Page { pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {"itemId": model.id}) break; default: - pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id}) + pageStack.push(Utils.getPageUrl(model.type), {"itemId": model.id}) } } } @@ -113,48 +110,6 @@ Page { VerticalScrollDecorator {} } - PageBusyIndicator { - running: pageRoot._loading - } - - onItemIdChanged: { - itemData = {} - if (itemId.length && PageStatus.Active) { - pageRoot._loading = true - ApiClient.fetchItem(itemId) - } - } - - onStatusChanged: { - if (status == PageStatus.Deactivating) { - backdrop.clear() - } - if (status == PageStatus.Active) { - if (itemId && !itemData) { - ApiClient.fetchItem(itemId) - appWindow.collectionId = itemId - } - - } - } - - Connections { - target: ApiClient - onItemFetched: { - if (itemId === pageRoot.itemId) { - pageRoot.itemData = result - pageRoot._loading = false - console.log(JSON.stringify(result)) - collectionModel.parentId = result.Id - collectionModel.reload() - if (status == PageStatus.Active) { - appWindow.itemData = null - appWindow.collectionId = itemId - } - } - } - } - Component { id: sortPageComponent Page { diff --git a/qml/pages/itemdetails/EpisodePage.qml b/qml/pages/itemdetails/EpisodePage.qml new file mode 100644 index 0000000..ade3cb0 --- /dev/null +++ b/qml/pages/itemdetails/EpisodePage.qml @@ -0,0 +1,75 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2020 Chris Josten + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import nl.netsoj.chris.Jellyfin 1.0 + +import "../../components" +import "../../" + +BaseDetailPage { + SilicaFlickable { + anchors.fill: parent + contentHeight: content.height + Column { + id: content + width: parent.width + + PageHeader { + title: itemData.Name + description: { + if (typeof itemData.IndexNumberEnd !== "undefined") { + qsTr("Episode %1–%2 | %3").arg(itemData.IndexNumber) + .arg(itemData.IndexNumberEnd) + .arg(itemData.SeasonName) + } else { + qsTr("Episode %1 | %2").arg(itemData.IndexNumber).arg(itemData.SeasonName) + } + } + } + + PlayToolbar { + imageSource: Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Primary", {"maxWidth": parent.width}) + imageAspectRatio: itemData.PrimaryImageAspectRatio + onPlayPressed: pageStack.push(Qt.resolvedUrl("../VideoPage.qml"), + {"itemId": itemId, "itemData": itemData, "audioTrack": trackSelector.audioTrack, + "subtitleTrack": trackSelector.subtitleTrack }) + width: parent.width + } + + VideoTrackSelector { + id: trackSelector + width: parent.width + tracks: itemData.MediaStreams + } + + SectionHeader { + text: qsTr("Overview") + } + + PlainLabel { + id: overviewText + text: itemData.Overview + font.pixelSize: Theme.fontSizeSmall + color: Theme.secondaryHighlightColor + } + } + } +} diff --git a/qml/pages/itemdetails/FilmPage.qml b/qml/pages/itemdetails/FilmPage.qml new file mode 100644 index 0000000..e02160a --- /dev/null +++ b/qml/pages/itemdetails/FilmPage.qml @@ -0,0 +1,70 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2020 Chris Josten + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +import QtQuick 2.6 +import Sailfish.Silica 1.0 + +import nl.netsoj.chris.Jellyfin 1.0 + +import "../../components" +import "../.." + +BaseDetailPage { + SilicaFlickable { + anchors.fill: parent + contentHeight: content.height + + Column { + id: content + width: parent.width + spacing: Theme.paddingMedium + + PageHeader { + title: itemData.Name + description: qsTr("Released: %1 — Run time: %2").arg(itemData.ProductionYear).arg(Utils.ticksToText(itemData.RunTimeTicks)) + } + + PlayToolbar { + width: parent.width + imageSource: Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Primary", {"maxWidth": parent.width}) + imageAspectRatio: 1.66666 //itemData.PrimaryImageAspectRatio + onPlayPressed: pageStack.push(Qt.resolvedUrl("../../pages/VideoPage.qml"), + {"itemId": itemId, "itemData": itemData, "audioTrack": trackSelector.audioTrack, + "subtitleTrack": trackSelector.subtitleTrack }) + } + + VideoTrackSelector { + id: trackSelector + width: parent.width + tracks: itemData.MediaStreams + } + + SectionHeader { + text: qsTr("Overview") + } + + PlainLabel { + id: overviewText + text: itemData.Overview + font.pixelSize: Theme.fontSizeSmall + color: Theme.secondaryHighlightColor + } + } + } +} diff --git a/qml/pages/itemdetails/MusicAlbumPage.qml b/qml/pages/itemdetails/MusicAlbumPage.qml new file mode 100644 index 0000000..9c36e13 --- /dev/null +++ b/qml/pages/itemdetails/MusicAlbumPage.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + +} diff --git a/qml/pages/itemdetails/SeasonPage.qml b/qml/pages/itemdetails/SeasonPage.qml new file mode 100644 index 0000000..e983c2d --- /dev/null +++ b/qml/pages/itemdetails/SeasonPage.qml @@ -0,0 +1,137 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2020 Chris Josten + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import nl.netsoj.chris.Jellyfin 1.0 + +import "../.." +import "../../components" +import ".." + +BaseDetailPage { + SilicaFlickable { + anchors.fill: parent + contentHeight: content.height + + Column { + id: content + width: parent.width + + PageHeader { + title: itemData.Name + description: itemData.SeriesName + } + + ShowEpisodesModel { + id: episodeModel + apiClient: ApiClient + show: itemData.SeriesId + seasonId: itemData.Id + fields: ["Overview"] + } + + ColumnView { + model: episodeModel + itemHeight: Constants.libraryDelegateHeight + delegate: BackgroundItem { + height: Constants.libraryDelegateHeight + RemoteImage { + id: episodeImage + anchors { + top: parent.top + left: parent.left + bottom: parent.bottom + } + width: Constants.libraryDelegateWidth + height: Constants.libraryDelegateHeight + source: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": height}) + fillMode: Image.PreserveAspectCrop + clip: true + + // Makes the progress bar stand out more + Shim { + anchors { + left: parent.left + bottom: parent.bottom + right: parent.right + } + height: parent.height / 3 + shimColor: Theme.overlayBackgroundColor + shimOpacity: Theme.opacityOverlay + //width: model.userData.PlayedPercentage * parent.width / 100 + visible: episodeProgress.width > 0 // It doesn't look nice when it's visible on every image + } + + Rectangle { + id: episodeProgress + anchors { + left: parent.left + bottom: parent.bottom + } + height: Theme.paddingMedium + width: model.userData.PlayedPercentage * parent.width / 100 + color: Theme.highlightColor + } + } + + Label { + id: episodeTitle + anchors { + left: episodeImage.right + leftMargin: Theme.paddingLarge + top: parent.top + right: parent.right + rightMargin: Theme.horizontalPageMargin + } + text: model.name + truncationMode: TruncationMode.Fade + horizontalAlignment: Text.AlignLeft + } + + Label { + id: episodeOverview + anchors { + left: episodeImage.right + leftMargin: Theme.paddingLarge + right: parent.right + rightMargin: Theme.horizontalPageMargin + top: episodeTitle.bottom + bottom: parent.bottom + } + color: highlighted ? Theme.secondaryHighlightColor: Theme.secondaryColor + font.pixelSize: Theme.fontSizeExtraSmall + //: No overview/summary text of an episode available + text: model.overview || qsTr("No overview available") + wrapMode: Text.WordWrap + elide: Text.ElideRight + } + onClicked: pageStack.push(Utils.getPageUrl(model.type), {"itemId": model.id}) + } + } + + } + } + onItemDataChanged: { + console.log(JSON.stringify(itemData)) + episodeModel.show = itemData.SeriesId + episodeModel.seasonId = itemData.Id + episodeModel.reload() + } +} diff --git a/qml/pages/itemdetails/SeriesPage.qml b/qml/pages/itemdetails/SeriesPage.qml new file mode 100644 index 0000000..be5c45d --- /dev/null +++ b/qml/pages/itemdetails/SeriesPage.qml @@ -0,0 +1,93 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2020 Chris Josten + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import nl.netsoj.chris.Jellyfin 1.0 + +import "../../components" +import "../.." + +BaseDetailPage { + SilicaFlickable { + anchors.fill: parent + contentHeight: content.height + + Column { + id: content + width: parent.width + + PageHeader { + id: header + title: itemData.Name + visible: !hasLogo + } + + Item { + visible: hasLogo + width: parent.width + height: Math.max(logoImage.height, header.height) + 2 * Theme.paddingLarge + RemoteImage { + id: logoImage + anchors.centerIn: parent + source: Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Logo") + } + } + + PlainLabel { + id: overviewText + text: itemData.Overview + font.pixelSize: Theme.fontSizeSmall + color: Theme.secondaryHighlightColor + } + + SectionHeader { + //: Seasons of a (TV) show + text: qsTr("Seasons") + } + + ShowSeasonsModel { + id: showSeasonsModel + apiClient: ApiClient + show: itemData.Id + } + + SilicaListView { + model: showSeasonsModel + clip: true + width: parent.width + height: Screen.width / 2 + orientation: ListView.Horizontal + spacing: Theme.paddingLarge + leftMargin: Theme.horizontalPageMargin + rightMargin: Theme.horizontalPageMargin + delegate: LibraryItemDelegate { + poster: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": height}) + title: model.name + onClicked: pageStack.push(Utils.getPageUrl(model.type), {"itemId": model.id}) + } + } + + } + } + onItemDataChanged: { + showSeasonsModel.show = itemData.Id + showSeasonsModel.reload() + } +} diff --git a/qml/components/itemdetails/UnsupportedDetails.qml b/qml/pages/itemdetails/UnsupportedPage.qml similarity index 71% rename from qml/components/itemdetails/UnsupportedDetails.qml rename to qml/pages/itemdetails/UnsupportedPage.qml index 32881c2..f0d70d7 100644 --- a/qml/components/itemdetails/UnsupportedDetails.qml +++ b/qml/pages/itemdetails/UnsupportedPage.qml @@ -20,10 +20,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import QtQuick 2.6 import Sailfish.Silica 1.0 -ViewPlaceholder { - property var itemData +BaseDetailPage { + SilicaFlickable { + anchors.fill: parent + PageHeader { + title: itemData.Name + } + ViewPlaceholder { - enabled: true - text: qsTr("Item type (%1) unsupported").arg(itemData.Type) - hintText: qsTr("This is still an alpha version :)") + enabled: true + text: qsTr("Item type (%1) unsupported").arg(itemData.Type) + hintText: qsTr("This is still an alpha version :)") + } + } } diff --git a/qml/qmldir b/qml/qmldir index c6de29c..0b84cf2 100644 --- a/qml/qmldir +++ b/qml/qmldir @@ -16,3 +16,4 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA singleton Constants 1.0 Constants.qml +Utils 1.0 Utils.js diff --git a/translations/harbour-sailfin.ts b/translations/harbour-sailfin.ts index 51d1f19..56ee869 100644 --- a/translations/harbour-sailfin.ts +++ b/translations/harbour-sailfin.ts @@ -102,14 +102,7 @@ - DetailPage - - Loading - - - - - EpisodeDetails + EpisodePage Episode %1–%2 Season %3 @@ -120,7 +113,7 @@ - FilmDetails + FilmPage Released: %1 — Run time: %2 @@ -205,7 +198,7 @@ - SeasonDetails + SeasonPage No overview available No overview/summary text of an episode available @@ -213,7 +206,7 @@ - SeriesDetails + SeriesPage Seasons Seasons of a (TV) show @@ -258,13 +251,13 @@ - UnsupportedDetails + UnsupportedPage - This is still an alpha version :) + Item type (%1) unsupported - Item type (%1) unsupported + This is still an alpha version :)