diff --git a/CMakeLists.txt b/CMakeLists.txt index 89506e3..3f5658a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ find_package(Qt6 COMPONENTS Widgets Qml QuickControls2 REQUIRED) add_executable(${PROJECT} src/main.cpp + src/FileIO.cpp src/resources.qrc src/Gui/Style/resources.qrc) diff --git a/src/FileIO.cpp b/src/FileIO.cpp new file mode 100644 index 0000000..35ddf83 --- /dev/null +++ b/src/FileIO.cpp @@ -0,0 +1,159 @@ +/** + * @file FileIO.cpp + * @author marisa (marisa@fwmari.net) + * @brief File I/O backend implementation + * @version 0.1 + * @date 2023-12-27 + * + * @copyright Copyright (c) 2023 + * + */ + +#include "FileIO.hpp" +#include +#include +#include + +static FileIO *m_fileIO = nullptr; + +QObject *FileIO::singletonProvider(QQmlEngine *engine, QJSEngine *) { + if (!m_fileIO) + m_fileIO = new FileIO((QObject *)engine); + + return (QObject *)m_fileIO; +} + +void FileIO::registerTypes(const char *uri) { + qmlRegisterSingletonType(uri, 0, 1, "FileIO", + FileIO::singletonProvider); +} + +QString FileIO::read(const QUrl &_path) { + QString path(_path.toLocalFile()); + + if (path.isEmpty()) { + emit this->error("Invalid path"); + return QString(); + } + + QFile file(path); + + if (!file.open(QIODevice::ReadOnly)) { + emit this->error("Could not open file"); + return QString(); + } + + QString line, content; + QTextStream stream((QIODevice *)&file); + + do { + line = stream.readLine(); + content += line; + } while (!line.isNull()); + + ((QFileDevice *)&file)->close(); + return content; +} + +bool FileIO::write(const QUrl &_path, const QString &data) { + QString path(_path.toLocalFile()); + QString tempPath(_path.toLocalFile() + ".temp"); + + if (path.isEmpty()) { + emit this->error("Invalid path: " + path); + return false; + } + + QFile file(tempPath); + + if (!file.open(QIODevice::WriteOnly)) { + emit this->error("Could not open file: " + tempPath); + return false; + } + + qint64 result = file.write(data.toUtf8()); + file.close(); + + if (result < 0) { + emit this->error("Failed to write data to file: " + tempPath); + return false; + } + + return this->move(tempPath, path); +} + +bool FileIO::move(const QUrl &_src, const QUrl &_dst) { + QString src(_src.toLocalFile()); + QString dst(_dst.toLocalFile()); + + return this->move(src, dst); +} + +bool FileIO::move(const QString &src, const QString &dst) { + if (src.isEmpty() || dst.isEmpty()) { + emit this->error("Invalid path: " + src); + return false; + } + + if (QFile::exists(dst)) + if (!QFile::remove(dst)) { + emit this->error("Could not remove: " + dst); + return false; + } + + if (!QFile::rename(src, dst)) { + emit this->error("Could not move to: " + dst); + return false; + } + + return true; +} + +bool FileIO::copy(const QUrl &_src, const QUrl &_dst) { + QString src(_src.toLocalFile()); + QString dst(_dst.toLocalFile()); + + return this->copy(src, dst); +} + +bool FileIO::copy(const QString &src, const QString &dst) { + if (src.isEmpty() || dst.isEmpty()) { + emit this->error("Invalid path: " + src); + return false; + } + + if (QFile::exists(dst)) + if (!QFile::remove(dst)) { + emit this->error("Could not remove: " + dst); + return false; + } + + if (!QFile::copy(src, dst)) { + emit this->error("Could not copy to: " + dst); + return false; + } + + return true; +} + +bool FileIO::mkpath(const QUrl &_path) { + QString path(_path.toLocalFile()); + + if (path.isEmpty()) { + emit this->error("Invalid path"); + return false; + } + + if (!QDir().mkpath(path)) { + emit this->error("Failed to make path"); + return false; + }; + + return true; +} + +bool FileIO::exists(const QUrl &_path) { + QString path(_path.toLocalFile()); + + return QDir(path).exists() || QFile(path).exists(); +} \ No newline at end of file diff --git a/src/FileIO.hpp b/src/FileIO.hpp new file mode 100644 index 0000000..760440c --- /dev/null +++ b/src/FileIO.hpp @@ -0,0 +1,41 @@ +/** + * @file FileIO.hpp + * @author marisa (marisa@fwmari.net) + * @brief File I/O backend + * @version 0.1 + * @date 2023-12-27 + * + * @copyright Copyright (c) 2023 + * + */ + +#pragma once + +#include +#include +#include + +class FileIO : public QObject { + Q_OBJECT + +public: + explicit FileIO(QObject *parent = nullptr) : QObject(parent){}; + + static void registerTypes(const char *uri); + static QObject *singletonProvider(QQmlEngine *engine, QJSEngine *); + + Q_INVOKABLE QString read(const QUrl &path); + Q_INVOKABLE bool write(const QUrl &path, const QString &data); + Q_INVOKABLE bool move(const QUrl &src, const QUrl &dst); + Q_INVOKABLE bool copy(const QUrl &src, const QUrl &dst); + + Q_INVOKABLE bool mkpath(const QUrl &path); + Q_INVOKABLE bool exists(const QUrl &path); + +signals: + void error(const QString &msg); + +private: + bool move(const QString &src, const QString &dst); + bool copy(const QString &src, const QString &dst); +}; \ No newline at end of file diff --git a/src/Gui/Login/InstanceInput.qml b/src/Gui/Login/InstanceInput.qml index 4774edc..825d0cf 100644 --- a/src/Gui/Login/InstanceInput.qml +++ b/src/Gui/Login/InstanceInput.qml @@ -64,6 +64,7 @@ ColumnLayout { function getInstanceInfo() { btn.enabled = false const instanceUrl = `https://${instanceInput.tfText}` + instanceInput.pTf.text = "" tryInstance(instanceUrl) } } \ No newline at end of file diff --git a/src/Gui/Settings/Settings.qml b/src/Gui/Settings/Settings.qml new file mode 100644 index 0000000..04f8b9c --- /dev/null +++ b/src/Gui/Settings/Settings.qml @@ -0,0 +1,24 @@ +pragma Singleton + +import QtQuick +import QtCore + +import QutePleroma + +QtObject { + property string configDir: StandardPaths.writableLocation(StandardPaths.AppConfigLocation) + property string dataDir: StandardPaths.writableLocation(StandardPaths.AppDataLocation) + + Component.onCompleted: { + print(`configDir: ${configDir}`) + print(`dataDir: ${dataDir}`) + print(`configDir exists: ${FileIO.exists(configDir)}`) + print(`dataDir exists: ${FileIO.exists(dataDir)}`) + + if (FileIO.exists(configDir) === false) + FileIO.mkpath(configDir) + + if (FileIO.exists(dataDir) === false) + FileIO.mkpath(dataDir) + } +} \ No newline at end of file diff --git a/src/Gui/Settings/qmldir b/src/Gui/Settings/qmldir new file mode 100644 index 0000000..446d3fd --- /dev/null +++ b/src/Gui/Settings/qmldir @@ -0,0 +1 @@ +singleton Settings 1.0 Settings.qml \ No newline at end of file diff --git a/src/Gui/Splash.qml b/src/Gui/Splash.qml index eab8ae0..b25a1bd 100644 --- a/src/Gui/Splash.qml +++ b/src/Gui/Splash.qml @@ -6,6 +6,7 @@ import QtQuick.Controls import Util import "Login" import "PStyle" +import "Settings" Window { visible: true @@ -13,6 +14,10 @@ Window { height: 480 title: qsTr("QutePleroma") + Component.onCompleted: { + const configDir = Settings.configDir + } + PBackground { anchors.fill: parent diff --git a/src/Gui/Style/PStyle/PInputField.qml b/src/Gui/Style/PStyle/PInputField.qml index f9a3e1e..0f7cf4d 100644 --- a/src/Gui/Style/PStyle/PInputField.qml +++ b/src/Gui/Style/PStyle/PInputField.qml @@ -13,7 +13,7 @@ ColumnLayout { PText { id: lbl - font.pointSize: 10 + font: PStyle.getFont(8) } PTextField { diff --git a/src/main.cpp b/src/main.cpp index 9a309f4..493f255 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,8 @@ #include #include +#include "FileIO.hpp" + int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi); @@ -23,6 +25,7 @@ int main(int argc, char *argv[]) { QObject::connect(engine, &QQmlEngine::quit, &QApplication::quit); engine->addImportPath("qrc:/"); + FileIO::registerTypes("QutePleroma"); QQmlContext *ctx = new QQmlContext(engine->rootContext()); QQmlComponent component(engine, QUrl("qrc:/Splash.qml")); diff --git a/src/resources.qrc b/src/resources.qrc index 63bd332..4d63860 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -11,6 +11,10 @@ Gui/Login/InstanceInput.qml Gui/Login/LoadingInfo.qml + + Gui/Settings/Settings.qml + Gui/Settings/qmldir + Icons/arrow-right.svg