diff --git a/src/databaseinterface.cpp b/src/databaseinterface.cpp --- a/src/databaseinterface.cpp +++ b/src/databaseinterface.cpp @@ -2821,16 +2821,6 @@ qCInfo(orgKdeElisaDatabase) << "finished update to v13 of database schema"; } -void DatabaseInterface::upgradeDatabaseV15() -{ - -} - -void DatabaseInterface::upgradeDatabaseV16() -{ - -} - void DatabaseInterface::upgradeDatabaseV14() { qCInfo(orgKdeElisaDatabase) << "begin update to v14 of database schema"; @@ -2932,6 +2922,141 @@ qCInfo(orgKdeElisaDatabase) << "finished update to v14 of database schema"; } +void DatabaseInterface::upgradeDatabaseV15() +{ + qCInfo(orgKdeElisaDatabase) << "begin update to v15 of database schema"; + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV15` (`Version` INTEGER PRIMARY KEY NOT NULL)")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery disableForeignKeys(d->mTracksDatabase); + + auto result = disableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=OFF")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << disableForeignKeys.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << disableForeignKeys.lastError(); + + Q_EMIT databaseError(); + } + } + + d->mTracksDatabase.transaction(); + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `RadiosNew` (" + "`ID` INTEGER PRIMARY KEY AUTOINCREMENT, " + "`HttpAddress` VARCHAR(255) NOT NULL, " + "`ImageAddress` VARCHAR(255) NOT NULL, " + "`Title` VARCHAR(85) NOT NULL, " + "`Rating` INTEGER NOT NULL DEFAULT 0, " + "`Genre` VARCHAR(55), " + "`Comment` VARCHAR(255), " + "UNIQUE (" + "`HttpAddress`" + "), " + "UNIQUE (" + "`Title`, `HttpAddress`" + ") " + "CONSTRAINT fk_tracks_genre FOREIGN KEY (`Genre`) REFERENCES `Genre`(`Name`))" + )); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("INSERT INTO RadiosNew SELECT ID, HttpAddress, '', Title, Rating, Genre, Comment FROM Radios")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `Radios`")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("ALTER TABLE `RadiosNew` RENAME TO `Radios`")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + const auto &result = createSchemaQuery.exec(QStringLiteral("INSERT INTO `Radios` (`HttpAddress`, `ImageAddress`, `Title`) " + "SELECT 'https://chai5she.cdn.dvmr.fr/francemusique-lofi.mp3', 'https://static.radio.fr/images/broadcasts/07/f7/3366/c44.png', 'France Musique'" + )); + if (!result) { + qCInfo(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << createSchemaQuery.lastQuery(); + qCInfo(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + d->mTracksDatabase.commit(); + + { + QSqlQuery enableForeignKeys(d->mTracksDatabase); + + auto result = enableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=ON")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << enableForeignKeys.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << enableForeignKeys.lastError(); + + Q_EMIT databaseError(); + } + } + + qCInfo(orgKdeElisaDatabase) << "finished update to v15 of database schema"; +} + +void DatabaseInterface::upgradeDatabaseV16() +{ + +} + void DatabaseInterface::checkDatabaseSchema() { checkAlbumsTableSchema(); @@ -3830,6 +3955,7 @@ "radios.`ID`, " "radios.`Title`, " "radios.`HttpAddress`, " + "radios.`ImageAddress`, " "radios.`Rating`, " "trackGenre.`Name`, " "radios.`Comment` " @@ -4761,6 +4887,7 @@ "radios.`ID`, " "radios.`Title`, " "radios.`HttpAddress`, " + "radios.`ImageAddress`, " "radios.`Rating`, " "trackGenre.`Name`, " "radios.`Comment` " @@ -5431,14 +5558,14 @@ "`httpAddress`, " "`Comment`, " "`Rating`, " - "`Priority`) " + "`ImageAddress`) " "VALUES " "(" ":title, " ":httpAddress, " ":comment, " ":trackRating," - "1)"); + ":imageAddress)"); auto result = prepareQuery(d->mInsertRadioQuery, insertRadioQueryText); @@ -5470,7 +5597,8 @@ "`HttpAddress` = :httpAddress, " "`Title` = :title, " "`Comment` = :comment, " - "`Rating` = :trackRating " + "`Rating` = :trackRating, " + "`ImageAddress` = :imageAddress " "WHERE " "`ID` = :radioId"); @@ -6729,16 +6857,15 @@ result[DataTypes::TrackDataType::key_type::DatabaseIdRole] = trackRecord.value(0); result[DataTypes::TrackDataType::key_type::TitleRole] = trackRecord.value(1); - result[DataTypes::TrackDataType::key_type::AlbumRole] = i18n("Radios"); result[DataTypes::TrackDataType::key_type::ArtistRole] = trackRecord.value(1); - result[DataTypes::TrackDataType::key_type::ResourceRole] = trackRecord.value(2); - result[DataTypes::TrackDataType::key_type::RatingRole] = trackRecord.value(3); - if (!trackRecord.value(4).isNull()) { - result[DataTypes::TrackDataType::key_type::GenreRole] = trackRecord.value(4); + result[DataTypes::TrackDataType::key_type::ImageUrlRole] = trackRecord.value(3); + result[DataTypes::TrackDataType::key_type::RatingRole] = trackRecord.value(4); + if (!trackRecord.value(5).isNull()) { + result[DataTypes::TrackDataType::key_type::GenreRole] = trackRecord.value(5); } - result[DataTypes::TrackDataType::key_type::CommentRole] = trackRecord.value(5); + result[DataTypes::TrackDataType::key_type::CommentRole] = trackRecord.value(6); result[DataTypes::TrackDataType::key_type::ElementTypeRole] = ElisaUtils::Radio; return result; @@ -7144,6 +7271,7 @@ query.bindValue(QStringLiteral(":title"), oneTrack.title()); query.bindValue(QStringLiteral(":comment"), oneTrack.comment()); query.bindValue(QStringLiteral(":trackRating"), oneTrack.rating()); + query.bindValue(QStringLiteral(":imageAddress"), oneTrack.albumCover()); auto result = execQuery(query); diff --git a/src/models/trackmetadatamodel.cpp b/src/models/trackmetadatamodel.cpp --- a/src/models/trackmetadatamodel.cpp +++ b/src/models/trackmetadatamodel.cpp @@ -165,16 +165,17 @@ case DataTypes::ResourceRole: result = i18nc("Radio HTTP address for radio metadata view", "Stream Http Address"); break; - case DataTypes::SecondaryTextRole: case DataTypes::ImageUrlRole: + result = i18nc("Image address for radio metadata view", "Image Address"); + break; + case DataTypes::SecondaryTextRole: case DataTypes::ShadowForImageRole: case DataTypes::ChildModelRole: case DataTypes::StringDurationRole: case DataTypes::IsValidAlbumArtistRole: case DataTypes::AllArtistsRole: case DataTypes::HighestTrackRating: case DataTypes::IdRole: - case DataTypes::ParentIdRole: case DataTypes::DatabaseIdRole: case DataTypes::IsSingleDiscAlbumRole: case DataTypes::ContainerDataRole: @@ -195,6 +196,7 @@ result = TextEntry; break; case DataTypes::ResourceRole: + case DataTypes::ImageUrlRole: result = TextEntry; break; case DataTypes::ArtistRole: @@ -244,7 +246,6 @@ case DataTypes::BitRateRole: case DataTypes::ChannelsRole: case DataTypes::SecondaryTextRole: - case DataTypes::ImageUrlRole: case DataTypes::ShadowForImageRole: case DataTypes::ChildModelRole: case DataTypes::StringDurationRole: @@ -500,6 +501,7 @@ DataTypes::TitleRole, DataTypes::ResourceRole, DataTypes::CommentRole, + DataTypes::ImageUrlRole, DataTypes::DatabaseIdRole }) { @@ -539,6 +541,14 @@ void TrackMetadataModel::saveData() { + QString imageUrl = mTrackData[DataTypes::ImageUrlRole].toString(); + if (!imageUrl.isEmpty() + && !imageUrl.startsWith(QStringLiteral("http://")) + && !imageUrl.startsWith(QStringLiteral("https://")) + && !imageUrl.startsWith(QStringLiteral("file://"))) { + mTrackData[DataTypes::ImageUrlRole] = QStringLiteral("file:/").append(imageUrl); + } + Q_EMIT saveRadioData(mTrackData); } @@ -557,7 +567,8 @@ } const QList fieldsForTrack({DataTypes::TitleRole, DataTypes::ResourceRole, - DataTypes::CommentRole, DataTypes::DatabaseIdRole}); + DataTypes::CommentRole, DataTypes::ImageUrlRole, + DataTypes::DatabaseIdRole}); fillDataFromTrackData(radiosData, fieldsForTrack); } diff --git a/src/qml/DataListView.qml b/src/qml/DataListView.qml --- a/src/qml/DataListView.qml +++ b/src/qml/DataListView.qml @@ -45,11 +45,12 @@ "initialDatabaseId": databaseId, "fileName": url, "modelType": viewHeader.modelType, - "showImage": false, + "showImage": true, "showTrackFileName": false, "showDeleteButton": databaseId !== -1, "showApplyButton": true, "editableMetadata": true, + "widthIndex": 4.5, }); } else { metadataLoader.setSource("MediaTrackMetadataView.qml", diff --git a/src/qml/ListBrowserDelegate.qml b/src/qml/ListBrowserDelegate.qml --- a/src/qml/ListBrowserDelegate.qml +++ b/src/qml/ListBrowserDelegate.qml @@ -164,6 +164,12 @@ color: myPalette.shadow } + + onStatusChanged: { + if (coverImageElement.status === Image.Error) { + source = 'image://icon/media-optical-audio' + } + } } } @@ -313,6 +319,16 @@ } } + Connections { + target: mediaTrack + + onImageUrlChanged: { + if (coverImageElement.source !== imageUrl) { + coverImageElement.source = (imageUrl != '' ? imageUrl : Qt.resolvedUrl(elisaTheme.defaultAlbumImage)) + } + } + } + states: [ State { name: 'notSelected' diff --git a/src/qml/MediaTrackMetadataView.qml b/src/qml/MediaTrackMetadataView.qml --- a/src/qml/MediaTrackMetadataView.qml +++ b/src/qml/MediaTrackMetadataView.qml @@ -35,6 +35,7 @@ property alias showTrackFileName: fileNameRow.visible property alias showDeleteButton: deleteButtonBox.visible property alias showApplyButton: applyButton.visible + property double widthIndex: 2.8 signal rejected() @@ -56,7 +57,7 @@ color: myPalette.window minimumHeight: elisaTheme.coverImageSize * 1.8 - minimumWidth: elisaTheme.coverImageSize * 2.8 + minimumWidth: elisaTheme.coverImageSize * trackMetadata.widthIndex ColumnLayout { anchors.fill: parent @@ -89,6 +90,12 @@ Layout.minimumWidth: elisaTheme.coverImageSize Layout.maximumHeight: elisaTheme.coverImageSize Layout.maximumWidth: elisaTheme.coverImageSize + + onStatusChanged: { + if (metadataImage.status === Image.Error) { + source = Qt.resolvedUrl(elisaTheme.defaultAlbumImage) + } + } } ListView { @@ -230,6 +237,14 @@ } } + Connections { + target: realModel + + onCoverUrlChanged: { + metadataImage.source = realModel.coverUrl + } + } + Component.onCompleted: { if (elisa.musicManager) { if (initialDatabaseId === -1) {