diff --git a/assets/assets.qrc b/assets/assets.qrc
index 7fea113..f0cc519 100644
--- a/assets/assets.qrc
+++ b/assets/assets.qrc
@@ -1,17 +1,18 @@
Type.png
Spaceship.png
Grow.png
BugSearch.png
Bomb.png
E-reading.png
Astronaut.png
Faq.png
buho.png
buho72.png
buho96.png
buho.svg
booklet.svg
+ notepad.png
diff --git a/assets/Knowledge base.png b/assets/notepad.png
similarity index 100%
rename from assets/Knowledge base.png
rename to assets/notepad.png
diff --git a/src/models/books/booklet.cpp b/src/models/books/booklet.cpp
index 5768aad..2e3c552 100644
--- a/src/models/books/booklet.cpp
+++ b/src/models/books/booklet.cpp
@@ -1,77 +1,101 @@
#include "booklet.h"
#include "syncer.h"
Booklet::Booklet(Syncer *_syncer, QObject *parent) : MauiList(parent),
syncer(_syncer)
{
-
+ connect(this->syncer, &Syncer::bookletReady, [&](FMH::MODEL_LIST booklets)
+ {
+ emit this->preListChanged();
+ this->m_list = booklets;
+ emit this->postListChanged();
+ });
+ connect(this, &Booklet::bookChanged, syncer, &Syncer::getBooklet);
}
FMH::MODEL_LIST Booklet::items() const
{
return this->m_list;
}
void Booklet::setSortBy(const Booklet::SORTBY &sort)
{
}
Booklet::SORTBY Booklet::getSortBy() const
{
return this->sort;
}
void Booklet::setOrder(const Booklet::ORDER &order)
{
}
Booklet::ORDER Booklet::getOrder() const
{
return this->order;
}
QString Booklet::getBook() const
{
return m_book;
}
-void Booklet::setBook(const QString &book)
+void Booklet::setBook(const QString &book) //book id
{
if (m_book == book)
return;
+ this->setBookTitle(book);
m_book = book;
emit bookChanged(m_book);
}
void Booklet::insert(const QVariantMap &data)
{
emit this->preItemAppended();
auto __booklet = FMH::toModel(data);
__booklet[FMH::MODEL_KEY::MODIFIED] = QDateTime::currentDateTime().toString(Qt::TextDate);
__booklet[FMH::MODEL_KEY::ADDDATE] = QDateTime::currentDateTime().toString(Qt::TextDate);
this->syncer->insertBooklet(this->m_book, __booklet);
this->m_list << __booklet;
emit this->postItemAppended();
}
void Booklet::update(const QVariantMap &data, const int &index)
{
}
void Booklet::remove(const int &index)
{
}
void Booklet::sortList()
{
}
+
+void Booklet::setBookTitle(const QString &title)
+{
+ if (m_bookTitle == title)
+ return;
+
+ m_bookTitle = title;
+ emit bookTitleChanged(m_bookTitle);
+}
+
+QVariantMap Booklet::get(const int &index) const
+{
+ if(index >= this->m_list.size() || index < 0)
+ return QVariantMap();
+
+ return FMH::toMap(this->m_list.at(index));
+}
diff --git a/src/models/books/booklet.h b/src/models/books/booklet.h
index 2b4ff9b..7506507 100644
--- a/src/models/books/booklet.h
+++ b/src/models/books/booklet.h
@@ -1,75 +1,87 @@
#ifndef BOOKLET_H
#define BOOKLET_H
#include "owl.h"
#ifdef STATIC_MAUIKIT
#include "fmh.h"
#include "mauilist.h"
#else
#include
#include
#endif
class Syncer;
class Booklet : public MauiList
{
Q_OBJECT
Q_PROPERTY(SORTBY sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged)
Q_PROPERTY(ORDER order READ getOrder WRITE setOrder NOTIFY orderChanged)
Q_PROPERTY(QString book READ getBook NOTIFY bookChanged)
+ Q_PROPERTY(QString bookTitle READ getBookTitle NOTIFY bookTitleChanged)
public:
Booklet(Syncer *_syncer = nullptr, QObject *parent = nullptr);
enum ORDER : uint8_t
{
DESC,
ASC
};
Q_ENUM(ORDER)
enum SORTBY : uint8_t
{
TITLE = FMH::MODEL_KEY::TITLE,
ADDDATE = FMH::MODEL_KEY::ADDDATE,
MODIFIED = FMH::MODEL_KEY::MODIFIED,
COLOR = FMH::MODEL_KEY::COLOR,
FAVORITE = FMH::MODEL_KEY::FAVORITE,
PIN = FMH::MODEL_KEY::PIN
};
Q_ENUM(SORTBY)
FMH::MODEL_LIST items() const override final;
void setSortBy(const SORTBY &sort);
SORTBY getSortBy() const;
void setOrder(const ORDER &order);
ORDER getOrder() const;
QString getBook() const;
void setBook(const QString &book);
+ void setBookTitle(const QString &title);
+ QString getBookTitle() const
+ {
+ return m_bookTitle;
+ }
+
public slots:
+ QVariantMap get(const int &index) const;
void insert(const QVariantMap &data);
void update(const QVariantMap &data, const int &index);
void remove(const int &index);
private:
FMH::MODEL_LIST m_list;
Syncer *syncer;
void sortList();
+
SORTBY sort = SORTBY::MODIFIED;
ORDER order = ORDER::DESC;
QString m_book;
+ QString m_bookTitle;
+
signals:
void sortByChanged();
void orderChanged();
void bookChanged(QString book);
+ void bookTitleChanged(QString bookTitle);
};
#endif // BOOKLET_H
diff --git a/src/models/books/books.cpp b/src/models/books/books.cpp
index 2cfe04b..8be6c42 100644
--- a/src/models/books/books.cpp
+++ b/src/models/books/books.cpp
@@ -1,114 +1,117 @@
#include "books.h"
#include "syncer.h"
#include "nextnote.h"
#include "booklet.h"
Books::Books(QObject *parent) : MauiList(parent),
syncer(new Syncer(this)), m_booklet(new Booklet(syncer, this))
{
this->syncer->setProvider(new NextNote);
+ connect(this, &Books::currentBookChanged, this, &Books::openBook);
+
connect(syncer, &Syncer::booksReady, [&](FMH::MODEL_LIST books)
{
emit this->preListChanged();
this->m_list = books;
qDebug()<< "ALL THE BOOKS ARE < "<< this->m_list;
emit this->postListChanged();
});
this->syncer->getBooks();
}
FMH::MODEL_LIST Books::items() const
{
return this->m_list;
}
void Books::setSortBy(const Books::SORTBY &sort)
{
}
Books::SORTBY Books::getSortBy() const
{
return this->sort;
}
void Books::setOrder(const Books::ORDER &order)
{
}
Books::ORDER Books::getOrder() const
{
return this->order;
}
Booklet *Books::getBooklet() const
{
return m_booklet;
}
int Books::getCurrentBook() const
{
return m_currentBook;
}
void Books::sortList()
{
}
QVariantMap Books::get(const int &index) const
{
if(index >= this->m_list.size() || index < 0)
return QVariantMap();
return FMH::toMap(this->m_list.at(index));
}
bool Books::insert(const QVariantMap &book)
{
emit this->preItemAppended();
auto __book = FMH::toModel(book);
__book[FMH::MODEL_KEY::THUMBNAIL] = "qrc:/booklet.svg";
__book[FMH::MODEL_KEY::LABEL] =__book[FMH::MODEL_KEY::TITLE];
__book[FMH::MODEL_KEY::MODIFIED] = QDateTime::currentDateTime().toString(Qt::TextDate);
__book[FMH::MODEL_KEY::ADDDATE] = QDateTime::currentDateTime().toString(Qt::TextDate);
this->syncer->insertBook(__book);
this->m_list << __book;
qDebug() << m_list;
emit this->postItemAppended();
return true;
}
bool Books::update(const QVariantMap &data, const int &index)
{
return false;
}
bool Books::remove(const int &index)
{
return false;
}
void Books::openBook(const int &index)
{
if(index >= this->m_list.size() || index < 0)
return;
+
this->m_booklet->setBook(this->m_list.at(index)[FMH::MODEL_KEY::ID]);
+ this->m_booklet->setBookTitle(this->m_list.at(index)[FMH::MODEL_KEY::TITLE]);
}
void Books::setCurrentBook(int currentBook)
{
if (m_currentBook == currentBook)
return;
m_currentBook = currentBook;
- this->openBook(m_currentBook);
emit currentBookChanged(m_currentBook);
}
diff --git a/src/syncing/syncer.cpp b/src/syncing/syncer.cpp
index cdbbd4f..3bc752e 100644
--- a/src/syncing/syncer.cpp
+++ b/src/syncing/syncer.cpp
@@ -1,501 +1,508 @@
#include "syncer.h"
#include "db/db.h"
#include "abstractnotesprovider.h"
#include
#ifdef STATIC_MAUIKIT
#include "tagging.h"
#include "fm.h"
#else
#include
#include
#endif
Syncer::Syncer(QObject *parent) : QObject(parent),
tag(Tagging::getInstance()),
db(DB::getInstance()),
provider(nullptr) {}
void Syncer::setAccount(const FMH::MODEL &account)
{
if(this->provider)
this->provider->setCredentials(account);
}
void Syncer::setProvider(AbstractNotesProvider *provider)
{
this->provider = std::move(provider);
this->provider->setParent(this);
this->provider->disconnect();
this->setConections();
}
void Syncer::insertNote(FMH::MODEL ¬e)
{
if(!this->insertNoteLocal(note))
{
qWarning()<< "The note could not be inserted locally, "
"therefore it was not attempted to insert it to the remote provider server, "
"even if it existed.";
return;
}
this->insertNoteRemote(note);
emit this->noteInserted(note, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Note inserted on the DB locally"});
}
void Syncer::updateNote(const QString &id, const FMH::MODEL ¬e)
{
if(!this->updateNoteLocal(id, note))
{
qWarning()<< "The note could not be updated locally, "
"therefore it was not attempted to update it on the remote server provider, "
"even if it existed.";
return;
}
//to update remote note we need to pass the stamp as the id
const auto stamp = Syncer::noteStampFromId(this->db, id);
if(!stamp.isEmpty())
this->updateNoteRemote(stamp, note);
emit this->noteUpdated(note, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Note updated on the DB locally"});
}
void Syncer::removeNote(const QString &id)
{
//to remove the remote note we need to pass the stamp as the id,
//and before removing the note locally we need to retireved first
const auto stamp = Syncer::noteStampFromId(this->db, id);
if(!this->removeNoteLocal(id))
{
qWarning()<< "The note could not be inserted locally, "
"therefore it was not attempted to insert it to the remote provider server, "
"even if it existed.";
return;
}
if(!stamp.isEmpty())
this->removeNoteRemote(stamp);
emit this->noteRemoved(FMH::MODEL(), {STATE::TYPE::LOCAL, STATE::STATUS::OK, "The note has been removed from the local DB"});
}
void Syncer::getNotes()
{
const auto notes = this->collectAllNotes();
if(this->provider && this->provider->isValid())
this->provider->getNotes();
else
qWarning()<< "Credentials are missing to get notes or the provider has not been set";
emit this->notesReady(notes);
}
void Syncer::getBooks()
{
const auto books = this->collectAllBooks();
// this service is still missing
// if(this->provider && this->provider->isValid())
// this->provider->getNotes();
// else
// qWarning()<< "Credentials are missing to get notes or the provider has not been set";
emit this->booksReady(books);
}
void Syncer::insertBook(FMH::MODEL &book)
{
if(!this->insertBookLocal(book))
{
qWarning()<< "Could not insert Book, Syncer::insertBook";
return;
}
emit this->bookInserted(book, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Book inserted locally sucessfully"});
}
+void Syncer::getBooklet(const QString &id)
+{
+ const auto res = this->db->getDBData(QString("select * from booklets where book = '%1'").arg(id));
+
+ emit this->bookletReady(res);
+}
+
void Syncer::insertBooklet(const QString &bookId, FMH::MODEL &booklet)
{
if(!this->insertBookletLocal(bookId, booklet))
{
qWarning()<< "Could not insert Booklet, Syncer::insertBooklet";
return;
}
emit this->bookletInserted(booklet, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Booklet inserted locally sucessfully"});
}
void Syncer::addId(FMH::MODEL &model)
{
const auto id = QUuid::createUuid().toString();
model[FMH::MODEL_KEY::ID] = id;
}
const QString Syncer::noteIdFromStamp(DB *_db, const QString &provider, const QString &stamp)
{
return [&]() -> QString {
const auto data = _db->getDBData(QString("select id from notes_sync where server = '%1' AND stamp = '%2'").arg(provider, stamp));
return data.isEmpty() ? QString() : data.first()[FMH::MODEL_KEY::ID];
}();
}
const QString Syncer::noteStampFromId(DB *_db, const QString &id)
{
return [&]() -> QString {
const auto data = _db->getDBData(QString("select stamp from notes_sync where id = '%1'").arg(id));
return data.isEmpty() ? QString() : data.first()[FMH::MODEL_KEY::STAMP];
}();
}
void Syncer::setConections()
{
connect(this->provider, &AbstractNotesProvider::noteInserted, [&](FMH::MODEL note)
{
qDebug()<< "STAMP OF THE NEWLY INSERTED NOTE" << note[FMH::MODEL_KEY::ID] << note;
this->db->insert(OWL::TABLEMAP[OWL::TABLE::NOTES_SYNC], FMH::toMap(FMH::filterModel(note, {FMH::MODEL_KEY::ID,
FMH::MODEL_KEY::STAMP,
FMH::MODEL_KEY::USER,
FMH::MODEL_KEY::SERVER})));
emit this->noteInserted(note, {STATE::TYPE::REMOTE, STATE::STATUS::OK, "Note inserted on server provider"});
});
connect(this->provider, &AbstractNotesProvider::notesReady, [&](FMH::MODEL_LIST notes)
{
// qDebug()<< "SERVER NOETS READY "<< notes;
//if there are no notes in the provider server, then just return
if(notes.isEmpty())
return;
qDebug()<< "NOETS READY << " << notes;
// there might be two case scenarios:
// the note exists locally in the db, so it needs to be updated with the server version
// the note does not exists locally, so it needs to be inserted into the db
for(const auto ¬e : notes)
{
const auto id = Syncer::noteIdFromStamp(this->db, this->provider->provider(), note[FMH::MODEL_KEY::ID]);
// if the id is empty then the note does nto exists, so ithe note is inserted into the local db
if(id.isEmpty())
{
//here insert the note into the db
auto __note = FMH::filterModel(note, {FMH::MODEL_KEY::TITLE,
FMH::MODEL_KEY::CONTENT,
FMH::MODEL_KEY::FAVORITE,
FMH::MODEL_KEY::MODIFIED,
FMH::MODEL_KEY::ADDDATE});
__note[FMH::MODEL_KEY::MODIFIED] = QDateTime::fromSecsSinceEpoch(note[FMH::MODEL_KEY::MODIFIED].toInt()).toString(Qt::TextDate);
__note[FMH::MODEL_KEY::ADDDATE] = __note[FMH::MODEL_KEY::MODIFIED];
if(!this->insertNoteLocal(__note))
{
qWarning()<< "Remote note could not be inserted to the local storage";
continue;
}
__note[FMH::MODEL_KEY::STAMP] = note[FMH::MODEL_KEY::ID];
__note[FMH::MODEL_KEY::USER] = this->provider->user();
__note[FMH::MODEL_KEY::SERVER] = this->provider->provider();
this->db->insert(OWL::TABLEMAP[OWL::TABLE::NOTES_SYNC], FMH::toMap(FMH::filterModel(__note, {FMH::MODEL_KEY::ID,
FMH::MODEL_KEY::STAMP,
FMH::MODEL_KEY::USER,
FMH::MODEL_KEY::SERVER})));
}else
{
//the note exists in the db locally, so update it
auto __note = FMH::filterModel(note, {FMH::MODEL_KEY::TITLE,
FMH::MODEL_KEY::CONTENT,
FMH::MODEL_KEY::MODIFIED,
FMH::MODEL_KEY::FAVORITE});
__note[FMH::MODEL_KEY::MODIFIED] = QDateTime::fromSecsSinceEpoch(note[FMH::MODEL_KEY::MODIFIED].toInt()).toString(Qt::TextDate);
this->updateNoteLocal(id, __note);
emit this->noteInserted(note, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Note inserted on local db, from the server provider"});
}
}
emit this->notesReady(this->collectAllNotes());
});
connect(this->provider, &AbstractNotesProvider::noteUpdated, [&](FMH::MODEL note)
{
const auto id = Syncer::noteIdFromStamp(this->db, this->provider->provider(), note[FMH::MODEL_KEY::ID]);
if(!note.isEmpty())
this->updateNoteLocal(id, FMH::filterModel(note, {FMH::MODEL_KEY::TITLE}));
emit this->noteUpdated(note, {STATE::TYPE::REMOTE, STATE::STATUS::OK, "Note updated on server provider"});
});
connect(this->provider, &AbstractNotesProvider::noteRemoved, [&]()
{
emit this->noteRemoved(FMH::MODEL(), {STATE::TYPE::REMOTE, STATE::STATUS::OK, "The note has been removed from the remove server provider"});
});
}
bool Syncer::insertNoteLocal(FMH::MODEL ¬e)
{
if(note.isEmpty())
{
qWarning()<< "Could not insert note locally. The note is empty";
return false;
}
Syncer::addId(note); //adds a local id to the note
// create a file for the note
const auto __notePath = Syncer::saveNoteFile(OWL::NotesPath, note);
if(__notePath.isEmpty())
{
qWarning()<< "File could not be saved. Syncer::insertNoteLocal.";
return false;
}
note[FMH::MODEL_KEY::URL] = __notePath.toString();
qDebug()<< "note saved to <<" << __notePath;
auto __noteMap = FMH::toMap(FMH::filterModel(note, {FMH::MODEL_KEY::ID,
FMH::MODEL_KEY::TITLE,
FMH::MODEL_KEY::COLOR,
FMH::MODEL_KEY::URL,
FMH::MODEL_KEY::PIN,
FMH::MODEL_KEY::FAVORITE,
FMH::MODEL_KEY::MODIFIED,
FMH::MODEL_KEY::ADDDATE}));
if(this->db->insert(OWL::TABLEMAP[OWL::TABLE::NOTES], __noteMap))
{
for(const auto &tg : note[FMH::MODEL_KEY::TAG].split(",", QString::SplitBehavior::SkipEmptyParts))
this->tag->tagAbstract(tg, OWL::TABLEMAP[OWL::TABLE::NOTES], note[FMH::MODEL_KEY::ID], note[FMH::MODEL_KEY::COLOR]);
return true;
}
return false;
}
void Syncer::insertNoteRemote(FMH::MODEL ¬e)
{
if(this->provider && this->provider->isValid())
this->provider->insertNote(note);
}
bool Syncer::updateNoteLocal(const QString &id, const FMH::MODEL ¬e)
{
for(const auto &tg : note[FMH::MODEL_KEY::TAG])
this->tag->tagAbstract(tg, OWL::TABLEMAP[OWL::TABLE::NOTES], id);
this->saveNoteFile(OWL::NotesPath, note);
return this->db->update(OWL::TABLEMAP[OWL::TABLE::NOTES],
FMH::toMap(FMH::filterModel(note, {FMH::MODEL_KEY::TITLE,
FMH::MODEL_KEY::COLOR,
FMH::MODEL_KEY::PIN,
FMH::MODEL_KEY::MODIFIED,
FMH::MODEL_KEY::FAVORITE})), QVariantMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id}});
}
void Syncer::updateNoteRemote(const QString &id, const FMH::MODEL ¬e)
{
if(this->provider && this->provider->isValid())
this->provider->updateNote(id, note);
}
bool Syncer::removeNoteLocal(const QString &id)
{
this->db->remove(OWL::TABLEMAP[OWL::TABLE::NOTES_SYNC], {{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id}});
return this->db->remove(OWL::TABLEMAP[OWL::TABLE::NOTES], {{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id}});
}
void Syncer::removeNoteRemote(const QString &id)
{
if(this->provider && this->provider->isValid())
this->provider->removeNote(id);
}
bool Syncer::insertBookLocal(FMH::MODEL &book)
{
const auto __path = QUrl::fromLocalFile(OWL::BooksPath+book[FMH::MODEL_KEY::TITLE]);
if(FMH::fileExists(__path))
{
qWarning()<< "The directory for the book already exists. Syncer::insertBookLocal" << book[FMH::MODEL_KEY::TITLE];
return false;
}
if(!FM::createDir(QUrl::fromLocalFile(OWL::BooksPath), book[FMH::MODEL_KEY::TITLE]))
{
qWarning() << "Could not create directory for the given book name. Syncer::insertBookLocal" << book[FMH::MODEL_KEY::TITLE];
return false;
}
Syncer::addId(book);
book[FMH::MODEL_KEY::URL] = __path.toString();
return(this->db->insert(OWL::TABLEMAP[OWL::TABLE::BOOKS], FMH::toMap(FMH::filterModel(book,{FMH::MODEL_KEY::ID,
FMH::MODEL_KEY::URL,
FMH::MODEL_KEY::TITLE,
FMH::MODEL_KEY::FAVORITE,
FMH::MODEL_KEY::ADDDATE,
FMH::MODEL_KEY::MODIFIED}
))));
}
void Syncer::insertBookRemote(FMH::MODEL &book)
{
}
bool Syncer::updateBookLocal(const QString &id, const FMH::MODEL &book)
{
return false;
}
void Syncer::updateBookRemote(const QString &id, const FMH::MODEL &book)
{
}
bool Syncer::removeBookLocal(const QString &id)
{
return false;
}
void Syncer::removeBookRemote(const QString &id)
{
}
bool Syncer::insertBookletLocal(const QString &bookId, FMH::MODEL &booklet)
{
qDebug()<< "trying to insert booklet" << booklet;
if(bookId.isEmpty() || booklet.isEmpty())
{
qWarning()<< "Could not insert booklet. Reference to book id or booklet are empty";
return false;
}
Syncer::addId(booklet); //adds a local id to the booklet
// create a file for the note
const auto __bookTitle = [&]() -> QString {
const auto data = this->db->getDBData(QString("select title from books where id = '%1'").arg(bookId));
return data.isEmpty() ? QString() : data.first()[FMH::MODEL_KEY::TITLE]; } ();
if(__bookTitle.isEmpty() || !FMH::fileExists(QUrl::fromLocalFile(OWL::BooksPath+__bookTitle)))
{
qWarning()<< "The book does not exists in the db or the directory is missing. Syncer::insertBookletLocal";
return false;
}
const auto __bookletPath = Syncer::saveNoteFile(OWL::BooksPath+__bookTitle+"/", booklet);
if(__bookletPath.isEmpty())
{
qWarning()<< "File could not be saved. Syncer::insertBookletLocal";
return false;
}
booklet[FMH::MODEL_KEY::URL] = __bookletPath.toString();
booklet[FMH::MODEL_KEY::BOOK] = bookId;
qDebug()<< "booklet saved to <<" << __bookletPath;
auto __bookletMap = FMH::toMap(FMH::filterModel(booklet, {FMH::MODEL_KEY::ID,
FMH::MODEL_KEY::BOOK,
FMH::MODEL_KEY::TITLE,
FMH::MODEL_KEY::URL,
FMH::MODEL_KEY::MODIFIED,
FMH::MODEL_KEY::ADDDATE}));
if(this->db->insert(OWL::TABLEMAP[OWL::TABLE::BOOKLETS], __bookletMap))
{
// for(const auto &tg : booklet[FMH::MODEL_KEY::TAG].split(",", QString::SplitBehavior::SkipEmptyParts))
// this->tag->tagAbstract(tg, OWL::TABLEMAP[OWL::TABLE::NOTES], booklet[FMH::MODEL_KEY::ID], booklet[FMH::MODEL_KEY::COLOR]);
return true;
}
return false;
}
void Syncer::insertBookletRemote(const QString &bookId, FMH::MODEL &booklet)
{
}
bool Syncer::updateBookletLocal(const QString &id, const FMH::MODEL &booklet)
{
return false;
}
void Syncer::updateBookletRemote(const QString &id, const FMH::MODEL &booklet)
{
}
bool Syncer::removeBookletLocal(const QString &id)
{
return false;
}
void Syncer::removeBookletRemote(const QString &id)
{
}
const FMH::MODEL_LIST Syncer::collectAllNotes()
{
FMH::MODEL_LIST __notes = this->db->getDBData("select * from notes");
for(auto ¬e : __notes)
note[FMH::MODEL_KEY::CONTENT] = this->noteFileContent(note[FMH::MODEL_KEY::URL]);
return __notes;
}
const FMH::MODEL_LIST Syncer::collectAllBooks()
{
return this->db->getDBData("select * from books");
}
const QUrl Syncer::saveNoteFile(const QString &dir, const FMH::MODEL &data)
{
if(data.isEmpty() /*|| !data.contains(FMH::MODEL_KEY::CONTENT)*/)
{
qWarning() << "the note is empty, therefore it could not be saved into a file";
return QUrl();
}
QFile file(dir+data[FMH::MODEL_KEY::ID]+QStringLiteral(".txt"));
file.open(QFile::WriteOnly);
file.write(data[FMH::MODEL_KEY::CONTENT].toUtf8());
file.close();
return QUrl::fromLocalFile(file.fileName());
}
const QString Syncer::noteFileContent(const QUrl &path)
{
if(!path.isLocalFile())
{
qWarning()<< "Can not open note file, the url is not a local path";
return QString();
}
QFile file(path.toLocalFile());
file.open(QFile::ReadOnly);
const auto content = file.readAll();
file.close();
return QString(content);
}
diff --git a/src/syncing/syncer.h b/src/syncing/syncer.h
index 94d2130..a4badf9 100644
--- a/src/syncing/syncer.h
+++ b/src/syncing/syncer.h
@@ -1,297 +1,296 @@
#ifndef SYNCER_H
#define SYNCER_H
#include
#ifdef STATIC_MAUIKIT
#include "fmh.h"
#else
#include
#endif
/**
* @brief The Syncer class
* This interfaces between local storage and cloud
* Its work is to try and keep thing synced and do the background work on updating notes
* from local to cloud and viceversa.
* This interface should be used to handle the whol offline and online work,
* instead of manually inserting to the db or the cloud providers
*/
struct STATE
{
enum TYPE : uint
{
LOCAL,
REMOTE
};
enum STATUS : uint
{
OK,
ERROR
};
TYPE type;
STATUS status;
QString msg = QString();
};
class DB;
class AbstractNotesProvider;
class Tagging;
class Syncer: public QObject
{
Q_OBJECT
public:
explicit Syncer(QObject *parent = nullptr);
/**
* @brief setProviderAccount
* sets the credentials to the current account
* for the current provider being used
* @param account
* the account data represented by FMH::MODEL
* where the valid keys are:
* FMH::MODEL_KEY::USER user name
* FMH::MODEL_KEY::PASSWORD users password
* FMH::MODEL_KEY::PROVIDER the url to the provider server
*/
void setAccount(const FMH::MODEL &account);
/**
* @brief setProvider
* sets the provider interface
* this allows to change the provider source
* @param provider
* the provider must inherit the asbtract class AbstractNotesProvider.
* The value passed is then moved to this class private property Syncer::provider
*/
void setProvider(AbstractNotesProvider *provider);
//// NOTES INTERFACES
/// interfaces with the the notes from both, local and remote
/**
* @brief insertNote
* saves a new note online and offline
* The signal Syncer::noteInserted(FMH::MODEL, STATE) is emitted,
* indicating the created note and the transaction resulting state
* @param note
* the note to be stored represented by FMH::MODEL
*/
void insertNote(FMH::MODEL ¬e);
/**
* @brief updateNote
* Update online and offline an existing note.
* The signal Syncer::noteUpdated(FMH::MODEL, STATE) is emitted,
* indicating the updated note and the transaction resulting state
* @param id
* ID of the existing note
* @param note
* the new note contents represented by FMH::MODEL
*/
void updateNote(const QString &id, const FMH::MODEL ¬e);
/**
* @brief removeNote
* remove a note from online and offline storage
* The signal Syncer::noteRemoved(FMH::MODEL, STATE) is emitted,
* indicating the removed note and the transaction resulting state
* @param id
* ID of the exisiting note
*/
void removeNote(const QString &id);
/**
* @brief getNote
* Retrieves an existing note, whether the note is located offline or online.
* When the note is ready the signal Syncer::noteReady(FMH::MODEL) is emitted
* @param id
* ID of the exisiting note
*/
void getNote(const QString &id);
/**
* @brief getNotes
* Retrieves all the notes, online and offline notes.
* When the notes are ready the signal Syncer::notesReady(FMH::MODEL_LIST) is emitted.
*/
void getNotes();
////BOOKS & BOOKLET INTERFACES
/// interfaces with the the books and booklets from both, local and remote
/**
* @brief getBooks
* Retrieves all the books, online and offline.
* When the books are ready the signal Syncer::booksReady(FMH::MODEL_LIST) is emitted
*/
void getBooks();
/**
* @brief getBook
* @param id
*/
void getBook(const QString &id);
/**
* @brief insertBook
* @param book
*/
void insertBook(FMH::MODEL &book);
/**
* @brief updateBook
* @param id
* @param book
*/
void updateBook(const QString &id, const FMH::MODEL &book);
/**
* @brief removeBook
* @param id
*/
void removeBook(const QString &id);
//BOOKLETS INTERFACES
/**
* @brief getBooklet
* @param id
*/
void getBooklet(const QString &id);
/**
* @brief updateBooklet
* @param id
* @param booklet
*/
void updateBooklet(const QString &id, FMH::MODEL &booklet);
/**
* @brief insertBooklet
* @param booklet
*/
void insertBooklet(const QString &bookId, FMH::MODEL &booklet);
/**
* @brief removeBooklet
* @param id
*/
void removeBooklet(const QString &id);
private:
/**
* @brief tag
* Instance of the Maui project tag-ger. It adds tags to the abtract notes
* For online tagging one could use the categories ?
*/
Tagging *tag;
/**
* @brief db
* Instance to the data base storing the notes information and location,
* offline and online.
*/
DB *db;
/**
* @brief server
* Abstract instance to the online server to perfom CRUD actions
*/
AbstractNotesProvider *provider;
/**
* @brief syncNote
* Has the job to sync a note between the offline and online versions
* @param id
* ID of the note to be synced
*/
void syncNote(const QString &id);
/**
* @brief stampNote
* Adds an stamp id to identify the note offline and online
* @param note
* the note model is passed by ref and a STAMP key value is inserted
*/
static void addId(FMH::MODEL &model);
static const QString noteIdFromStamp(DB *_db, const QString &provider, const QString &stamp) ;
static const QString noteStampFromId(DB *_db, const QString &id) ;
void setConections();
protected:
/**
* @brief insertLocal
* performs the insertion of a new note in the local storage
* @param note
* note to be inserted
* @return bool
* true if the note was inserted sucessfully in the local storage
*/
bool insertNoteLocal(FMH::MODEL ¬e);
/**
* @brief insertRemote
* perfroms the insertion of a new note in the remote provider server
* @param note
* the note to be inserted
*/
void insertNoteRemote(FMH::MODEL ¬e);
bool updateNoteLocal(const QString &id, const FMH::MODEL ¬e);
void updateNoteRemote(const QString &id, const FMH::MODEL ¬e);
bool removeNoteLocal(const QString &id);
void removeNoteRemote(const QString &id);
bool insertBookLocal(FMH::MODEL &book);
void insertBookRemote(FMH::MODEL &book);
bool updateBookLocal(const QString &id, const FMH::MODEL &book);
void updateBookRemote(const QString &id, const FMH::MODEL &book);
bool removeBookLocal(const QString &id);
void removeBookRemote(const QString &id);
bool insertBookletLocal(const QString &bookId, FMH::MODEL &booklet);
void insertBookletRemote(const QString &bookId, FMH::MODEL &booklet);
bool updateBookletLocal(const QString &id, const FMH::MODEL &booklet);
void updateBookletRemote(const QString &id, const FMH::MODEL &booklet);
bool removeBookletLocal(const QString &id);
void removeBookletRemote(const QString &id);
const FMH::MODEL_LIST collectAllNotes();
const FMH::MODEL_LIST collectAllBooks();
static inline const QUrl saveNoteFile(const QString &dir, const FMH::MODEL &data);
static inline const QString noteFileContent(const QUrl &path);
signals:
//FOR NOTES
void noteInserted(FMH::MODEL note, STATE state);
void noteUpdated(FMH::MODEL note, STATE state);
void noteRemoved(FMH::MODEL note, STATE state);
void noteReady(FMH::MODEL note);
void notesReady(FMH::MODEL_LIST notes);
//FOR BOOKS
void bookInserted(FMH::MODEL book, STATE state);
void bookUpdated(FMH::MODEL book, STATE state);
void bookRemoved(FMH::MODEL book, STATE state);
void bookReady(FMH::MODEL book);
void booksReady(FMH::MODEL_LIST books);
//FOR BOOKLETS
void bookletInserted(FMH::MODEL booklet, STATE state);
void bookletUpdated(FMH::MODEL booklet, STATE state);
void bookletRemoved(FMH::MODEL booklet, STATE state);
- void bookletReady(FMH::MODEL booklet);
void bookletReady(FMH::MODEL_LIST booklets);
public slots:
};
#endif // SYNCER_H
diff --git a/src/views/books/BookletPage.qml b/src/views/books/BookletPage.qml
index cc84d9e..61c4ea5 100644
--- a/src/views/books/BookletPage.qml
+++ b/src/views/books/BookletPage.qml
@@ -1,116 +1,181 @@
import QtQuick 2.9
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import org.kde.mauikit 1.0 as Maui
import org.kde.kirigami 2.7 as Kirigami
Item
{
id: control
signal exit()
+
Maui.BaseModel
{
id: _bookletModel
list: _booksList.booklet
}
Maui.Page
{
id: _page
anchors.fill: parent
anchors.rightMargin: _drawer.modal === false ? _drawer.contentItem.width * _drawer.position : 0
headBar.leftContent: [
ToolButton
- {
- icon.name: "go-previous"
- onClicked: control.exit()
- },
-
- TextField
- {
- id: title
- Layout.fillWidth: true
- Layout.margins: space.medium
- placeholderText: qsTr("New chapter...")
- font.weight: Font.Bold
- font.bold: true
- font.pointSize: fontSizes.large
- // Kirigami.Theme.backgroundColor: selectedColor
- // Kirigami.Theme.textColor: Qt.darker(selectedColor, 2.5)
- // color: fgColor
- background: Rectangle
- {
- color: "transparent"
- }
- }
+ {
+ icon.name: "go-previous"
+ onClicked: control.exit()
+ },
+
+ ToolButton
+ {
+ icon.name: "document-save"
+// onClicked: control.exit()
+ },
+
+ TextField
+ {
+ id: title
+ Layout.fillWidth: true
+ Layout.margins: space.medium
+ placeholderText: qsTr("New chapter...")
+ font.weight: Font.Bold
+ font.bold: true
+ font.pointSize: fontSizes.large
+ // Kirigami.Theme.backgroundColor: selectedColor
+ // Kirigami.Theme.textColor: Qt.darker(selectedColor, 2.5)
+ // color: fgColor
+ background: Rectangle
+ {
+ color: "transparent"
+ }
+ }
]
+ Maui.Holder
+ {
+ id: _holder
+ visible: !_listView.count
+ emoji: "qrc:/Type.png"
+ emojiSize: iconSizes.huge
+ isMask: false
+ title : "Nothing to edit!"
+ body: "Select a chapter or create a new one"
+ }
+
Maui.Editor
{
anchors.fill: parent
+ visible: !_holder.visible
}
Maui.Dialog
{
id: _newChapter
title: qsTr("New Chapter")
message: qsTr("Create a new chapter for your current book. Give it a title")
entryField: true
onAccepted:
{
_booksList.booklet.insert({title: textEntry.text})
}
}
Kirigami.OverlayDrawer
{
id: _drawer
edge: Qt.RightEdge
width: Kirigami.Units.gridUnit * 16
- height: parent.height - headBar.height
- y: headBar.height
+ height: parent.height - _page.headBar.height
+ y: _page.headBar.height
modal: !isWide
+ visible: _holder.visible
-
- ListView
+ contentItem: Maui.Page
{
anchors.fill: parent
- model: _bookletModel
- delegate: Maui.LabelDelegate
+ title: "argh"
+
+ headBar.visible: true
+ headBar.rightContent: ToolButton
{
- label: model.title
+ icon.name: "view-sort"
}
- }
- Rectangle
- {
- z: 999
- anchors.bottom: parent.bottom
- anchors.margins: toolBarHeight
- anchors.horizontalCenter: parent.horizontalCenter
- height: toolBarHeight
- width: height
+ background: Rectangle
+ {
+ color: "transparent"
+ }
- color: Kirigami.Theme.highlightColor
- radius: radiusV
+ Maui.Holder
+ {
+ anchors.margins: space.huge
+ visible: !_listView.count
+ emoji: "qrc:/E-reading.png"
+ emojiSize: iconSizes.huge
+ isMask: false
+ title : "This book is empty!"
+ body: "Start by creating a new chapter for your book by clicking the + icon"
+ }
- ToolButton
+ ListView
{
- anchors.centerIn: parent
- icon.name: "list-add"
- icon.color: Qt.darker(parent.color, 2)
+ id: _listView
+ anchors.fill: parent
+ model: _bookletModel
+ clip: true
+ delegate: Maui.LabelDelegate
+ {
+ id: _delegate
+ label: index + " - " + model.title
+
+ Connections
+ {
+ target:_delegate
+
+ onClicked:
+ {
+ _listView.currentIndex = index
+ console.log("Booklet cliked:", _booksList.booklet.get(index).url, _booksList.booklet.get(index).content )
+ }
+ }
+ }
+
- onClicked: _newChapter.open()
+ }
+
+ Rectangle
+ {
+ z: 999
+ anchors.bottom: parent.bottom
+ anchors.margins: space.huge
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: toolBarHeight
+ width: height
+
+ color: Kirigami.Theme.positiveTextColor
+ radius: radiusV
+
+ ToolButton
+ {
+ anchors.centerIn: parent
+ icon.name: "list-add"
+ icon.color: "white"
+
+ onClicked: _newChapter.open()
+ }
}
}
+
+
}
}
}