From 14b5d56d13bb316e58cdcd7ebfb4231bec50791f Mon Sep 17 00:00:00 2001 From: Grigorii Zimin Date: Fri, 13 Mar 2020 11:04:46 +0300 Subject: [webradio] refactor webradio app Task-number: AUTOSUITE-1472 Change-Id: I448f7ec0f077c74541e77574fffaf2d9e39599ee Reviewed-by: Grigorii Zimin --- com.pelagicore.webradio/Main.qml | 57 +++++ com.pelagicore.webradio/assets/logo-dark.png | Bin 0 -> 17050 bytes com.pelagicore.webradio/assets/logo.png | Bin 0 -> 21004 bytes com.pelagicore.webradio/assets/onair.jpg | Bin 0 -> 30284 bytes .../com.pelagicore.webradio.pro | 19 ++ com.pelagicore.webradio/icon.png | Bin 0 -> 878 bytes com.pelagicore.webradio/info.yaml | 13 ++ .../panels/CurrentStationScreen.qml | 107 +++++++++ com.pelagicore.webradio/panels/SelectionScreen.qml | 173 +++++++++++++++ com.pelagicore.webradio/panels/StationCover.qml | 137 ++++++++++++ com.pelagicore.webradio/popups/AboutPopup.qml | 79 +++++++ .../popups/MusicSourcesPopup.qml | 101 +++++++++ com.pelagicore.webradio/stores/RadioStore.qml | 244 +++++++++++++++++++++ com.pelagicore.webradio/views/WebRadioContent.qml | 85 +++++++ qt-auto-extra-apps.pro | 3 +- 15 files changed, 1017 insertions(+), 1 deletion(-) create mode 100644 com.pelagicore.webradio/Main.qml create mode 100644 com.pelagicore.webradio/assets/logo-dark.png create mode 100644 com.pelagicore.webradio/assets/logo.png create mode 100644 com.pelagicore.webradio/assets/onair.jpg create mode 100644 com.pelagicore.webradio/com.pelagicore.webradio.pro create mode 100644 com.pelagicore.webradio/icon.png create mode 100644 com.pelagicore.webradio/info.yaml create mode 100644 com.pelagicore.webradio/panels/CurrentStationScreen.qml create mode 100644 com.pelagicore.webradio/panels/SelectionScreen.qml create mode 100644 com.pelagicore.webradio/panels/StationCover.qml create mode 100644 com.pelagicore.webradio/popups/AboutPopup.qml create mode 100644 com.pelagicore.webradio/popups/MusicSourcesPopup.qml create mode 100644 com.pelagicore.webradio/stores/RadioStore.qml create mode 100644 com.pelagicore.webradio/views/WebRadioContent.qml diff --git a/com.pelagicore.webradio/Main.qml b/com.pelagicore.webradio/Main.qml new file mode 100644 index 0000000..00a20bf --- /dev/null +++ b/com.pelagicore.webradio/Main.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Copyright (C) 2014-2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtAuto Extra Apps. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.2 +import shared.controls 1.0 +import shared.Sizes 1.0 +import shared.Style 1.0 +import application.windows 1.0 + +import "stores" +import "views" + +QtObject { + property var mainWindow: ApplicationCCWindow { + id: mainWindow + + WebRadioContent { + x: mainWindow.exposedRect.x + y: mainWindow.exposedRect.y + width: mainWindow.exposedRect.width + height: mainWindow.exposedRect.height + anchors.top: parent.top + anchors.topMargin: Sizes.dp(200) + store: RadioStore { } + rootItem: mainWindow.contentItem + } + } +} diff --git a/com.pelagicore.webradio/assets/logo-dark.png b/com.pelagicore.webradio/assets/logo-dark.png new file mode 100644 index 0000000..61bf203 Binary files /dev/null and b/com.pelagicore.webradio/assets/logo-dark.png differ diff --git a/com.pelagicore.webradio/assets/logo.png b/com.pelagicore.webradio/assets/logo.png new file mode 100644 index 0000000..847b054 Binary files /dev/null and b/com.pelagicore.webradio/assets/logo.png differ diff --git a/com.pelagicore.webradio/assets/onair.jpg b/com.pelagicore.webradio/assets/onair.jpg new file mode 100644 index 0000000..86364c2 Binary files /dev/null and b/com.pelagicore.webradio/assets/onair.jpg differ diff --git a/com.pelagicore.webradio/com.pelagicore.webradio.pro b/com.pelagicore.webradio/com.pelagicore.webradio.pro new file mode 100644 index 0000000..8eae043 --- /dev/null +++ b/com.pelagicore.webradio/com.pelagicore.webradio.pro @@ -0,0 +1,19 @@ +TEMPLATE = aux + +FILES += info.yaml \ + icon.png \ + Main.qml \ + panels \ + stores \ + assets \ + popups \ + views \ + +app.files = $$FILES +app.path = /apps/com.pelagicore.webradio +INSTALLS += app + +AM_MANIFEST = info.yaml +AM_PACKAGE_DIR = $$app.path + +load(am-app) diff --git a/com.pelagicore.webradio/icon.png b/com.pelagicore.webradio/icon.png new file mode 100644 index 0000000..9b8ba23 Binary files /dev/null and b/com.pelagicore.webradio/icon.png differ diff --git a/com.pelagicore.webradio/info.yaml b/com.pelagicore.webradio/info.yaml new file mode 100644 index 0000000..326876d --- /dev/null +++ b/com.pelagicore.webradio/info.yaml @@ -0,0 +1,13 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'com.pelagicore.webradio' +icon: 'icon.png' +code: 'Main.qml' +runtime: 'qml' +runtimeParameters: { importPaths: ['.'] } +name: + en: 'WebRadio' + de: 'WebRadio' + +categories: [ 'media' ] diff --git a/com.pelagicore.webradio/panels/CurrentStationScreen.qml b/com.pelagicore.webradio/panels/CurrentStationScreen.qml new file mode 100644 index 0000000..49f38c3 --- /dev/null +++ b/com.pelagicore.webradio/panels/CurrentStationScreen.qml @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Copyright (C) 2014-2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtAuto Extra Apps. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.2 +import shared.controls 1.0 +import shared.Sizes 1.0 + +import shared.Style 1.0 + +Item { + id: root + + property string stationName: "" + property string stationImage: "" + property string bitRate: "" + property string streamingUrl: "" + property alias currentOperationStatus: stationInfo.status + property bool playing + + signal nextStation() + signal prevStation() + signal playStation() + signal pauseStation() + + StationCover { + id: stationInfo + + anchors.left: parent.left + anchors.leftMargin: Sizes.dp(80) + source: root.stationImage === "" ? "../assets/onair.jpg" : root.stationImage + title: root.stationName + subTitle: qsTr("Bitrate: ") + root.bitRate + description: qsTr("Streaming: ") + root.streamingUrl + } + + Image { + anchors.bottomMargin: -Sizes.dp(80) + anchors.bottom: controlsRow.top + anchors.left: stationInfo.right + height: Sizes.dp(278 / 3) + width: Sizes.dp(1000 / 3) + fillMode: Image.PreserveAspectCrop + source: Style.theme === Style.Dark ? "../assets/logo-dark.png" : "../assets/logo.png" + } + + RowLayout { + id: controlsRow + anchors.top: parent.top + anchors.topMargin: Sizes.dp(52) + anchors.left: stationInfo.right + ToolButton { + Layout.preferredWidth: Sizes.dp(80) + Layout.preferredHeight: Sizes.dp(240) + icon.name: "ic_skipprevious" + onClicked: { + root.prevStation() + } + } + + ToolButton { + Layout.preferredWidth: Sizes.dp(160) + Layout.preferredHeight: Sizes.dp(240) + icon.name: root.playing ? "ic-pause" : "ic_play" + onClicked: root.playing ? root.pauseStation() : root.playStation() + } + + ToolButton { + Layout.preferredWidth: Sizes.dp(80) + Layout.preferredHeight: Sizes.dp(240) + icon.name: "ic_skipnext" + onClicked: { + root.nextStation() + } + } + } +} diff --git a/com.pelagicore.webradio/panels/SelectionScreen.qml b/com.pelagicore.webradio/panels/SelectionScreen.qml new file mode 100644 index 0000000..48dcc7a --- /dev/null +++ b/com.pelagicore.webradio/panels/SelectionScreen.qml @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Copyright (C) 2014-2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtAuto Extra Apps. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.2 + +import shared.controls 1.0 +import shared.Sizes 1.0 +import shared.Style 1.0 +import shared.utils 1.0 +import shared.animations 1.0 + +import "../stores" +import "../popups" + + +Item { + id: root + + property RadioStore store + property Item rootItem + signal chosenGenre(var genre) + + Image { + width: root.width - Sizes.dp(80) + height: Sizes.dp(16) + anchors.horizontalCenter: root.horizontalCenter + anchors.bottom: genrelist.top + source: Style.image("list-divider") + opacity: genrelist.contentY > 0 ? 1.0 : 0.0 + Behavior on opacity { DefaultNumberAnimation { duration: 100 } } + } + + ToolsColumn { + id: toolsColumn + width: Sizes.dp(264) + anchors.left: parent.left + anchors.top: parent.top + model: root.store.toolsColumnModel + + onClicked: { + if (currentText === "sources") { + //FIXME in multiprocess store.musicSourcesModel.length returns 1 + //even though is more. When spotify and/or web radio are uninstalled + //and installed again, then it updates fine. + var pos = currentItem.mapToItem(root.rootItem + , currentItem.width/2, currentItem.height/2); + + //set model each time to ensure data accuracy + musicSourcesPopup.model = root.store.musicSourcesModel + musicSourcesPopup.originItemX = pos.x; + musicSourcesPopup.originItemY = pos.y; + musicSourcesPopup.visible = true; + } else if (currentText === "ABOUT...") { + pos = currentItem.mapToItem(root.rootItem + , currentItem.width/2, currentItem.height/2); + aboutPopup.originItemX = pos.x; + aboutPopup.originItemY = pos.y; + aboutPopup.visible = true; + } + + toolsColumn.currentIndex = 0; + } + } + + MusicSourcesPopup { + id: musicSourcesPopup + width: root.Sizes.dp(910) + // caclulate popup height based on musicSources list items + // + 200 for header & margins + height: model ? root.Sizes.dp(200 + (model.count * 96)) : root.Sizes.dp(296) + popupY: root.Sizes.dp(Config.centerConsoleHeight / 4) + onSwitchSourceClicked: { + store.switchSource(source) + } + } + + AboutPopup { + id: aboutPopup + width: root.Sizes.dp(910) + // caclulate popup height based on musicSources list items + // + 200 for header & margins + height: root.Sizes.dp(450) + popupY: root.Sizes.dp(Config.centerConsoleHeight / 4) + } + + GridView { + id: genrelist + + width: root.width - Sizes.dp(247.5) + height: root.height + anchors.centerIn: parent + anchors.horizontalCenter: parent.horizontalCenter + anchors.horizontalCenterOffset: toolsColumn.width / 3 + + model: root.store.musicGenres + clip: true + cellWidth: Sizes.dp(202.5) ; cellHeight: cellWidth + + ScrollIndicator.vertical: ScrollIndicator { + parent: genrelist.parent + anchors.top: genrelist.top + anchors.right: genrelist.right + anchors.rightMargin: - Sizes.dp(9) + anchors.bottom: genrelist.bottom + } + + delegate: Item { + width: Sizes.dp(193,5) + height: Sizes.dp(180) + + Rectangle { + anchors.fill: parent + opacity: 0.2 + color: "black" + border.width: mouseArea.containsPress ? 2 : 1 + border.color: "#888" + radius: 4 + gradient: Gradient { + GradientStop { position: 0 ; color: mouseArea.containsPress ? "#ccc" : "#eee" } + GradientStop { position: 1 ; color: mouseArea.containsPress ? "#aaa" : "#ccc" } + } + } + + Label { + anchors.centerIn: parent + width: Sizes.dp(157,5) + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Sizes.fontSizeS + text: model.name + } + + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: { + root.chosenGenre(model.name) + } + } + } + } +} diff --git a/com.pelagicore.webradio/panels/StationCover.qml b/com.pelagicore.webradio/panels/StationCover.qml new file mode 100644 index 0000000..364b473 --- /dev/null +++ b/com.pelagicore.webradio/panels/StationCover.qml @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Copyright (C) 2014-2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtAuto Extra Apps. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Layouts 1.0 +import QtGraphicalEffects 1.0 +import QtQuick.Controls 2.0 + +import shared.Sizes 1.0 +import shared.controls 1.0 +import shared.Style 1.0 + +Item { + id: root + + width: Sizes.dp(607.5) + height: Sizes.dp(480) + + property alias source: image.source + property alias title: title.text + property alias description: description.text + property alias subTitle: subTitle.text + property string status + signal clicked() + + RowLayout { + id: currentRadio + anchors.left: parent.left + spacing: Sizes.dp(30) + Item { + Layout.preferredWidth: Sizes.dp(270) + Layout.preferredHeight: Sizes.dp(270) + Rectangle { + anchors.fill: parent + color: "white" + border.color: Qt.darker(color, 1.2) + } + Image { + id: image + anchors.fill: parent + anchors.margins: Sizes.dp(2) + fillMode: Image.PreserveAspectCrop + asynchronous: true + Image { + anchors.top: parent.bottom + width: Sizes.dp(270) + anchors.horizontalCenter: parent.horizontalCenter + source: Style.image("album-art-shadow-widget") + fillMode: Image.PreserveAspectFit + } + } + } + + Label { + id: titelPlaceholder + Layout.preferredWidth: Sizes.dp(306) + horizontalAlignment: Text.AlignLeft + font.pixelSize: Sizes.fontSizeM + wrapMode: Text.WordWrap + visible: title.text === "" + text: qsTr("No Stream Selected") + } + + Label { + id: title + Layout.preferredWidth: Sizes.dp(306) + horizontalAlignment: Text.AlignLeft + font.pixelSize: Sizes.fontSizeM + wrapMode: Text.WordWrap + } + } + + ColumnLayout { + anchors.top: currentRadio.bottom + anchors.topMargin: Sizes.dp(80) + anchors.left: currentRadio.left + spacing: Sizes.dp(5) + + Label { + id: subTitle + font.pixelSize: Sizes.fontSizeS + font.weight: Font.Light + } + + Label { + id: description + Layout.preferredWidth: root.width + Layout.preferredHeight: Sizes.dp(70) + font.pixelSize: Sizes.fontSizeS + font.weight: Font.Light + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + + Label { + visible: root.status !== "" + text: root.status + font.pixelSize: Sizes.fontSizeM + font.weight: Font.Light + Layout.preferredWidth: root.width + Layout.alignment: Qt.AlignCenter + } + } + + MouseArea { + anchors.fill: parent + onClicked: root.clicked() + } +} diff --git a/com.pelagicore.webradio/popups/AboutPopup.qml b/com.pelagicore.webradio/popups/AboutPopup.qml new file mode 100644 index 0000000..a8ec0cc --- /dev/null +++ b/com.pelagicore.webradio/popups/AboutPopup.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtAuto Extra Apps. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.2 +import QtApplicationManager 2.0 +import QtQuick.Layouts 1.14 +import shared.utils 1.0 +import application.windows 1.0 + +import shared.Style 1.0 +import shared.controls 1.0 +import shared.Sizes 1.0 + +PopupWindow { + id: root + + Item { + id: popupContent + + anchors.fill: parent + + Label { + id: header + anchors.baseline: parent.top + anchors.baselineOffset: Sizes.dp(75) + width: parent.width + text: qsTr("About com.pelagicore.webradio") + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Sizes.fontSizeM + } + Image { + id: shadow + anchors.top: parent.top + anchors.topMargin: Sizes.dp(120) + width: parent.width + height: Sizes.dp(sourceSize.height) + source: Style.image("popup-title-shadow") + } + + TextArea { + anchors.topMargin: Sizes.dp(200) + anchors.fill: parent + readOnly: true + font.pixelSize: Sizes.fontSizeM + text: qsTr("The integration of the Shoutcast is provided for demonstration purposes only. This does not imply any sub-licensing of Shoutcast technologies. A final customer product using the code of this app should be covered by a dedicated license from Shoutcast") + wrapMode: TextEdit.WordWrap + color: Style.contrastColor + } + } +} diff --git a/com.pelagicore.webradio/popups/MusicSourcesPopup.qml b/com.pelagicore.webradio/popups/MusicSourcesPopup.qml new file mode 100644 index 0000000..71c2257 --- /dev/null +++ b/com.pelagicore.webradio/popups/MusicSourcesPopup.qml @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Copyright (C) 2014-2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtAuto Extra Apps. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.2 +import QtApplicationManager 2.0 +import shared.utils 1.0 +import application.windows 1.0 + +import shared.Style 1.0 +import shared.Sizes 1.0 + +PopupWindow { + id: root + + property alias model: listView.model + signal switchSourceClicked(string source) + + Item { + id: popupContent + + anchors.fill: parent + + Label { + id: header + anchors.baseline: parent.top + anchors.baselineOffset: Sizes.dp(75) + width: parent.width + text: qsTr("Choose Source") + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Sizes.fontSizeM + } + Image { + id: shadow + anchors.top: parent.top + anchors.topMargin: Sizes.dp(120) + width: parent.width + height: Sizes.dp(sourceSize.height) + source: Style.image("popup-title-shadow") + } + + ListView { + id: listView + anchors { + top: shadow.bottom + left: parent.left + leftMargin: Sizes.dp(40) + right: parent.right + rightMargin: Sizes.dp(40) + bottom: parent.bottom + bottomMargin: Sizes.dp(40) + } + interactive: false + delegate: RadioButton { + checked: appId == "com.pelagicore.webradio" + width: parent.width + height: Sizes.dp(96) + font.pixelSize: Sizes.fontSizeS + indicator.implicitHeight: Sizes.dp(30) + indicator.implicitWidth: Sizes.dp(30) + text: model.text + spacing: Sizes.dp(20) + onClicked: { + root.switchSourceClicked(appId) + root.close(); + } + + checkable: false + } + } + } +} diff --git a/com.pelagicore.webradio/stores/RadioStore.qml b/com.pelagicore.webradio/stores/RadioStore.qml new file mode 100644 index 0000000..ff9c9d6 --- /dev/null +++ b/com.pelagicore.webradio/stores/RadioStore.qml @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Copyright (C) 2017-2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Neptune 3 IVI UI. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.8 +import QtMultimedia 5.9 +import QtQuick.XmlListModel 2.14 +import QtApplicationManager.Application 2.0 +import QtApplicationManager 2.0 + +import shared.utils 1.0 +import shared.Sizes 1.0 + +Store { + id: root + + property bool nextStation: true + Component.onCompleted: { + getAllGenres(); + } + + property ListModel musicGenres: ListModel {} + property ListModel currentStations: ListModel {} + + property Audio player: Audio { + id: player + source: url + } + + property alias volume: player.volume + property bool playing: player.playbackState === Audio.PlayingState + + property var station + property int currentIndex + property string url + property string currentOperationStatus + + property ListModel toolsColumnModel: ListModel { + id: toolsColumnModel + + ListElement { icon: "ic-installed"; text: "genres"; greyedOut: false } + ListElement { icon: "ic-toolbar-sources-tuner"; text: "sources"; greyedOut: false } + ListElement { icon: ""; text: "ABOUT..."; greyedOut: false } + } + + property ListModel musicSourcesModel: ListModel { + id: musicSourcesModel + ListElement { + text: "AM/FM Radio" + appId: "com.pelagicore.tuner" + } + ListElement { + text: "Music" + appId: "com.pelagicore.music" + } + } + + QtObject { + id: d + readonly property string devID: "5ClwKdIfc6j5Nitn" + readonly property string base_tuneIN: "/sbin/tunein-station.pls" + readonly property var xmlGenresParser: XmlListModel { + query: "/genrelist/genre" + XmlRole { name: "name"; query: "@name/string()" } + XmlRole { name: "count"; query: "@count/number()" } + onStatusChanged: { + if (status === XmlListModel.Ready) { + musicGenres.clear(); + root.currentOperationStatus = ""; + var tmpAr = [] + for (var i = 0; i < count; ++i) { + var obj = get(i); + if (obj.count > 0) { + tmpAr.push({'name': obj.name}); + } + } + + // append array is not documented + // see qt5/qtdeclarative/src/qml/types/qqmllistmodel.cpp + musicGenres.append(tmpAr); + } else if (status === XmlListModel.Error) { + root.currentOperationStatus = + qsTr("Failed to load genres list, try to restart the app later"); + } + } + } + + readonly property var xmlStationsParser: XmlListModel { + query: "/stationlist/station" + XmlRole { name: "name"; query: "@name/string()" } + XmlRole { name: "mt"; query: "@mt/string()" } + XmlRole { name: "id"; query: "@id/string()" } + XmlRole { name: "br"; query: "@br/string()" } + XmlRole { name: "logo"; query: "@logo/string()" } + onStatusChanged: { + if (status === XmlListModel.Ready) { + currentStations.clear(); + root.currentOperationStatus = ""; + var tmpAr = [] + for (var i = 0; i < count; ++i) { + var obj = get(i); + tmpAr.push( + {'name': obj.name + , "id": obj.id + , "logo": obj.logo + , "br": obj.br + }); + } + + currentStations.append(tmpAr); + playFirst(); + } else if (status === XmlListModel.Error) { + root.currentOperationStatus = + qsTr("Failed to get stations for the given genre"); + } + } + } + } + + function playFirst() { + if (currentStations.count > 0) { + currentIndex = 0; + var station = currentStations.get(currentIndex); + getSourceForStation(station.id); + root.station = station; + } + } + + function next() { + if (currentStations.count > 0) { + currentIndex = (currentIndex + 1) % currentStations.count; + var station = currentStations.get(currentIndex); + getSourceForStation(station.id); + root.station = station; + } + } + + function previous() { + if (currentStations.count > 0) { + currentIndex = currentIndex == 0 ? currentStations.count - 1 : currentIndex - 1; + var station = currentStations.get(currentIndex); + getSourceForStation(station.id); + root.station = station; + } + } + + function play() { + player.autoPlay = true + player.play() + } + + function pause() { + player.autoPlay = false + player.pause() + } + + function switchSource(source) { + root.pause() + if (source === "com.pelagicore.music" || source === "com.pelagicore.tuner") { + var request = IntentClient.sendIntentRequest("activate-app", source, {}) + request.onReplyReceived.connect(function() { + if (request.succeeded) { + var result = request.result + console.log(Logging.apps, "Intent result: " + result.done) + } else { + console.log(Logging.apps, "Intent request failed: " + request.errorMessage) + } + }) + } + } + + // A SHOUTcast Radio Directory API is used with the devId + function getAllGenres() { + root.currentOperationStatus = qsTr("Trying to load genres"); + var xhr = new XMLHttpRequest; + xhr.open("GET", "http://api.shoutcast.com/legacy/genrelist?k=" + d.devID) + xhr.responseType = "document"; + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + d.xmlGenresParser.xml = xhr.responseText; + } + } + xhr.send() + } + + //http://api.shoutcast.com/legacy/genresearch?k=5ClwKdIfc6j5Nitn&genre=50s + //http://api.shoutcast.com/legacy/genresearch?k=[Your Dev ID]&genre= + function getStationsForGenre(genre) { + root.currentOperationStatus = qsTr("Trying to load stations for ") + genre; + var xhr = new XMLHttpRequest; + xhr.open("GET" + , "http://api.shoutcast.com/legacy/genresearch?k=" + + d.devID + "&genre=" + genre.replace("&","%26") + ); + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + d.xmlStationsParser.xml = xhr.responseText; + } + } + xhr.send(); + } + + //http://yp.shoutcast.com/sbin/tunein-station.pls?id=1513982 + function getSourceForStation(id) { + root.currentOperationStatus = qsTr("Trying to get url for the given station"); + var xhr = new XMLHttpRequest; + xhr.open("GET", "http://yp.shoutcast.com/sbin/tunein-station.pls?id=" + id); + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + root.url = xhr.responseText.match("File1=(.*)")[1]; + root.currentOperationStatus = ""; + } + } + xhr.send(); + } +} diff --git a/com.pelagicore.webradio/views/WebRadioContent.qml b/com.pelagicore.webradio/views/WebRadioContent.qml new file mode 100644 index 0000000..32661d5 --- /dev/null +++ b/com.pelagicore.webradio/views/WebRadioContent.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** Copyright (C) 2014-2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtAuto Extra Apps. +** +** $QT_BEGIN_LICENSE:GPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite licenses may use +** this file in accordance with the commercial license agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.2 + +import shared.controls 1.0 +import shared.Sizes 1.0 +import shared.Style 1.0 + +import "../stores" +import "../panels" + +Item { + id: root + + property RadioStore store + property var station: store.station + property alias rootItem: selectionScreen.rootItem + property bool playerVisible: false + + CurrentStationScreen { + id: currentStation + + width: parent.width + height: Sizes.dp(560) + stationName: root.station && root.station.name ? root.station.name : "" + stationImage: root.station && root.station.logo ? root.station.logo : "" + bitRate: root.station && root.station.br? root.station.br : "" + streamingUrl: root.store.url + currentOperationStatus: root.store.currentOperationStatus + playing: root.store.playing + + onNextStation: { + root.store.next(); + } + + onPrevStation: { + root.store.previous(); + } + + onPlayStation: root.store.play() + onPauseStation: root.store.pause() + } + + SelectionScreen { + id: selectionScreen + width: parent.width + height: parent.height - currentStation.height + anchors.top: currentStation.bottom + store: root.store + + onChosenGenre: { + store.getStationsForGenre(genre); + } + } +} diff --git a/qt-auto-extra-apps.pro b/qt-auto-extra-apps.pro index 9052160..ae4a1be 100644 --- a/qt-auto-extra-apps.pro +++ b/qt-auto-extra-apps.pro @@ -4,7 +4,8 @@ SUBDIRS = com.pelagicore.camera \ com.luxoft.webbrowser \ com.luxoft.videoplayer \ com.luxoft.greenomics \ - com.pelagicore.samegame + com.pelagicore.samegame \ + com.pelagicore.webradio # Top-level package target QMAKE_EXTRA_TARGETS += package -- cgit v1.2.3