commit d4cd7f8bdcc42bb3274ef8e15e1caacfb9bdaefe Author: Niels Date: Wed May 28 20:47:14 2025 +0200 ny commit diff --git a/harbour-allradio.desktop b/harbour-allradio.desktop new file mode 100644 index 0000000..680441f --- /dev/null +++ b/harbour-allradio.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +X-Nemo-Application-Type=silica-qt5 +Name=harbour-allradio +Icon=harbour-allradio +Exec=harbour-allradio + +[X-Sailjail] +Permissions=Internet;Audio +OrganizationName=org.nesnomis +ApplicationName=AllRadio2 diff --git a/harbour-allradio.pro b/harbour-allradio.pro new file mode 100644 index 0000000..f11189d --- /dev/null +++ b/harbour-allradio.pro @@ -0,0 +1,54 @@ +# NOTICE: +# +# Application name defined in TARGET has a corresponding QML filename. +# If name defined in TARGET is changed, the following needs to be done +# to match new name: +# - corresponding QML filename must be changed +# - desktop icon filename must be changed +# - desktop filename must be changed +# - icon definition filename in desktop file must be changed +# - translation filenames have to be changed + +# The name of your application +TARGET = harbour-allradio + +CONFIG += sailfishapp + +# App version +DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\" + +SOURCES += src/harbour-allradio.cpp + +DISTFILES += qml/harbour-allradio.qml \ + ../../Programmering/harbour-labyrinth/qml/pages/About.qml \ + qml/cover/CoverPage.qml \ + qml/helpers/dummy.qml \ + qml/items/HeaderButton.qml \ + qml/items/SleepTimer.qml \ + qml/pages/AboutPage.qml \ + qml/pages/AllRadio.qml \ + qml/pages/CountryStationsPage.qml \ + qml/pages/FavoritesPage.qml \ + qml/pages/HistoryPage.qml \ + qml/pages/SearchStationsPage.qml \ + qml/pages/SecondPage.qml \ + qml/pages/SettingsPage.qml \ + qml/pages/TagListPage.qml \ + rpm/harbour-allradio.changes.in \ + rpm/harbour-allradio.changes.run.in \ + rpm/harbour-allradio.spec \ + rpm/harbour-allradio.yaml \ + translations/*.ts \ + harbour-allradio.desktop + +SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172 + +# to disable building translations every time, comment out the +# following CONFIG line +CONFIG += sailfishapp_i18n + +# German translation is enabled as an example. If you aren't +# planning to localize your app, remember to comment out the +# following TRANSLATIONS line. And also do not forget to +# modify the localized app name in the the .desktop file. +TRANSLATIONS += translations/harbour-allradio-de.ts diff --git a/icons/108x108/harbour-allradio.png b/icons/108x108/harbour-allradio.png new file mode 100644 index 0000000..976c5df Binary files /dev/null and b/icons/108x108/harbour-allradio.png differ diff --git a/icons/128x128/harbour-allradio.png b/icons/128x128/harbour-allradio.png new file mode 100644 index 0000000..87cb1f4 Binary files /dev/null and b/icons/128x128/harbour-allradio.png differ diff --git a/icons/172x172/harbour-allradio.png b/icons/172x172/harbour-allradio.png new file mode 100644 index 0000000..059d55c Binary files /dev/null and b/icons/172x172/harbour-allradio.png differ diff --git a/icons/86x86/harbour-allradio.png b/icons/86x86/harbour-allradio.png new file mode 100644 index 0000000..68cb71f Binary files /dev/null and b/icons/86x86/harbour-allradio.png differ diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml new file mode 100644 index 0000000..2e145d2 --- /dev/null +++ b/qml/cover/CoverPage.qml @@ -0,0 +1,66 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import "../delegates" + +CoverBackground { + + RadioImage { + id:stationimage + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Theme.paddingLarge + width: parent.width - Theme.paddingMedium * 2 + height: width + stationImage: radioPlayer._favicon + stationLabel: radioPlayer._name + flag: false + } + Item { + id: artistSongName + + anchors.top: stationimage.bottom + anchors.bottom: coverActionArea.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: Theme.paddingLarge + width: parent.width - (Theme.paddingMedium * 2) //parent.width - (Theme.paddingMedium * 2) + height: radioname.height + radiocountry.height + (Theme.paddingMedium * 3) + + Column { + width: parent.width//radioname.width > radiocountry.width ? radioname.width : radiocountry.width + anchors.verticalCenter: parent.verticalCenter + Label { + id: radioname + font.bold: true + color: Theme.primaryColor + wrapMode: Text.WordWrap + font.pixelSize: Theme.fontSizeTiny + fontSizeMode: Text.Fit + maximumLineCount: 2 + width: parent.width + elide: Text.ElideLeft + horizontalAlignment: Text.AlignHCenter + text: radioPlayer.radioArtist ? radioPlayer.radioArtist : "AllRadio2" + } + Label { + id: radiocountry + color: Theme.primaryColor + wrapMode: Text.WordWrap + font.pixelSize: Theme.fontSizeTiny + fontSizeMode: Text.Fit + maximumLineCount: 2 + width: parent.width + elide: Text.ElideLeft + horizontalAlignment: Text.AlignHCenter + visible: radioPlayer.radioSong ? true : false + text: radioPlayer.radioSong + } + } + } + CoverActionList { + CoverAction { + iconSource: radioPlayer.isPlaying ? "image://theme/icon-cover-pause" : "image://theme/icon-cover-play" + onTriggered: radioPlayer.isPlaying ? radioPlayer.pauseStream() : radioPlayer.resumeStream()// radioPlayer.radioPlaying ? radioPlayer.pauseStream() : radioPlayer.resumeStream()//icon.source == "image://theme/icon-l-play" ? icon.source = "image://theme/icon-l-pause" : icon.source = "image://theme/icon-l-play" + } + } +} diff --git a/qml/delegates/ButtonRect.qml b/qml/delegates/ButtonRect.qml new file mode 100644 index 0000000..c6b876b --- /dev/null +++ b/qml/delegates/ButtonRect.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 + +Rectangle { + property bool fill: true + property bool borderVisible: true + anchors.fill: parent + anchors.margins: Theme.paddingSmall + color: "transparent" + border.color: borderVisible ? Theme.rgba(Theme.highlightBackgroundColor, 0.8) : "transparent" + radius: 20 + + Rectangle { + visible: fill + anchors.fill: parent + anchors.topMargin: parent.border.width + anchors.leftMargin: parent.border.width + anchors.rightMargin: parent.border.width + anchors.bottomMargin: parent.border.width + radius: 30 + gradient: Gradient { + GradientStop { position: 0.0; color: Theme.rgba(Theme.highlightBackgroundColor,0.125) } + GradientStop { position: 1.0; color: "transparent" } + } + } +} diff --git a/qml/delegates/CountryListDelegate.qml b/qml/delegates/CountryListDelegate.qml new file mode 100644 index 0000000..3c1a4d9 --- /dev/null +++ b/qml/delegates/CountryListDelegate.qml @@ -0,0 +1,38 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 + +BackgroundItem { + id: delegate + width: parent.width; + height: Theme.itemSizeExtraSmall + Image { + id: countryImage + height: parent.height * 0.6 + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + source: "../flags/"+alpha_2.toLowerCase()+".png" + } + + Label { + id: land + anchors.verticalCenter: parent.verticalCenter + anchors.left: countryImage.right + anchors.leftMargin: Theme.paddingMedium + anchors.right: count.left + anchors.rightMargin: Theme.paddingMedium + color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor + font.pixelSize: Theme.fontSizeSmall + text: radioBrowser.getCountryName(alpha_2) + } + Label { + id: count + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Theme.paddingMedium + color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor + font.pixelSize: Theme.fontSizeSmall; + text: "["+stationcount+"]" + } +} diff --git a/qml/delegates/FavoriteCountryList.qml b/qml/delegates/FavoriteCountryList.qml new file mode 100644 index 0000000..e11f13c --- /dev/null +++ b/qml/delegates/FavoriteCountryList.qml @@ -0,0 +1,31 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +//import "../../helpers/jsFunctions.js" as JS + +BackgroundItem { + id: delegate + width: parent.width / 2; + height: Theme.itemSizeExtraSmall + ButtonRect {fill: false} + Image { + id: countryImage + height: parent.height * 0.6 + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + source: "../flags/"+alpha_2.toLowerCase()+".png" + } + + Label { + id: land + anchors.verticalCenter: parent.verticalCenter + anchors.left: countryImage.right + anchors.leftMargin: Theme.paddingMedium + color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor + font.pixelSize: Theme.fontSizeSmall; + width: parent.width - countryImage.width - Theme.paddingMedium - (Theme.paddingLarge * 2) + elide: Text.ElideRight + text: radioBrowser.getCountryName(alpha_2) + } +} diff --git a/qml/delegates/FavoriteStations.qml b/qml/delegates/FavoriteStations.qml new file mode 100644 index 0000000..69f99d3 --- /dev/null +++ b/qml/delegates/FavoriteStations.qml @@ -0,0 +1,253 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 +import "../helpers/jsFunctions.js" as JS +ListItem { + id: delegate + property alias favIcon: favIcon + property alias contextMenuHeight: contextMenu.height + property bool favo: favorite ? true : false + property variant view + // property bool favorite: false + + height: menuOpen ? contextMenu.height + Theme.itemSizeExtraLarge : Theme.itemSizeExtraLarge + menu: contextMenu + contentHeight: Theme.itemSizeExtraLarge + showMenuOnPressAndHold: true + + ContextMenu { + id: contextMenu + MenuItem { + Row { + anchors.centerIn: parent + spacing: Theme.paddingMedium + Image { + source: "image://theme/icon-m-like" + anchors.verticalCenter: parent.verticalCenter + height: Theme.itemSizeExtraSmall * 0.5 + width: height + fillMode: Image.PreserveAspectFit + } + Label { + font.pixelSize: Theme.fontSizeSmall + text: qsTr("Vote on Community Radio Browser") + } + } + onClicked: console.log("LIKE!!!") //remove()//listView.currentItem.remove(rpindex,rpsource) //listView.remorseAction(); + } + MenuItem { + Row { + anchors.centerIn: parent + spacing: Theme.paddingMedium + Image { + source: favo ? "image://theme/icon-m-favorite-selected" : "image://theme/icon-m-favorite" + anchors.verticalCenter: parent.verticalCenter + height: Theme.itemSizeExtraSmall * 0.5 + width: height + fillMode: Image.PreserveAspectFit + } + Label { + font.pixelSize: Theme.fontSizeSmall + text: favo ? qsTr("Remove from favorites") : qsTr("Add to favorites") + } + } + onClicked: { + favo ? favo = false : favo = true + //radioPlayer._favorite = favo + radioPlayer.setStationFavorite(stationuuid,name,countrycode,homepage,url_resolved,favicon,tags,codec,bitrate,hls,favo) + } + } + /* MenuItem { + Row { + anchors.centerIn: parent + spacing: Theme.paddingMedium + Image { + source: "image://theme/icon-m-delete" + anchors.verticalCenter: parent.verticalCenter + height: Theme.itemSizeExtraSmall * 0.5 + width: height + fillMode: Image.PreserveAspectFit + } + Label { + font.pixelSize: Theme.fontSizeSmall + text: qsTr("Remove from AllRadio2") + } + } + onClicked: remove()//console.log("DELETE!!!") //remove()//listView.currentItem.remove(rpindex,rpsource) //listView.remorseAction(); + } */ + } + + +/* Rectangle { + id: stationLogo + anchors.top: header.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - (Theme.paddingLarge * 2) + height: width + radius: 20 + color: "transparent" //Theme.rgba(Theme.highlightDimmerColor,0.8) + border.color: Theme.rgba(Theme.highlightDimmerColor,0.8) + border.width: Theme.paddingSmall + } */ + + Rectangle { + id: favIcon + property alias source: stationimage.source + anchors.left: parent.left + anchors.leftMargin: Theme.paddingMedium + anchors.verticalCenter: parent.verticalCenter + height: Theme.itemSizeLarge//nameLabel.height + codecLabel.height + tagLabel.height + width: height + radius: 20 + + color: "transparent" //Theme.rgba(Theme.highlightDimmerColor,0.8) + border.color: Theme.rgba(Theme.highlightDimmerColor,0.8) + border.width: Theme.paddingSmall + } + + Image { + id: stationimage + anchors.fill: favIcon + anchors.margins: favIcon.border.width + fillMode: Image.PreserveAspectFit + source: favicon ? favicon : "../images/community.png" + // layer.enabled: true + // layer.effect: OpacityMask { + // maskSource: parent + // } + // layer { + // enabled: false + // effect: ColorOverlay { + // color: Theme.highlightBackgroundColor + // } + // } + + BusyIndicator { + size: BusyIndicatorSize.Medium + anchors.centerIn: stationimage + //running: appActive && stationimage.status != Image.Ready + + } + + onStatusChanged: + switch(stationimage.status){ + case Image.Null: + //console.log("no image has been set: "+ name); + source = "../images/community.png" + break; + case Image.Ready: + //console.log("the image has been loaded: "+name+"\n" + // + stationimage.width + " x " + stationimage.height); + break; + case Image.Loading: + + break; + case Image.Error: + //console.log("an error occurred while loading the image: "+name); + source = "../images/community.png" + break; + } + + + + } + /* Image { + height: stationimage.height * 0.50 + fillMode: Image.PreserveAspectFit + opacity: 0.9 + anchors.right: favIcon.right + anchors.bottom: favIcon.bottom + source: "../flags/"+countrycode.toLowerCase()+".png" + } */ + // } + + Label { + id: nameLabel + anchors.bottom: countryLabel.top + // anchors.bottomMargin: Theme.paddingSmall + anchors.left: favIcon.right + anchors.right: fav.left + anchors.leftMargin: Theme.paddingLarge + anchors.rightMargin: Theme.paddingMedium + elide: Text.ElideRight + width: parent.width - (favIcon.width + (Theme.paddingLarge * 2)) + text: lastcheckok == "1" ? name : " [DOWN] "+name + color: lastcheckok == "1" ? Theme.primaryColor : Theme.secondaryColor + font.strikeout: lastcheckok == "1" ? false : true + font.pixelSize: Theme.fontSizeSmall + } + Image { + id:countryImage + height: countryLabel.height * 0.8 + + anchors.leftMargin: Theme.paddingLarge + fillMode: Image.PreserveAspectFit + opacity: 0.7 + anchors.left: favIcon.right + anchors.bottom: countryLabel.bottom + source: "../flags/"+countrycode.toLowerCase()+".png" + } + Label { + id: countryLabel + anchors.verticalCenter: parent.verticalCenter + anchors.left: countryImage.right + anchors.leftMargin: Theme.paddingMedium + font.pixelSize: Theme.fontSizeExtraSmall + text: radioBrowser.getCountryName(countrycode)//"Country name"//getAll(hls,codec,bitrate) + color: delegate.highlighted ? Theme.highlightColor : Theme.secondaryColor + } + Label { + id: codecLabel + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.leftMargin: Theme.paddingLarge + font.pixelSize: Theme.fontSizeExtraSmall + text: JS.getAll(hls,codec,bitrate) + color: delegate.highlighted ? Theme.highlightColor : Theme.secondaryColor + } + Label { + id: tagLabel + anchors.top: countryLabel.bottom + //anchors.topMargin: Theme.paddingSmall + anchors.left: favIcon.right + anchors.leftMargin: Theme.paddingLarge + font.pixelSize: Theme.fontSizeExtraSmall + width: parent.width - (favIcon.width + (Theme.paddingLarge * 2)) + elide: Text.ElideRight + + text: tags + color: delegate.highlighted ? Theme.highlightColor : Theme.secondaryColor + } + Image { + id: fav + height: nameLabel.height * 0.8 + width: height + fillMode: Image.PreserveAspectFit + opacity: 0.8 + visible: favo + anchors.right: parent.right + anchors.verticalCenter: nameLabel.verticalCenter + //anchors.top: nameLabel.top + anchors.rightMargin: Theme.paddingMedium + source: "image://theme/icon-m-favorite-selected" //favo ? "image://theme/icon-m-favorite-selected" : "image://theme/icon-m-favorite" + } + + //onFavoChanged: if (favo) setRadioData() + + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer._favorite = favo + radioPlayer.clicked = false + } else radioPlayer.clicked = true + } + } diff --git a/qml/delegates/RadioImage.qml b/qml/delegates/RadioImage.qml new file mode 100644 index 0000000..d4e4c45 --- /dev/null +++ b/qml/delegates/RadioImage.qml @@ -0,0 +1,109 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 +//import "../../helpers/jsFunctions.js" as JS + +Column { + property string stationImage: "" //stationImage + property string stationLabel: "" //imagelabel + property bool flag: false + property string flagimage: "" //flagimage + property bool stationBorder: true + property alias imageVisible: stationimage.visible + spacing: Theme.paddingMedium + Rectangle { + width: parent.width + height: width + color: Theme.overlayBackgroundColor + border.color: stationBorder ? Theme.rgba(Theme.highlightBackgroundColor, 0.8) : "transparent" + anchors.horizontalCenter: parent.horizontalCenter + //border.width: + //onWidthChanged: console.log(" *********** WIDTH: "+width) + /* BusyIndicator { + z:99 + size: BusyIndicatorSize.Medium + anchors.centerIn: stationimage + running: stationimage.loading && stationImage !== ""//appActive && stationimage.status != Image.Ready + } */ + Image { + property bool loading: false + id: stationimage + width: parent.width - (Theme.paddingSmall * 2) + height: width + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + visible: false + source: stationImage ? Qt.resolvedUrl(stationImage) : ""// ? stationImage : stationimage.visible = false + + /* BusyIndicator { + size: BusyIndicatorSize.Medium + anchors.centerIn: stationimage + running: stationimage.status != Image.Ready && stationimage.visible//appActive && stationimage.status != Image.Ready + } */ + onStatusChanged: + switch(stationimage.status){ + case Image.Null: + loading = false + visible = false + break; + case Image.Ready: + loading = false + visible = true + break; + case Image.Loading: + loading = true + break; + case Image.Error: + loading = false + visible = false + break; + default: + loading = false + visible = false + } + } + Label { + id: stationlabel + anchors.fill: stationimage + anchors.margins: Theme.paddingMedium + visible: !stationimage.visible + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + width: parent.width - (parent.border.width * 2) + height: width + text: stationLabel ? stationLabel : "AllRadio"//lastcheckok == "1" ? name : " [DOWN] "+name + color: Theme.primaryColor//stationlabel === "1" ? Theme.lightPrimaryColor : Theme.secondaryColor + wrapMode: Text.WordWrap + maximumLineCount: 4 + //font.strikeout: lastcheckok == "1" ? false : true + font.pixelSize: Theme.fontSizeHuge * 4 + fontSizeMode: Text.Fit + font.bold: true + opacity: 0.6 + + } + /* Glow { + id: stationglow + visible: stationlabel.visible + radius: Math.round((parent.width / Screen.width) * 10) + samples: radius * 2 + spread: radius / 10//0.9//parent.width / Screen.width + //opacity: 0.4 + transparentBorder: true + color: Theme.secondaryColor//JS.getRandomColor() + source: stationlabel + anchors.fill: stationlabel + } */ + Image { + id:countryImage + visible: flag + width: Theme.itemSizeSmall * 0.5 + anchors.top: stationimage.visible ? stationimage.top : parent.top + anchors.right: stationimage.visible ? stationimage.right : parent.right + anchors.margins: Theme.paddingMedium + fillMode: Image.PreserveAspectFit + source: flagimage + } + } +} diff --git a/qml/delegates/SmallStationsDelegate.qml b/qml/delegates/SmallStationsDelegate.qml new file mode 100644 index 0000000..e0e3a44 --- /dev/null +++ b/qml/delegates/SmallStationsDelegate.qml @@ -0,0 +1,34 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 +import "../helpers/jsFunctions.js" as JSfunctions + +ListItem { + id: delegate + property bool flagVisible: false + height: parent.height //Theme.itemSizeHuge * 2 + width: height * 0.83 + contentHeight: height + contentWidth: width + Column { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Theme.paddingMedium + spacing: Theme.paddingMedium + RadioImage {id:stationimage;anchors.horizontalCenter: parent.horizontalCenter; width: delegate.width * 0.8;stationImage: favicon ? favicon : ""; flag: flagVisible;stationLabel: name;flagimage: "../flags/"+countrycode.toLowerCase()+".png"} + Label { + id: nameLabel + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + width: stationimage.width + height: Theme.itemSizeExtraSmall + text: lastcheckok === "1" ? name : " [DOWN] "+name + color: lastcheckok === "1" ? Theme.primaryColor : Theme.secondaryColor + wrapMode: Text.WordWrap + maximumLineCount: 2 + font.strikeout: lastcheckok === "1" ? false : true + font.pixelSize: Theme.fontSizeTiny + } + } +} diff --git a/qml/delegates/SmallTagsDelegate.qml b/qml/delegates/SmallTagsDelegate.qml new file mode 100644 index 0000000..e84ce07 --- /dev/null +++ b/qml/delegates/SmallTagsDelegate.qml @@ -0,0 +1,34 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 +import "../helpers/jsFunctions.js" as JSfunctions + +ListItem { + id: delegate + property bool flagVisible: false + height: parent.height //Theme.itemSizeHuge * 2 + width: height * 0.83 + contentHeight: height + contentWidth: width + Column { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Theme.paddingMedium + spacing: Theme.paddingMedium + TagImage {id:stationimage;anchors.horizontalCenter: parent.horizontalCenter; width: delegate.width * 0.8;stationImage: ""; stationLabel: tag;} + Label { + id: nameLabel + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + width: stationimage.width + height: Theme.itemSizeExtraSmall + text: tag ? tag : "No Tag" + color: Theme.primaryColor + wrapMode: Text.WordWrap + maximumLineCount: 2 + //font.strikeout: lastcheckok == "1" ? false : true + font.pixelSize: Theme.fontSizeTiny + } + } +} diff --git a/qml/delegates/StationsDelegate.qml b/qml/delegates/StationsDelegate.qml new file mode 100644 index 0000000..7e93bc0 --- /dev/null +++ b/qml/delegates/StationsDelegate.qml @@ -0,0 +1,154 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 +import "../helpers/jsFunctions.js" as JSfunctions + +ListItem { + id: delegate + property alias favIcon: favIcon + property alias contextMenuHeight: contextMenu.height + //property bool favo: favorite ? true : false + property variant view + enabled: lastcheckok + opacity: lastcheckok ? 1.0 : 0.3 + // property bool favorite: false + height: menuOpen ? contextMenu.height + Theme.itemSizeExtraLarge : Theme.itemSizeExtraLarge + menu: contextMenu + contentHeight: Theme.itemSizeExtraLarge + showMenuOnPressAndHold: true + + ContextMenu { + id: contextMenu + MenuItem { + Row { + anchors.centerIn: parent + spacing: Theme.paddingMedium + Image { + source: "image://theme/icon-m-like" + anchors.verticalCenter: parent.verticalCenter + height: Theme.itemSizeExtraSmall * 0.5 + width: height + fillMode: Image.PreserveAspectFit + } + Label { + font.pixelSize: Theme.fontSizeSmall + text: qsTr("Vote on Community Radio Browser") + } + } + onClicked: console.log("LIKE!!!") //remove()//listView.currentItem.remove(rpindex,rpsource) //listView.remorseAction(); + } + MenuItem { + Row { + anchors.centerIn: parent + spacing: Theme.paddingMedium + Image { + //source: favo ? "image://theme/icon-m-favorite-selected" : "image://theme/icon-m-favorite" + anchors.verticalCenter: parent.verticalCenter + height: Theme.itemSizeExtraSmall * 0.5 + width: height + fillMode: Image.PreserveAspectFit + } + Label { + font.pixelSize: Theme.fontSizeSmall + //text: favo ? qsTr("Remove from favorites") : qsTr("Add to favorites") + } + } + onClicked: { + favo ? favo = false : favo = true + //radioPlayer._favorite = favo + + radioPlayer.setStationFavorite(stationuuid,name,countrycode,homepage,url_resolved,favicon,tags,codec,bitrate,hls,favo) + } + } + } + + RadioImage { + id: favIcon + anchors.left: parent.left + anchors.leftMargin: Theme.paddingSmall + anchors.verticalCenter: parent.verticalCenter + height: Theme.itemSizeLarge//nameLabel.height + codecLabel.height + tagLabel.height + width: height + stationImage: favicon ? favicon : "" + stationLabel: name + //radius: 20 + } + + Label { + id: nameLabel + anchors.bottom: countryLabel.top + // anchors.bottomMargin: Theme.paddingSmall + anchors.left: favIcon.right + anchors.right: fav.left + anchors.leftMargin: Theme.paddingLarge + anchors.rightMargin: Theme.paddingMedium + elide: Text.ElideRight + width: parent.width - (favIcon.width + (Theme.paddingLarge * 2)) + text: lastcheckok == "1" ? name : " [DOWN] "+name + color: lastcheckok == "1" ? Theme.primaryColor : Theme.secondaryColor + font.strikeout: lastcheckok == "1" ? false : true + font.pixelSize: Theme.fontSizeSmall + } + Image { + id:countryImage + height: countryLabel.height * 0.8 + + anchors.leftMargin: Theme.paddingLarge + fillMode: Image.PreserveAspectFit + opacity: 0.7 + anchors.left: favIcon.right + anchors.bottom: countryLabel.bottom + source: countrycode ? "../flags/"+countrycode.toLowerCase()+".png" : "" + } + Label { + id: countryLabel + anchors.verticalCenter: parent.verticalCenter + anchors.left: countryImage.right + anchors.leftMargin: Theme.paddingMedium + + font.pixelSize: Theme.fontSizeExtraSmall + text: countrycode ? radioBrowser.getCountryName(countrycode) : "No country"//"Country name"//getAll(hls,codec,bitrate) + color: delegate.highlighted ? Theme.highlightColor : Theme.secondaryColor + } + Label { + id: codecLabel + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.leftMargin: Theme.paddingLarge + anchors.rightMargin: Theme.paddingSmall + font.pixelSize: Theme.fontSizeExtraSmall + text: lastcheckok ? JSfunctions.getAll(hls,codec,bitrate) : "[OFFLINES]" + color: delegate.highlighted ? Theme.highlightColor : Theme.secondaryColor + } + Label { + id: tagLabel + anchors.top: countryLabel.bottom + //anchors.topMargin: Theme.paddingSmall + anchors.left: favIcon.right + anchors.leftMargin: Theme.paddingLarge + font.pixelSize: Theme.fontSizeExtraSmall + font.italic: true + width: parent.width - (favIcon.width + (Theme.paddingLarge * 2)) + elide: Text.ElideRight + + text: tags + color: delegate.highlighted ? Theme.highlightColor : Theme.secondaryColor + } + Image { + id: fav + height: nameLabel.height * 0.8 + width: height + fillMode: Image.PreserveAspectFit + opacity: 0.8 + visible: false//favo + anchors.right: parent.right + anchors.verticalCenter: nameLabel.verticalCenter + //anchors.top: nameLabel.top + anchors.rightMargin: Theme.paddingMedium + source: "image://theme/icon-m-favorite-selected" //favo ? "image://theme/icon-m-favorite-selected" : "image://theme/icon-m-favorite" + } + + //onFavoChanged: if (favo) setRadioData() + + + } diff --git a/qml/delegates/TabButton.qml b/qml/delegates/TabButton.qml new file mode 100644 index 0000000..113edda --- /dev/null +++ b/qml/delegates/TabButton.qml @@ -0,0 +1,50 @@ +import QtQuick 2.0 +import QtGraphicalEffects 1.0 +import Sailfish.Silica 1.0 + + + Rectangle { + property alias text: text.text + property bool down: false + property alias fontSize: text.font.pixelSize + property alias fontColor: text.color + property alias icon: image.source + property alias iconVisible: image.visible + signal buttonClick() + height: column.height + width: column.width + color: "transparent"// !down ? Theme.highlightDimmerColor : "transparent" + opacity: !down ? 0.8 : 1.0 + //anchors.fill: parent + Column { + id: column + anchors.centerIn: parent + Image { + id: image + height: visible ? Theme.itemSizeExtraSmall * 0.8 : 0 + anchors.horizontalCenter: parent.horizontalCenter + width: height + } + + Label { + id: text + visible: text.text !== "" ? true : false + anchors.horizontalCenter: parent.horizontalCenter + color: down ? Theme.primaryColor : Theme.secondaryColor//highlighted ? Theme.primaryColor : Theme.secondaryColor + // font.bold: down ? true : false + } + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + visible: down + width: text.width + height: Theme.paddingSmall * 0.4 + color: fontColor//Theme.secondaryHighlightColor + } + } + MouseArea { + anchors.fill: parent + onClicked: parent.buttonClick() + } + } + + diff --git a/qml/delegates/TabDelegate.qml b/qml/delegates/TabDelegate.qml new file mode 100644 index 0000000..e9f3d13 --- /dev/null +++ b/qml/delegates/TabDelegate.qml @@ -0,0 +1,39 @@ +import QtQuick 2.0 + +Item { + property string page: "FavoritesTab.qml" + property real showP: 0.0 + property int tab: 0 + width: parent.width + height: Theme.itemSizeMedium//play.height + (Theme.paddingMedium * 2) + Row { + id: row + width: parent.width + height: parent.height//Theme.itemSizeMedium//play.height + (Theme.paddingMedium * 2) + anchors.verticalCenter: parent.verticalCenter + TabButton { + id: home + down: tab === 0 + width: parent.width / 3 + // icon: "image://theme/icon-m-home" //"image://theme/icon-m-video" + text: "Favorites" + onButtonClick: {showP=0.0;tab = 0} + } + TabButton { + id: search + down: tab === 1 + width: parent.width / 3 + // icon: "image://theme/icon-m-search" + text: "History" + onButtonClick: {showP=0.0;tab = 1} + } + TabButton { + id: favorite + down: tab === 2 + width: parent.width / 3 + // icon: "image://theme/icon-m-favorite" + text: "Search" + onButtonClick: {showP=0.0;tab = 2;console.log("CLICK")} + } + } +} diff --git a/qml/delegates/TagImage.qml b/qml/delegates/TagImage.qml new file mode 100644 index 0000000..dbaa530 --- /dev/null +++ b/qml/delegates/TagImage.qml @@ -0,0 +1,106 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 +//import "../../helpers/jsFunctions.js" as JS + +Column { + property string stationImage: "" //stationImage + property string stationLabel: "" //imagelabel + property bool flag: false + property string flagimage: "" //flagimage + spacing: Theme.paddingMedium + Rectangle { + width: parent.width + height: width + color: Theme.overlayBackgroundColor + border.color: Theme.rgba(Theme.highlightBackgroundColor, 0.8) + anchors.horizontalCenter: parent.horizontalCenter + //onWidthChanged: console.log(" *********** WIDTH: "+width) + /* BusyIndicator { + z:99 + size: BusyIndicatorSize.Medium + anchors.centerIn: stationimage + running: stationimage.loading && stationImage !== ""//appActive && stationimage.status != Image.Ready + } */ + Image { + property bool loading: false + id: stationimage + width: parent.width - (Theme.paddingSmall * 2) + height: width + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + visible: false + source: stationImage ? stationImage : ""// ? stationImage : stationimage.visible = false + + /* BusyIndicator { + size: BusyIndicatorSize.Medium + anchors.centerIn: stationimage + running: stationimage.status != Image.Ready && stationimage.visible//appActive && stationimage.status != Image.Ready + } */ + onStatusChanged: + switch(stationimage.status){ + case Image.Null: + loading = false + visible = false + break; + case Image.Ready: + loading = false + visible = true + break; + case Image.Loading: + loading = true + break; + case Image.Error: + loading = false + visible = false + break; + default: + loading = false + visible = false + } + } + Label { + id: stationlabel + anchors.fill: stationimage + anchors.margins: Theme.paddingMedium + visible: !stationimage.visible + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + width: parent.width - (parent.border.width * 2) + height: width + text: stationLabel ? stationLabel : "No Tag"//lastcheckok == "1" ? name : " [DOWN] "+name + color: stationlabel === "1" ? Theme.lightPrimaryColor : Theme.secondaryColor + wrapMode: Text.WordWrap + maximumLineCount: 4 + //font.strikeout: lastcheckok == "1" ? false : true + font.pixelSize: Theme.fontSizeHuge + fontSizeMode: Text.Fit + font.bold: false + opacity: 0.5 + + } + Glow { + id: stationglow + visible: stationlabel.visible + radius: Math.round((parent.width / Screen.width) * 10) + samples: radius * 2 + spread: 0.7//parent.width / Screen.width + + transparentBorder: true + color: Theme.secondaryHighlightColor//JS.getRandomColor() + source: stationlabel + anchors.fill: stationlabel + } + Image { + id:countryImage + visible: flag + width: Theme.itemSizeSmall * 0.5 + anchors.top: stationimage.visible ? stationimage.top : parent.top + anchors.right: stationimage.visible ? stationimage.right : parent.right + anchors.margins: Theme.paddingMedium + fillMode: Image.PreserveAspectFit + source: flagimage + } + } +} diff --git a/qml/flags/0 country.png b/qml/flags/0 country.png new file mode 100644 index 0000000..a92f936 Binary files /dev/null and b/qml/flags/0 country.png differ diff --git a/qml/flags/ad.png b/qml/flags/ad.png new file mode 100644 index 0000000..e232ab6 Binary files /dev/null and b/qml/flags/ad.png differ diff --git a/qml/flags/ae.png b/qml/flags/ae.png new file mode 100644 index 0000000..ac0815b Binary files /dev/null and b/qml/flags/ae.png differ diff --git a/qml/flags/af.png b/qml/flags/af.png new file mode 100644 index 0000000..ad607f5 Binary files /dev/null and b/qml/flags/af.png differ diff --git a/qml/flags/ag.png b/qml/flags/ag.png new file mode 100644 index 0000000..d6749f3 Binary files /dev/null and b/qml/flags/ag.png differ diff --git a/qml/flags/ai.png b/qml/flags/ai.png new file mode 100644 index 0000000..07e1875 Binary files /dev/null and b/qml/flags/ai.png differ diff --git a/qml/flags/al.png b/qml/flags/al.png new file mode 100644 index 0000000..0f25f36 Binary files /dev/null and b/qml/flags/al.png differ diff --git a/qml/flags/am.png b/qml/flags/am.png new file mode 100644 index 0000000..bf35e81 Binary files /dev/null and b/qml/flags/am.png differ diff --git a/qml/flags/an.png b/qml/flags/an.png new file mode 100644 index 0000000..6955003 Binary files /dev/null and b/qml/flags/an.png differ diff --git a/qml/flags/ao.png b/qml/flags/ao.png new file mode 100644 index 0000000..f811dfa Binary files /dev/null and b/qml/flags/ao.png differ diff --git a/qml/flags/aq.png b/qml/flags/aq.png new file mode 100644 index 0000000..449f40b Binary files /dev/null and b/qml/flags/aq.png differ diff --git a/qml/flags/ar.png b/qml/flags/ar.png new file mode 100644 index 0000000..92519e8 Binary files /dev/null and b/qml/flags/ar.png differ diff --git a/qml/flags/as.png b/qml/flags/as.png new file mode 100644 index 0000000..9684cbf Binary files /dev/null and b/qml/flags/as.png differ diff --git a/qml/flags/at.png b/qml/flags/at.png new file mode 100644 index 0000000..da2c02c Binary files /dev/null and b/qml/flags/at.png differ diff --git a/qml/flags/au.png b/qml/flags/au.png new file mode 100644 index 0000000..b0be113 Binary files /dev/null and b/qml/flags/au.png differ diff --git a/qml/flags/aw.png b/qml/flags/aw.png new file mode 100644 index 0000000..a5e66f5 Binary files /dev/null and b/qml/flags/aw.png differ diff --git a/qml/flags/ax.png b/qml/flags/ax.png new file mode 100644 index 0000000..1f493b4 Binary files /dev/null and b/qml/flags/ax.png differ diff --git a/qml/flags/az.png b/qml/flags/az.png new file mode 100644 index 0000000..35c1502 Binary files /dev/null and b/qml/flags/az.png differ diff --git a/qml/flags/ba.png b/qml/flags/ba.png new file mode 100644 index 0000000..5487821 Binary files /dev/null and b/qml/flags/ba.png differ diff --git a/qml/flags/bb.png b/qml/flags/bb.png new file mode 100644 index 0000000..029bdb2 Binary files /dev/null and b/qml/flags/bb.png differ diff --git a/qml/flags/bd.png b/qml/flags/bd.png new file mode 100644 index 0000000..18490d1 Binary files /dev/null and b/qml/flags/bd.png differ diff --git a/qml/flags/be.png b/qml/flags/be.png new file mode 100644 index 0000000..555663b Binary files /dev/null and b/qml/flags/be.png differ diff --git a/qml/flags/bf.png b/qml/flags/bf.png new file mode 100644 index 0000000..d9be29b Binary files /dev/null and b/qml/flags/bf.png differ diff --git a/qml/flags/bg.png b/qml/flags/bg.png new file mode 100644 index 0000000..b267511 Binary files /dev/null and b/qml/flags/bg.png differ diff --git a/qml/flags/bh.png b/qml/flags/bh.png new file mode 100644 index 0000000..18a205a Binary files /dev/null and b/qml/flags/bh.png differ diff --git a/qml/flags/bi.png b/qml/flags/bi.png new file mode 100644 index 0000000..0a89c40 Binary files /dev/null and b/qml/flags/bi.png differ diff --git a/qml/flags/bj.png b/qml/flags/bj.png new file mode 100644 index 0000000..92a5224 Binary files /dev/null and b/qml/flags/bj.png differ diff --git a/qml/flags/bl.png b/qml/flags/bl.png new file mode 100644 index 0000000..5c8210c Binary files /dev/null and b/qml/flags/bl.png differ diff --git a/qml/flags/bm.png b/qml/flags/bm.png new file mode 100644 index 0000000..fe0e0b8 Binary files /dev/null and b/qml/flags/bm.png differ diff --git a/qml/flags/bn.png b/qml/flags/bn.png new file mode 100644 index 0000000..1a55bc4 Binary files /dev/null and b/qml/flags/bn.png differ diff --git a/qml/flags/bo.png b/qml/flags/bo.png new file mode 100644 index 0000000..732a26e Binary files /dev/null and b/qml/flags/bo.png differ diff --git a/qml/flags/bq.png b/qml/flags/bq.png new file mode 100644 index 0000000..f64e97d Binary files /dev/null and b/qml/flags/bq.png differ diff --git a/qml/flags/br.png b/qml/flags/br.png new file mode 100644 index 0000000..bfbbf82 Binary files /dev/null and b/qml/flags/br.png differ diff --git a/qml/flags/bs.png b/qml/flags/bs.png new file mode 100644 index 0000000..5a5f4ee Binary files /dev/null and b/qml/flags/bs.png differ diff --git a/qml/flags/bt.png b/qml/flags/bt.png new file mode 100644 index 0000000..da3fc16 Binary files /dev/null and b/qml/flags/bt.png differ diff --git a/qml/flags/bv.png b/qml/flags/bv.png new file mode 100644 index 0000000..601bd92 Binary files /dev/null and b/qml/flags/bv.png differ diff --git a/qml/flags/bw.png b/qml/flags/bw.png new file mode 100644 index 0000000..8a1aa95 Binary files /dev/null and b/qml/flags/bw.png differ diff --git a/qml/flags/by.png b/qml/flags/by.png new file mode 100644 index 0000000..fb2ec49 Binary files /dev/null and b/qml/flags/by.png differ diff --git a/qml/flags/bz.png b/qml/flags/bz.png new file mode 100644 index 0000000..4ce12be Binary files /dev/null and b/qml/flags/bz.png differ diff --git a/qml/flags/ca.png b/qml/flags/ca.png new file mode 100644 index 0000000..1873e9c Binary files /dev/null and b/qml/flags/ca.png differ diff --git a/qml/flags/cc.png b/qml/flags/cc.png new file mode 100644 index 0000000..87fbb1f Binary files /dev/null and b/qml/flags/cc.png differ diff --git a/qml/flags/cd.png b/qml/flags/cd.png new file mode 100644 index 0000000..e455c2e Binary files /dev/null and b/qml/flags/cd.png differ diff --git a/qml/flags/cf.png b/qml/flags/cf.png new file mode 100644 index 0000000..25db063 Binary files /dev/null and b/qml/flags/cf.png differ diff --git a/qml/flags/cg.png b/qml/flags/cg.png new file mode 100644 index 0000000..e4f4cfe Binary files /dev/null and b/qml/flags/cg.png differ diff --git a/qml/flags/ch.png b/qml/flags/ch.png new file mode 100644 index 0000000..72a1439 Binary files /dev/null and b/qml/flags/ch.png differ diff --git a/qml/flags/ci.png b/qml/flags/ci.png new file mode 100644 index 0000000..52563d1 Binary files /dev/null and b/qml/flags/ci.png differ diff --git a/qml/flags/ck.png b/qml/flags/ck.png new file mode 100644 index 0000000..00c296d Binary files /dev/null and b/qml/flags/ck.png differ diff --git a/qml/flags/cl.png b/qml/flags/cl.png new file mode 100644 index 0000000..4745f70 Binary files /dev/null and b/qml/flags/cl.png differ diff --git a/qml/flags/cm.png b/qml/flags/cm.png new file mode 100644 index 0000000..0effb5d Binary files /dev/null and b/qml/flags/cm.png differ diff --git a/qml/flags/cn.png b/qml/flags/cn.png new file mode 100644 index 0000000..f684a88 Binary files /dev/null and b/qml/flags/cn.png differ diff --git a/qml/flags/co.png b/qml/flags/co.png new file mode 100644 index 0000000..f439d4a Binary files /dev/null and b/qml/flags/co.png differ diff --git a/qml/flags/cr.png b/qml/flags/cr.png new file mode 100644 index 0000000..f782673 Binary files /dev/null and b/qml/flags/cr.png differ diff --git a/qml/flags/cu.png b/qml/flags/cu.png new file mode 100644 index 0000000..861c435 Binary files /dev/null and b/qml/flags/cu.png differ diff --git a/qml/flags/cv.png b/qml/flags/cv.png new file mode 100644 index 0000000..723ab37 Binary files /dev/null and b/qml/flags/cv.png differ diff --git a/qml/flags/cw.png b/qml/flags/cw.png new file mode 100644 index 0000000..5523a44 Binary files /dev/null and b/qml/flags/cw.png differ diff --git a/qml/flags/cx.png b/qml/flags/cx.png new file mode 100644 index 0000000..e822b5c Binary files /dev/null and b/qml/flags/cx.png differ diff --git a/qml/flags/cy.png b/qml/flags/cy.png new file mode 100644 index 0000000..8ad22e7 Binary files /dev/null and b/qml/flags/cy.png differ diff --git a/qml/flags/cz.png b/qml/flags/cz.png new file mode 100644 index 0000000..90982b9 Binary files /dev/null and b/qml/flags/cz.png differ diff --git a/qml/flags/de.png b/qml/flags/de.png new file mode 100644 index 0000000..14d3676 Binary files /dev/null and b/qml/flags/de.png differ diff --git a/qml/flags/dj.png b/qml/flags/dj.png new file mode 100644 index 0000000..445c712 Binary files /dev/null and b/qml/flags/dj.png differ diff --git a/qml/flags/dk.png b/qml/flags/dk.png new file mode 100644 index 0000000..ad7693b Binary files /dev/null and b/qml/flags/dk.png differ diff --git a/qml/flags/dm.png b/qml/flags/dm.png new file mode 100644 index 0000000..30ff8ae Binary files /dev/null and b/qml/flags/dm.png differ diff --git a/qml/flags/do.png b/qml/flags/do.png new file mode 100644 index 0000000..12fe119 Binary files /dev/null and b/qml/flags/do.png differ diff --git a/qml/flags/dz.png b/qml/flags/dz.png new file mode 100644 index 0000000..6332d56 Binary files /dev/null and b/qml/flags/dz.png differ diff --git a/qml/flags/ec.png b/qml/flags/ec.png new file mode 100644 index 0000000..0e6a832 Binary files /dev/null and b/qml/flags/ec.png differ diff --git a/qml/flags/ee.png b/qml/flags/ee.png new file mode 100644 index 0000000..327340e Binary files /dev/null and b/qml/flags/ee.png differ diff --git a/qml/flags/eg.png b/qml/flags/eg.png new file mode 100644 index 0000000..4e6d74f Binary files /dev/null and b/qml/flags/eg.png differ diff --git a/qml/flags/eh.png b/qml/flags/eh.png new file mode 100644 index 0000000..c9c1166 Binary files /dev/null and b/qml/flags/eh.png differ diff --git a/qml/flags/er.png b/qml/flags/er.png new file mode 100644 index 0000000..95fa006 Binary files /dev/null and b/qml/flags/er.png differ diff --git a/qml/flags/es.png b/qml/flags/es.png new file mode 100644 index 0000000..7c62f76 Binary files /dev/null and b/qml/flags/es.png differ diff --git a/qml/flags/et.png b/qml/flags/et.png new file mode 100644 index 0000000..2addd6c Binary files /dev/null and b/qml/flags/et.png differ diff --git a/qml/flags/fi.png b/qml/flags/fi.png new file mode 100644 index 0000000..942e5e4 Binary files /dev/null and b/qml/flags/fi.png differ diff --git a/qml/flags/fj.png b/qml/flags/fj.png new file mode 100644 index 0000000..96ca4f2 Binary files /dev/null and b/qml/flags/fj.png differ diff --git a/qml/flags/fk.png b/qml/flags/fk.png new file mode 100644 index 0000000..6d5081f Binary files /dev/null and b/qml/flags/fk.png differ diff --git a/qml/flags/fm.png b/qml/flags/fm.png new file mode 100644 index 0000000..9d6011b Binary files /dev/null and b/qml/flags/fm.png differ diff --git a/qml/flags/fo.png b/qml/flags/fo.png new file mode 100644 index 0000000..9a2988f Binary files /dev/null and b/qml/flags/fo.png differ diff --git a/qml/flags/fr.png b/qml/flags/fr.png new file mode 100644 index 0000000..f3805eb Binary files /dev/null and b/qml/flags/fr.png differ diff --git a/qml/flags/ga.png b/qml/flags/ga.png new file mode 100644 index 0000000..160b9b8 Binary files /dev/null and b/qml/flags/ga.png differ diff --git a/qml/flags/gb.png b/qml/flags/gb.png new file mode 100644 index 0000000..790095e Binary files /dev/null and b/qml/flags/gb.png differ diff --git a/qml/flags/gd.png b/qml/flags/gd.png new file mode 100644 index 0000000..e633066 Binary files /dev/null and b/qml/flags/gd.png differ diff --git a/qml/flags/ge.png b/qml/flags/ge.png new file mode 100644 index 0000000..16fa38a Binary files /dev/null and b/qml/flags/ge.png differ diff --git a/qml/flags/gf.png b/qml/flags/gf.png new file mode 100644 index 0000000..74a4222 Binary files /dev/null and b/qml/flags/gf.png differ diff --git a/qml/flags/gg.png b/qml/flags/gg.png new file mode 100644 index 0000000..1294535 Binary files /dev/null and b/qml/flags/gg.png differ diff --git a/qml/flags/gh.png b/qml/flags/gh.png new file mode 100644 index 0000000..bfce5aa Binary files /dev/null and b/qml/flags/gh.png differ diff --git a/qml/flags/gi.png b/qml/flags/gi.png new file mode 100644 index 0000000..01b41f8 Binary files /dev/null and b/qml/flags/gi.png differ diff --git a/qml/flags/gl.png b/qml/flags/gl.png new file mode 100644 index 0000000..63ea4e6 Binary files /dev/null and b/qml/flags/gl.png differ diff --git a/qml/flags/gm.png b/qml/flags/gm.png new file mode 100644 index 0000000..e3089d6 Binary files /dev/null and b/qml/flags/gm.png differ diff --git a/qml/flags/gn.png b/qml/flags/gn.png new file mode 100644 index 0000000..25277a0 Binary files /dev/null and b/qml/flags/gn.png differ diff --git a/qml/flags/gp.png b/qml/flags/gp.png new file mode 100644 index 0000000..9b40fe1 Binary files /dev/null and b/qml/flags/gp.png differ diff --git a/qml/flags/gq.png b/qml/flags/gq.png new file mode 100644 index 0000000..bd1bd3e Binary files /dev/null and b/qml/flags/gq.png differ diff --git a/qml/flags/gr.png b/qml/flags/gr.png new file mode 100644 index 0000000..7014de8 Binary files /dev/null and b/qml/flags/gr.png differ diff --git a/qml/flags/gs.png b/qml/flags/gs.png new file mode 100644 index 0000000..30093c3 Binary files /dev/null and b/qml/flags/gs.png differ diff --git a/qml/flags/gt.png b/qml/flags/gt.png new file mode 100644 index 0000000..8486a4f Binary files /dev/null and b/qml/flags/gt.png differ diff --git a/qml/flags/gu.png b/qml/flags/gu.png new file mode 100644 index 0000000..52c6a99 Binary files /dev/null and b/qml/flags/gu.png differ diff --git a/qml/flags/gw.png b/qml/flags/gw.png new file mode 100644 index 0000000..5dcf889 Binary files /dev/null and b/qml/flags/gw.png differ diff --git a/qml/flags/gy.png b/qml/flags/gy.png new file mode 100644 index 0000000..e51a77b Binary files /dev/null and b/qml/flags/gy.png differ diff --git a/qml/flags/hk.png b/qml/flags/hk.png new file mode 100644 index 0000000..ea7f153 Binary files /dev/null and b/qml/flags/hk.png differ diff --git a/qml/flags/hm.png b/qml/flags/hm.png new file mode 100644 index 0000000..b0be113 Binary files /dev/null and b/qml/flags/hm.png differ diff --git a/qml/flags/hn.png b/qml/flags/hn.png new file mode 100644 index 0000000..43373a6 Binary files /dev/null and b/qml/flags/hn.png differ diff --git a/qml/flags/hr.png b/qml/flags/hr.png new file mode 100644 index 0000000..ba7d7de Binary files /dev/null and b/qml/flags/hr.png differ diff --git a/qml/flags/ht.png b/qml/flags/ht.png new file mode 100644 index 0000000..b3eb681 Binary files /dev/null and b/qml/flags/ht.png differ diff --git a/qml/flags/hu.png b/qml/flags/hu.png new file mode 100644 index 0000000..5cc03df Binary files /dev/null and b/qml/flags/hu.png differ diff --git a/qml/flags/id.png b/qml/flags/id.png new file mode 100644 index 0000000..09dfe43 Binary files /dev/null and b/qml/flags/id.png differ diff --git a/qml/flags/ie.png b/qml/flags/ie.png new file mode 100644 index 0000000..dc687f0 Binary files /dev/null and b/qml/flags/ie.png differ diff --git a/qml/flags/il.png b/qml/flags/il.png new file mode 100644 index 0000000..23b9531 Binary files /dev/null and b/qml/flags/il.png differ diff --git a/qml/flags/im.png b/qml/flags/im.png new file mode 100644 index 0000000..cca3022 Binary files /dev/null and b/qml/flags/im.png differ diff --git a/qml/flags/in.png b/qml/flags/in.png new file mode 100644 index 0000000..2709d71 Binary files /dev/null and b/qml/flags/in.png differ diff --git a/qml/flags/io.png b/qml/flags/io.png new file mode 100644 index 0000000..4132c30 Binary files /dev/null and b/qml/flags/io.png differ diff --git a/qml/flags/iq.png b/qml/flags/iq.png new file mode 100644 index 0000000..6e80293 Binary files /dev/null and b/qml/flags/iq.png differ diff --git a/qml/flags/ir.png b/qml/flags/ir.png new file mode 100644 index 0000000..e4bff1f Binary files /dev/null and b/qml/flags/ir.png differ diff --git a/qml/flags/is.png b/qml/flags/is.png new file mode 100644 index 0000000..ff65d3b Binary files /dev/null and b/qml/flags/is.png differ diff --git a/qml/flags/it.png b/qml/flags/it.png new file mode 100644 index 0000000..4861c45 Binary files /dev/null and b/qml/flags/it.png differ diff --git a/qml/flags/je.png b/qml/flags/je.png new file mode 100644 index 0000000..02d9cc1 Binary files /dev/null and b/qml/flags/je.png differ diff --git a/qml/flags/jm.png b/qml/flags/jm.png new file mode 100644 index 0000000..93e6339 Binary files /dev/null and b/qml/flags/jm.png differ diff --git a/qml/flags/jo.png b/qml/flags/jo.png new file mode 100644 index 0000000..e812ff4 Binary files /dev/null and b/qml/flags/jo.png differ diff --git a/qml/flags/jp.png b/qml/flags/jp.png new file mode 100644 index 0000000..833bdee Binary files /dev/null and b/qml/flags/jp.png differ diff --git a/qml/flags/ke.png b/qml/flags/ke.png new file mode 100644 index 0000000..74d9b95 Binary files /dev/null and b/qml/flags/ke.png differ diff --git a/qml/flags/kg.png b/qml/flags/kg.png new file mode 100644 index 0000000..6e6411b Binary files /dev/null and b/qml/flags/kg.png differ diff --git a/qml/flags/kh.png b/qml/flags/kh.png new file mode 100644 index 0000000..ff219bd Binary files /dev/null and b/qml/flags/kh.png differ diff --git a/qml/flags/ki.png b/qml/flags/ki.png new file mode 100644 index 0000000..54cc5af Binary files /dev/null and b/qml/flags/ki.png differ diff --git a/qml/flags/km.png b/qml/flags/km.png new file mode 100644 index 0000000..afe9522 Binary files /dev/null and b/qml/flags/km.png differ diff --git a/qml/flags/kn.png b/qml/flags/kn.png new file mode 100644 index 0000000..d9aa699 Binary files /dev/null and b/qml/flags/kn.png differ diff --git a/qml/flags/kp.png b/qml/flags/kp.png new file mode 100644 index 0000000..1fa4473 Binary files /dev/null and b/qml/flags/kp.png differ diff --git a/qml/flags/kr.png b/qml/flags/kr.png new file mode 100644 index 0000000..9b550ba Binary files /dev/null and b/qml/flags/kr.png differ diff --git a/qml/flags/kw.png b/qml/flags/kw.png new file mode 100644 index 0000000..54af348 Binary files /dev/null and b/qml/flags/kw.png differ diff --git a/qml/flags/ky.png b/qml/flags/ky.png new file mode 100644 index 0000000..a0d1e98 Binary files /dev/null and b/qml/flags/ky.png differ diff --git a/qml/flags/kz.png b/qml/flags/kz.png new file mode 100644 index 0000000..3988ff8 Binary files /dev/null and b/qml/flags/kz.png differ diff --git a/qml/flags/la.png b/qml/flags/la.png new file mode 100644 index 0000000..1d7a216 Binary files /dev/null and b/qml/flags/la.png differ diff --git a/qml/flags/lb.png b/qml/flags/lb.png new file mode 100644 index 0000000..1f9ffd1 Binary files /dev/null and b/qml/flags/lb.png differ diff --git a/qml/flags/lc.png b/qml/flags/lc.png new file mode 100644 index 0000000..38e9fe6 Binary files /dev/null and b/qml/flags/lc.png differ diff --git a/qml/flags/li.png b/qml/flags/li.png new file mode 100644 index 0000000..e1d1eca Binary files /dev/null and b/qml/flags/li.png differ diff --git a/qml/flags/lk.png b/qml/flags/lk.png new file mode 100644 index 0000000..17f7634 Binary files /dev/null and b/qml/flags/lk.png differ diff --git a/qml/flags/lr.png b/qml/flags/lr.png new file mode 100644 index 0000000..32c23c8 Binary files /dev/null and b/qml/flags/lr.png differ diff --git a/qml/flags/ls.png b/qml/flags/ls.png new file mode 100644 index 0000000..0ff701b Binary files /dev/null and b/qml/flags/ls.png differ diff --git a/qml/flags/lt.png b/qml/flags/lt.png new file mode 100644 index 0000000..107decb Binary files /dev/null and b/qml/flags/lt.png differ diff --git a/qml/flags/lu.png b/qml/flags/lu.png new file mode 100644 index 0000000..d7693c0 Binary files /dev/null and b/qml/flags/lu.png differ diff --git a/qml/flags/lv.png b/qml/flags/lv.png new file mode 100644 index 0000000..987f17d Binary files /dev/null and b/qml/flags/lv.png differ diff --git a/qml/flags/ly.png b/qml/flags/ly.png new file mode 100644 index 0000000..90b347d Binary files /dev/null and b/qml/flags/ly.png differ diff --git a/qml/flags/ma.png b/qml/flags/ma.png new file mode 100644 index 0000000..c5374c6 Binary files /dev/null and b/qml/flags/ma.png differ diff --git a/qml/flags/mc.png b/qml/flags/mc.png new file mode 100644 index 0000000..4a26741 Binary files /dev/null and b/qml/flags/mc.png differ diff --git a/qml/flags/md.png b/qml/flags/md.png new file mode 100644 index 0000000..30321da Binary files /dev/null and b/qml/flags/md.png differ diff --git a/qml/flags/me.png b/qml/flags/me.png new file mode 100644 index 0000000..f3e1f53 Binary files /dev/null and b/qml/flags/me.png differ diff --git a/qml/flags/mf.png b/qml/flags/mf.png new file mode 100644 index 0000000..9224191 Binary files /dev/null and b/qml/flags/mf.png differ diff --git a/qml/flags/mg.png b/qml/flags/mg.png new file mode 100644 index 0000000..ddac4d4 Binary files /dev/null and b/qml/flags/mg.png differ diff --git a/qml/flags/mh.png b/qml/flags/mh.png new file mode 100644 index 0000000..e057157 Binary files /dev/null and b/qml/flags/mh.png differ diff --git a/qml/flags/mk.png b/qml/flags/mk.png new file mode 100644 index 0000000..76cba22 Binary files /dev/null and b/qml/flags/mk.png differ diff --git a/qml/flags/ml.png b/qml/flags/ml.png new file mode 100644 index 0000000..c164ddf Binary files /dev/null and b/qml/flags/ml.png differ diff --git a/qml/flags/mm.png b/qml/flags/mm.png new file mode 100644 index 0000000..537cc82 Binary files /dev/null and b/qml/flags/mm.png differ diff --git a/qml/flags/mn.png b/qml/flags/mn.png new file mode 100644 index 0000000..10ed819 Binary files /dev/null and b/qml/flags/mn.png differ diff --git a/qml/flags/mo.png b/qml/flags/mo.png new file mode 100644 index 0000000..779d9c5 Binary files /dev/null and b/qml/flags/mo.png differ diff --git a/qml/flags/mp.png b/qml/flags/mp.png new file mode 100644 index 0000000..28913bc Binary files /dev/null and b/qml/flags/mp.png differ diff --git a/qml/flags/mq.png b/qml/flags/mq.png new file mode 100644 index 0000000..89efd20 Binary files /dev/null and b/qml/flags/mq.png differ diff --git a/qml/flags/mr.png b/qml/flags/mr.png new file mode 100644 index 0000000..25a4aba Binary files /dev/null and b/qml/flags/mr.png differ diff --git a/qml/flags/ms.png b/qml/flags/ms.png new file mode 100644 index 0000000..f17feb3 Binary files /dev/null and b/qml/flags/ms.png differ diff --git a/qml/flags/mt.png b/qml/flags/mt.png new file mode 100644 index 0000000..bd1e322 Binary files /dev/null and b/qml/flags/mt.png differ diff --git a/qml/flags/mu.png b/qml/flags/mu.png new file mode 100644 index 0000000..4b5d92f Binary files /dev/null and b/qml/flags/mu.png differ diff --git a/qml/flags/mv.png b/qml/flags/mv.png new file mode 100644 index 0000000..caa1ccd Binary files /dev/null and b/qml/flags/mv.png differ diff --git a/qml/flags/mw.png b/qml/flags/mw.png new file mode 100644 index 0000000..4327493 Binary files /dev/null and b/qml/flags/mw.png differ diff --git a/qml/flags/mx.png b/qml/flags/mx.png new file mode 100644 index 0000000..0d19da8 Binary files /dev/null and b/qml/flags/mx.png differ diff --git a/qml/flags/my.png b/qml/flags/my.png new file mode 100644 index 0000000..1377d7f Binary files /dev/null and b/qml/flags/my.png differ diff --git a/qml/flags/mz.png b/qml/flags/mz.png new file mode 100644 index 0000000..2683fdc Binary files /dev/null and b/qml/flags/mz.png differ diff --git a/qml/flags/na.png b/qml/flags/na.png new file mode 100644 index 0000000..9457b71 Binary files /dev/null and b/qml/flags/na.png differ diff --git a/qml/flags/nc.png b/qml/flags/nc.png new file mode 100644 index 0000000..0c3792f Binary files /dev/null and b/qml/flags/nc.png differ diff --git a/qml/flags/ne.png b/qml/flags/ne.png new file mode 100644 index 0000000..5d94da5 Binary files /dev/null and b/qml/flags/ne.png differ diff --git a/qml/flags/nf.png b/qml/flags/nf.png new file mode 100644 index 0000000..f8b4406 Binary files /dev/null and b/qml/flags/nf.png differ diff --git a/qml/flags/ng.png b/qml/flags/ng.png new file mode 100644 index 0000000..97bebf6 Binary files /dev/null and b/qml/flags/ng.png differ diff --git a/qml/flags/ni.png b/qml/flags/ni.png new file mode 100644 index 0000000..66d173a Binary files /dev/null and b/qml/flags/ni.png differ diff --git a/qml/flags/nl.png b/qml/flags/nl.png new file mode 100644 index 0000000..f64e97d Binary files /dev/null and b/qml/flags/nl.png differ diff --git a/qml/flags/no.png b/qml/flags/no.png new file mode 100644 index 0000000..4924df6 Binary files /dev/null and b/qml/flags/no.png differ diff --git a/qml/flags/np.png b/qml/flags/np.png new file mode 100644 index 0000000..06c9c54 Binary files /dev/null and b/qml/flags/np.png differ diff --git a/qml/flags/nr.png b/qml/flags/nr.png new file mode 100644 index 0000000..689a2c6 Binary files /dev/null and b/qml/flags/nr.png differ diff --git a/qml/flags/nu.png b/qml/flags/nu.png new file mode 100644 index 0000000..2eab1d3 Binary files /dev/null and b/qml/flags/nu.png differ diff --git a/qml/flags/nz.png b/qml/flags/nz.png new file mode 100644 index 0000000..933045a Binary files /dev/null and b/qml/flags/nz.png differ diff --git a/qml/flags/om.png b/qml/flags/om.png new file mode 100644 index 0000000..e852030 Binary files /dev/null and b/qml/flags/om.png differ diff --git a/qml/flags/pa.png b/qml/flags/pa.png new file mode 100644 index 0000000..3ef5da3 Binary files /dev/null and b/qml/flags/pa.png differ diff --git a/qml/flags/pe.png b/qml/flags/pe.png new file mode 100644 index 0000000..6d82b4f Binary files /dev/null and b/qml/flags/pe.png differ diff --git a/qml/flags/pf.png b/qml/flags/pf.png new file mode 100644 index 0000000..1940db9 Binary files /dev/null and b/qml/flags/pf.png differ diff --git a/qml/flags/pg.png b/qml/flags/pg.png new file mode 100644 index 0000000..584ac62 Binary files /dev/null and b/qml/flags/pg.png differ diff --git a/qml/flags/ph.png b/qml/flags/ph.png new file mode 100644 index 0000000..6138ace Binary files /dev/null and b/qml/flags/ph.png differ diff --git a/qml/flags/pk.png b/qml/flags/pk.png new file mode 100644 index 0000000..903e2d0 Binary files /dev/null and b/qml/flags/pk.png differ diff --git a/qml/flags/pl.png b/qml/flags/pl.png new file mode 100644 index 0000000..e3a9271 Binary files /dev/null and b/qml/flags/pl.png differ diff --git a/qml/flags/pm.png b/qml/flags/pm.png new file mode 100644 index 0000000..e2f6d8b Binary files /dev/null and b/qml/flags/pm.png differ diff --git a/qml/flags/pn.png b/qml/flags/pn.png new file mode 100644 index 0000000..10b044e Binary files /dev/null and b/qml/flags/pn.png differ diff --git a/qml/flags/pr.png b/qml/flags/pr.png new file mode 100644 index 0000000..b694c6c Binary files /dev/null and b/qml/flags/pr.png differ diff --git a/qml/flags/ps.png b/qml/flags/ps.png new file mode 100644 index 0000000..98ad4c9 Binary files /dev/null and b/qml/flags/ps.png differ diff --git a/qml/flags/pt.png b/qml/flags/pt.png new file mode 100644 index 0000000..7b9302e Binary files /dev/null and b/qml/flags/pt.png differ diff --git a/qml/flags/pw.png b/qml/flags/pw.png new file mode 100644 index 0000000..13b0f03 Binary files /dev/null and b/qml/flags/pw.png differ diff --git a/qml/flags/py.png b/qml/flags/py.png new file mode 100644 index 0000000..1548d05 Binary files /dev/null and b/qml/flags/py.png differ diff --git a/qml/flags/qa.png b/qml/flags/qa.png new file mode 100644 index 0000000..2cb666e Binary files /dev/null and b/qml/flags/qa.png differ diff --git a/qml/flags/re.png b/qml/flags/re.png new file mode 100644 index 0000000..e3aa0d8 Binary files /dev/null and b/qml/flags/re.png differ diff --git a/qml/flags/ro.png b/qml/flags/ro.png new file mode 100644 index 0000000..7df59da Binary files /dev/null and b/qml/flags/ro.png differ diff --git a/qml/flags/rs.png b/qml/flags/rs.png new file mode 100644 index 0000000..f28baf0 Binary files /dev/null and b/qml/flags/rs.png differ diff --git a/qml/flags/ru.png b/qml/flags/ru.png new file mode 100644 index 0000000..ecf4f9d Binary files /dev/null and b/qml/flags/ru.png differ diff --git a/qml/flags/rw.png b/qml/flags/rw.png new file mode 100644 index 0000000..258f608 Binary files /dev/null and b/qml/flags/rw.png differ diff --git a/qml/flags/sa.png b/qml/flags/sa.png new file mode 100644 index 0000000..019364c Binary files /dev/null and b/qml/flags/sa.png differ diff --git a/qml/flags/sb.png b/qml/flags/sb.png new file mode 100644 index 0000000..7cfa8e4 Binary files /dev/null and b/qml/flags/sb.png differ diff --git a/qml/flags/sc.png b/qml/flags/sc.png new file mode 100644 index 0000000..01e3ea3 Binary files /dev/null and b/qml/flags/sc.png differ diff --git a/qml/flags/sd.png b/qml/flags/sd.png new file mode 100644 index 0000000..ee62438 Binary files /dev/null and b/qml/flags/sd.png differ diff --git a/qml/flags/se.png b/qml/flags/se.png new file mode 100644 index 0000000..a91ce78 Binary files /dev/null and b/qml/flags/se.png differ diff --git a/qml/flags/sg.png b/qml/flags/sg.png new file mode 100644 index 0000000..30eced5 Binary files /dev/null and b/qml/flags/sg.png differ diff --git a/qml/flags/sh.png b/qml/flags/sh.png new file mode 100644 index 0000000..5edcf71 Binary files /dev/null and b/qml/flags/sh.png differ diff --git a/qml/flags/si.png b/qml/flags/si.png new file mode 100644 index 0000000..117b5dd Binary files /dev/null and b/qml/flags/si.png differ diff --git a/qml/flags/sj.png b/qml/flags/sj.png new file mode 100644 index 0000000..4924df6 Binary files /dev/null and b/qml/flags/sj.png differ diff --git a/qml/flags/sk.png b/qml/flags/sk.png new file mode 100644 index 0000000..36ce03c Binary files /dev/null and b/qml/flags/sk.png differ diff --git a/qml/flags/sl.png b/qml/flags/sl.png new file mode 100644 index 0000000..3aa02f4 Binary files /dev/null and b/qml/flags/sl.png differ diff --git a/qml/flags/sm.png b/qml/flags/sm.png new file mode 100644 index 0000000..e51e365 Binary files /dev/null and b/qml/flags/sm.png differ diff --git a/qml/flags/sn.png b/qml/flags/sn.png new file mode 100644 index 0000000..b5bfee9 Binary files /dev/null and b/qml/flags/sn.png differ diff --git a/qml/flags/so.png b/qml/flags/so.png new file mode 100644 index 0000000..43e36d1 Binary files /dev/null and b/qml/flags/so.png differ diff --git a/qml/flags/sr.png b/qml/flags/sr.png new file mode 100644 index 0000000..e41913d Binary files /dev/null and b/qml/flags/sr.png differ diff --git a/qml/flags/ss.png b/qml/flags/ss.png new file mode 100644 index 0000000..0085ad0 Binary files /dev/null and b/qml/flags/ss.png differ diff --git a/qml/flags/st.png b/qml/flags/st.png new file mode 100644 index 0000000..4567d08 Binary files /dev/null and b/qml/flags/st.png differ diff --git a/qml/flags/sv.png b/qml/flags/sv.png new file mode 100644 index 0000000..9bf51d2 Binary files /dev/null and b/qml/flags/sv.png differ diff --git a/qml/flags/sx.png b/qml/flags/sx.png new file mode 100644 index 0000000..d5c87c2 Binary files /dev/null and b/qml/flags/sx.png differ diff --git a/qml/flags/sy.png b/qml/flags/sy.png new file mode 100644 index 0000000..bc3c612 Binary files /dev/null and b/qml/flags/sy.png differ diff --git a/qml/flags/sz.png b/qml/flags/sz.png new file mode 100644 index 0000000..28d8416 Binary files /dev/null and b/qml/flags/sz.png differ diff --git a/qml/flags/tc.png b/qml/flags/tc.png new file mode 100644 index 0000000..b80afbc Binary files /dev/null and b/qml/flags/tc.png differ diff --git a/qml/flags/td.png b/qml/flags/td.png new file mode 100644 index 0000000..fc2e50a Binary files /dev/null and b/qml/flags/td.png differ diff --git a/qml/flags/tf.png b/qml/flags/tf.png new file mode 100644 index 0000000..d2c7ffc Binary files /dev/null and b/qml/flags/tf.png differ diff --git a/qml/flags/tg.png b/qml/flags/tg.png new file mode 100644 index 0000000..6609476 Binary files /dev/null and b/qml/flags/tg.png differ diff --git a/qml/flags/th.png b/qml/flags/th.png new file mode 100644 index 0000000..22691ea Binary files /dev/null and b/qml/flags/th.png differ diff --git a/qml/flags/tj.png b/qml/flags/tj.png new file mode 100644 index 0000000..d6b4686 Binary files /dev/null and b/qml/flags/tj.png differ diff --git a/qml/flags/tk.png b/qml/flags/tk.png new file mode 100644 index 0000000..0e870d3 Binary files /dev/null and b/qml/flags/tk.png differ diff --git a/qml/flags/tl.png b/qml/flags/tl.png new file mode 100644 index 0000000..f8b06a1 Binary files /dev/null and b/qml/flags/tl.png differ diff --git a/qml/flags/tm.png b/qml/flags/tm.png new file mode 100644 index 0000000..42d17e0 Binary files /dev/null and b/qml/flags/tm.png differ diff --git a/qml/flags/tn.png b/qml/flags/tn.png new file mode 100644 index 0000000..4af231d Binary files /dev/null and b/qml/flags/tn.png differ diff --git a/qml/flags/to.png b/qml/flags/to.png new file mode 100644 index 0000000..271e005 Binary files /dev/null and b/qml/flags/to.png differ diff --git a/qml/flags/tr.png b/qml/flags/tr.png new file mode 100644 index 0000000..b22b096 Binary files /dev/null and b/qml/flags/tr.png differ diff --git a/qml/flags/tt.png b/qml/flags/tt.png new file mode 100644 index 0000000..cfac76a Binary files /dev/null and b/qml/flags/tt.png differ diff --git a/qml/flags/tv.png b/qml/flags/tv.png new file mode 100644 index 0000000..f426f61 Binary files /dev/null and b/qml/flags/tv.png differ diff --git a/qml/flags/tw.png b/qml/flags/tw.png new file mode 100644 index 0000000..e1a659f Binary files /dev/null and b/qml/flags/tw.png differ diff --git a/qml/flags/tz.png b/qml/flags/tz.png new file mode 100644 index 0000000..5a8ef07 Binary files /dev/null and b/qml/flags/tz.png differ diff --git a/qml/flags/ua.png b/qml/flags/ua.png new file mode 100644 index 0000000..05f07c1 Binary files /dev/null and b/qml/flags/ua.png differ diff --git a/qml/flags/ug.png b/qml/flags/ug.png new file mode 100644 index 0000000..2ab62ea Binary files /dev/null and b/qml/flags/ug.png differ diff --git a/qml/flags/um.png b/qml/flags/um.png new file mode 100644 index 0000000..4619e78 Binary files /dev/null and b/qml/flags/um.png differ diff --git a/qml/flags/us.png b/qml/flags/us.png new file mode 100644 index 0000000..a488297 Binary files /dev/null and b/qml/flags/us.png differ diff --git a/qml/flags/uy.png b/qml/flags/uy.png new file mode 100644 index 0000000..74fcf1e Binary files /dev/null and b/qml/flags/uy.png differ diff --git a/qml/flags/uz.png b/qml/flags/uz.png new file mode 100644 index 0000000..ae19033 Binary files /dev/null and b/qml/flags/uz.png differ diff --git a/qml/flags/va.png b/qml/flags/va.png new file mode 100644 index 0000000..5045344 Binary files /dev/null and b/qml/flags/va.png differ diff --git a/qml/flags/vc.png b/qml/flags/vc.png new file mode 100644 index 0000000..3a36503 Binary files /dev/null and b/qml/flags/vc.png differ diff --git a/qml/flags/ve.png b/qml/flags/ve.png new file mode 100644 index 0000000..5a90b7d Binary files /dev/null and b/qml/flags/ve.png differ diff --git a/qml/flags/vg.png b/qml/flags/vg.png new file mode 100644 index 0000000..f070dbf Binary files /dev/null and b/qml/flags/vg.png differ diff --git a/qml/flags/vi.png b/qml/flags/vi.png new file mode 100644 index 0000000..93eaf8b Binary files /dev/null and b/qml/flags/vi.png differ diff --git a/qml/flags/vn.png b/qml/flags/vn.png new file mode 100644 index 0000000..e3a6517 Binary files /dev/null and b/qml/flags/vn.png differ diff --git a/qml/flags/vu.png b/qml/flags/vu.png new file mode 100644 index 0000000..061a601 Binary files /dev/null and b/qml/flags/vu.png differ diff --git a/qml/flags/wf.png b/qml/flags/wf.png new file mode 100644 index 0000000..24a314d Binary files /dev/null and b/qml/flags/wf.png differ diff --git a/qml/flags/ws.png b/qml/flags/ws.png new file mode 100644 index 0000000..91a9a15 Binary files /dev/null and b/qml/flags/ws.png differ diff --git a/qml/flags/xk.png b/qml/flags/xk.png new file mode 100644 index 0000000..2f08c0c Binary files /dev/null and b/qml/flags/xk.png differ diff --git a/qml/flags/ye.png b/qml/flags/ye.png new file mode 100644 index 0000000..a1c4781 Binary files /dev/null and b/qml/flags/ye.png differ diff --git a/qml/flags/yt.png b/qml/flags/yt.png new file mode 100644 index 0000000..4bead0d Binary files /dev/null and b/qml/flags/yt.png differ diff --git a/qml/flags/za.png b/qml/flags/za.png new file mode 100644 index 0000000..ffea4a2 Binary files /dev/null and b/qml/flags/za.png differ diff --git a/qml/flags/zm.png b/qml/flags/zm.png new file mode 100644 index 0000000..ec5f68c Binary files /dev/null and b/qml/flags/zm.png differ diff --git a/qml/flags/zw.png b/qml/flags/zw.png new file mode 100644 index 0000000..e3ffa4a Binary files /dev/null and b/qml/flags/zw.png differ diff --git a/qml/flags/zzxx.png b/qml/flags/zzxx.png new file mode 100644 index 0000000..e5ca3db Binary files /dev/null and b/qml/flags/zzxx.png differ diff --git a/qml/harbour-allradio.qml b/qml/harbour-allradio.qml new file mode 100644 index 0000000..3d518eb --- /dev/null +++ b/qml/harbour-allradio.qml @@ -0,0 +1,67 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import Nemo.Configuration 1.0 ///////// +import Nemo.Notifications 1.0 /////////// +import "pages" +import "items" +//import "radio-player" +//import "video-player" +import "helpers" +//import "jupii" + + +ApplicationWindow +{ + id: allRadio + property string _version: Qt.application.version + property string _language: Qt.locale().name.slice(0,2) + property string _country: Qt.locale().name.slice(-2) + property int sleepTime: 0 + property alias settings: allradioSettings + property alias mediaPlayerPanel: mediaPlayerPanel + property RadioPlayer radioPlayer : RadioPlayer {id:radioPlayer} + property RadioBrowser radioBrowser : RadioBrowser {id:radioBrowser;parent: allRadio} + property SleepTimer sleepTimer : SleepTimer {id:sleepTimer} + + // property alias online: radioBrowser.online + //property alias mediaPlayerPanel: playerPanel + // property Media MediaPlayerPanel {id: mediaPlayerPanel} +// property Jupii jupii: Jupii {id: jupii} + + MediaPlayerPanel {id: mediaPlayerPanel} + ConfigurationGroup {id:settingsGroup;path: "/apps/harbour-allradio";ConfigurationGroup {id: allradioSettings;path: "/settings"}} + Notification {id: notification;onClicked: console.log("Clicked")} + //MprisPlayer {} + + function handleArguments() { + for(var i = 1; i < Qt.application.arguments.length; i++) { + switch (Qt.application.arguments[i]) { + case "--help": help();break; // no argument + //case "--codec": console.info("*** CODEC *** "+Qt.application.arguments[i+1]);break; // argument can be: mp3, aac, aac+, hls + //case "--favorite": console.info("*** FAVORITE *** "+Qt.application.arguments[i+1]);break; // argument can be: top, latest, random + //case "--pause": console.info("*** HISTORY *** "+Qt.application.arguments[i+1]);break; // argument can be: top, latest, random + case "--sleep": console.info("*** SLEEP *** : "+Qt.application.arguments[i+1]);break; // play for 1-120 minutes (sleeptimer) + case "--latest": console.info("*** PLAY *** : "+Qt.application.arguments[i+1]);latest();break; // latest, saved, random, world + case "--random": console.info("*** PLAY *** : "+Qt.application.arguments[i+1]);random();break; // latest, saved, random, world + } + } + } + function help(){ + console.info("help") + + } + function latest(){ + radioPlayer.loadRecentPlay() + radioPlayer.playStream() + + } + function random(){ + radioPlayer.loadRandomPlay() + radioPlayer.playStream() + + } + initialPage: Component { AllRadio { } } + cover: Qt.resolvedUrl("cover/CoverPage.qml") + allowedOrientations: defaultAllowedOrientations + Component.onCompleted: {mediaPlayerPanel.parent.z = 99;handleArguments()} +} diff --git a/qml/helpers/db.js b/qml/helpers/db.js new file mode 100644 index 0000000..bcc6e12 --- /dev/null +++ b/qml/helpers/db.js @@ -0,0 +1,328 @@ +var db = undefined; +var newStation = false + +function settings_db_open() { + if (db === undefined) + db = LocalStorage.openDatabaseSync("harbour-allradio-2", "2.0", "Database", 100000); + return db; +} + +function checkforold() { + db = settings_db_open(); + try { + db.transaction(function(tx) + { + var rs = tx.executeSql('SELECT * FROM channels'); + // console.log("OLD DATABSE TABLE EXISTS") + }); + } + catch(a) + { + // console.log("NO OLD DATABASE") + } + } + +function init() { + db = settings_db_open(); + checkforold() + try { + db.transaction( + function(tx) { + //tx.executeSql('CREATE TABLE IF NOT EXISTS settings(setting TEXT UNIQUE, value TEXT)'); + tx.executeSql('CREATE TABLE IF NOT EXISTS stations (id TEXT UNIQUE, name TEXT, countrycode STRING, homepage TEXT, radiourlresolved TEXT, favicon TEXT, tagslist TEXT, codec TEXT, bitrate TEXT, hls TEXT, myclicktimestamp STRING, myclickcount INTEGER, favorite INTEGER)'); + tx.executeSql('CREATE TABLE IF NOT EXISTS countries (countrycode TEXT UNIQUE, myclickcount INTEGER)'); + tx.executeSql('CREATE TABLE IF NOT EXISTS tags (tag TEXT UNIQUE, myclickcount INTEGER)'); + } + ); + } + catch(a) + { + console.log("create failed: "+a) + return false + } +} +// id TEXT UNIQUE, name TEXT, countrycode STRING, homepage TEXT, radiourlresolved TEXT, favicon TEXT, tagslist TEXT, codec TEXT, bitrate TEXT, hls TEXT, myclicktimestamp STRING, myclickcount INTEGER, favorite INTEGER +// UPDATE OR INSERT STATION CLICKED +function setStationClicked(myclicktimestamp,id,name,countrycode,homepage,radiourlresolved,favicon,tagslist,codec,bitrate,hls,favorite) { + db = settings_db_open(); + var cc + var t + var fav + if (countrycode === "") cc = "No Country"; else cc = countrycode + if (tagslist === "") t = "NoTag"; else t = tagslist + if (favorite === true) fav = 1; else fav = 0 + try { + db.transaction(function(tx) { + var rs = tx.executeSql('UPDATE stations SET myclicktimestamp="'+myclicktimestamp+'",favorite='+fav+',myclickcount=myclickcount+1 WHERE id="'+id+'"'); + if (rs.rowsAffected > 0) { + // console.log("DB UPDATE STATION CLICK: "+id) + } else { + tx.executeSql('INSERT INTO stations VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)',[id, name, cc, homepage, radiourlresolved,favicon,t,codec,bitrate,hls,myclicktimestamp,1,fav]); + // console.log("DB INSERT STATION CLICK: "+id) + } + } + ); + setCountryClicked(cc) + setTagClicked(t) + } + catch(a) + { + console.log("ERROR SETSTATIONCLICKED: "+a) + } +} +// GET LIMIT NUMBER OF RECENT CLICKED TO MODEL +function getStationRecentClicked(model,limit) +{ + db = settings_db_open(); + try { + db.transaction(function(tx) + { + model.clear() + var rs = tx.executeSql('SELECT * FROM stations ORDER BY myclicktimestamp DESC LIMIT ?',limit); + for(var i = 0; i < rs.rows.length; i++) { + model.append({"stationuuid" : rs.rows.item(i).id, "name" : rs.rows.item(i).name, "countrycode" : rs.rows.item(i).countrycode,"homepage" : rs.rows.item(i).homepage,"url_resolved": rs.rows.item(i).radiourlresolved,"favicon":rs.rows.item(i).favicon, + "tags":rs.rows.item(i).tagslist,"codec":rs.rows.item(i).codec, "bitrate":rs.rows.item(i).bitrate,"hls":rs.rows.item(i).hls,"lastcheckok": "1","favorite": rs.rows.item(i).favorite}) + } + return true + }); + } + catch(a) + { + console.log("FAVO STATION RESENT failed: "+a); + return false; + } +} +function getFavorites(model,sort,limit) // name, myclickcount,myclicktimestamp +{ + var reverse = sort === "name" ? "ASC" : "DESC" + db = settings_db_open(); + try { + db.transaction(function(tx) + { + model.clear() + var rs = tx.executeSql('SELECT * FROM stations WHERE favorite=1 ORDER BY '+sort+' '+reverse+' LIMIT '+limit); + for(var i = 0; i < rs.rows.length; i++) { + model.append({"stationuuid" : rs.rows.item(i).id, "name" : rs.rows.item(i).name, "countrycode" : rs.rows.item(i).countrycode,"homepage" : rs.rows.item(i).homepage,"url_resolved": rs.rows.item(i).radiourlresolved,"favicon":rs.rows.item(i).favicon, + "tags":rs.rows.item(i).tagslist,"codec":rs.rows.item(i).codec, "bitrate":rs.rows.item(i).bitrate,"hls":rs.rows.item(i).hls,"lastcheckok": "1","favorite": rs.rows.item(i).favorite}) + } + return true + }); + } + catch(a) + { + console.log("FAVO STATION MOST PLAYED failed: "+a); + return false; + } +} +function getHistory(model,limit) +{ + db = settings_db_open(); + try { + db.transaction(function(tx) + { + model.clear() + var rs = tx.executeSql('SELECT * FROM stations ORDER BY myclicktimestamp DESC LIMIT ?',limit); + for(var i = 0; i < rs.rows.length; i++) { + model.append({"stationuuid" : rs.rows.item(i).id, "name" : rs.rows.item(i).name, "countrycode" : rs.rows.item(i).countrycode,"homepage" : rs.rows.item(i).homepage,"url_resolved": rs.rows.item(i).radiourlresolved,"favicon":rs.rows.item(i).favicon, + "tags":rs.rows.item(i).tagslist,"codec":rs.rows.item(i).codec, "bitrate":rs.rows.item(i).bitrate,"hls":rs.rows.item(i).hls,"lastcheckok": "1","favorite": rs.rows.item(i).favorite}) + } + return true + }); + } + catch(a) + { + console.log("FAVO STATION MOST PLAYED failed: "+a); + return false; + } +} +function getMostPlayedFavorites(model,limit) +{ + db = settings_db_open(); + try { + db.transaction(function(tx) + { + model.clear() + var rs = tx.executeSql('SELECT * FROM stations WHERE favorite=1 ORDER BY myclickcount DESC LIMIT ?',limit); + for(var i = 0; i < rs.rows.length; i++) { + model.append({"stationuuid" : rs.rows.item(i).id, "name" : rs.rows.item(i).name, "countrycode" : rs.rows.item(i).countrycode,"homepage" : rs.rows.item(i).homepage,"url_resolved": rs.rows.item(i).radiourlresolved,"favicon":rs.rows.item(i).favicon, + "tags":rs.rows.item(i).tagslist,"codec":rs.rows.item(i).codec, "bitrate":rs.rows.item(i).bitrate,"hls":rs.rows.item(i).hls,"lastcheckok": "1","favorite": rs.rows.item(i).favorite}) + } + return true + }); + } + catch(a) + { + console.log("FAVO STATION MOST PLAYED failed: "+a); + return false; + } +} +function setStationFavorite(id,name,countrycode,homepage,radiourlresolved,favicon,tagslist,codec,bitrate,hls,favorite) { + db = settings_db_open(); + var cc + var t + var fav + // console.log("FAVORITE = "+favorite) + if (countrycode === "") cc = "No Country"; else cc = countrycode + if (tagslist === "") t = "NoTag"; else t = tagslist + if (favorite === true) fav = 1; else fav = 0 + try { + db.transaction(function(tx) { + var rs = tx.executeSql('UPDATE stations SET favorite='+fav+' WHERE id="'+id+'"'); + if (rs.rowsAffected > 0) { + // console.log("DB UPDATE STATION CLICK: "+fav+" - "+id) + } else { + tx.executeSql('INSERT INTO stations VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)',[id, name, cc, homepage, radiourlresolved,favicon,t,codec,bitrate,hls,"",1,fav]); + // console.log("DB INSERT STATION CLICK: "+id) + } + } + ); + } + catch(a) + { + console.log("ERROR SET FAVORITE: "+a) + } +} +// get if favorite +// get if favorite +function getStationFavorite(id) { // Get info about number of clicks and if station is a favorite + //model.clear() + var db = settings_db_open(); + var res = 0; + try { + db.transaction(function(tx) { + var rs = tx.executeSql('SELECT * FROM stations WHERE id = "'+id+'" AND favorite = 1'); + res = rs.rows.length + // console.log("FAVO RESULT: "+res+" ID: "+id ) + if (res>0) return true; else return false; + + + }) + } catch (err) { + res = 0 + console.log("ERROR ON FAVORITE CHECK: "+err) + return false + }; + return res +} +function setCountryClicked(countrycode) { + db = settings_db_open(); + // var clicks = getCountryClick(countrycode) + 1 + try { + db.transaction(function(tx) { + var rs = tx.executeSql('UPDATE countries SET myclickcount=myclickcount+1 WHERE countrycode="'+countrycode+'"'); + if (rs.rowsAffected > 0) { + // console.log("DB UPDATE COUNTRY CLICK: "+countrycode) + } else { + tx.executeSql('INSERT INTO countries VALUES (?,?);', [countrycode, 1]); + // console.log("DB INSERT COUNTRY CLICK: "+countrycode) + } + } + ); + } + catch(a) + { + console.log("Failed setCountryClicked: "+a) + return false + } +} +function getCountryRecentClicked(model,limit) +{ + db = settings_db_open(); + try { + db.transaction(function(tx) + { + model.clear() + var rs = tx.executeSql('SELECT * FROM countries ORDER BY myclickcount DESC LIMIT '+limit); + for(var i = 0; i < rs.rows.length; i++) { + model.append({"alpha_2" : rs.rows.item(i).countrycode}) + } + return true + }); + } + catch(a) + { + console.log("FAVO COUNTRY failed: "+a); + return false; + } +} +function setTagClicked(tagslist) { + db = settings_db_open(); + var tags = tagslist.split(",") + //var tempTag + try { + db.transaction(function(tx) { + for(var i = 0; i < tags.length; i++) { + var rs = tx.executeSql('UPDATE tags SET myclickcount=myclickcount+1 WHERE tag="'+tags[i]+'"'); + if (rs.rowsAffected > 0) { + // console.log("DB UPDATE TAG CLICK: "+tags[i]) + } else { + tx.executeSql('INSERT INTO tags VALUES (?,?);', [tags[i], 1]); + // console.log("DB INSERT TAG CLICK: "+tags[i]) + } + } + } + ); + } + catch(a) + { + console.log("Failed settagsclicked: "+a) + return false + } +} +function getTagsRecentClicked(model,limit) +{ + db = settings_db_open(); + //var max = 0 + try { + db.transaction(function(tx) + { + model.clear() + var rs = tx.executeSql('SELECT * FROM tags ORDER BY myclickcount DESC limit '+limit); + for(var i = 0; i < rs.rows.length; i++) { + if (rs.rows.item(i).tag !== "NoTag") { + model.append({"tag" : rs.rows.item(i).tag,"myclickcount" : rs.rows.item(i).myclickcount}) + } + // if (rs.rows.item(i).myclickcount > max) max = rs.rows.item(i).myclickcount + } + // radioPlayer.maxTagClicks = max + // console.log("MAX TAGS: "+max) + return true + }); + + + } + catch(a) + { + console.log("FAVO TAGS failed: "+a); + return false; + } +} +function getTagsClicked(model,limit) +{ + db = settings_db_open(); + var max = 0 + try { + db.transaction(function(tx) + { + model.clear() + var rs = tx.executeSql('SELECT * FROM tags ORDER BY tag limit '+limit); + for(var i = 0; i < rs.rows.length; i++) { + if (rs.rows.item(i).tag !== "NoTag") { + model.append({"tag" : rs.rows.item(i).tag,"myclickcount" : rs.rows.item(i).myclickcount}) + if (rs.rows.item(i).myclickcount > max) max = rs.rows.item(i).myclickcount + } + } + // radioPlayer.maxTagClicks = max + console.log("MAX TAGS: "+max) + maxTags = max + return true + }); + + + } + catch(a) + { + console.log("FAVO TAGS failed: "+a); + return false; + } +} diff --git a/qml/helpers/dummy.qml b/qml/helpers/dummy.qml new file mode 100644 index 0000000..9c36e13 --- /dev/null +++ b/qml/helpers/dummy.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + +} diff --git a/qml/helpers/jsFunctions.js b/qml/helpers/jsFunctions.js new file mode 100644 index 0000000..43a54f9 --- /dev/null +++ b/qml/helpers/jsFunctions.js @@ -0,0 +1,106 @@ +function getGreeting() { + var display + var datetoday = new Date(); + var timenow=datetoday.getTime(); + datetoday.setTime(timenow); + var thehour = datetoday.getHours(); + + if (thehour >= 2 && thehour < 12) display = "morning"; + else if (thehour >= 12 && thehour <=17) display = "afternoon"; + else display = "evening" + + + + var greeting = ("Good " + display + "!"); + return greeting//document.write(greeting); +} + + +function getAll(hls,codec,bitrate) { + var h =false + var retVal = "" + if (hls === "1") h = true + if (h) retVal = "[HLS] " + if (codec && codec !== "UNKNOWN") retVal = retVal + "[" + codec + if (bitrate && bitrate > 0) retVal = retVal + " : " + bitrate + if (retVal !== "") retVal = retVal + "]"; else retVal = "[UNKNOWN]" + + return retVal +} + +function getHLS(hls,codec,bitrate) { + var h =false + var retVal = "" + if (hls === "1") h = true + if (h) retVal = "HLS" + + return retVal +} + +function getCodec(codec) { + var retVal = "" + if (codec && codec !== "UNKNOWN") retVal = codec + return retVal +} + +function getBitrate(bitrate) { + var retVal = "" + if (bitrate && bitrate > 0) retVal = bitrate + return retVal +} + +function getTimeStamp () { + var now = new Date(); + var year = "" + now.getFullYear(); + var month = "" + (now.getMonth() + 1); if (month.length === 1) { month = "0" + month; } + var day = "" + now.getDate(); if (day.length === 1) { day = "0" + day; } + var hour = "" + now.getHours(); if (hour.length === 1) { hour = "0" + hour; } + var minute = "" + now.getMinutes(); if (minute.length === 1) { minute = "0" + minute; } + var second = "" + now.getSeconds(); if (second.length === 1) { second = "0" + second; } + return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second; +} +// Random color generator +function getRandomColor() { + var letters = '0123456789ABCDEF'; + var color = '#FF'; + for (var i = 0; i < 4; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +} + +// future experiment to set dark or light background in favicons +function getImageLightness(imageSrc,callback) { + var img = document.createElement("img"); + img.src = imageSrc; + img.style.display = "none"; + document.body.appendChild(img); + + var colorSum = 0; + + img.onload = function() { + // create canvas + var canvas = document.createElement("canvas"); + canvas.width = this.width; + canvas.height = this.height; + + var ctx = canvas.getContext("2d"); + ctx.drawImage(this,0,0); + + var imageData = ctx.getImageData(0,0,canvas.width,canvas.height); + var data = imageData.data; + var r,g,b,avg; + + for(var x = 0, len = data.length; x < len; x+=4) { + r = data[x]; + g = data[x+1]; + b = data[x+2]; + + avg = Math.floor((r+g+b)/3); + colorSum += avg; + } + + var brightness = Math.floor(colorSum / (this.width*this.height)); + callback(brightness); + } +} diff --git a/qml/images/bycountry_t.png b/qml/images/bycountry_t.png new file mode 100644 index 0000000..c16c080 Binary files /dev/null and b/qml/images/bycountry_t.png differ diff --git a/qml/images/bylatest_t.png b/qml/images/bylatest_t.png new file mode 100644 index 0000000..cd10334 Binary files /dev/null and b/qml/images/bylatest_t.png differ diff --git a/qml/images/bysearch_t.png b/qml/images/bysearch_t.png new file mode 100644 index 0000000..0714a76 Binary files /dev/null and b/qml/images/bysearch_t.png differ diff --git a/qml/images/bytag_t.png b/qml/images/bytag_t.png new file mode 100644 index 0000000..01e5012 Binary files /dev/null and b/qml/images/bytag_t.png differ diff --git a/qml/images/byvote_t.png b/qml/images/byvote_t.png new file mode 100644 index 0000000..4ea0114 Binary files /dev/null and b/qml/images/byvote_t.png differ diff --git a/qml/images/community.png b/qml/images/community.png new file mode 100644 index 0000000..6bfc0ba Binary files /dev/null and b/qml/images/community.png differ diff --git a/qml/images/dlna.png b/qml/images/dlna.png new file mode 100644 index 0000000..aadc305 Binary files /dev/null and b/qml/images/dlna.png differ diff --git a/qml/images/dlna__.png b/qml/images/dlna__.png new file mode 100644 index 0000000..cbb4fd7 Binary files /dev/null and b/qml/images/dlna__.png differ diff --git a/qml/images/harbour-allradio2.png b/qml/images/harbour-allradio2.png new file mode 100644 index 0000000..b5ab57c Binary files /dev/null and b/qml/images/harbour-allradio2.png differ diff --git a/qml/images/icon-l-play.png b/qml/images/icon-l-play.png new file mode 100644 index 0000000..485ba82 Binary files /dev/null and b/qml/images/icon-l-play.png differ diff --git a/qml/images/jupii-108.png b/qml/images/jupii-108.png new file mode 100644 index 0000000..940284d Binary files /dev/null and b/qml/images/jupii-108.png differ diff --git a/qml/images/lastplayed_t.png b/qml/images/lastplayed_t.png new file mode 100644 index 0000000..0151b78 Binary files /dev/null and b/qml/images/lastplayed_t.png differ diff --git a/qml/images/mostclicked_t.png b/qml/images/mostclicked_t.png new file mode 100644 index 0000000..a28e701 Binary files /dev/null and b/qml/images/mostclicked_t.png differ diff --git a/qml/images/noimg.png b/qml/images/noimg.png new file mode 100644 index 0000000..b71e069 Binary files /dev/null and b/qml/images/noimg.png differ diff --git a/qml/images/timepicker.png b/qml/images/timepicker.png new file mode 100644 index 0000000..b2cab99 Binary files /dev/null and b/qml/images/timepicker.png differ diff --git a/qml/items/HeaderButton.qml b/qml/items/HeaderButton.qml new file mode 100644 index 0000000..c0533e0 --- /dev/null +++ b/qml/items/HeaderButton.qml @@ -0,0 +1,41 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 + +BackgroundItem { + property string headerText: "" + height: label.height + (Theme.paddingLarge * 2) + Label { + id: label + + width: parent.width - image.width + //height: Theme.itemSizeLarge + text: headerText + maximumLineCount: 2 + wrapMode: Text.WordWrap + font.pixelSize: Theme.fontSizeLarge + font.bold: true + //verticalAlignment: Text.AlignVCenter + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + anchors.right: image.left + anchors.rightMargin: Theme.paddingLarge + color: Theme.primaryColor + // visible: radioBrowser.getCountryName(_country) || playedCountries.count > 0 ? true : false + } + Image { + id: image + anchors.right: parent.right + anchors.rightMargin: Theme.paddingLarge + anchors.verticalCenter: label.verticalCenter + source: "image://theme/icon-m-right" + } + Rectangle { + //visible: fill + anchors.fill: parent + gradient: Gradient { + GradientStop { position: 0.0; color: Theme.rgba(Theme.highlightBackgroundColor,0.125) } + GradientStop { position: 1.0; color: "transparent" } + } + } +} diff --git a/qml/items/MediaPlayerPanel.qml b/qml/items/MediaPlayerPanel.qml new file mode 100644 index 0000000..db7da99 --- /dev/null +++ b/qml/items/MediaPlayerPanel.qml @@ -0,0 +1,142 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import "../delegates" +//import "../delegates_" +import "../items" + +DockedPanel { + // property real showP: 0.0 +// property int tab: 0 + id: dock + + // property alias videoSource: videoPlayer.videoSource + + dock: Dock.Bottom + z: 99 + width: parent.width + height: Theme.itemSizeExtraLarge //play.height + (Theme.paddingMedium * 2) + animationDuration: 250 + open: !radioBrowser.loading ? true : false + + // onOpenChanged: if (open) { + // mediaPlayerPanel.videoSource = radioPlayer + // if (radioPlayer.isPlaying || radioPlayer.isPaused && radioPlayer.radioVideo) radioPlayer.resumeStream() + // } + + // onVisibleChanged: if (visible) { + // mediaPlayerPanel.videoSource = radioPlayer + // if (radioPlayer.isPlaying || radioPlayer.isPaused && radioPlayer.radioVideo) radioPlayer.resumeStream() + // } + + // onOpenChanged: open ? videoOn() : videoOff() + + + SilicaItem { + anchors.top: parent.top + width: parent.width + height: Theme.itemSizeExtraLarge + /* VideoPlayer { + id: videoPlayer + z:98 + //anchors.top: orientation === Orientation.Portrait ? stationimage.top : allRadio.top + //anchors.bottom: orientation === Orientation.Portrait ? stationimage.bottom : allRadio.bottom + //anchors.left: orientation === Orientation.Portrait ? stationimage.left : allRadio.left + //anchors.right: orientation === Orientation.Portrait ? stationimage.right : allRadio.right + //anchors.margins: orientation === Orientation.Portrait ? stationimage.border.width : 0 + anchors.fill: stationimage + visible: radioPlayer.isVideo && !radioPlayer.isPaused ? true : false + onVisibleChanged: visible ? enabled=true : enabled = false + // videoSource: radioPlayer//dock.open ? radioPlayer : null + //color: orientation === Orientation.Portrait ? "transparent" : "black" + //videoSource: radioPlayer.videoP ? null : radioPlayer + //videoSource: radioPlayer.playerPageOpen ? null : radioPlayer + } */ + RadioImage { + id: stationimage + // visible: !videoPlayer.visible + height: parent.height * 0.8 //- (Theme.paddingMedium * 2) + width: height + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Theme.paddingMedium + stationImage: radioPlayer._favicon + stationLabel: radioPlayer._name + } + + Item { + id: songInfo + anchors.verticalCenter: stationimage.verticalCenter + height: play.height //- (Theme.paddingMedium * 2) + anchors.leftMargin: Theme.paddingLarge + anchors.rightMargin: Theme.paddingLarge + anchors.left: stationimage.right + anchors.right: play.left + Column { + anchors.verticalCenter: parent.verticalCenter + width: parent.width + Label { + id: rname + font.pixelSize: Theme.fontSizeSmall + elide: Text.ElideRight + width: parent.width + font.bold: true + text: radioPlayer._name + } + Row { + spacing: Theme.paddingMedium + Image { + id: headerLogo + anchors.bottom: rcountry.bottom + height: rcountry.height * 0.8 + fillMode: Image.PreserveAspectFit + smooth: true + source: radioPlayer._countrycode === "" ? radioPlayer._countrycode ? "../images/bycountry_t.png" : "" : "../flags/"+radioPlayer._countrycode.toLowerCase()+".png" + } + Label { + id: rcountry + color: Theme.secondaryColor + font.pixelSize: Theme.fontSizeSmall + width: parent.width + elide: Text.ElideRight + text: radioPlayer.radioCountryName + } + } + } + } + + MouseArea { + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.right: songInfo.right + onClicked: { + // if (radioPlayer.isPlaying && radioPlayer.radioVideo) + //if (radioPlayer.radioVideo) radioPlayer.videoPause() + pageStack.push("../pages/RadioPlayerPage.qml") + } + } + + IconButton { + id: play + anchors.right: parent.right + anchors.rightMargin: Theme.paddingMedium + anchors.verticalCenter: parent.verticalCenter + icon.source: radioPlayer.isPlaying ? "image://theme/icon-l-pause" : "image://theme/icon-l-play" + onClicked: if (radioPlayer.isPlaying) radioPlayer.pauseStream(); else {radioPlayer.resumeStream(); }//if (radioPlayer.radioVideo) pageStack.push("RadioPlayerPage.qml")}//icon.source == "image://theme/icon-l-play" ? icon.source = "image://theme/icon-l-pause" : icon.source = "image://theme/icon-l-play" + } + BusyIndicator { + id: busy + visible: running + anchors.centerIn: play + size: BusyIndicatorSize.Medium + running: radioPlayer.radioStatus===2 + } + + } + + + + + + +} diff --git a/qml/items/QDtimer.qml b/qml/items/QDtimer.qml new file mode 100644 index 0000000..c0e4f42 --- /dev/null +++ b/qml/items/QDtimer.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +// This is my "quick and dirty" solution to fix the initial stuttering when playing a radio station. +// It is not pretty but it works, until there is a better solution (or fix in MediaPlayer. + +Timer { + interval: 100; running: false; repeat: false + onTriggered: playStreamTimer() + + function playStreamTimer() { + source = "" + source = _url_resolved + isPlaying = true + isPaused = false + play() + } +} diff --git a/qml/items/RadioBrowser.qml b/qml/items/RadioBrowser.qml new file mode 100644 index 0000000..a10f9e2 --- /dev/null +++ b/qml/items/RadioBrowser.qml @@ -0,0 +1,162 @@ +// properties: +// ----------- +// server - selected server name) +// serverUrl - Url of the selected server +// stations - Number of stations in selected server +// tags - Number of tags in selected server +// countries - Number of countries in selected server +// count - Number of servers in model +// model - Model containing list of servers (if you want to manually choose server) +// -------------------------------------------------------------------------------- +// functions: +// ---------- +// getList - Refresh the ListModel and add a random url to server +// getRandom - Get a random url from the ListModel and add url to server +// --------------------------------------------------------------------- +import QtQuick 2.0 +import "../models" + +Item { + property string _useragent: "AllRadio/2.0.0 (test) (SailfishOS; Linux) nesnomis@gmail.com" + property int _tags: 0 + property int _countries: 0 + // Properties to be used in application ------------------------------------------------- + property ListModel serversModel : ListModel { id: serversModel } + property ListModel votedModel : ListModel {id: votedModel} + property CountryListModel countriesModel : CountryListModel {id:countriesModel} + //property TagListModel tagsModel : TagListModel {id:tagsModel} + property string serverUrl: "" + property string server: "" + property bool online: false + property bool voted: false + property int stationCount: 0 + property int tagCount: 0 + //property int viewTagCount: tagsModel.maxCount + property int countryCount: 0 + property bool loading: stationCount !== 0 && tagCount !== 0 && countryCount !== 0 ? false : true + property string lookup: "http://all.api.radio-browser.info/json/servers" //"http://all.api.radio-browser.info/json/servers" + + // --------------------------------------------------------------------------------------- + + onOnlineChanged: { + //console.log("onOnlineChanged") + if (online && serverUrl !== "") { + countriesModel.source = serverUrl + "/xml/countrycodes?hidebroken=true" + //tagsModel.source = serverUrl + "/xml/tags?hidebroken=true" + } + } + function getServer(s,u) { + //console.log("getServer") + stationCount = 0 + tagCount = 0 + countryCount = 0 + server = s + serverUrl = u + getStats() + } + + function getRandom() { + //console.log("getRandom") + if (serversModel.count > 0) { + var random = Math.floor((Math.random() * serversModel.count) + 1) - 1 + serverUrl = serversModel.get(random).serverUrl + server = serversModel.get(random).server + //console.log("getRandom: "+server) + getStats() + + } //else getList() + } + + function getList() { + //console.log("getList") + var req = new XMLHttpRequest(); + req.open("get", lookup,true); + req.setRequestHeader('User-Agent',_useragent); + req.timeout = 4000; // Set timeout to 4 seconds (4000 milliseconds) + req.ontimeout = function () { console.log("Timed out!!!"); } + //console.log("server 2") + req.onreadystatechange = function () { + //console.log(console.log("getList: "+req.status)) + if (req.readyState === 4 && req.status === 200) { + var obj = JSON.parse(req.responseText) + serversModel.clear() + for (var key in obj) { + addIfNotExist(obj[key]) + } + getRandom() + } else if (req.readyState === 4 && req.status === 502) lookup="http://de1.api.radio-browser.info/json/servers" + }; + + req.send(); + } + + function addIfNotExist(server) { + for (var i = 0; i < serversModel.count; i++) { + + if (serversModel.get(i).server === server.name) { + return + } + } + serversModel.append({"serverUrl": "http://"+server.name,"server": server.name}) + } + + function getStats() { + //console.log("getStats") + + var req = new XMLHttpRequest(); + req.open("get", serverUrl+"/json/stats",true); + req.setRequestHeader('User-Agent',_useragent); + req.onreadystatechange = function () { + //console.log("XMLHTTPREQUEST READYSTATE: "+req.readyState + " STATUS: "+req.status) + if (req.readyState === 4 && req.status === 200) { + //console.log("STATUS:"+req.status) + var obj = req.response.split("{").pop(); + obj = JSON.parse("{"+obj) + + if (obj.status === "OK") { + stationCount = obj.stations-obj.stations_broken + tagCount = obj.tags + if (obj.status === "OK") {online = true} else {online = false} + } + } else if (req.readyState === 4 && req.status === 502) getRandom() + }; + req.send(); + } + + function upVote(stationuuid,returnValue) { + var req = new XMLHttpRequest(); + var ret = false + req.open("get", serverUrl+"/json/vote/"+stationuuid,true); + req.setRequestHeader('User-Agent',_useragent); + req.onreadystatechange = function () { + //console.log("XMLHTTPREQUEST READYSTATE: "+req.readyState + " STATUS: "+req.status) + if (req.readyState === 4 && req.status === 200) { + var obj = req.response.split("{").pop(); + obj = JSON.parse("{"+obj) + //console.log(obj.ok) + if (obj.ok) { + //stationCount = obj.stations-obj.stations_broken + //tagCount = obj.tags + if (obj.ok) {returnValue=true;console.log(" ****** VOTED *****")} else {returnValue=false;console.log(" ****** NOT VOTED *****")} + } + return ret + + } + }; + req.send(); + + } + + + CountryNameModel {id: countryNameModel} + + function getCountryName(land) { // Get translated countryname + for(var i = 0; i < countryNameModel.count; i++) { + var current = countryNameModel.get(i); + if(land === current.code) { + return countryNameModel.countryname(i) + } + } + } + +} diff --git a/qml/items/RadioPlayer.qml b/qml/items/RadioPlayer.qml new file mode 100644 index 0000000..d265bf5 --- /dev/null +++ b/qml/items/RadioPlayer.qml @@ -0,0 +1,392 @@ +import QtQuick 2.0 +import QtMultimedia 5.6 +import QtQuick.LocalStorage 2.0 + +import "../helpers/jsFunctions.js" as JsFunctions +import "../helpers/db.js" as Favorites +import "../items" + +MediaPlayer { + // Media info from clicking play + property string _stationuuid: "" + property string _name: "" + property string _favicon: "" + property string _countrycode: "" + property string _tags: "" + property string _codec: "" + property string _bitrate: "" + property string _hls: "" + property string _url_resolved: "" + property string _homepage: "" + // property string _votes: "" + // property string _plays: "" + // property string _trend: "" + property bool _favorite: false + //-------------------------------- + // property bool videoP: false + property bool playerPageOpen: false +// property bool jupiiOn: false + property string radioId: "" + property string metaInfo: metaData.title ? metaData.title : "" + property string radioArtist: "" + property string radioSong: "" + property bool radioVideo: false + property bool radioAudio: false + property string radioCountryName + property string radioHLS: JsFunctions.getHLS(_hls) + property string radioCodec: JsFunctions.getCodec(_codec) + property string radioBitrate: JsFunctions.getBitrate(_bitrate) + property real radioBufferProgress: bufferProgress + property int radioStatus + property string radioStatusString + property bool isPlaying: false + property bool isPaused: false + property int stationOk: 3 + property int maxTagClicks: 0 + property int playlistCount: playlist.count - 1 + property int playlistIndex: allradioSettings.value("currentFavorite",-1) + property QDtimer timer: QDtimer {id: qdTimer} + //property string videoOut: "" +// property ListModel mostPlayedFavorites: ListModel {id: mostPlayedFavorites} + //videoOutput: videoOut +// property variant magnitudeArray: null +// property int millisecondsPerBar: 68 + + property ListModel playHistory: ListModel {id: playHistory} + property ListModel playlist: ListModel {id: playlist} + + + autoPlay: false + autoLoad: true + + + //on_FavoriteChanged: {setStationFavorite(_stationuuid,_name,_countrycode,_homepage,_url_resolved,_favicon,_tags,_codec,_bitrate,_hls,_favorite);Favorites.getMostPlayedFavorites(mostPlayedFavorites,15)} + onPlaying: if (!playerPageOpen) pageStack.push("../pages/RadioPlayerPage.qml") + + // onPlaylistIndexChanged: loadPlaylistSelected() + + onMetaInfoChanged: { + // console.log(" ******* METAINFO: "+metaInfo) + if (metaInfo.search(" - ") > -1) { + var res = metaInfo.split(" - ") + radioArtist = res[0] + radioSong = res[1] + } else { + radioArtist = metaInfo + radioSong = "" + } + } + + onRadioAudioChanged: { + // if (hasVideo) console.log(" *** VIDEO"); else console.log(" *** AUDIO") + } + + onStationOkChanged: { + // console.log("StationOK?: "+stationOk) + if (stationOk === 1) { + setStationClick() + getStationFavorite(_stationuuid) + playStream() + stationOk === 0 + reloadDbData() + if (_favorite) allradioSettings.setValue("currentFavorite",playlistIndex) + } + } + + on_StationuuidChanged: { //if (_stationuuid !== "") {getStationUrl(_stationuuid);radioPlayUrl = _url_resolved} else radioPlayUrl = "" + radioCountryName = radioBrowser.getCountryName(_countrycode) + stop() + source = "" + //metaInfo = "" + radioVideo = false + radioAudio = false + isPaused = false + isPlaying = false + stationOk = 3 + getStationUrl(_stationuuid); + } + + //onIsPausedChanged: if (_paused) { + //radioPlaying = false + ///radioPaused = true + // radioSource = "" + // metaInfo = "" + // if(radioVideo) { + // videoPlayer.visible = false + // radioSource = "" + // } + // } + + onHasVideoChanged: if (hasVideo) radioVideo = true + onHasAudioChanged: if (hasAudio) radioAudio = true + + function stopStream() { // stop and clear stream + source = "" + isPaused = false + isPlaying = false + radioArtist = "" + radioSong = "" + radioVideo = false + radioAudio = false + stationOk = 3 + _stationuuid = "" + _name = "" + _favicon = "" + _countrycode = "" + _tags = "" + _codec = "" + _bitrate = "" + _hls = "" + _homepage = "" + stop() + // metaInfo = "" + } + + + function videoPause() { + source = "" + stop() + + } + + + function pauseStream() { // stop stream without clear + + + isPaused = true + isPlaying = false + source = "" + stop() + // metaInfo = "" + } + + function resumeStream() { + isPlaying = true + isPaused = false + playStream() + + } + + + + function playStream() { // resume paused stream + //radioSource = "" + + + source = _url_resolved + play() + isPlaying = true + isPaused = false + qdTimer.start() + // play() + } + + onError: { + notification.category = "Error" + notification.summary = _name + //notification.subText = _name + notification.body = errorString + notification.publish() + radioPlayer.stopStream() + + } + + /* onRadioStatusChanged: { + notification.body = radioStatusString + notification.publish() + }*/ + + + + + onStatusChanged: { + console.log(" ___ STATUS: "+status) + switch (status) { + case 1: status1();break; // NoMedia + case 2: status2();break; // Loading + case 3: status3();break; // Loaded + case 4: status4();break; // Buffering + case 5: status5();break; // Stalled + case 6: status6();break; // Buffered + case 7: status7();break; // EndOfMedia + case 8: status8();break; // InvalidMedia + case 9: status9();break; // UnknownStatus + } + } + function tryagain() { + tryTimer.running = true + } + function status1 () { // NoMedia + radioStatus = status + radioStatusString = "No Media" + console.log("Status: No Media") + } + function status2 () { // Loading + radioStatus = status + radioStatusString = "Loading" + console.log("Status: Loading") + } + function status3 () { // Loaded + radioStatus = status + radioStatusString = "Loaded" + console.log("Status: Loaded") + } + function status4 () { // Buffering + radioStatus = status + radioStatusString = "Buffering" + console.log("Status: Buffering") + } + function status5 () { // Stalled + radioStatus = status + radioStatusString = "Stalled" + notification.category = "Status" + notification.summary = _name + //notification.subText = _name + notification.body = "Stalled" + notification.publish() + console.log("Status: Stalled") + radioPlayer.stopStream() + } + function status6 () { // Buffered + radioStatus = status + radioStatusString = "Buffered" + console.log("Status: Buffered") + } + function status7 () { // EndOfMedia + /* if (errorCount<4) { + //errorCount = errorCount + 1 + tryTimer.start() + }else{ */ + radioStatus = status + radioStatusString = "End Of Media" + notification.category = "Status" + notification.summary = _name + //notification.subText = _name + notification.body = "End of media" + notification.publish() + console.log("Status: End Of Media") + radioPlayer.stopStream() + // } + } + function status8 () { // InvalidMedia + radioStatus = status + radioStatusString = "Invalid Media" + notification.category = "Status" + notification.summary = _name + //notification.subText = _name + notification.body = "Invalid media" + notification.publish() + console.log("Status: Invalid Media") + radioPlayer.stopStream() + } + function status9 () { // UnknownStatus + radioStatus = status + radioStatusString = "Unknown Status" + console.log("Status: Unknown Status") + } + + function getStationUrl(id) { // Register as radio station click on community radio and get station info from Community Radio and save it to Db. Initiate playback. + var req = new XMLHttpRequest(); + req.open("post", radioBrowser.serverUrl + "/xml/url/" +id, true); + // console.log(radioBrowser.serverUrl) + req.responseType = "document"; + req.setRequestHeader('User-Agent',radioBrowser._useragent); + req.onreadystatechange = function () { + if (req.readyState === 4 && req.status === 200) { + var temp = req.responseText + var ok = temp.indexOf('status ok="true"') !== -1 + // console.log("OK: "+ok) + if (ok) { + stationOk = 1 + } else { + stationOk = 0 + } + } //else if (req.readyState === 4) {stationOk = 2} + }; + req.send(); + } + function setStationClick() { + //getStationFavorite(_stationuuid) + Favorites.setStationClicked(JsFunctions.getTimeStamp(),_stationuuid,_name,_countrycode,_homepage,_url_resolved,_favicon,_tags,_codec,_bitrate,_hls,_favorite) + + // property bool favo: isFavorite(stationuuid) ? true : false + + //getIfFavorite(_stationuuid) + //getIfFavorite(_stationuuid) + } // myclicktimestamp,id,name,countrycode,homepage,radiourlresolved,favicon,tagslist,codec,bitrate,hls,favorite + function setStationFavorite(stationuuid,name,countrycode,homepage,url_resolved,favicon,tags,codec,bitrate,hls,favorite) { + Favorites.setStationFavorite(stationuuid,name,countrycode,homepage,url_resolved,favicon,tags,codec,bitrate,hls,favorite) + } + function getStationFavorite(id){ + _favorite = Favorites.getStationFavorite(id) + } + + function reloadDbData() { + Favorites.getStationRecentClicked(playHistory,15) + Favorites.getFavorites(playlist,"name",10000) + //Favorites.getStationMostClickedFav(radioPlayermostPlayed,settings._nrOfFavoritePreview) + //Favorites.getCountryRecentClicked(playedCountries,2) + //Favorites.getTagsRecentClicked(playedTags,10) + //Favorites.getMostPlayedFavorites(mostPlayedFavorites,15) + } + function loadPlaylistSelected(){ + if (playlist.get(playlistIndex).url_resolved) { + _favicon = playlist.get(playlistIndex).favicon + _name = playlist.get(playlistIndex).name + _countrycode = playlist.get(playlistIndex).countrycode + _tags = playlist.get(playlistIndex).tags + _codec = playlist.get(playlistIndex).codec//getCodec(model.codec) + _bitrate = playlist.get(playlistIndex).bitrate //getBitrate(model.bitrate) + _hls = playlist.get(playlistIndex).hls + _url_resolved = playlist.get(playlistIndex).url_resolved + _homepage = playlist.get(playlistIndex).homepage + _stationuuid = playlist.get(playlistIndex).stationuuid + _favorite = playlist.get(playlistIndex).favorite + isPlaying = true + isPaused = false + playStream() + // pageStack.push("RadioPlayerPage.qml") + } + } + function loadRecentPlay(){ + if (playHistory.get(0).url_resolved) { + _favicon = playHistory.get(0).favicon + _name = playHistory.get(0).name + _countrycode = playHistory.get(0).countrycode + _tags = playHistory.get(0).tags + _codec = playHistory.get(0).codec//getCodec(model.codec) + _bitrate = playHistory.get(0).bitrate //getBitrate(model.bitrate) + _hls = playHistory.get(0).hls + _url_resolved = playHistory.get(0).url_resolved + _homepage = playHistory.get(0).homepage + _stationuuid = playHistory.get(0).stationuuid + _favorite = playHistory.get(0).favorite + isPlaying = false + isPaused = true + // pageStack.push("RadioPlayerPage.qml") + } + } + function loadRandomPlay(){ + var rnd = Math.floor(Math.random() * playlistCount) + if (playHistory.get(rnd).url_resolved) { + _favicon = playHistory.get(rnd).favicon + _name = playHistory.get(rnd).name + _countrycode = playHistory.get(rnd).countrycode + _tags = playHistory.get(rnd).tags + _codec = playHistory.get(rnd).codec//getCodec(model.codec) + _bitrate = playHistory.get(rnd).bitrate //getBitrate(model.bitrate) + _hls = playHistory.get(rnd).hls + _url_resolved = playHistory.get(rnd).url_resolved + _homepage = playHistory.get(rnd).homepage + _stationuuid = playHistory.get(rnd).stationuuid + _favorite = playHistory.get(rnd).favorite + isPlaying = false + isPaused = true + // pageStack.push("RadioPlayerPage.qml") + } + } + + + Component.onCompleted: {reloadDbData();loadRecentPlay()} +} + diff --git a/qml/items/ScreenBlank.qml b/qml/items/ScreenBlank.qml new file mode 100644 index 0000000..cf3ef39 --- /dev/null +++ b/qml/items/ScreenBlank.qml @@ -0,0 +1,40 @@ +import QtQuick 2.0 +import Nemo.DBus 2.0 + +Item { + property bool enabled: false + function request(){ + var method = "req_display"+(enabled?"":"_cancel")+"_blanking_pause"; + dbif.call(method, []) + } + + onEnabledChanged: { + request(); + } + + DBusInterface { + id: dbif + + service: "com.nokia.mce" + path: "/com/nokia/mce/request" + iface: "com.nokia.mce.request" + + bus: DBusInterface.SystemBus + } + Timer { + running: parent.enabled + interval: 15000 + repeat: true + onTriggered: { + if(parent.enabled) { + parent.request() + } + } + } + + Component.onDestruction: { + if(enabled){ + enabled=false + } + } +} diff --git a/qml/items/SleepTimer.qml b/qml/items/SleepTimer.qml new file mode 100644 index 0000000..b2bba66 --- /dev/null +++ b/qml/items/SleepTimer.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Timer { + id: sleepTimer + interval: 60000 + repeat: false + onTriggered: { + if (sleepTime == 1) { radioPlayer.pauseStream();sleepTime = 0;} else sleepTime = (sleepTime = sleepTime -1); + } + running: sleepTime > 0 +} diff --git a/qml/items/Splash.qml b/qml/items/Splash.qml new file mode 100644 index 0000000..a06fb6f --- /dev/null +++ b/qml/items/Splash.qml @@ -0,0 +1,41 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 +//import "../helpers/jsFunctions.js" as JS + +Column { + id: column + spacing: Theme.paddingMedium + //property alias busy: busyIndicator.running + anchors.centerIn: parent + + Image { + id: logo + anchors.horizontalCenter: parent.horizontalCenter + height: Theme.itemSizeHuge * 1.5 + width: height + smooth: true + source: "../images/community.png" + ColorOverlay { + anchors.fill: parent + source: parent + color: Theme.highlightColor + } + } + + Label { + text: radioBrowser.serversModel.count > 0 ? "Found: "+radioBrowser.serversModel.count + " servers" : "Searching for servers..." + anchors.horizontalCenter: parent.horizontalCenter + } + Label { + visible: radioBrowser.serversModel.count > 0 + text: "Connecting to:" + anchors.horizontalCenter: parent.horizontalCenter + } + Label { + text: radioBrowser.server + font.pixelSize: Theme.fontSizeSmall + color: Theme.highlightColor + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/qml/items/ValuePicker.qml b/qml/items/ValuePicker.qml new file mode 100644 index 0000000..df6f7e7 --- /dev/null +++ b/qml/items/ValuePicker.qml @@ -0,0 +1,175 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 + +// TODO: Investigate using one quarter of the image mirrored in two directions +// TODO: Investigate using a scaled down version of the image + +Item { + id: valuePicker + + property int value + property int max + property int min + + property real _scaleRatio: valueCircle.width / 408 + + width: valueCircle.width + height: valueCircle.height + + onValueChanged: { + value = (value < 1 ? 1 : (value > max ? max : value)) + + if (mouse.changingProperty == 0) { + var delta = (value - valueIndicator.value) + valueIndicator.value += (delta % (max - 1)) + } + } + + function _xTranslation(value, bound) { + // Use sine to map range of 0-bound to the X translation of a circular locus (-1 to 1) + return Math.sin((value % bound) / bound * Math.PI * 2) + } + + function _yTranslation(value, bound) { + // Use cosine to map range of 0-bound to the Y translation of a circular locus (-1 to 1) + return Math.cos((value % bound) / bound * Math.PI * 2) + } + + Image { + id: valueCircle + width: page.width * 0.75 + height: width + source: "../images/timepicker.png" + opacity: 0.2 + } + + GlassItem { + id: valueIndicator + falloffRadius: 0.22 + radius: 0.25 + anchors.centerIn: valueCircle + color: mouse.changingProperty == 2 ? Theme.highlightColor : Theme.primaryColor + + property real value + + transform: Translate { + // The ss band is 72px wide, ending at 204px from the center + x: _scaleRatio*168 * _xTranslation(valueIndicator.value, max) + y: -_scaleRatio*168 * _yTranslation(valueIndicator.value, max) + } + + Behavior on value { + id: valueAnimation + SmoothedAnimation { velocity: 80 } + enabled: !mouse.isMoving || mouse.isLagging + } + } + + MouseArea { + id: mouse + + property int changingProperty + property bool isMoving + property bool isLagging + + anchors.fill: parent + preventStealing: true + + function radiusForCoord(x, y) { + // Return the distance from the mouse position to the center + return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) + } + + function angleForCoord(x, y) { + // Return the angular position in degrees, rising anticlockwise from the positive X-axis + var result = Math.atan(y / x) / (Math.PI * 2) * 360 + + // Adjust for various quadrants + if (x < 0) { + result += 180 + } else if (y < 0) { + result += 360 + } + return result + } + + function remapAngle(value, bound) { + // Return the angle in degrees mapped to the adjusted range 0 - (bound-1) and + // translated to the clockwise from positive Y-axis orientation + return Math.round(bound - (((value - 90) / 360) * bound)) % bound + } + + function remapMouse(mouseX, mouseY) { + // Return the mouse coordinates in cartesian coords relative to the circle center + return { x: mouseX - (width / 2), y: 0 - (mouseY - (height / 2)) } + } + + function propertyForRadius(radius) { + // Return the property associated with clicking at radius distance from the center + if (radius < mouse.width / 2) { + return 2 // Minutes + } + return 0 + } + + function updateForAngle(angle) { + // Update the selected property for the specified angular position + // Minutes + // Map angular position to 0-59 + var m = remapAngle(angle, max) + + // Round single touch to the nearest 5 min mark + if (!isMoving) m = (Math.round(m/5) * 5) % (max - 1) + + var delta = (m - valueIndicator.value) % (max - 1) + + // It is not possible to make jumps of more than 30 minutes - reverse the direction + if (delta > 60) { + delta -= max + } else if (delta < -60) { + delta += max + } + if (isMoving && isLagging) { + if (Math.abs(delta) < 2) { + isLagging = false + } + } + + valueIndicator.value += delta + + valuePicker.value = m + } + + onPressed: { + console.log("PRESSED") + var coords = remapMouse(mouseX, mouseY) + var radius = radiusForCoord(coords.x, coords.y) + + changingProperty = propertyForRadius(radius) + if (changingProperty != 0) { + preventStealing = true + var angle = angleForCoord(coords.x, coords.y) + + isLagging = true + updateForAngle(angle) + } else { + // Outside the minutes band - allow pass through to underlying component + preventStealing = false + } + } + onPositionChanged: { + if (changingProperty > 0) { + var coords = remapMouse(mouseX, mouseY) + var angle = angleForCoord(coords.x, coords.y) + + isMoving = true + updateForAngle(angle) + } + } + onReleased: { + changingProperty = 0 + isMoving = false + isLagging = false + } + } +} diff --git a/qml/items/VideoPlayer.qml b/qml/items/VideoPlayer.qml new file mode 100644 index 0000000..ab835f0 --- /dev/null +++ b/qml/items/VideoPlayer.qml @@ -0,0 +1,75 @@ +import QtQuick 2.0 +import QtMultimedia 5.6 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 + +Rectangle { + id: videoRect + //property bool keepScreenOn: Qt.application.active && visible ? true : false + property bool stateVisible: radioPlayer.radioVideo && radioPlayer.isPlaying + property alias videoSource: output.source + //property alias source: output.source + opacity: 0 + color: "black" + + //JupiiItem {id: jupii} + + onOpacityChanged: { + opacity === 0 ? visible = false : visible = true + } + + states: [ + State { when: videoRect.stateVisible; + PropertyChanges { target: videoRect; opacity: 1.0 }}, + State { when: !videoRect.stateVisible; + PropertyChanges { target: videoRect; opacity: 0.0 }} + ] + + transitions: [ Transition { NumberAnimation { property: "opacity"; duration: 500}} ] + + /* ScreenBlank { + id: screenBlank + enabled: keepScreenOn + } */ + + MouseArea { + anchors.fill: parent + onClicked: videoOverlay.stateVisible = !videoOverlay.stateVisible + } + + VideoOutput { + id: output + anchors.fill: parent + source: null + fillMode: VideoOutput.PreserveAspectFit + } + + /* Timer { + interval: 5000; running: videoOverlay.visible ; repeat: false + onTriggered: videoOverlay.stateVisible = false + } */ + + Item { + id: videoOverlay + anchors.fill: parent + visible: false + + property bool stateVisible: true + + opacity: 1 + onOpacityChanged: { + opacity === 0 ? visible = false : visible = true + } + + states: [ + State { when: videoOverlay.stateVisible; + PropertyChanges { target: videoOverlay; opacity: 1.0 }}, + State { when: !videoOverlay.stateVisible; + PropertyChanges { target: videoOverlay; opacity: 0.0 }} + ] + transitions: [ Transition { NumberAnimation { property: "opacity"; duration: 250}} ] + } + // Component.onCompleted: {playerPanel.open = false;radioPlayer.videoPlayerPageOpen=true;} + // Component.onDestruction: radioPlayer.videoPlayerPageOpen=false //Component.onDestruction: {if (radioPlayer.radioPlaying) playerPanel.open = true;radioPlayer.radioPlayerPageOpen = false} +} + diff --git a/qml/models/AdvancedSearchModel.qml b/qml/models/AdvancedSearchModel.qml new file mode 100644 index 0000000..8d2c783 --- /dev/null +++ b/qml/models/AdvancedSearchModel.qml @@ -0,0 +1,61 @@ +import QtQuick 2.0 +import QtQuick.XmlListModel 2.0 + +XmlListModel { + property bool finished: true + property bool clear: false + property ListModel stationsModel: ListModel {id: stationsModel} + + // onFinishedChanged: console.log("*** FINISHED: "+finished+" ***") + + //onClearChanged: if (clear) {stationsModel.clear()} + + query: "/result/station" + XmlRole { name: "stationuuid"; query: "@stationuuid/string()" } + XmlRole { name: "name"; query: "@name/string()" } + XmlRole { name: "homepage"; query: "@homepage/string()" } + XmlRole { name: "favicon"; query: "@favicon/string()" } + XmlRole { name: "tags"; query: "@tags/string()" } + XmlRole { name: "codec"; query: "@codec/string()" } + XmlRole { name: "bitrate"; query: "@bitrate/string()" } + XmlRole { name: "hls"; query: "@hls/string()" } + XmlRole { name: "url_resolved"; query: "@url_resolved/string()" } + XmlRole { name: "country"; query: "@country/string()" } + XmlRole { name: "countrycode"; query: "@countrycode/string()" } + XmlRole { name: "votes"; query: "@votes/string()" } + XmlRole { name: "clicktrend"; query: "@clicktrend/string()" } + XmlRole { name: "clickcount"; query: "@clickcount/string()" } + XmlRole { name: "lastcheckok"; query: "@lastcheckok/string()" } + + onStatusChanged: { + if (status === XmlListModel.Ready) {addToModel()} + if (status === XmlListModel.Loading) finished = false; + if (status === XmlListModel.Error) finished = true + if (status === XmlListModel.Null) finished = true + } + + function addToModel() { + for(var i = 0; i < count; i++) { + stationsModel.append({ + "stationuuid" : get(i).stationuuid, + "name" : get(i).name, + "homepage" : get(i).homepage, + "favicon" : get(i).favicon, + "tags" : get(i).tags, + "codec" : get(i).codec, + "bitrate" : get(i).bitrate, + "hls" : get(i).hls, + "url_resolved" : get(i).url_resolved, + "country" : get(i).country, + "countrycode" : get(i).countrycode, + "votes" : get(i).votes, + "clicktrend" : get(i).clicktrend, + "clickcount" : get(i).clickcount, + "lastcheckok" : get(i).lastcheckok + }) + } + finished = true + // console.log(" ***** APPENDED ******") + } +} + diff --git a/qml/models/CountryListModel.qml b/qml/models/CountryListModel.qml new file mode 100644 index 0000000..ebf01db --- /dev/null +++ b/qml/models/CountryListModel.qml @@ -0,0 +1,69 @@ +import QtQuick 2.0 +import QtQuick.XmlListModel 2.0 + +Item { + property bool running: true + property string filter: "" + property alias countryModel: countryModel + property alias source: xmlModel.source + + function addtomodel(){ + countryModel.clear() + var cname + var filt + for(var i = 0; i < xmlModel.count; i++) { + cname = getCountryName(xmlModel.get(i).name) + //if (cname) filt = cname.toLowerCase() + if (cname) {filt = cname.toLowerCase(); if (filt.indexOf(filter) !== -1) countryModel.append({"name" : cname, "alpha_2" : xmlModel.get(i).name,"stationcount" : xmlModel.get(i).stationcount})} + //console.log(cname) + } + countryModel.listModelSort(countryModel, compareElements) + //numberOfCountries = i + countryCount = countryModel.count + // console.log("COUNTRIESMODEL DONE: "+countryModel.count) + running = false + } + + function compareElements(elem1, elem2) { + return elem1.name.localeCompare(elem2.name) + } + + ListModel { + id: countryModel + function listModelSort(listModel, compareFunc) { + var indexes = new Array(listModel.count); + for (var i = 0; i < listModel.count; i++) indexes[i] = i; + indexes.sort(function (indexA, indexB) { return compareFunc(get(indexA), get(indexB)) } ); + var sorted = 0; + while (sorted < indexes.length && sorted === indexes[sorted]) sorted++; + if (sorted === indexes.length) return; + for (i = sorted; i < indexes.length; i++) { + var idx = indexes[i]; + listModel.move(idx, listModel.count - 1, 1); + listModel.insert(idx, { } ); + } + listModel.remove(sorted, indexes.length - sorted); + } + } + + XmlListModel { + id: xmlModel + query: "/result/countrycode" + //source: radioServers.serverUrl + type + "/countrycodes?hidebroken=true" + + XmlRole { name: "name"; query: "@name/string()" } + XmlRole { name: "stationcount"; query: "@stationcount/string()" } + + onStatusChanged: { + //if (status === XmlListModel.Loading) loadingInfo = "Preloading countries" + if (status === XmlListModel.Ready) { + addtomodel() + running = false + } + //if (status === XmlListModel.Loading) running = true; + } + } + + onFilterChanged: addtomodel() +} + diff --git a/qml/models/CountryNameModel.qml b/qml/models/CountryNameModel.qml new file mode 100644 index 0000000..6ed5e32 --- /dev/null +++ b/qml/models/CountryNameModel.qml @@ -0,0 +1,517 @@ +import QtQuick 2.0 + +ListModel { + id: countryNameModel + ListElement {code: "AF"} + ListElement {code: "AX"} + ListElement {code: "AL"} + ListElement {code: "DZ"} + ListElement {code: "AS"} + ListElement {code: "AD"} + ListElement {code: "AO"} + ListElement {code: "AI"} + ListElement {code: "AQ"} + ListElement {code: "AG"} + ListElement {code: "AR"} + ListElement {code: "AM"} + ListElement {code: "AW"} + ListElement {code: "AU"} + ListElement {code: "AT"} + ListElement {code: "AZ"} + ListElement {code: "BS"} + ListElement {code: "BH"} + ListElement {code: "BD"} + ListElement {code: "BB"} + ListElement {code: "BY"} + ListElement {code: "BE"} + ListElement {code: "BZ"} + ListElement {code: "BJ"} + ListElement {code: "BM"} + ListElement {code: "BT"} + ListElement {code: "BO"} + ListElement {code: "BA"} + ListElement {code: "BW"} + ListElement {code: "BV"} + ListElement {code: "BR"} + ListElement {code: "IO"} + ListElement {code: "VG"} + ListElement {code: "BN"} + ListElement {code: "BG"} + ListElement {code: "BF"} + ListElement {code: "BI"} + ListElement {code: "KH"} + ListElement {code: "CM"} + ListElement {code: "CA"} + ListElement {code: "CV"} + ListElement {code: "BQ"} + ListElement {code: "KY"} + ListElement {code: "CF"} + ListElement {code: "TD"} + ListElement {code: "CL"} + ListElement {code: "CN"} + ListElement {code: "CX"} + ListElement {code: "CC"} + ListElement {code: "CO"} + ListElement {code: "KM"} + ListElement {code: "CG"} + ListElement {code: "CD"} + ListElement {code: "CK"} + ListElement {code: "CR"} + ListElement {code: "CI"} + ListElement {code: "HR"} + ListElement {code: "CU"} + ListElement {code: "CW"} + ListElement {code: "CY"} + ListElement {code: "CZ"} + ListElement {code: "DK"} + ListElement {code: "DJ"} + ListElement {code: "DM"} + ListElement {code: "DO"} + ListElement {code: "EC"} + ListElement {code: "EG"} + ListElement {code: "SV"} + ListElement {code: "GQ"} + ListElement {code: "ER"} + ListElement {code: "EE"} + ListElement {code: "SZ"} + ListElement {code: "ET"} + ListElement {code: "FK"} + ListElement {code: "FO"} + ListElement {code: "FJ"} + ListElement {code: "FI"} + ListElement {code: "FR"} + ListElement {code: "GF"} + ListElement {code: "PF"} + ListElement {code: "TF"} + ListElement {code: "GA"} + ListElement {code: "GM"} + ListElement {code: "GE"} + ListElement {code: "DE"} + ListElement {code: "GH"} + ListElement {code: "GI"} + ListElement {code: "GR"} + ListElement {code: "GL"} + ListElement {code: "GD"} + ListElement {code: "GP"} + ListElement {code: "GU"} + ListElement {code: "GT"} + ListElement {code: "GG"} + ListElement {code: "GN"} + ListElement {code: "GW"} + ListElement {code: "GY"} + ListElement {code: "HT"} + ListElement {code: "HM"} + ListElement {code: "HN"} + ListElement {code: "HK"} + ListElement {code: "HU"} + ListElement {code: "IS"} + ListElement {code: "IN"} + ListElement {code: "ID"} + ListElement {code: "IR"} + ListElement {code: "IQ"} + ListElement {code: "IE"} + ListElement {code: "IM"} + ListElement {code: "IL"} + ListElement {code: "IT"} + ListElement {code: "JM"} + ListElement {code: "JP"} + ListElement {code: "JE"} + ListElement {code: "JO"} + ListElement {code: "KZ"} + ListElement {code: "KE"} + ListElement {code: "KI"} + ListElement {code: "KW"} + ListElement {code: "KG"} + ListElement {code: "LA"} + ListElement {code: "LV"} + ListElement {code: "LB"} + ListElement {code: "LS"} + ListElement {code: "LR"} + ListElement {code: "LY"} + ListElement {code: "LI"} + ListElement {code: "LT"} + ListElement {code: "LU"} + ListElement {code: "MO"} + ListElement {code: "MG"} + ListElement {code: "MW"} + ListElement {code: "MY"} + ListElement {code: "MV"} + ListElement {code: "ML"} + ListElement {code: "MT"} + ListElement {code: "MH"} + ListElement {code: "MQ"} + ListElement {code: "MR"} + ListElement {code: "MU"} + ListElement {code: "YT"} + ListElement {code: "MX"} + ListElement {code: "FM"} + ListElement {code: "MD"} + ListElement {code: "MC"} + ListElement {code: "MN"} + ListElement {code: "ME"} + ListElement {code: "MS"} + ListElement {code: "MA"} + ListElement {code: "MZ"} + ListElement {code: "MM"} + ListElement {code: "NA"} + ListElement {code: "NR"} + ListElement {code: "NP"} + ListElement {code: "NL"} + ListElement {code: "NC"} + ListElement {code: "NZ"} + ListElement {code: "NI"} + ListElement {code: "NE"} + ListElement {code: "NG"} + ListElement {code: "NU"} + ListElement {code: "NF"} + ListElement {code: "KP"} + ListElement {code: "MK"} + ListElement {code: "MP"} + ListElement {code: "NO"} + ListElement {code: "OM"} + ListElement {code: "PK"} + ListElement {code: "PW"} + ListElement {code: "PS"} + ListElement {code: "PA"} + ListElement {code: "PG"} + ListElement {code: "PY"} + ListElement {code: "PE"} + ListElement {code: "PH"} + ListElement {code: "PN"} + ListElement {code: "PL"} + ListElement {code: "PT"} + ListElement {code: "PR"} + ListElement {code: "QA"} + ListElement {code: "RE"} + ListElement {code: "RO"} + ListElement {code: "RU"} + ListElement {code: "RW"} + ListElement {code: "WS"} + ListElement {code: "SM"} + ListElement {code: "ST"} + ListElement {code: "SA"} + ListElement {code: "SN"} + ListElement {code: "RS"} + ListElement {code: "SC"} + ListElement {code: "SL"} + ListElement {code: "SG"} + ListElement {code: "SX"} + ListElement {code: "SK"} + ListElement {code: "SI"} + ListElement {code: "SB"} + ListElement {code: "SO"} + ListElement {code: "ZA"} + ListElement {code: "GS"} + ListElement {code: "KR"} + ListElement {code: "SS"} + ListElement {code: "ES"} + ListElement {code: "LK"} + ListElement {code: "BL"} + ListElement {code: "SH"} + ListElement {code: "KN"} + ListElement {code: "LC"} + ListElement {code: "MF"} + ListElement {code: "PM"} + ListElement {code: "VC"} + ListElement {code: "SD"} + ListElement {code: "SR"} + ListElement {code: "SJ"} + ListElement {code: "SE"} + ListElement {code: "CH"} + ListElement {code: "SY"} + ListElement {code: "TW"} + ListElement {code: "TJ"} + ListElement {code: "TZ"} + ListElement {code: "TH"} + ListElement {code: "TL"} + ListElement {code: "TG"} + ListElement {code: "TK"} + ListElement {code: "TO"} + ListElement {code: "TT"} + ListElement {code: "TN"} + ListElement {code: "TR"} + ListElement {code: "TM"} + ListElement {code: "TC"} + ListElement {code: "TV"} + ListElement {code: "UM"} + ListElement {code: "VI"} + ListElement {code: "UG"} + ListElement {code: "UA"} + ListElement {code: "AE"} + ListElement {code: "GB"} + ListElement {code: "US"} + ListElement {code: "UY"} + ListElement {code: "UZ"} + ListElement {code: "VU"} + ListElement {code: "VA"} + ListElement {code: "VE"} + ListElement {code: "VN"} + ListElement {code: "WF"} + ListElement {code: "EH"} + ListElement {code: "YE"} + ListElement {code: "ZM"} + ListElement {code: "ZW"} + ListElement {code: "XK"} + ListElement {code: "ZZXX"} + + // Workaround to be able to use qsTr for translating the country names (qsTr doesn't work in ListModel/ListElement ... :( ..) + function countryname(index) { + if (countryname["text"] === undefined) { + countryname.text = [ + qsTr("Afghanistan"), + qsTr("Åland Islands"), + qsTr("Albania"), + qsTr("Algeria"), + qsTr("American Samoa"), + qsTr("Andorra"), + qsTr("Angola"), + qsTr("Anguilla"), + qsTr("Antarctica"), + qsTr("Antigua & Barbuda"), + qsTr("Argentina"), + qsTr("Armenia"), + qsTr("Aruba"), + qsTr("Australia"), + qsTr("Austria"), + qsTr("Azerbaijan"), + qsTr("Bahamas"), + qsTr("Bahrain"), + qsTr("Bangladesh"), + qsTr("Barbados"), + qsTr("Belarus"), + qsTr("Belgium"), + qsTr("Belize"), + qsTr("Benin"), + qsTr("Bermuda"), + qsTr("Bhutan"), + qsTr("Bolivia"), + qsTr("Bosnia & Herzegovina"), + qsTr("Botswana"), + qsTr("Bouvet Island"), + qsTr("Brazil"), + qsTr("British Indian Ocean Territory"), + qsTr("British Virgin Islands"), + qsTr("Brunei"), + qsTr("Bulgaria"), + qsTr("Burkina Faso"), + qsTr("Burundi"), + qsTr("Cambodia"), + qsTr("Cameroon"), + qsTr("Canada"), + qsTr("Cape Verde"), + qsTr("Caribbean Netherlands"), + qsTr("Cayman Islands"), + qsTr("Central African Republic"), + qsTr("Chad"), + qsTr("Chile"), + qsTr("China"), + qsTr("Christmas Island"), + qsTr("Cocos (Keeling) Islands"), + qsTr("Colombia"), + qsTr("Comoros"), + qsTr("Congo - Brazzaville"), + qsTr("Congo - Kinshasa"), + qsTr("Cook Islands"), + qsTr("Costa Rica"), + qsTr("Côte d’Ivoire"), + qsTr("Croatia"), + qsTr("Cuba"), + qsTr("Curaçao"), + qsTr("Cyprus"), + qsTr("Czechia"), + qsTr("Denmark"), + qsTr("Djibouti"), + qsTr("Dominica"), + qsTr("Dominican Republic"), + qsTr("Ecuador"), + qsTr("Egypt"), + qsTr("El Salvador"), + qsTr("Equatorial Guinea"), + qsTr("Eritrea"), + qsTr("Estonia"), + qsTr("Eswatini"), + qsTr("Ethiopia"), + qsTr("Falkland Islands"), + qsTr("Faroe Islands"), + qsTr("Fiji"), + qsTr("Finland"), + qsTr("France"), + qsTr("French Guiana"), + qsTr("French Polynesia"), + qsTr("French Southern Territories"), + qsTr("Gabon"), + qsTr("Gambia"), + qsTr("Georgia"), + qsTr("Germany"), + qsTr("Ghana"), + qsTr("Gibraltar"), + qsTr("Greece"), + qsTr("Greenland"), + qsTr("Grenada"), + qsTr("Guadeloupe"), + qsTr("Guam"), + qsTr("Guatemala"), + qsTr("Guernsey"), + qsTr("Guinea"), + qsTr("Guinea-Bissau"), + qsTr("Guyana"), + qsTr("Haiti"), + qsTr("Heard & McDonald Islands"), + qsTr("Honduras"), + qsTr("Hong Kong SAR China"), + qsTr("Hungary"), + qsTr("Iceland"), + qsTr("India"), + qsTr("Indonesia"), + qsTr("Iran"), + qsTr("Iraq"), + qsTr("Ireland"), + qsTr("Isle of Man"), + qsTr("Israel"), + qsTr("Italy"), + qsTr("Jamaica"), + qsTr("Japan"), + qsTr("Jersey"), + qsTr("Jordan"), + qsTr("Kazakhstan"), + qsTr("Kenya"), + qsTr("Kiribati"), + qsTr("Kuwait"), + qsTr("Kyrgyzstan"), + qsTr("Laos"), + qsTr("Latvia"), + qsTr("Lebanon"), + qsTr("Lesotho"), + qsTr("Liberia"), + qsTr("Libya"), + qsTr("Liechtenstein"), + qsTr("Lithuania"), + qsTr("Luxembourg"), + qsTr("Macao SAR China"), + qsTr("Madagascar"), + qsTr("Malawi"), + qsTr("Malaysia"), + qsTr("Maldives"), + qsTr("Mali"), + qsTr("Malta"), + qsTr("Marshall Islands"), + qsTr("Martinique"), + qsTr("Mauritania"), + qsTr("Mauritius"), + qsTr("Mayotte"), + qsTr("Mexico"), + qsTr("Micronesia"), + qsTr("Moldova"), + qsTr("Monaco"), + qsTr("Mongolia"), + qsTr("Montenegro"), + qsTr("Montserrat"), + qsTr("Morocco"), + qsTr("Mozambique"), + qsTr("Myanmar (Burma)"), + qsTr("Namibia"), + qsTr("Nauru"), + qsTr("Nepal"), + qsTr("Netherlands"), + qsTr("New Caledonia"), + qsTr("New Zealand"), + qsTr("Nicaragua"), + qsTr("Niger"), + qsTr("Nigeria"), + qsTr("Niue"), + qsTr("Norfolk Island"), + qsTr("North Korea"), + qsTr("North Macedonia"), + qsTr("Northern Mariana Islands"), + qsTr("Norway"), + qsTr("Oman"), + qsTr("Pakistan"), + qsTr("Palau"), + qsTr("Palestinian Territories"), + qsTr("Panama"), + qsTr("Papua New Guinea"), + qsTr("Paraguay"), + qsTr("Peru"), + qsTr("Philippines"), + qsTr("Pitcairn Islands"), + qsTr("Poland"), + qsTr("Portugal"), + qsTr("Puerto Rico"), + qsTr("Qatar"), + qsTr("Réunion"), + qsTr("Romania"), + qsTr("Russia"), + qsTr("Rwanda"), + qsTr("Samoa"), + qsTr("San Marino"), + qsTr("São Tomé & Príncipe"), + qsTr("Saudi Arabia"), + qsTr("Senegal"), + qsTr("Serbia"), + qsTr("Seychelles"), + qsTr("Sierra Leone"), + qsTr("Singapore"), + qsTr("Sint Maarten"), + qsTr("Slovakia"), + qsTr("Slovenia"), + qsTr("Solomon Islands"), + qsTr("Somalia"), + qsTr("South Africa"), + qsTr("South Georgia & South Sandwich Islands"), + qsTr("South Korea"), + qsTr("South Sudan"), + qsTr("Spain"), + qsTr("Sri Lanka"), + qsTr("St. Barthélemy"), + qsTr("St. Helena"), + qsTr("St. Kitts & Nevis"), + qsTr("St. Lucia"), + qsTr("St. Martin"), + qsTr("St. Pierre & Miquelon"), + qsTr("St. Vincent & Grenadines"), + qsTr("Sudan"), + qsTr("Suriname"), + qsTr("Svalbard & Jan Mayen"), + qsTr("Sweden"), + qsTr("Switzerland"), + qsTr("Syria"), + qsTr("Taiwan"), + qsTr("Tajikistan"), + qsTr("Tanzania"), + qsTr("Thailand"), + qsTr("Timor-Leste"), + qsTr("Togo"), + qsTr("Tokelau"), + qsTr("Tonga"), + qsTr("Trinidad & Tobago"), + qsTr("Tunisia"), + qsTr("Turkey"), + qsTr("Turkmenistan"), + qsTr("Turks & Caicos Islands"), + qsTr("Tuvalu"), + qsTr("U.S. Outlying Islands"), + qsTr("U.S. Virgin Islands"), + qsTr("Uganda"), + qsTr("Ukraine"), + qsTr("United Arab Emirates"), + qsTr("United Kingdom"), + qsTr("United States"), + qsTr("Uruguay"), + qsTr("Uzbekistan"), + qsTr("Vanuatu"), + qsTr("Vatican City"), + qsTr("Venezuela"), + qsTr("Vietnam"), + qsTr("Wallis & Futuna"), + qsTr("Western Sahara"), + qsTr("Yemen"), + qsTr("Zambia"), + qsTr("Zimbabwe "), + qsTr("Kosovo"), + qsTr("No country") + ] + } + return countryname.text[index] + } + +} diff --git a/qml/models/GetCountryStations.qml b/qml/models/GetCountryStations.qml new file mode 100644 index 0000000..d0c5304 --- /dev/null +++ b/qml/models/GetCountryStations.qml @@ -0,0 +1,50 @@ +import QtQuick 2.0 +import QtQuick.XmlListModel 2.0 + +Item { + // radio-browser advanced: + ////property int bitrateMin: 0 + ////property int bitrateMax: 1000000 + ////property string state: "" + ////property bool stateExact: false + ////property string language: "" + ////property bool languageExact: false + ////property string tagList: "" // commaseparated string + property string name: "" + property bool nameExact: false + property string countrycode: "" + property string tag: "" + property bool tagExcact: false + property string codec: "" + property string order: "" // name, url, homepage, favicon, tags, country, state, language, votes, codec, bitrate, lastcheckok, lastchecktime, clicktimestamp, clickcount, clicktrend, random + property bool reverse: false//order === name ? false : true // true if name + property int offset: 0 + property int limit: 150 + property string source: "" + + // Allradio specific: + property string country: countrycode ? radioBrowser.getCountryName(countrycode) : "World" + property alias finished: searchModel.finished + property string filterString + property alias stationsModel: searchModel.stationsModel + property bool clear: false + property AdvancedSearchModel searchModel : AdvancedSearchModel {id:searchModel} + + onSourceChanged: {searchModel.source = source} + onClearChanged: if (clear) {searchModel.clear;searchModel.stationsModel.clear();offset=0;clear=false} + + function getStations() { + searchModel.xml="" + filterString = "" + if (name !== "") {filterString = "&name="+name+"&nameExact="+nameExact} + if (countrycode !== "") filterString = filterString + "&countrycode="+countrycode + if (tag !== "") filterString = filterString + "&tag="+tag+"&tagExact="+tagExcact + if (codec !== "") filterString = filterString + "&codec="+codec + if (order !== "") filterString = filterString + "&order="+order + if (order === "name") reverse = false; else reverse = true + filterString = filterString + "&reverse="+reverse + "&offset="+offset+"&limit="+limit + // console.log(radioBrowser.serverUrl + "/xml/stations/search?hidebroken=true"+filterString) + source = radioBrowser.serverUrl + "/xml/stations/search?hidebroken=true"+filterString + } +} + diff --git a/qml/models/GetCountryStations___.qml b/qml/models/GetCountryStations___.qml new file mode 100644 index 0000000..eee3106 --- /dev/null +++ b/qml/models/GetCountryStations___.qml @@ -0,0 +1,83 @@ +import QtQuick 2.0 +import QtQuick.XmlListModel 2.0 + +XmlListModel { + // radio-browser advanced: + property string name: "" + property bool nameExact: false + property string countrycode: "" + ////property string state: "" + ////property bool stateExact: false + ////property string language: "" + ////property bool languageExact: false + property string tag: "" + property bool tagExcact: false + ////property string tagList: "" // commaseparated string + property string codec: "" + ////property int bitrateMin: 0 + ////property int bitrateMax: 1000000 + property string order: "" // name, url, homepage, favicon, tags, country, state, language, votes, codec, bitrate, lastcheckok, lastchecktime, clicktimestamp, clickcount, clicktrend, random + property bool reverse: false//order === name ? false : true // true if name + property int offset: 0 + property int limit: 100000 + + // Allradio specific: + // property string filter: "" + property string country: radioBrowser.getCountryName(countrycode) + // property string searchby: "name" + // property string searchorder: "clickcount" + property bool running: false + property string filterString + + //property AdvancedSearchModel searchModel : AdvancedSearchModel {id:searchModel} + + onRunningChanged: {console.log("RUNNING: "+running);if (running) getStations()} + + //onNameChanged: if (name !== "") tag = "" + //onTagChanged: if (tag !=="") name = "" + + + + function getStations() { + xml="" + source="" + filterString = "" + //filterString = "&name="+name+"&nameExact="+nameExact+"&countrycode="+countrycode+"&tag="+tag+"&tagExact="+tagExcact+"&codec="+codec+"&order="+order+"&reverse="+reverse + + if (name !== "") {filterString = "&name="+name+"&nameExact="+nameExact} + if (countrycode !== "") filterString = filterString + "&countrycode="+countrycode + if (tag !== "") filterString = filterString + "&tag="+tag+"&tagExact="+tagExcact + if (codec !== "") filterString = filterString + "&codec="+codec + if (order !== "") filterString = filterString + "&order="+order + if (order === "name") reverse = false; else reverse = true + filterString = filterString + "&reverse="+reverse + "&offset="+offset+"&limit="+limit + + console.log(radioBrowser.serverUrl + "/xml/stations/search?hidebroken=true"+filterString) + source = radioBrowser.serverUrl + "/xml/stations/search?hidebroken=true"+filterString + } + + + query: "/result/station" + XmlRole { name: "stationuuid"; query: "@stationuuid/string()" } + XmlRole { name: "name"; query: "@name/string()" } + XmlRole { name: "homepage"; query: "@homepage/string()" } + XmlRole { name: "favicon"; query: "@favicon/string()" } + XmlRole { name: "tags"; query: "@tags/string()" } + XmlRole { name: "codec"; query: "@codec/string()" } + XmlRole { name: "bitrate"; query: "@bitrate/string()" } + XmlRole { name: "hls"; query: "@hls/string()" } + XmlRole { name: "url_resolved"; query: "@url_resolved/string()" } + XmlRole { name: "country"; query: "@country/string()" } + XmlRole { name: "countrycode"; query: "@countrycode/string()" } + XmlRole { name: "votes"; query: "@votes/string()" } + XmlRole { name: "clicktrend"; query: "@clicktrend/string()" } + XmlRole { name: "clickcount"; query: "@clickcount/string()" } + XmlRole { name: "lastcheckok"; query: "@lastcheckok/string()" } + onStatusChanged: { + if (status === XmlListModel.Ready) {running = false} + //if (status === XmlListModel.Loading) running = true; + if (status === XmlListModel.Error) running = false; + if (status === XmlListModel.Null) running = false; + } +} + diff --git a/qml/models/GetStationsByUrl.qml b/qml/models/GetStationsByUrl.qml new file mode 100644 index 0000000..9c36e13 --- /dev/null +++ b/qml/models/GetStationsByUrl.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + +} diff --git a/qml/models/ItemsModel.qml b/qml/models/ItemsModel.qml new file mode 100644 index 0000000..8cb72c2 --- /dev/null +++ b/qml/models/ItemsModel.qml @@ -0,0 +1,42 @@ +import QtQuick 2.0 + +ListModel { + ListElement { + name: "Name" + description: "Search by name" + icon: "../images/bysearch_t.png" + page: "SearchStationsPage.qml" + } + ListElement { + name: "Countries" + description: "Search by tag" + icon: "../images/bycountry_t.png" + page: "CountryListPage.qml" + } + + /* ListElement { + name: "New/Changed" + description: "View by new/changed" + icon: "../images/bylatest_t.png" + page: "CrNewChangedPage.qml" + } + ListElement { + name: "Recently played" + description: "View by recently played" + icon: "../images/lastplayed_t.png" + page: "CrRecentPlayedPage.qml" + } + + ListElement { + name: "Most votes" + description: "View by most votes" + icon: "../images/byvote_t.png" + page: "CrTopVotedPage.qml" + } + ListElement { + name: "Most Played" + description: "Viwe by most played" + icon: "../images/mostclicked_t.png" + page: "CrMostPlayedPage.qml" + }*/ +} diff --git a/qml/models/TagListModel.qml b/qml/models/TagListModel.qml new file mode 100644 index 0000000..a1f2efb --- /dev/null +++ b/qml/models/TagListModel.qml @@ -0,0 +1,50 @@ +import QtQuick 2.0 +import QtQuick.XmlListModel 2.0 + +Item { + property string filter: "" + property bool clear: false + property bool running: false + property alias tagsListModel: tagModel + property int maxCount: 0 +// property alias tagsListModel: xmlModel + property alias source: xmlModel.source + + onClearChanged: if (clear===true) {xmlModel.xml="";clear=false} + + ListModel {id: tagModel} + + XmlListModel { + id: xmlModel + query: "/result/tag" + XmlRole { name: "tag"; query: "@name/string()" } + XmlRole { name: "stationcount"; query: "@stationcount/string()" } + onStatusChanged: { + if (status === XmlListModel.Ready) { + addtomodel() + // console.log("TAGSLISTMODEL DONE: "+xmlModel.count) + tagCount = xmlModel.count + } + } + } + + function addtomodel(){ + tagModel.clear() + var cname + var count + var filt + for(var i = 0; i < xmlModel.count; i++) { + cname = xmlModel.get(i).tag + count = xmlModel.get(i).stationcount + if (count > 99) { + if (count > maxCount) maxCount = count + filt = cname.toLowerCase(); if (filt.indexOf(filter) !== -1) tagModel.append({"tag" : cname, "stationcount" : xmlModel.get(i).stationcount}) + } + // cname = getCountryName(xmlModel.get(i).name) + // if (cname) {filt = cname.toLowerCase(); if (filt.indexOf(filter) !== -1) countryModel.append({"name" : cname, "alpha_2" : xmlModel.get(i).name,"stationcount" : xmlModel.get(i).stationcount})} + } + //countryModel.listModelSort(countryModel, compareElements) + //numberOfCountries = i + running = false + } +} diff --git a/qml/pages/AboutPage.qml b/qml/pages/AboutPage.qml new file mode 100644 index 0000000..0123139 --- /dev/null +++ b/qml/pages/AboutPage.qml @@ -0,0 +1,100 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +Page { + Flickable { + id: flick + width:parent.width + height: parent.height - Theme.paddingLarge * 3 + anchors.top: parent.top + anchors.topMargin: Theme.paddingLarge * 3 + contentHeight: column1.height + + Column{ + id: column1 + width: parent.width + spacing: Theme.paddingLarge + Label { + font.pixelSize: Theme.fontSizeExtraLarge + font.bold: true + text: "AllRadio v"+ _version + anchors.horizontalCenter: parent.horizontalCenter + + } + + Label { + text: "License: GPL" + anchors.horizontalCenter: parent.horizontalCenter + } + + Image{ + source: "../images/community.png" + height: Theme.itemSizeHuge + width: height + fillMode: Image.PreserveAspectFit + anchors { + horizontalCenter: parent.horizontalCenter + } + } + /* Rectangle{ + gradient: Gradient { + GradientStop { position: 0.0; color: "#333333" } + GradientStop { position: 1.0; color: "#777777" } + } + anchors { + horizontalCenter: parent.horizontalCenter + } + height: 3 + width: parent.width-64 + } + + Label { + width: 360 + font.pixelSize: Theme.fontSizeMedium + text: "Created by llelectronics" + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignHCenter + } + Repeater{ + anchors.horizontalCenter: parent.horizontalCenter + //model: credits + Label { + anchors.horizontalCenter: parent.horizontalCenter + text: title + font.pixelSize: Theme.fontSizeSmall + } + } + Rectangle{ + gradient: Gradient { + GradientStop { position: 0.0; color: "#333333" } + GradientStop { position: 1.0; color: "#777777" } + } + anchors { + horizontalCenter: parent.horizontalCenter + } + height: 3 + width: parent.width-64 + } + + Button { + id: homepage + anchors.horizontalCenter: parent.horizontalCenter + text: "Sourcecode on Github" + onClicked: { + mainWindow.openNewTab('page-'+salt(), "https://github.com/llelectronics/webcat", false); + } + } */ + + Label { + width: parent.width-70 + font.pixelSize: Theme.fontSizeSmall + text: qsTr("AllRadio is an internet radio station player") + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignHCenter + height: 200 + wrapMode: Text.WordWrap + } + } + } +} diff --git a/qml/pages/AllRadio.qml b/qml/pages/AllRadio.qml new file mode 100644 index 0000000..5684759 --- /dev/null +++ b/qml/pages/AllRadio.qml @@ -0,0 +1,430 @@ +import QtQuick 2.2 +import Sailfish.Silica 1.0 +import QtQuick.LocalStorage 2.0 +import QtGraphicalEffects 1.0 +import "../items" +import "../models" +import "../delegates" +import "../helpers/db.js" as Favorites +import "../helpers/jsFunctions.js" as JS + +Page { + + id: page + anchors.fill: parent + anchors.bottomMargin: mediaPlayerPanel.visibleSize + + property bool stationOk: radioPlayer.stationOk + property bool online: radioBrowser.online + property GetCountryStations getTrending1: GetCountryStations {id: getTrending1} + property GetCountryStations getTrending2: GetCountryStations {id: getTrending2} + property GetCountryStations getTrendingWorld: GetCountryStations {id: getTrendingWorld} + property GetCountryStations getTags1: GetCountryStations {id: getTags1} + property GetCountryStations getTags2: GetCountryStations {id: getTags2} + property GetCountryStations getTags3: GetCountryStations {id: getTags3} + property ListModel playedCountries: ListModel {id: playedCountries} + property ListModel playedTags: ListModel {id: playedTags} + property ListModel favorites: ListModel {id: favorites} + + onOnlineChanged: if (online) reloadDbData() + onStationOkChanged: if (stationOk) reloadDbData() + + Splash { + id: splashItem + visible: radioBrowser.loading ? true : false + } + + SilicaFlickable { + anchors.fill: parent + contentHeight: mainColumn.height + clip: mediaPlayerPanel.expanded + visible: !splashItem.visible + + onVisibleChanged: if (visible) reloadDbData() + + PullDownMenu { + MenuItem { + text: "About" + onClicked: pageStack.push("AboutPage.qml") + } + MenuItem { + text: "Settings" + onClicked: pageStack.push("SettingsPage.qml") + } + MenuItem { + text: "Sleep timer" + onClicked: { + pageStack.push("SleepTimerPage.qml") + } + + /* var dialog = pageStack.push("Sailfish.Silica.TimePickerDialog", { + hour: 0, + minute: 30, + hourMode: DateTime.TwentyFourHours + }) + dialog.accepted.connect(function() { + }) + } */ + } + } + + Column { + id: mainColumn + width: parent.width + spacing: Theme.paddingMedium + + Item { + width: parent.width + height: Theme.itemSizeHuge + Label { + id: hlabel + font.pixelSize: Theme.fontSizeExtraLarge + text: JS.getGreeting() + color: Theme.highlightColor + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + } + + Image { + id: logo + anchors.verticalCenter: hlabel.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Theme.paddingLarge + height: Theme.itemSizeMedium + width: height + smooth: true + source: "../images/community.png" + } + ColorOverlay { + anchors.fill: logo + source: logo + color: Theme.highlightColor + } + } + + BackgroundItem { + width: parent.width + height: Theme.itemSizeMedium + + ButtonRect {fill: false} + + Row { + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.paddingMedium + + Image { + anchors.verticalCenter: parent.verticalCenter + source: "image://theme/icon-m-search" + } + + Label { + anchors.verticalCenter: parent.verticalCenter + text: "Search" + font.pixelSize: Theme.fontSizeLarge + } + } + + Image { + anchors.right: parent.right + anchors.rightMargin: Theme.paddingLarge + anchors.verticalCenter: parent.verticalCenter + source: "image://theme/icon-m-right" + } + + onClicked: pageStack.push("SearchStationsPage.qml",{searchby:"name"})} + + // Most played countries + Column { + //visible: playedCountries.count > 0 + width: parent.width + + Item {height: Theme.paddingLarge;width: parent.width} + + HeaderButton { + headerText: "Countries" + onClicked: pageStack.push("CountryListPage.qml") + } + + Item {height: Theme.paddingMedium;width: parent.width} + + SilicaGridView { + clip: true + visible: playedCountries.count > 0 + width: parent.width + height: playedCountries.count > 0 ? Theme.itemSizeExtraSmall * Math.round(playedCountries.count / 2) : 0 + cellWidth: parent.width / 2 + cellHeight: Theme.itemSizeExtraSmall + model: playedCountries + delegate: FavoriteCountryList {onClicked: pageStack.push("CountryStationsPage.qml",{searchby:"name",_countrycode: alpha_2})} + } + } + + // Most played favorites + Item {height: Theme.paddingLarge;width: parent.width;visible: favorites.count > 0} + + HeaderButton { + visible: favorites.count > 0 + headerText: "My Favorites" + onClicked: pageStack.push("FavoritesPage.qml") + } + + GridView { + //clip: true + clip: true + height: Theme.itemSizeHuge * 1.35 + width: page.width + cellHeight: height + cellWidth: cellHeight * 0.75//Theme.itemSizeHuge + Theme.itemSizeMedium * 2 + flow: GridView.TopToBottom + snapMode: SlideshowView.NoSnap + layoutDirection: Qt.LeftToRight + visible: favorites.count > 0//radioBrowser.getCountryName(_country) || playedCountries.count > 0 ? true : false + + model: favorites + + delegate: SmallStationsDelegate { + flagVisible: true + + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer.getStationFavorite(model.stationuuid) + } + } + } + } + + // Recently played + Item {height: Theme.paddingLarge;width: parent.width;visible: radioPlayer.playHistory.count > 0} + + HeaderButton { + visible: radioPlayer.playHistory.count > 0 + headerText: "Play history"//playedCountries.count > 0 ? "Trending in " + radioBrowser.getCountryName(playedCountries.get(0).alpha_2) : "Trending in " + radioBrowser.getCountryName(_country) + onClicked: pageStack.push("HistoryPage.qml") + } + + GridView { + visible: radioPlayer.playHistory.count > 0 + clip: true + height: playedTags.count > 0 ? Theme.itemSizeHuge * 1.35 : 0 + width: page.width + cellHeight: height + cellWidth: cellHeight * 0.75//Theme.itemSizeHuge + Theme.itemSizeMedium * 2 + flow: GridView.TopToBottom + snapMode: SlideshowView.NoSnap + layoutDirection: Qt.LeftToRight + + model: radioPlayer.playHistory + + delegate: SmallStationsDelegate { + flagVisible: true + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer.getStationFavorite(model.stationuuid) + } + } + } + } + + // Most played tags + Item {height: Theme.paddingLarge;width: parent.width;visible: radioPlayer.playHistory.count > 0} + + HeaderButton { + visible: radioPlayer.playHistory.count > 0 + headerText: "My most played Tags"//playedCountries.count > 0 ? "Trending in " + radioBrowser.getCountryName(playedCountries.get(0).alpha_2) : "Trending in " + radioBrowser.getCountryName(_country) + onClicked: pageStack.push("TagListPage.qml",{}) + } + + GridView { + visible: radioPlayer.playHistory.count > 0 + clip: true + height: playedTags.count > 0 ? Theme.itemSizeHuge * 1.35 : 0 + width: page.width + cellHeight: height + cellWidth: cellHeight * 0.75//Theme.itemSizeHuge + Theme.itemSizeMedium * 2 + flow: GridView.TopToBottom + snapMode: SlideshowView.NoSnap + layoutDirection: Qt.LeftToRight + model: playedTags + delegate: SmallTagsDelegate { + onClicked: pageStack.push("CountryStationsPage.qml",{filterby: "tag",searchby: "clicktrend",stext: tag,comboIndex: 1 }) + } + } + + Item {height: Theme.paddingLarge;width: parent.width;visible: radioBrowser.getCountryName(_country) || playedCountries.count > 0 ? true : false} + + HeaderButton { + visible: radioBrowser.getCountryName(_country) || playedCountries.count > 0 ? true : false + headerText: playedCountries.count > 0 ? "Trending in " + radioBrowser.getCountryName(playedCountries.get(0).alpha_2) : "Trending in " + radioBrowser.getCountryName(_country) + onClicked: pageStack.push("CountryStationsPage.qml",{searchby:"clicktrend",_countrycode: playedCountries.get(0).alpha_2}) + } + + GridView { + clip: true + height: Theme.itemSizeHuge * 1.35 + width: page.width + cellHeight: height + cellWidth: cellHeight * 0.75//Theme.itemSizeHuge + Theme.itemSizeMedium * 2 + flow: GridView.TopToBottom + snapMode: SlideshowView.NoSnap + layoutDirection: Qt.LeftToRight + visible: radioBrowser.getCountryName(_country) || playedCountries.count > 0 ? true : false + + model: getTrending1.searchModel + + delegate: SmallStationsDelegate { + flagVisible: false + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer.getStationFavorite(model.stationuuid) + } + } + } + } + + Item {height: Theme.paddingLarge;width: parent.width;visible: playedCountries.count > 1} + + HeaderButton { + visible: playedCountries.count > 1 + headerText: playedCountries.count > 0 ? "Trending in " + radioBrowser.getCountryName(playedCountries.get(1).alpha_2) : "Trending in " + radioBrowser.getCountryName(_country) + onClicked: pageStack.push("CountryStationsPage.qml",{searchby:"clicktrend",_countrycode: playedCountries.get(1).alpha_2}) + } + + GridView { + clip: true + height: Theme.itemSizeHuge * 1.35 + width: page.width + cellHeight: height + cellWidth: cellHeight * 0.75//Theme.itemSizeHuge + Theme.itemSizeMedium * 2 + flow: GridView.TopToBottom + snapMode: SlideshowView.NoSnap + layoutDirection: Qt.LeftToRight + visible: playedCountries.count > 1 + + model: getTrending2.searchModel + + delegate: SmallStationsDelegate { + flagVisible: false + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer.getStationFavorite(model.stationuuid) + } + } + } + } + + Item {height: Theme.paddingLarge;width: parent.width} + + HeaderButton { + headerText: "Trending in the world"//playedCountries.count > 0 ? "Trending in " + radioBrowser.getCountryName(playedCountries.get(0).alpha_2) : "Trending in " + radioBrowser.getCountryName(_country) + onClicked: pageStack.push("CountryStationsPage.qml",{searchby:"clicktrend",_countrycode: ""}) + } + + GridView { + clip: true + height: Theme.itemSizeHuge * 1.35 + width: page.width + cellHeight: height + cellWidth: cellHeight * 0.75//Theme.itemSizeHuge + Theme.itemSizeMedium * 2 + flow: GridView.TopToBottom + snapMode: SlideshowView.NoSnap + layoutDirection: Qt.LeftToRight + model: getTrendingWorld.searchModel + delegate: SmallStationsDelegate { + flagVisible: true + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer.getStationFavorite(model.stationuuid) + } + } + } + } + } + } + + function reloadDbData() { + Favorites.getTagsRecentClicked(playedTags,15) + Favorites.getFavorites(favorites,"myclickcount",15) + Favorites.getCountryRecentClicked(playedCountries,4) + + + getTrending1.countrycode = playedCountries.count > 0 ? playedCountries.get(0).alpha_2 : _country + getTrending1.order = "clicktrend" + getTrending1.offset = 0 + getTrending1.limit = 15 + if (getTrending1.searchModel.count !== 0) getTrending1.clear = true; else getTrending1.getStations() + + if (playedCountries.count > 1) { + getTrending2.countrycode = playedCountries.get(1).alpha_2 + getTrending2.order = "clicktrend" + getTrending2.offset = 0 + getTrending2.limit = 15 + if (getTrending2.searchModel.count !== 0) getTrending2.clear = true; else getTrending2.getStations() + } + + getTrendingWorld.countrycode = "" + getTrendingWorld.order = "clicktrend" + getTrendingWorld.offset = 0 + getTrendingWorld.limit = 15 + if (getTrendingWorld.searchModel.count !== 0) getTrendingWorld.clear=true; else getTrendingWorld.getStations() + } + + Component.onCompleted: { + Favorites.init() + radioBrowser.getList() + reloadDbData() + } +} + diff --git a/qml/pages/CountryListPage.qml b/qml/pages/CountryListPage.qml new file mode 100644 index 0000000..110cd6e --- /dev/null +++ b/qml/pages/CountryListPage.qml @@ -0,0 +1,50 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtQuick.LocalStorage 2.0 +import "../delegates" + +Page { + property bool sfocus: false + property bool pageAcitve + + z:1 + + SilicaListView { + id: view + anchors.fill: parent + clip: mediaPlayerPanel.expanded + anchors.bottomMargin: mediaPlayerPanel.visibleSize + VerticalScrollDecorator {} + + header: Column { + width: parent.width + + PageHeader {title: "Community Radio Browser";description: "Found "+view.count + " countries"} + + SearchField { + id: sfield + width: parent.width + placeholderText: "Search" + text: "" + inputMethodHints: Qt.ImhNoAutoUppercase //| Qt.ImhNoPredictiveText + EnterKey.iconSource: "image://theme/icon-m-enter-close" + EnterKey.onClicked: {focus = false} + focus: sfocus + onTextChanged: radioBrowser.countriesModel.filter = text + onClicked: {view.currentIndex = -1} + } + } + + model: radioBrowser.countriesModel.countryModel + + delegate: CountryListDelegate { + id: countryListDelegate; + + onClicked: { + sfocus=false; + settings.setValue("lastCountry",alpha_2) + pageStack.push("CountryStationsPage.qml",{stationCount: stationcount,_countrycode: alpha_2,searchby:"name"}) + } + } + } +} diff --git a/qml/pages/CountryStationsPage.qml b/qml/pages/CountryStationsPage.qml new file mode 100644 index 0000000..6257d3c --- /dev/null +++ b/qml/pages/CountryStationsPage.qml @@ -0,0 +1,213 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import "../models" +import "../delegates" + +Page { + property string sortedby: "" + property string filterby + property alias searchby: getCountryStations.order + property string searchtext: "" + property string _countrycode: "" + property int stationCount: 0 + property alias name: getCountryStations.name + property alias tag: getCountryStations.tag + property string stext: "" + property GetCountryStations getCountryStations: GetCountryStations {id: getCountryStations} + property bool sfocus + property int comboIndex: 0 + + onStatusChanged: if (status !== PageStatus.Active) sfocus=false + + onSearchbyChanged: { + switch (searchby){ + case "name": sortedby = "Sorted by Name";break; + case "votes": sortedby = "Most likes";break; + case "clicktrend": sortedby = "Trending right now";break; + case "clickcount": sortedby = "Most played"; + } + } + + BusyIndicator { + id: busy + visible: running + anchors.centerIn: parent + size: BusyIndicatorSize.Large + running: !getCountryStations.finished && getCountryStations.offset > 0 + } + + SilicaListView { + id: view + enabled: !busy.visible + opacity: enabled ? 1 : 0.5 + anchors.fill: parent + clip: mediaPlayerPanel.expanded + anchors.bottomMargin: sfocus ? 0 : mediaPlayerPanel.visibleSize + + ViewPlaceholder { + anchors.centerIn: parent + enabled: view.count == 0 + text: getCountryStations.finished && view.count === 0 ? "Oh no..." : "Please wait" + hintText: getCountryStations.finished && view.count === 0 ? "No radio stations!?!" : "getting radio stations" + } + + VerticalScrollDecorator {} + + onAtYEndChanged: { + if (atYEnd && view.count >= getCountryStations.limit) { + if (getCountryStations.offset + getCountryStations.limit < stationCount) { + getCountryStations.offset = getCountryStations.offset + getCountryStations.limit + 1 + getCountryStations.getStations() + } + } + } + + header: Column { + width: parent.width + + PageHeader { + id: pheader + + Column { + id: headerCol + anchors.top: parent.top + anchors.topMargin: Theme.paddingLarge + anchors.right: parent.right + anchors.left: parent.left + anchors.rightMargin: Theme.paddingLarge//headerLogo.width + (Theme.paddingLarge * 2) + anchors.leftMargin: Theme.paddingLarge + + Row { + anchors.right: parent.right + spacing: Theme.paddingMedium + Image { + id: headerLogo + anchors.bottom: ccode.bottom + height: ccode.height * 0.8 + fillMode: Image.PreserveAspectFit + smooth: true + source: _countrycode === "" ? "../images/bycountry_t.png" : "../flags/"+_countrycode.toLowerCase()+".png" + } + Label { + id: ccode + font.pixelSize: Theme.fontSizeLarge + color: Theme.highlightColor + wrapMode: Text.WordWrap + elide: Text.ElideLeft + text: getCountryStations.country //+ " ["+stationCount+"]" + } + } + Label { + font.pixelSize: Theme.fontSizeSmall + color: Theme.secondaryHighlightColor + width: parent.width + horizontalAlignment: Text.AlignRight + text: sortedby//view.count + " channels" + } + } + } + + Row { + id: row + width: parent.width + SearchField { + id: sfield + placeholderText: "Search" + inputMethodHints: Qt.ImhNoAutoUppercase + EnterKey.iconSource: "image://theme/icon-m-enter-close" + EnterKey.onClicked: focus = false + focus: sfocus + text: stext + + onFocusChanged: sfocus = focus + + onTextChanged: { + if (searchtext !== text) { + if (text.length > 0) { + searchtext = text + switch(searchCombo.currentIndex) { + case 0: filterby="name";getCountryStations.offset=0;getCountryStations.name=text;getCountryStations.tag="";break + case 1: filterby="tag";getCountryStations.offset=0;getCountryStations.tag=text;getCountryStations.name="" + } + } else { + getCountryStations.name="" + getCountryStations.tag="" + } + getCountryStations.offset=0; + getCountryStations.clear = true + getCountryStations.getStations() + } + } + onClicked: {view.currentIndex = -1} + + } + } + + ComboBox { + id: searchCombo + label: "Search by:" + currentIndex: comboIndex + menu: ContextMenu { + MenuItem { text: "Name" } + MenuItem { text: "Tag" } + } + onValueChanged: { + switch(currentIndex) { + case 0: filterby="name";getCountryStations.offset=0;getCountryStations.name=sfield.text;getCountryStations.tag="";break + case 1: filterby="tag";getCountryStations.offset=0;getCountryStations.tag=sfield.text;getCountryStations.name="" + } + if (searchtext.length !== 0) { + getCountryStations.offset=0; + getCountryStations.clear = true + getCountryStations.getStations() + } + } + } + + } + + PullDownMenu { + MenuItem { + text: "Name" + onClicked: {getCountryStations.clear=true;getCountryStations.order = "name";getCountryStations.getStations()}//;xmlModel.running = true} + } + MenuItem { + text: "Most likes" + onClicked: {getCountryStations.clear=true;getCountryStations.order = "votes";getCountryStations.getStations()}//;xmlModel.running = true} + } + MenuItem { + text: "Most played" + onClicked: {getCountryStations.clear=true;getCountryStations.order = "clickcount";getCountryStations.getStations()}//xmlModel.running = true} + } + MenuItem { + text: "Trending right now" + onClicked: {getCountryStations.clear=true;getCountryStations.order = "clicktrend";getCountryStations.getStations()}//xmlModel.running = true} + } + } + + model: getCountryStations.stationsModel + + delegate: StationsDelegate{ + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec + radioPlayer._bitrate = model.bitrate + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer.getStationFavorite(model.stationuuid) + } + } + } + } + Component.onCompleted: { + getCountryStations.countrycode=_countrycode + getCountryStations.order=searchby + getCountryStations.getStations() + } +} diff --git a/qml/pages/FavoritesPage.qml b/qml/pages/FavoritesPage.qml new file mode 100644 index 0000000..03fb952 --- /dev/null +++ b/qml/pages/FavoritesPage.qml @@ -0,0 +1,123 @@ +import QtQuick 2.2 +import Sailfish.Silica 1.0 +import QtQuick.LocalStorage 2.0 +import "../delegates" +import "../helpers/db.js" as Favorites + +Page { + property ListModel favorites: ListModel {id: favorites} + property real showP: 0.0 + property int tab: allradioSettings.value("favoriteTab",0) + SilicaListView { + + id: view + // enabled: !splashItem.visible + opacity: enabled ? 1 : 0 + anchors.fill: parent + anchors.bottomMargin: mediaPlayerPanel.visibleSize + clip: mediaPlayerPanel.expanded + + onVisibleChanged: if (visible) updateFav() + + + header: Column { + width: parent.width + spacing: Theme.paddingLarge + PageHeader{ + title: "Favorites" + description: "Radio stations: "+view.count + } + + Row { + id: row + + // width: parent.width + //anchors.verticalCenter: parent.verticalCenter + width: parent.width + TabButton { + id: home + //anchors.verticalCenter: parent.verticalCenter + down: tab === 0 + width: parent.width / 3 + fontSize: Theme.fontSizeMedium + fontColor: down ? Theme.secondaryColor : Theme.secondaryColor + iconVisible: false + // icon: "image://theme/icon-m-home" //"image://theme/icon-m-video" + text: "By name" + onButtonClick: {showP=0.0;tab = 0;Favorites.getFavorites(favorites,"name",10000)} + } + TabButton { + id: search + // anchors.verticalCenter: parent.verticalCenter + down: tab === 1 + width: parent.width / 3 + fontSize: Theme.fontSizeMedium + fontColor: down ? Theme.secondaryColor : Theme.secondaryColor + iconVisible: false + // icon: "image://theme/icon-m-search" + text: "Most played" + onButtonClick: {showP=0.0;tab = 1;Favorites.getFavorites(favorites,"myclickcount",10000)} + } + TabButton { + id: favorite + // anchors.verticalCenter: parent.verticalCenter + down: tab === 2 + width: parent.width / 3 + fontSize: Theme.fontSizeMedium + fontColor: down ? Theme.secondaryColor : Theme.secondaryColor + iconVisible: false + // icon: "image://theme/icon-m-favorite" + text: "Last played" + onButtonClick: {showP=0.0;tab = 2;Favorites.getFavorites(favorites,"myclicktimestamp",10000);console.log("CLICK")} + } + } + Item {width: parent.width;height: Theme.paddingLarge} + } + + + ViewPlaceholder { + anchors.centerIn: allRadio.center + enabled: view.count == 0 + text: "Favorites" + hintText: "add favorites here" + } + + VerticalScrollDecorator {} + model: favorites + delegate: StationsDelegate{ + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer._favorite = model.favorite ? true : false + //pageStack.push("RadioPlayerPage.qml") + } + } + } + function updateFav() { + var sort + switch (tab){ + case 0: sort = "name";break + case 1: sort = "myclickcount";break + case 2: sort = "myclicktimestamp";break + } + Favorites.getFavorites(favorites,sort,10000) + } + + Component.onCompleted: { + + updateFav() + } + Component.onDestruction: { + allradioSettings.setValue("favoriteTab",tab) + } + } +} diff --git a/qml/pages/HistoryPage.qml b/qml/pages/HistoryPage.qml new file mode 100644 index 0000000..72565e6 --- /dev/null +++ b/qml/pages/HistoryPage.qml @@ -0,0 +1,65 @@ +import QtQuick 2.2 +import Sailfish.Silica 1.0 +import QtQuick.LocalStorage 2.0 +import "../delegates" +import "../helpers/db.js" as Favorites + +Page { + property ListModel history: ListModel {id: history} + SilicaListView { + id: view + + enabled: !splashItem.visible + //visible: enabled + opacity: enabled ? 1 : 0 + anchors.fill: parent + anchors.bottomMargin: mediaPlayerPanel.visibleSize + clip: mediaPlayerPanel.expanded + onVisibleChanged: if (visible) updateHist() + ViewPlaceholder { + anchors.centerIn: allRadio.center + enabled: view.count == 0 + text: "History" + hintText: "see you play history here" + } + + VerticalScrollDecorator {} + header: PageHeader{title: "Play history";description: "Radio stations: "+view.count} + + + /* onAtYEndChanged: { + if (atYEnd && view.count >= getCountryStations.limit) { + // console.log("AT BOTTOM: "+view.count) + if (getCountryStations.offset + getCountryStations.limit < stationCount) { + getCountryStations.offset = getCountryStations.offset + getCountryStations.limit + 1 + getCountryStations.getStations() + } + } + } */ + model: history + delegate: StationsDelegate{ + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + radioPlayer._favorite = model.favorite ? true : false + //pageStack.push("RadioPlayerPage.qml") + } + } + } + function updateHist() { + Favorites.getHistory(history,10000) + } + + Component.onCompleted: updateHist() + + } +} diff --git a/qml/pages/RadioPlayerPage.qml b/qml/pages/RadioPlayerPage.qml new file mode 100644 index 0000000..9ec2297 --- /dev/null +++ b/qml/pages/RadioPlayerPage.qml @@ -0,0 +1,320 @@ +import QtQuick 2.0 +import QtGraphicalEffects 1.0 +import Sailfish.Silica 1.0 +import "../delegates" +import "../items" +import "../helpers/jsFunctions.js" as JSfunctions + +Page { + id: page + property bool keepScreenOn: Qt.application.active && radioPlayer.isPlaying ? true : false + + allowedOrientations: radioPlayer.isPlaying && radioPlayer.radioVideo ? Orientation.All : Orientation.Portrait + + backNavigation: orientation === Orientation.Portrait ? true : false//radioPlayer.isPlaying && radioPlayer.radioVideo && Orientation.Portrait ? false : true + + ScreenBlank { + id: screenBlank + enabled: keepScreenOn + } + + VideoPlayer { + id: videoPlayer + z:97 + anchors.top: orientation === Orientation.Portrait ? radioName.top : page.top + anchors.bottom: orientation === Orientation.Portrait ? radioName.bottom : page.bottom + anchors.left: orientation === Orientation.Portrait ? radioName.left : page.left + anchors.right: orientation === Orientation.Portrait ? radioName.right : page.right + anchors.margins: orientation === Orientation.Portrait ? radioName.border.width : 0 + visible: radioPlayer.radioVideo && !radioPlayer.isPaused ? true : false + onVisibleChanged: visible ? enabled=true : enabled = false + videoSource: radioPlayer + } + + PageHeader { + id: pheader + z: orientation === Orientation.Portrait || !screenTimer.running ? 98 : 0 + visible: orientation !== Orientation.LandscapeMask + + Column { + id: headerCol + visible: orientation === Orientation.Portrait + anchors.top: parent.top + anchors.topMargin: Theme.paddingLarge + anchors.verticalCenter: parent.verticalCenter + width: parent.width + anchors.right: parent.right + anchors.rightMargin: Theme.paddingLarge + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + spacing: Theme.paddingSmall + Row { + spacing: Theme.paddingMedium + anchors.right: parent.right + Text{ + id: countryName + font.pixelSize: Theme.fontSizeLarge + color: Theme.highlightColor + horizontalAlignment: Text.AlignRight + text: radioPlayer.radioCountryName + } + Image { + anchors.bottom: countryName.bottom + height: countryName.height * 0.9 + fillMode: Image.PreserveAspectFit + smooth: false + source: radioPlayer._countrycode === "" ? "../images/bycountry_t.png" : "../flags/"+radioPlayer._countrycode.toLowerCase()+".png" + } + } + Label { + anchors.right: parent.right + color: Theme.secondaryHighlightColor + font.pixelSize: Theme.fontSizeExtraSmall + text: JSfunctions.getAll(radioPlayer._hls,radioPlayer._codec,radioPlayer._bitrate) + } + } + } + Rectangle { + id: radioName + anchors.top: pheader.bottom + anchors.topMargin: Theme.paddingLarge + anchors.bottom: artistSongName.top + anchors.bottomMargin: Theme.paddingLarge + color: Theme.rgba(Theme.overlayBackgroundColor,0.5) + radius: 20 + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - (Theme.paddingLarge * 2) + + Behavior on opacity { + FadeAnimator {} + } + + + Label { + id: nameLabel + z:99 + anchors.top: parent.top + anchors.topMargin: Theme.paddingLarge * 2 + anchors.leftMargin: Theme.paddingLarge + anchors.rightMargin: Theme.paddingLarge + anchors.horizontalCenter: parent.horizontalCenter + font.bold: false + color: Theme.secondaryColor + wrapMode: Text.WordWrap + font.pixelSize: Theme.fontSizeLarge + fontSizeMode: Text.Fit + maximumLineCount: 2 + width: parent.width - (Theme.paddingLarge * 2) + height: Theme.itemSizeExtraSmall + elide: Text.ElideLeft + horizontalAlignment: Text.AlignHCenter + text: radioPlayer._name + } + + RadioImage { + anchors.top: nameLabel.bottom + anchors.bottom: parent.bottom + anchors.topMargin: Theme.paddingLarge + anchors.bottomMargin: Theme.paddingLarge * 2 + id: radioImage + width: height + stationBorder: false + anchors.horizontalCenter: parent.horizontalCenter + stationImage: radioPlayer._favicon ? radioPlayer._favicon : "" + stationLabel: radioPlayer._name + flag: false + onWidthChanged: if (width > radioName.width - (Theme.paddingLarge * 2)) width = radioName.width - (Theme.paddingLarge * 2) + } + } + + Rectangle { + id: artistSongName + anchors.bottom: playerControls.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Theme.paddingLarge + color: Theme.rgba(Theme.overlayBackgroundColor,0.5) + radius: 20 + width: parent.width + height: radioname.height + radiocountry.height + (Theme.paddingMedium * 3) + opacity: radioname.text !== "" ? 1.0 : 0.0 + Behavior on opacity { + FadeAnimator {} + } + + Column { + width: parent.width + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Theme.paddingSmall + + Label { + id: radioname + color: Theme.secondaryColor + wrapMode: Text.WordWrap + font.pixelSize: Theme.fontSizeLarge + fontSizeMode: Text.Fit + maximumLineCount: 5 + width: parent.width - (Theme.paddingMedium * 2) + elide: Text.ElideLeft + horizontalAlignment: Text.AlignHCenter + visible: text.length > 0 + text: radioPlayer.radioVideo && !radioPlayer.isPaused ? radioPlayer._name : radioPlayer.radioArtist // radioPlayer._name + } + + Label { + id: radiocountry + color: Theme.secondaryColor + wrapMode: Text.WordWrap + font.pixelSize: Theme.fontSizeLarge + fontSizeMode: Text.Fit + maximumLineCount: 5 + width: parent.width - (Theme.paddingMedium * 2) + elide: Text.ElideLeft + horizontalAlignment: Text.AlignHCenter + visible: text.length > 0 + text: radioPlayer.radioSong + } + } + } + + // Radio player controls + Item { + id: playerControls + visible: orientation === Orientation.Portrait + anchors.bottom: parent.bottom + anchors.bottomMargin: Theme.paddingMedium + anchors.horizontalCenter: parent.horizontalCenter + height: Theme.itemSizeLarge + width: parent.width + + Rectangle { + width: row.width + (Theme.paddingMedium * 3) + height: play.height + (Theme.paddingMedium * 2) + radius: 90 + color: Theme.rgba(Theme.overlayBackgroundColor,0.5) + border.width: 0 + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + + Row { + id: row + anchors.centerIn: parent + spacing: Theme.paddingMedium + Image { + id: play + source: radioPlayer.isPlaying ? "image://theme/icon-l-pause" : "image://theme/icon-l-play" + height: Theme.itemSizeSmall * 0.75 + width: height + MouseArea { + anchors.fill: parent + onClicked: radioPlayer.isPlaying ? radioPlayer.pauseStream() : radioPlayer.resumeStream()//icon.source == "image://theme/icon-l-play" ? icon.source = "image://theme/icon-l-pause" : icon.source = "image://theme/icon-l-play" + } + } + Image { + + id: playDLNA + source: "image://theme/icon-m-next" + height: play.height + width: height + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: play.verticalCenter + + MouseArea { + anchors.fill: parent + onClicked: { + console.log(radioPlayer.playlistIndex + " | "+radioPlayer.playlistCount) + radioPlayer.playlistIndex < radioPlayer.playlistCount && radioPlayer.playlistIndex > -1 ? radioPlayer.playlistIndex = radioPlayer.playlistIndex + 1 : radioPlayer.playlistIndex = 0 + radioPlayer.loadPlaylistSelected() + + } + } + } + Image { + source: "image://theme/icon-s-timer" + height: play.height + width: height + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: play.verticalCenter + MouseArea { + anchors.fill: parent + onClicked: { + pageStack.push("SleepTimerPage.qml") + /* console.log(radioPlayer.playlistIndex + " | "+radioPlayer.playlistCount) + + if (radioPlayer.playlistIndex > -1) { + radioPlayer.playlistIndex > 0 ? radioPlayer.playlistIndex = radioPlayer.playlistIndex - 1 : radioPlayer.playlistIndex = 16 + } else radioPlayer.playlistIndex = 0 + radioPlayer.loadPlaylistSelected() */ + } + } + } + + } + } + + Rectangle { + visible: orientation === Orientation.Portrait + width: upvote.width + url.width + favorite.width + (Theme.paddingMedium * 4) + height: upvote.height + (Theme.paddingMedium * 2) + radius: 90 + color: Theme.rgba(Theme.overlayBackgroundColor,0.5) + border.width: 0 + anchors.right: parent.right + anchors.rightMargin: Theme.paddingLarge + Row { + anchors.centerIn: parent + spacing: Theme.paddingMedium + Image { + id: favorite + source: radioPlayer._favorite ? "image://theme/icon-m-favorite-selected" : "image://theme/icon-m-favorite" + height: Theme.itemSizeSmall * 0.75 + width: height + MouseArea { + anchors.fill: parent + onClicked: { + radioPlayer._favorite ? radioPlayer._favorite = false : radioPlayer._favorite = true + radioPlayer.setStationFavorite(radioPlayer._stationuuid,radioPlayer._name,radioPlayer._countrycode,radioPlayer._homepage,radioPlayer._url_resolved,radioPlayer._favicon,radioPlayer._tags,radioPlayer._codec,radioPlayer._bitrate,radioPlayer._hls,radioPlayer._favorite) + } + } + } + Image { + id: upvote + property bool returnValue: false + source: returnValue ? "image://theme/icon-m-like" : "image://theme/icon-m-outline-like" + height: favorite.height + width: height + fillMode: Image.PreserveAspectFit + onReturnValueChanged: console.log(" RETURN VALUE: "+upvote.returnValue) + MouseArea { + anchors.fill: parent + onClicked: {radioBrowser.upVote(radioPlayer._stationuuid,upvote.returnValue)} + } + } + Image { + id: url + source: "image://theme/icon-m-website" + height: favorite.height + width: height + fillMode: Image.PreserveAspectFit + MouseArea { + anchors.fill: parent + onClicked: { + statusInfo.visible = true;remorse.execute(statusInfo,qsTr("

Open radio station webpage

"), function() {Qt.openUrlExternally(radioPlayer._homepage)}, 5000) + } + } + } + } + } + } + + Component.onCompleted: { + mediaPlayerPanel.open=false + radioPlayer.playerPageOpen=true + } + Component.onDestruction: { + if (radioPlayer.radioVideo) radioPlayer.pauseStream() + radioPlayer.playerPageOpen=false + mediaPlayerPanel.open=true + } +} + diff --git a/qml/pages/SearchStationsPage.qml b/qml/pages/SearchStationsPage.qml new file mode 100644 index 0000000..1d1350f --- /dev/null +++ b/qml/pages/SearchStationsPage.qml @@ -0,0 +1,222 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import "../models" +import "../delegates" +//import "../radio-browser" + +Page { + property string sortedby: "" + property string filterby + property alias searchby: getCountryStations.order + property string searchtext: "" + property string _countrycode: "" + property int stationCount: 0 + property alias name: getCountryStations.name + property alias tag: getCountryStations.tag + property GetCountryStations getCountryStations: GetCountryStations {id: getCountryStations} + property bool sfocus + + onStatusChanged: if (status !== PageStatus.Active) sfocus=false + + onSearchbyChanged: { + // console.log("SEARCHBY: "+searchby) + switch (searchby){ + case "name": sortedby = "Sorted by Name";break; + case "votes": sortedby = "Most likes";break; + case "clicktrend": sortedby = "Trending right now";break; + case "clickcount": sortedby = "Most played"; + } + } + + BusyIndicator { + id: busy + visible: running + anchors.centerIn: parent + size: BusyIndicatorSize.Large + running: !getCountryStations.finished && getCountryStations.offset > 0 + } + + SilicaListView { + id: view + enabled: !busy.visible + opacity: enabled ? 1 : 0.5 + anchors.fill: parent + + clip: mediaPlayerPanel.expanded + anchors.bottomMargin: sfocus ? 0 : mediaPlayerPanel.visibleSize + + ViewPlaceholder { + anchors.centerIn: parent + enabled: view.count == 0 + text: getCountryStations.finished && view.count === 0 ? "Search" : "Please wait" + hintText: getCountryStations.finished && view.count === 0 ? "radio stations" : "getting radio stations" + } + + VerticalScrollDecorator {} + + onAtYEndChanged: { + if (atYEnd && view.count >= getCountryStations.limit) { + // console.log("AT BOTTOM: "+view.count) + if (getCountryStations.offset + getCountryStations.limit < stationCount) { + getCountryStations.offset = getCountryStations.offset + getCountryStations.limit + 1 + getCountryStations.getStations() + } + } + } + + header: Column { + width: parent.width + + PageHeader { + id: pheader + + + Column { + id: headerCol + anchors.top: parent.top + anchors.topMargin: Theme.paddingLarge + anchors.right: parent.right + anchors.left: parent.left + anchors.rightMargin: Theme.paddingLarge//headerLogo.width + (Theme.paddingLarge * 2) + anchors.leftMargin: Theme.paddingLarge + Row { + anchors.right: parent.right + spacing: Theme.paddingMedium + Image { + id: headerLogo + anchors.bottom: ccode.bottom + height: ccode.height * 0.8 + fillMode: Image.PreserveAspectFit + smooth: true + source: _countrycode === "" ? "../images/bycountry_t.png" : "../flags/"+_countrycode.toLowerCase()+".png" + } + Label { + id: ccode + font.pixelSize: Theme.fontSizeLarge + color: Theme.highlightColor + wrapMode: Text.WordWrap + elide: Text.ElideLeft + text: getCountryStations.country //+ " ["+stationCount+"]" + } + } + Label { + font.pixelSize: Theme.fontSizeSmall + color: Theme.secondaryHighlightColor + width: parent.width + horizontalAlignment: Text.AlignRight + text: sortedby//view.count + " channels" + } + } + } + + Row { + id: row + width: parent.width + SearchField { + id: sfield + placeholderText: "Search" + inputMethodHints: Qt.ImhNoAutoUppercase //| Qt.ImhNoPredictiveText + EnterKey.iconSource: "image://theme/icon-m-enter-close" + EnterKey.onClicked: focus = false + focus: sfocus + + onFocusChanged: { + sfocus = focus + //radioPlayer.isPlaying || radioPlayer.isPaused && !focus ? mediaPlayerPanel.open = false : mediaPlayerPanel.open = true + } + + onTextChanged: { + if (searchtext !== text) { + // console.log(" *** TEXT CHANGED: "+searchCombo.currentIndex+" --- TEXT: "+text) + if (text.length > 0) { + searchtext = text + switch(searchCombo.currentIndex) { + case 0: filterby="name";getCountryStations.offset=0;getCountryStations.name=text;getCountryStations.tag="";break + case 1: filterby="tag";getCountryStations.offset=0;getCountryStations.tag=text;getCountryStations.name="" + } + } else { + getCountryStations.name="" + getCountryStations.tag="" + } + getCountryStations.offset=0; + getCountryStations.clear = true + if (text !== "") getCountryStations.getStations() + } + } + onClicked: {view.currentIndex = -1} + + } + } + + ComboBox { + id: searchCombo + label: "Search by:" + currentIndex: 0 + menu: ContextMenu { + MenuItem { text: "Name" } + MenuItem { text: "Tag" } + } + onValueChanged: { + switch(currentIndex) { + case 0: filterby="name";getCountryStations.offset=0;getCountryStations.name=sfield.text;getCountryStations.tag="";break + case 1: filterby="tag";getCountryStations.offset=0;getCountryStations.tag=sfield.text;getCountryStations.name="" + } + if (searchtext.length !== 0) { + getCountryStations.offset=0; + getCountryStations.clear = true + getCountryStations.getStations() + } + } + } + + } + + PullDownMenu { + MenuItem { + text: "Name" + onClicked: {getCountryStations.order = "name";if (view.count > 0) {getCountryStations.clear=true;getCountryStations.getStations()}}//;xmlModel.running = true} + } + + MenuItem { + text: "Most likes" + onClicked: {getCountryStations.order = "votes";if (view.count > 0) {getCountryStations.clear=true;getCountryStations.getStations()}}//;xmlModel.running = true} + } + MenuItem { + text: "Most played" + onClicked: {getCountryStations.order = "clickcount";if (view.count > 0) {getCountryStations.clear=true;getCountryStations.getStations()}}//xmlModel.running = true} + } + MenuItem { + text: "Trending right now" + onClicked: {getCountryStations.order = "clicktrend";if (view.count > 0) {getCountryStations.clear=true;getCountryStations.getStations()}}//xmlModel.running = true} + } + } + + model: getCountryStations.stationsModel + delegate: StationsDelegate{ + onClicked: { + if (model.url_resolved !== radioPlayer._url_resolved) { + radioPlayer._favicon = model.favicon + radioPlayer._name = model.name + radioPlayer._countrycode = model.countrycode + radioPlayer._tags = model.tags + radioPlayer._codec = model.codec//getCodec(model.codec) + radioPlayer._bitrate = model.bitrate //getBitrate(model.bitrate) + radioPlayer._hls = model.hls + radioPlayer._url_resolved = model.url_resolved + radioPlayer._homepage = model.homepage + radioPlayer._stationuuid = model.stationuuid + //radioPlayer._favorite = model.favorite ? true : false + radioPlayer.getStationFavorite(model.stationuuid) + // pageStack.push("RadioPlayerPage.qml") + } + } + } + } + Component.onCompleted: { + //MediaPlayerPanel.open = false + getCountryStations.countrycode="" + getCountryStations.order=searchby + //getCountryStations.getStations() + } + // Component.onDestruction: if (radioPlayer.isPlaying || radioPlayer.isPaused) mediaPlayerPanel.open ? mediaPlayerPanel.open = false : mediaPlayerPanel.open = true +} diff --git a/qml/pages/SecondPage.qml b/qml/pages/SecondPage.qml new file mode 100644 index 0000000..6dbadf4 --- /dev/null +++ b/qml/pages/SecondPage.qml @@ -0,0 +1,30 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 + +Page { + id: page + + // The effective value will be restricted by ApplicationWindow.allowedOrientations + allowedOrientations: Orientation.All + + SilicaListView { + id: listView + model: 20 + anchors.fill: parent + header: PageHeader { + title: qsTr("Nested Page") + } + delegate: BackgroundItem { + id: delegate + + Label { + x: Theme.horizontalPageMargin + text: qsTr("Item") + " " + index + anchors.verticalCenter: parent.verticalCenter + color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor + } + onClicked: console.log("Clicked " + index) + } + VerticalScrollDecorator {} + } +} diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml new file mode 100644 index 0000000..dbc8920 --- /dev/null +++ b/qml/pages/SettingsPage.qml @@ -0,0 +1,39 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +Page { + Flickable { + id: flick + width:parent.width + height: parent.height - Theme.paddingLarge * 3 + anchors.top: parent.top + anchors.topMargin: Theme.paddingLarge * 3 + contentHeight: column1.height + + Column{ + id: column1 + width: parent.width + spacing: Theme.paddingLarge + + Image{ + source: "../images/community.png" + height: Theme.itemSizeHuge + width: height + fillMode: Image.PreserveAspectFit + anchors { + horizontalCenter: parent.horizontalCenter + } + } + + Label { + width: parent.width-70 + font.pixelSize: Theme.fontSizeSmall + text: qsTr("Working on it.....") + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignHCenter + height: 200 + wrapMode: Text.WordWrap + } + } + } +} diff --git a/qml/pages/SleepTimerPage.qml b/qml/pages/SleepTimerPage.qml new file mode 100644 index 0000000..d4503af --- /dev/null +++ b/qml/pages/SleepTimerPage.qml @@ -0,0 +1,54 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import "../items" + +Page { + id: page + property bool closePanel: false + onClosePanelChanged: if (closePanel) mediaPlayerPanel.open = false + // property int sleepTime: 0 + + //allowedOrientations: Orientation.All + + SilicaFlickable { + anchors.fill: parent + clip: true + anchors.bottomMargin: mediaPlayerPanel.visibleSize + VerticalScrollDecorator {} + PageHeader {title: "Sleep timer";description: ((sleepTime > 0) ? (qsTr("Remaning time: ") + (sleepTime) + qsTr(" minutes")) : qsTr("choose time: ") + minutes.value )} + + ValuePicker { + id: minutes + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + max: 121 + min: 1 + value: sleepTime + } + Label { + text: minutes.value + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + color: Theme.secondaryHighlightColor + font.family: Theme.fontFamilyHeading + font.pixelSize: Theme.fontSizeHuge + } + Row { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 40 + spacing: Theme.paddingLarge + + Button { + text: ((sleepTime > 0) ? (qsTr("Change")) : (qsTr("Start"))) + onPressed: sleepTime = minutes.value + } + Button { + text: qsTr("Stop") + onPressed: sleepTime = 0; + } + } + } + Component.onCompleted: if (mediaPlayerPanel.open) closePanel = true; else closePanel = false; + Component.onDestruction: if (closePanel) mediaPlayerPanel.open = true +} diff --git a/qml/pages/TagListPage.qml b/qml/pages/TagListPage.qml new file mode 100644 index 0000000..9b87c0c --- /dev/null +++ b/qml/pages/TagListPage.qml @@ -0,0 +1,83 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import QtQuick.LocalStorage 2.0 +import "../helpers/db.js" as Favorites + +Page { + property int maxTags: 0 + + property int fontMin: Theme.fontSizeExtraSmall + property int fontMax: Theme.fontSizeHuge + + property ListModel playedTags: ListModel {id: playedTags} + + function getCrSize(size) { /// Calculate and return a more nice looking fontsize based on number of stations. + //console.log("FUNCTION: "+size) + var fs = size === 100 ? fontMin : (size / maxTags) * (fontMax - fontMin) + fontMin; + return fs + } + + onMaxTagsChanged: console.log("MAXTAGS: "+maxTags) + + SilicaFlickable { + id: flick + anchors.fill: parent + anchors.bottomMargin: mediaPlayerPanel.visibleSize + contentWidth: parent.width; + contentHeight: flow.childrenRect.height + header.height + (Theme.paddingLarge * 2) + + clip: true + // header: PageHeader{title: "Play history";description: "Radio stations: "+view.count} + + ScrollDecorator {flickable:flick} + + Column { + id: header + width: parent.width + + PageHeader { + title: "Played tags" + description: "Found "+playedTags.count + } + } + + Flow { + id: flow + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Theme.paddingMedium + clip: true + spacing: Theme.paddingLarge + + Repeater { + id: elements + model: playedTags + + //onItemAdded: "ITEM ADDED: "+model.tag + + Text { + id: tagtext + text: tag + font.pixelSize: getCrSize(myclickcount) //((stationcount / 3000) * 100) * (Theme.fontSizeExtraLarge - Theme.fontSizeSmall) + Theme.fontSizeSmall + //font.bold: if (font.pixelSize >= Theme.fontSizeLarge) true; else false + + color: { + if (font.pixelSize <= Theme.fontSizeMedium) Theme.secondaryColor; + else if (font.pixelSize > Theme.fontSizeMedium) Theme.primaryColor + + } + + MouseArea { + id: m + anchors.fill: parent + onPressedChanged: pressed ? tagtext.color = Theme.highlightColor : tagtext.color = Theme.primaryColor + onClicked: pageStack.push("CountryStationsPage.qml",{filterby: "tag",searchby: "name",stext: tag,comboIndex: 1 })//pageStack.push("CrTagStationsPage.qml",{filter: tag}) //pageStack.push("TagStationsPage.qml",{filter: tag,running: true})// //{Qt.inputMethod.hide();flick.focus=true ;pageStack.push("TagStationsPage.qml",{filter: tag,running: true})} + } + } + } + } + } + Component.onCompleted: {Favorites.getTagsClicked(playedTags,100000)} +} diff --git a/rpm/harbour-allradio.spec b/rpm/harbour-allradio.spec new file mode 100644 index 0000000..ea3f5b2 --- /dev/null +++ b/rpm/harbour-allradio.spec @@ -0,0 +1,42 @@ +Name: harbour-allradio + +Summary: AllRadio +Version: 2.0.9 +Release: 1 +Group: Qt/Qt +License: GPL2 +URL: http://example.org/ +Source0: %{name}-%{version}.tar.bz2 +Requires: sailfishsilica-qt5 >= 0.10.9 +Requires: qt5-qtdeclarative-import-xmllistmodel +BuildRequires: pkgconfig(sailfishapp) >= 1.0.2 +BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(Qt5Qml) +BuildRequires: pkgconfig(Qt5Quick) +BuildRequires: desktop-file-utils + +%description +AllRadio2 is a new version of AllRadio. + + +%prep +%setup -q -n %{name}-%{version} + +%build + +%qmake5 \ +VERSION='%{version}' + +%make_build + +%install +%qmake5_install + +desktop-file-install --delete-original --dir %{buildroot}%{_datadir}/applications %{buildroot}%{_datadir}/applications/*.desktop + +%files +%defattr(-,root,root,-) +%{_bindir}/%{name} +%{_datadir}/%{name} +%{_datadir}/applications/%{name}.desktop +%{_datadir}/icons/hicolor/*/apps/%{name}.png diff --git a/src/harbour-allradio.cpp b/src/harbour-allradio.cpp new file mode 100644 index 0000000..0ba0500 --- /dev/null +++ b/src/harbour-allradio.cpp @@ -0,0 +1,23 @@ +#ifdef QT_QML_DEBUG +#include +#endif +#include +#include + +int main(int argc, char *argv[]) +{ + // SailfishApp::main() will display "qml/harbour-allradio.qml", if you need more + // control over initialization, you can use: + // + // - SailfishApp::application(int, char *[]) to get the QGuiApplication * + // - SailfishApp::createView() to get a new QQuickView * instance + // - SailfishApp::pathTo(QString) to get a QUrl to a resource file + // - SailfishApp::pathToMainQml() to get a QUrl to the main QML file + // + // To display the view, call "show()" (will show fullscreen on device). + + QScopedPointer app(SailfishApp::application(argc,argv)); + app->setApplicationVersion(QString(APP_VERSION)); + + return SailfishApp::main(argc, argv); +} diff --git a/translations/harbour-allradio-de.ts b/translations/harbour-allradio-de.ts new file mode 100644 index 0000000..96aa76e --- /dev/null +++ b/translations/harbour-allradio-de.ts @@ -0,0 +1,1092 @@ + + + + + AboutPage + + AllRadio is an internet radio station player + + + + + CountryNameModel + + Afghanistan + + + + Åland Islands + + + + Albania + + + + Algeria + + + + American Samoa + + + + Andorra + + + + Angola + + + + Anguilla + + + + Antarctica + + + + Antigua & Barbuda + + + + Argentina + + + + Armenia + + + + Aruba + + + + Australia + + + + Austria + + + + Azerbaijan + + + + Bahamas + + + + Bahrain + + + + Bangladesh + + + + Barbados + + + + Belarus + + + + Belgium + + + + Belize + + + + Benin + + + + Bermuda + + + + Bhutan + + + + Bolivia + + + + Bosnia & Herzegovina + + + + Botswana + + + + Bouvet Island + + + + Brazil + + + + British Indian Ocean Territory + + + + British Virgin Islands + + + + Brunei + + + + Bulgaria + + + + Burkina Faso + + + + Burundi + + + + Cambodia + + + + Cameroon + + + + Canada + + + + Cape Verde + + + + Caribbean Netherlands + + + + Cayman Islands + + + + Central African Republic + + + + Chad + + + + Chile + + + + China + + + + Christmas Island + + + + Cocos (Keeling) Islands + + + + Colombia + + + + Comoros + + + + Congo - Brazzaville + + + + Congo - Kinshasa + + + + Cook Islands + + + + Costa Rica + + + + Côte d’Ivoire + + + + Croatia + + + + Cuba + + + + Curaçao + + + + Cyprus + + + + Czechia + + + + Denmark + + + + Djibouti + + + + Dominica + + + + Dominican Republic + + + + Ecuador + + + + Egypt + + + + El Salvador + + + + Equatorial Guinea + + + + Eritrea + + + + Estonia + + + + Eswatini + + + + Ethiopia + + + + Falkland Islands + + + + Faroe Islands + + + + Fiji + + + + Finland + + + + France + + + + French Guiana + + + + French Polynesia + + + + French Southern Territories + + + + Gabon + + + + Gambia + + + + Georgia + + + + Germany + + + + Ghana + + + + Gibraltar + + + + Greece + + + + Greenland + + + + Grenada + + + + Guadeloupe + + + + Guam + + + + Guatemala + + + + Guernsey + + + + Guinea + + + + Guinea-Bissau + + + + Guyana + + + + Haiti + + + + Heard & McDonald Islands + + + + Honduras + + + + Hong Kong SAR China + + + + Hungary + + + + Iceland + + + + India + + + + Indonesia + + + + Iran + + + + Iraq + + + + Ireland + + + + Isle of Man + + + + Israel + + + + Italy + + + + Jamaica + + + + Japan + + + + Jersey + + + + Jordan + + + + Kazakhstan + + + + Kenya + + + + Kiribati + + + + Kuwait + + + + Kyrgyzstan + + + + Laos + + + + Latvia + + + + Lebanon + + + + Lesotho + + + + Liberia + + + + Libya + + + + Liechtenstein + + + + Lithuania + + + + Luxembourg + + + + Macao SAR China + + + + Madagascar + + + + Malawi + + + + Malaysia + + + + Maldives + + + + Mali + + + + Malta + + + + Marshall Islands + + + + Martinique + + + + Mauritania + + + + Mauritius + + + + Mayotte + + + + Mexico + + + + Micronesia + + + + Moldova + + + + Monaco + + + + Mongolia + + + + Montenegro + + + + Montserrat + + + + Morocco + + + + Mozambique + + + + Myanmar (Burma) + + + + Namibia + + + + Nauru + + + + Nepal + + + + Netherlands + + + + New Caledonia + + + + New Zealand + + + + Nicaragua + + + + Niger + + + + Nigeria + + + + Niue + + + + Norfolk Island + + + + North Korea + + + + North Macedonia + + + + Northern Mariana Islands + + + + Norway + + + + Oman + + + + Pakistan + + + + Palau + + + + Palestinian Territories + + + + Panama + + + + Papua New Guinea + + + + Paraguay + + + + Peru + + + + Philippines + + + + Pitcairn Islands + + + + Poland + + + + Portugal + + + + Puerto Rico + + + + Qatar + + + + Réunion + + + + Romania + + + + Russia + + + + Rwanda + + + + Samoa + + + + San Marino + + + + São Tomé & Príncipe + + + + Saudi Arabia + + + + Senegal + + + + Serbia + + + + Seychelles + + + + Sierra Leone + + + + Singapore + + + + Sint Maarten + + + + Slovakia + + + + Slovenia + + + + Solomon Islands + + + + Somalia + + + + South Africa + + + + South Georgia & South Sandwich Islands + + + + South Korea + + + + South Sudan + + + + Spain + + + + Sri Lanka + + + + St. Barthélemy + + + + St. Helena + + + + St. Kitts & Nevis + + + + St. Lucia + + + + St. Martin + + + + St. Pierre & Miquelon + + + + St. Vincent & Grenadines + + + + Sudan + + + + Suriname + + + + Svalbard & Jan Mayen + + + + Sweden + + + + Switzerland + + + + Syria + + + + Taiwan + + + + Tajikistan + + + + Tanzania + + + + Thailand + + + + Timor-Leste + + + + Togo + + + + Tokelau + + + + Tonga + + + + Trinidad & Tobago + + + + Tunisia + + + + Turkey + + + + Turkmenistan + + + + Turks & Caicos Islands + + + + Tuvalu + + + + U.S. Outlying Islands + + + + U.S. Virgin Islands + + + + Uganda + + + + Ukraine + + + + United Arab Emirates + + + + United Kingdom + + + + United States + + + + Uruguay + + + + Uzbekistan + + + + Vanuatu + + + + Vatican City + + + + Venezuela + + + + Vietnam + + + + Wallis & Futuna + + + + Western Sahara + + + + Yemen + + + + Zambia + + + + Zimbabwe + + + + Kosovo + + + + No country + + + + + FavoriteStations + + Vote on Community Radio Browser + + + + Remove from favorites + + + + Add to favorites + + + + + RadioPlayerPage + + <h2>Open radio station webpage</h2> + + + + + SecondPage + + Nested Page + Unterseite + + + Item + Element + + + + SettingsPage + + Working on it..... + + + + + SleepTimerPage + + Remaning time: + + + + minutes + + + + choose time: + + + + Change + + + + Start + + + + Stop + + + + + StationsDelegate + + Vote on Community Radio Browser + + + + diff --git a/translations/harbour-allradio.ts b/translations/harbour-allradio.ts new file mode 100644 index 0000000..5f0ac85 --- /dev/null +++ b/translations/harbour-allradio.ts @@ -0,0 +1,1092 @@ + + + + + AboutPage + + AllRadio is an internet radio station player + + + + + CountryNameModel + + Afghanistan + + + + Åland Islands + + + + Albania + + + + Algeria + + + + American Samoa + + + + Andorra + + + + Angola + + + + Anguilla + + + + Antarctica + + + + Antigua & Barbuda + + + + Argentina + + + + Armenia + + + + Aruba + + + + Australia + + + + Austria + + + + Azerbaijan + + + + Bahamas + + + + Bahrain + + + + Bangladesh + + + + Barbados + + + + Belarus + + + + Belgium + + + + Belize + + + + Benin + + + + Bermuda + + + + Bhutan + + + + Bolivia + + + + Bosnia & Herzegovina + + + + Botswana + + + + Bouvet Island + + + + Brazil + + + + British Indian Ocean Territory + + + + British Virgin Islands + + + + Brunei + + + + Bulgaria + + + + Burkina Faso + + + + Burundi + + + + Cambodia + + + + Cameroon + + + + Canada + + + + Cape Verde + + + + Caribbean Netherlands + + + + Cayman Islands + + + + Central African Republic + + + + Chad + + + + Chile + + + + China + + + + Christmas Island + + + + Cocos (Keeling) Islands + + + + Colombia + + + + Comoros + + + + Congo - Brazzaville + + + + Congo - Kinshasa + + + + Cook Islands + + + + Costa Rica + + + + Côte d’Ivoire + + + + Croatia + + + + Cuba + + + + Curaçao + + + + Cyprus + + + + Czechia + + + + Denmark + + + + Djibouti + + + + Dominica + + + + Dominican Republic + + + + Ecuador + + + + Egypt + + + + El Salvador + + + + Equatorial Guinea + + + + Eritrea + + + + Estonia + + + + Eswatini + + + + Ethiopia + + + + Falkland Islands + + + + Faroe Islands + + + + Fiji + + + + Finland + + + + France + + + + French Guiana + + + + French Polynesia + + + + French Southern Territories + + + + Gabon + + + + Gambia + + + + Georgia + + + + Germany + + + + Ghana + + + + Gibraltar + + + + Greece + + + + Greenland + + + + Grenada + + + + Guadeloupe + + + + Guam + + + + Guatemala + + + + Guernsey + + + + Guinea + + + + Guinea-Bissau + + + + Guyana + + + + Haiti + + + + Heard & McDonald Islands + + + + Honduras + + + + Hong Kong SAR China + + + + Hungary + + + + Iceland + + + + India + + + + Indonesia + + + + Iran + + + + Iraq + + + + Ireland + + + + Isle of Man + + + + Israel + + + + Italy + + + + Jamaica + + + + Japan + + + + Jersey + + + + Jordan + + + + Kazakhstan + + + + Kenya + + + + Kiribati + + + + Kuwait + + + + Kyrgyzstan + + + + Laos + + + + Latvia + + + + Lebanon + + + + Lesotho + + + + Liberia + + + + Libya + + + + Liechtenstein + + + + Lithuania + + + + Luxembourg + + + + Macao SAR China + + + + Madagascar + + + + Malawi + + + + Malaysia + + + + Maldives + + + + Mali + + + + Malta + + + + Marshall Islands + + + + Martinique + + + + Mauritania + + + + Mauritius + + + + Mayotte + + + + Mexico + + + + Micronesia + + + + Moldova + + + + Monaco + + + + Mongolia + + + + Montenegro + + + + Montserrat + + + + Morocco + + + + Mozambique + + + + Myanmar (Burma) + + + + Namibia + + + + Nauru + + + + Nepal + + + + Netherlands + + + + New Caledonia + + + + New Zealand + + + + Nicaragua + + + + Niger + + + + Nigeria + + + + Niue + + + + Norfolk Island + + + + North Korea + + + + North Macedonia + + + + Northern Mariana Islands + + + + Norway + + + + Oman + + + + Pakistan + + + + Palau + + + + Palestinian Territories + + + + Panama + + + + Papua New Guinea + + + + Paraguay + + + + Peru + + + + Philippines + + + + Pitcairn Islands + + + + Poland + + + + Portugal + + + + Puerto Rico + + + + Qatar + + + + Réunion + + + + Romania + + + + Russia + + + + Rwanda + + + + Samoa + + + + San Marino + + + + São Tomé & Príncipe + + + + Saudi Arabia + + + + Senegal + + + + Serbia + + + + Seychelles + + + + Sierra Leone + + + + Singapore + + + + Sint Maarten + + + + Slovakia + + + + Slovenia + + + + Solomon Islands + + + + Somalia + + + + South Africa + + + + South Georgia & South Sandwich Islands + + + + South Korea + + + + South Sudan + + + + Spain + + + + Sri Lanka + + + + St. Barthélemy + + + + St. Helena + + + + St. Kitts & Nevis + + + + St. Lucia + + + + St. Martin + + + + St. Pierre & Miquelon + + + + St. Vincent & Grenadines + + + + Sudan + + + + Suriname + + + + Svalbard & Jan Mayen + + + + Sweden + + + + Switzerland + + + + Syria + + + + Taiwan + + + + Tajikistan + + + + Tanzania + + + + Thailand + + + + Timor-Leste + + + + Togo + + + + Tokelau + + + + Tonga + + + + Trinidad & Tobago + + + + Tunisia + + + + Turkey + + + + Turkmenistan + + + + Turks & Caicos Islands + + + + Tuvalu + + + + U.S. Outlying Islands + + + + U.S. Virgin Islands + + + + Uganda + + + + Ukraine + + + + United Arab Emirates + + + + United Kingdom + + + + United States + + + + Uruguay + + + + Uzbekistan + + + + Vanuatu + + + + Vatican City + + + + Venezuela + + + + Vietnam + + + + Wallis & Futuna + + + + Western Sahara + + + + Yemen + + + + Zambia + + + + Zimbabwe + + + + Kosovo + + + + No country + + + + + FavoriteStations + + Vote on Community Radio Browser + + + + Remove from favorites + + + + Add to favorites + + + + + RadioPlayerPage + + <h2>Open radio station webpage</h2> + + + + + SecondPage + + Nested Page + + + + Item + + + + + SettingsPage + + Working on it..... + + + + + SleepTimerPage + + Remaning time: + + + + minutes + + + + choose time: + + + + Change + + + + Start + + + + Stop + + + + + StationsDelegate + + Vote on Community Radio Browser + + + +