1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-22 10:42:29 +01: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) {
if (nav.currentNavigationName === name) {
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

View File

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

View File

@ -29,6 +29,14 @@ Item {
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
state: "inactive"
onContentFolderNameChanged: {
@ -48,8 +56,10 @@ Item {
btnSetWallpaper.enabled = false;
}
Connections {
function onSetSidebarItem(folderName, type) {
// Toggle sidebar if clicked on the same content twice
if (root.contentFolderName === folderName && root.state !== "inactive") {
root.state = "inactive";
@ -152,10 +162,12 @@ Item {
AnimatedImage {
id: image
// Do NOT enable async image loading!
// Otherwhise it will still hold the file
// when calling InstalledListModel::deinstallItemAt
asynchronous: false
playing: true
fillMode: Image.PreserveAspectCrop
asynchronous: true
anchors.fill: parent
onStatusChanged: {
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
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()) {
qWarning() << "remove folder error, invalid index " << index;
return false;
}
QTimer::singleShot(1000, this, [this, absoluteStoragePath]() {
int index = -1;
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);
const QString path = QUrl::fromUserInput(m_screenPlayFiles.at(index).m_absoluteStoragePath.toString()).toLocalFile();
if (index < 0 || index >= m_screenPlayFiles.count()) {
qWarning() << "Remove folder error, invalid index " << index;
return;
}
QDir dir(path);
const bool success = dir.removeRecursively();
beginRemoveRows(QModelIndex(), index, index);
m_screenPlayFiles.removeAt(index);
endRemoveRows();
if (!success)
qWarning() << "Could not remove folder: " << m_screenPlayFiles.at(index).m_absoluteStoragePath.toString();
const QString path = ScreenPlayUtil::toLocal(absoluteStoragePath);
m_screenPlayFiles.removeAt(index);
endRemoveRows();
return success;
QDir dir(path);
bool success = true;
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()
{
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);
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)
return {};
QVariantMap map;
for (int i = 0; i < m_screenPlayFiles.count(); i++) {
const QString localInstalledPath = ScreenPlayUtil::toLocal(m_globalVariables->localStoragePath().toString());
if (m_screenPlayFiles[i].m_folderId == folderId) {
map.insert("m_title", m_screenPlayFiles[i].m_title);
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);
map.insert("m_type", QVariant::fromValue(m_screenPlayFiles[i].m_type));
map.insert("m_absoluteStoragePath", m_screenPlayFiles[i].m_absoluteStoragePath);
map.insert("m_publishedFileID", m_screenPlayFiles[i].m_publishedFileID);
map.insert("m_isNew", m_screenPlayFiles[i].m_isNew);
map.insert("m_lastModified", m_screenPlayFiles[i].m_lastModified);
if (!QDir(localInstalledPath + "/" + folderName).exists()) {
return {};
}
for (const auto& item : m_screenPlayFiles) {
if (item.m_folderId == folderName) {
QVariantMap map;
map.insert("m_title", item.m_title);
map.insert("m_preview", item.m_preview);
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;
}
}
@ -227,7 +277,7 @@ QVariantMap InstalledListModel::get(const QString& folderId) const
}
/*!
\brief .
\brief Removes all entires and loads it again.
*/
void InstalledListModel::reset()
{

View File

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