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() + } } } + + } } }