1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-09-18 08:22:33 +02:00

Fix project deletion when content (preview.gif) was in use

This commit is contained in:
Elias Steurer 2021-09-01 16:43:54 +02:00
parent 2226ed1b7e
commit c0d528048b
5 changed files with 147 additions and 46 deletions

View File

@ -34,11 +34,17 @@ ApplicationWindow {
function switchPage(name) { function switchPage(name) {
if (nav.currentNavigationName === name) { if (nav.currentNavigationName === name) {
if (name === "Installed") if (name === "Installed")
ScreenPlay.installedListModel.reset(); ScreenPlay.installedListModel.reset()
} }
stackView.replace("qrc:/qml/" + name + "/" + name + ".qml");
sidebar.state = "inactive"; if (name === "Installed") {
stackView.replace("qrc:/qml/" + name + "/" + name + ".qml", {
"sidebar": sidebar
})
return
}
stackView.replace("qrc:/qml/" + name + "/" + name + ".qml")
sidebar.state = "inactive"
} }
color: Material.theme === Material.Dark ? Qt.darker(Material.background) : Material.background color: Material.theme === Material.Dark ? Qt.darker(Material.background) : Material.background

View File

@ -13,6 +13,7 @@ Item {
property bool refresh: false property bool refresh: false
property bool enabled: true property bool enabled: true
property Sidebar sidebar
signal setNavigationItem(var pos) signal setNavigationItem(var pos)
signal setSidebarActive(var active) signal setSidebarActive(var active)
@ -102,6 +103,36 @@ Item {
onDragStarted: isDragging = true onDragStarted: isDragging = true
onDragEnded: isDragging = false onDragEnded: isDragging = false
model: ScreenPlay.installedListFilter model: ScreenPlay.installedListFilter
removeDisplaced: Transition {
SequentialAnimation {
PauseAnimation {
duration: 150
}
NumberAnimation {
properties: "x,y"
duration: 250
easing.type: Easing.InOutQuart
}
}
}
remove: Transition {
SequentialAnimation {
NumberAnimation {
property: "opacity"
to: 0
duration: 200
easing.type: Easing.InOutQuart
}
NumberAnimation {
properties: "y"
to: 100
duration: 200
easing.type: Easing.InOutQuart
}
}
}
onContentYChanged: { onContentYChanged: {
if (contentY <= -180) if (contentY <= -180)
gridView.headerItem.isVisible = true; gridView.headerItem.isVisible = true;
@ -262,8 +293,8 @@ Item {
enabled: contextMenu.publishedFileID !== 0 enabled: contextMenu.publishedFileID !== 0
icon.source: "qrc:/assets/icons/icon_steam.svg" icon.source: "qrc:/assets/icons/icon_steam.svg"
onClicked: { onClicked: {
print(contextMenu.publishedFileID) Qt.openUrlExternally(
Qt.openUrlExternally("steam://url/CommunityFilePage/" + contextMenu.publishedFileID); "steam://url/CommunityFilePage/" + contextMenu.publishedFileID)
} }
} }
@ -271,15 +302,16 @@ Item {
Dialog { Dialog {
id: deleteDialog id: deleteDialog
property int currentItemIndex: 0
title: qsTr("Are you sure you want to delete this item?") title: qsTr("Are you sure you want to delete this item?")
standardButtons: Dialog.Ok | Dialog.Cancel standardButtons: Dialog.Ok | Dialog.Cancel
modal: true modal: true
dim: true dim: true
anchors.centerIn: Overlay.overlay anchors.centerIn: Overlay.overlay
onAccepted: ScreenPlay.installedListModel.deinstallItemAt(currentItemIndex) onAccepted: {
root.sidebar.clear()
ScreenPlay.installedListModel.deinstallItemAt(
contextMenu.absoluteStoragePath)
}
} }
Navigation { Navigation {

View File

@ -29,6 +29,14 @@ Item {
return -1; return -1;
} }
// This is used for removing wallpaper. We need to clear
// the preview image/gif so we can release the file for deletion.
function clear(){
image.source = ""
txtHeadline.text = ""
root.state = "inactive"
}
width: 400 width: 400
state: "inactive" state: "inactive"
onContentFolderNameChanged: { onContentFolderNameChanged: {
@ -48,8 +56,10 @@ Item {
btnSetWallpaper.enabled = false; btnSetWallpaper.enabled = false;
} }
Connections { Connections {
function onSetSidebarItem(folderName, type) { function onSetSidebarItem(folderName, type) {
// Toggle sidebar if clicked on the same content twice // Toggle sidebar if clicked on the same content twice
if (root.contentFolderName === folderName && root.state !== "inactive") { if (root.contentFolderName === folderName && root.state !== "inactive") {
root.state = "inactive"; root.state = "inactive";
@ -152,10 +162,12 @@ Item {
AnimatedImage { AnimatedImage {
id: image id: image
// Do NOT enable async image loading!
// Otherwhise it will still hold the file
// when calling InstalledListModel::deinstallItemAt
asynchronous: false
playing: true playing: true
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
asynchronous: true
anchors.fill: parent anchors.fill: parent
onStatusChanged: { onStatusChanged: {
if (image.status === Image.Error) if (image.status === Image.Error)

View File

@ -45,27 +45,65 @@ void InstalledListModel::init()
/*! /*!
\brief Deleted the item from the local storage and removes it from the \brief Deleted the item from the local storage and removes it from the
installed list. installed list. We wait for the qml engine to free all resources before
we proceed. This like the preview.gif will be in use when clicking on an item
*/ */
bool InstalledListModel::deinstallItemAt(const int index) void InstalledListModel::deinstallItemAt(const QString& absoluteStoragePath)
{ {
if (index < 0 || index >= m_screenPlayFiles.count()) { QTimer::singleShot(1000, this, [this, absoluteStoragePath]() {
qWarning() << "remove folder error, invalid index " << index; int index = -1;
return false; for (int i = 0; i < m_screenPlayFiles.size(); ++i) {
} if (m_screenPlayFiles.at(i).m_absoluteStoragePath.toString() == absoluteStoragePath) {
index = i;
break;
}
}
beginRemoveRows(QModelIndex(), index, index); if (index < 0 || index >= m_screenPlayFiles.count()) {
const QString path = QUrl::fromUserInput(m_screenPlayFiles.at(index).m_absoluteStoragePath.toString()).toLocalFile(); qWarning() << "Remove folder error, invalid index " << index;
return;
}
QDir dir(path); beginRemoveRows(QModelIndex(), index, index);
const bool success = dir.removeRecursively(); m_screenPlayFiles.removeAt(index);
endRemoveRows();
if (!success) const QString path = ScreenPlayUtil::toLocal(absoluteStoragePath);
qWarning() << "Could not remove folder: " << m_screenPlayFiles.at(index).m_absoluteStoragePath.toString();
m_screenPlayFiles.removeAt(index); QDir dir(path);
endRemoveRows(); bool success = true;
return success; if (!dir.exists()) {
qWarning() << "Directory does not exist!" << dir;
return;
}
// We must pause the QFileSystemWatcher to not trigger
// a reload for every removed file
m_fileSystemWatcher.blockSignals(true);
for (auto& item : dir.entryInfoList(QDir::Files)) {
if (!QFile::remove(item.absoluteFilePath())) {
qWarning() << "Unable to remove file:" << item;
success = false;
break;
}
}
if (!success) {
qWarning() << "Could not remove folder content at: " << path;
loadInstalledContent();
}
if (!dir.rmdir(path)) {
qWarning() << "Could not remove folder at: " << path;
return;
}
// Add delay to the watcher, because it was trigger by
// something when enabling after the removal.
QTimer::singleShot(3000, this, [this]() {
m_fileSystemWatcher.blockSignals(false);
});
});
} }
/*! /*!
@ -156,11 +194,17 @@ void InstalledListModel::append(const QJsonObject& obj, const QString& folderNam
} }
/*! /*!
\brief Loads all installed content. Skips projects.json without a "type" field. \brief Loads all installed content.
- Skips if the loadContentFuture is already running.
- Skips projects.json without a "type" field.
*/ */
void InstalledListModel::loadInstalledContent() void InstalledListModel::loadInstalledContent()
{ {
QtConcurrent::run([this]() { qInfo() << "loadInstalledContent";
if (m_loadContentFuture.isRunning())
return;
m_loadContentFuture = QtConcurrent::run([this]() {
QFileInfoList list = QDir(m_globalVariables->localStoragePath().toLocalFile()).entryInfoList(QDir::NoDotAndDotDot | QDir::AllDirs); QFileInfoList list = QDir(m_globalVariables->localStoragePath().toLocalFile()).entryInfoList(QDir::NoDotAndDotDot | QDir::AllDirs);
int counter = 0; int counter = 0;
@ -198,27 +242,33 @@ void InstalledListModel::loadInstalledContent()
} }
/*! /*!
\brief . \brief Used for receiving values from qml. One must add all new fields
when adding new roles to this model.
*/ */
QVariantMap InstalledListModel::get(const QString& folderId) const QVariantMap InstalledListModel::get(const QString& folderName) const
{ {
if (m_screenPlayFiles.count() == 0) if (m_screenPlayFiles.count() == 0)
return {}; return {};
QVariantMap map; const QString localInstalledPath = ScreenPlayUtil::toLocal(m_globalVariables->localStoragePath().toString());
for (int i = 0; i < m_screenPlayFiles.count(); i++) {
if (m_screenPlayFiles[i].m_folderId == folderId) { if (!QDir(localInstalledPath + "/" + folderName).exists()) {
map.insert("m_title", m_screenPlayFiles[i].m_title); return {};
map.insert("m_preview", m_screenPlayFiles[i].m_preview); }
map.insert("m_previewGIF", m_screenPlayFiles[i].m_previewGIF);
map.insert("m_file", m_screenPlayFiles[i].m_file); for (const auto& item : m_screenPlayFiles) {
map.insert("m_type", QVariant::fromValue(m_screenPlayFiles[i].m_type)); if (item.m_folderId == folderName) {
map.insert("m_absoluteStoragePath", m_screenPlayFiles[i].m_absoluteStoragePath); QVariantMap map;
map.insert("m_publishedFileID", m_screenPlayFiles[i].m_publishedFileID); map.insert("m_title", item.m_title);
map.insert("m_isNew", m_screenPlayFiles[i].m_isNew); map.insert("m_preview", item.m_preview);
map.insert("m_lastModified", m_screenPlayFiles[i].m_lastModified); map.insert("m_previewGIF", item.m_previewGIF);
map.insert("m_file", item.m_file);
map.insert("m_type", QVariant::fromValue(item.m_type));
map.insert("m_absoluteStoragePath", item.m_absoluteStoragePath);
map.insert("m_publishedFileID", item.m_publishedFileID);
map.insert("m_isNew", item.m_isNew);
map.insert("m_lastModified", item.m_lastModified);
return map; return map;
} }
} }
@ -227,7 +277,7 @@ QVariantMap InstalledListModel::get(const QString& folderId) const
} }
/*! /*!
\brief . \brief Removes all entires and loads it again.
*/ */
void InstalledListModel::reset() void InstalledListModel::reset()
{ {

View File

@ -99,13 +99,13 @@ public:
} }
public slots: public slots:
QVariantMap get(const QString& folderId) const; QVariantMap get(const QString& folderName) const;
void loadInstalledContent(); void loadInstalledContent();
void append(const QJsonObject&, const QString&, const bool isNew, const QDateTime& lastModified); void append(const QJsonObject&, const QString&, const bool isNew, const QDateTime& lastModified);
void reset(); void reset();
void init(); void init();
bool deinstallItemAt(const int index); void deinstallItemAt(const QString& absoluteStoragePath);
void setCount(int count) void setCount(int count)
{ {
@ -124,6 +124,7 @@ private:
QFileSystemWatcher m_fileSystemWatcher; QFileSystemWatcher m_fileSystemWatcher;
QVector<ProjectFile> m_screenPlayFiles; QVector<ProjectFile> m_screenPlayFiles;
int m_count { 0 }; int m_count { 0 };
QFuture<void> m_loadContentFuture;
const std::shared_ptr<GlobalVariables>& m_globalVariables; const std::shared_ptr<GlobalVariables>& m_globalVariables;
}; };