Commit 6eebf6ef authored by camilo higuita's avatar camilo higuita

now we have an asbtract base for handlign contacts workflow for different...

now we have an asbtract base for handlign contacts workflow for different platforms, for now android and linux. also multiple ui fixes, clean up and now contacts can be removed also on linux
parent cc3d5349
var Query = {
allPics : "select * from images order by strftime(\"%s\", addDate) desc",
picLikeUrl_ : "select * from images where url like \"%1%\" order by strftime(\"%s\", addDate) desc",
picUrl_ : "select * from images where url = \"%1\"",
albumTags_ : "select * from albums_tags where album = \"%1\"",
picTags_ : "select * from images_tags where url = \"%1\"",
allTags : "select * from tags",
tagPics_: "select i.* from images i inner join images_tags it on it.url = i.url where it.tag = \"%1\"",
allAlbums : "select * from albums",
allAlbumPics_ : "select distinct i.* from images i inner join images_tags it on it.url = i.url inner join albums_tags at on at.tag = it.tag where at.album = \"%1\" union select i.* from images_albums ia inner join images i on i.url = ia.url where ia.album = \"%1\"",
albumPics_ : "select i.* from images_albums ia inner join images i on i.url = ia.url where ia.album = \"%1\" order by strftime(\"%s\", ia.addDate) desc",
albumPicsTags_ : "select i.* from images i inner join images_tags it on it.url = i.url inner join albums_tags at on at.tag = it.tag where at.album = \"%1\"",
favPics: "select * from images where fav = 1",
recentPics: "select * from images order by strftime(\"%s\", addDate) desc limit 50",
folders_: "select distinct s.url from images i inner join sources s on s.url = i.sources_url where i.url like \"%%1%\" or i.title like \"%%1%\"",
searchFor_: "select * from images where title like \"%%1%\" or url like \"%%1%\" union select distinct i.* from images i inner join images_tags it on it.url = i.url where it.tag like \"%%1%\" collate nocase limit 1000"
}
/***
Pix Copyright (C) 2018 Camilo Higuita
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "db.h"
#include <QUuid>
#include <QString>
#include <QStringList>
#include <QSqlQuery>
DB::DB(QObject *parent) : QObject(parent)
{
this->init();
}
DB::~DB()
{
this->m_db.close();
}
void DB::init()
{
QDir collectionDBPath_dir(UNI::CollectionDBPath);
if (!collectionDBPath_dir.exists())
collectionDBPath_dir.mkpath(".");
this->name = QUuid::createUuid().toString();
if(!FMH::fileExists(UNI::CollectionDBPath + UNI::DBName))
{
this->openDB(this->name);
qDebug()<<"Collection doesn't exists, trying to create it" << UNI::CollectionDBPath + UNI::DBName;
this->prepareCollectionDB();
}else this->openDB(this->name);
}
void DB::openDB(const QString &name)
{
if(!QSqlDatabase::contains(name))
{
this->m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), name);
this->m_db.setDatabaseName(UNI::CollectionDBPath + UNI::DBName);
}
if (!this->m_db.isOpen())
{
if(!this->m_db.open())
qDebug()<<"ERROR OPENING DB"<<this->m_db.lastError().text()<<m_db.connectionName();
}
auto query = this->getQuery("PRAGMA synchronous=OFF");
query.exec();
}
void DB::prepareCollectionDB() const
{
QSqlQuery query(this->m_db);
QFile file(":/db/script.sql");
if (!file.exists())
{
QString log = QStringLiteral("Fatal error on build database. The file '");
log.append(file.fileName() + QStringLiteral("' for database and tables creation query cannot be not found!"));
qDebug()<<log;
return;
}
if (!file.open(QIODevice::ReadOnly))
{
qDebug()<<QStringLiteral("Fatal error on try to create database! The file with sql queries for database creation cannot be opened!");
return;
}
bool hasText;
QString line;
QByteArray readLine;
QString cleanedLine;
QStringList strings;
while (!file.atEnd())
{
hasText = false;
line = "";
readLine = "";
cleanedLine = "";
strings.clear();
while (!hasText)
{
readLine = file.readLine();
cleanedLine = readLine.trimmed();
strings = cleanedLine.split("--");
cleanedLine = strings.at(0);
if (!cleanedLine.startsWith("--") && !cleanedLine.startsWith("DROP") && !cleanedLine.isEmpty())
line += cleanedLine;
if (cleanedLine.endsWith(";"))
break;
if (cleanedLine.startsWith("COMMIT"))
hasText = true;
}
if (!line.isEmpty())
{
if (!query.exec(line))
{
qDebug()<<"exec failed"<<query.lastQuery()<<query.lastError();
}
} else qDebug()<<"exec wrong"<<query.lastError();
}
file.close();
}
bool DB::checkExistance(const QString &tableName, const QString &searchId, const QString &search)
{
auto queryStr = QString("SELECT %1 FROM %2 WHERE %3 = \"%4\"").arg(searchId, tableName, searchId, search);
auto query = this->getQuery(queryStr);
if (query.exec())
{
if (query.next()) return true;
}else qDebug()<<query.lastError().text();
return false;
}
QSqlQuery DB::getQuery(const QString &queryTxt)
{
QSqlQuery query(queryTxt, this->m_db);
return query;
}
bool DB::insert(const QString &tableName, const QVariantMap &insertData)
{
if (tableName.isEmpty())
{
qDebug()<<QStringLiteral("Fatal error on insert! The table name is empty!");
return false;
} else if (insertData.isEmpty())
{
qDebug()<<QStringLiteral("Fatal error on insert! The insertData is empty!");
return false;
}
QStringList strValues;
QStringList fields = insertData.keys();
QVariantList values = insertData.values();
int totalFields = fields.size();
for (int i = 0; i < totalFields; ++i)
strValues.append("?");
QString sqlQueryString = "INSERT INTO " + tableName + " (" + QString(fields.join(",")) + ") VALUES(" + QString(strValues.join(",")) + ")";
QSqlQuery query(this->m_db);
query.prepare(sqlQueryString);
int k = 0;
foreach (const QVariant &value, values)
query.bindValue(k++, value);
qDebug()<< query.lastQuery();
return query.exec();
}
bool DB::update(const QString &tableName, const FMH::MODEL &updateData, const QVariantMap &where)
{
if (tableName.isEmpty())
{
qDebug()<<QStringLiteral("Fatal error on insert! The table name is empty!");
return false;
} else if (updateData.isEmpty())
{
qDebug()<<QStringLiteral("Fatal error on insert! The insertData is empty!");
return false;
}
QStringList set;
for (auto key : updateData.keys())
set.append(FMH::MODEL_NAME[key]+" = '"+updateData[key]+"'");
QStringList condition;
for (auto key : where.keys())
condition.append(key+" = '"+where[key].toString()+"'");
QString sqlQueryString = "UPDATE " + tableName + " SET " + QString(set.join(",")) + " WHERE " + QString(condition.join(",")) ;
auto query = this->getQuery(sqlQueryString);
qDebug()<<sqlQueryString;
return query.exec();
}
bool DB::update(const QString &table, const QString &column, const QVariant &newValue, const QVariant &op, const QString &id)
{
auto queryStr = QString("UPDATE %1 SET %2 = \"%3\" WHERE %4 = \"%5\"").arg(table, column, newValue.toString().replace("\"","\"\""), op.toString(), id);
auto query = this->getQuery(queryStr);
return query.exec();
}
bool DB::remove(const QString &tableName, const FMH::MODEL &removeData)
{
if (tableName.isEmpty())
{
qDebug()<<QStringLiteral("Fatal error on removing! The table name is empty!");
return false;
} else if (removeData.isEmpty())
{
qDebug()<<QStringLiteral("Fatal error on insert! The removeData is empty!");
return false;
}
QString strValues;
auto i = 0;
for (auto key : removeData.keys())
{
strValues.append(QString("%1 = \"%2\"").arg(FMH::MODEL_NAME[key], removeData[key]));
i++;
if(removeData.keys().size() > 1 && i<removeData.keys().size())
strValues.append(" AND ");
}
QString sqlQueryString = "DELETE FROM " + tableName + " WHERE " + strValues;
qDebug()<< sqlQueryString;
return this->getQuery(sqlQueryString).exec();
}
QVariantList DB::get(const QString &queryTxt)
{
QVariantList mapList;
auto query = this->getQuery(queryTxt);
if(query.exec())
{
while(query.next())
{
QVariantMap data;
for(auto key : FMH::MODEL_NAME.keys())
if(query.record().indexOf(FMH::MODEL_NAME[key])>-1)
data[FMH::MODEL_NAME[key]] = query.value(FMH::MODEL_NAME[key]).toString();
auto url = data[FMH::MODEL_NAME[FMH::MODEL_KEY::URL]].toString();
// if(!url.isEmpty())
// {
// if(FMH::fileExists(url))
// mapList<< data;
// else
// removePic(data[PIX::KEYMAP[PIX::KEY::URL]].toString());
// }else
mapList<< data;
}
}else qDebug()<< query.lastError()<< query.lastQuery();
return mapList;
}
/***
Pix Copyright (C) 2018 Camilo Higuita
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef DB_H
#define DB_H
#include <QObject>
#include <QString>
#include <QStringList>
#include <QList>
#include <QSqlDatabase>
#include <QDebug>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlRecord>
#include <QSqlDriver>
#include <QFileInfo>
#include <QDir>
#include <QVariantMap>
#include "./../union.h"
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
#include <MauiKit/fmh.h>
#else
#include "fmh.h"
#endif
class DB : public QObject
{
Q_OBJECT
private:
QString name;
QSqlDatabase m_db;
public:
explicit DB(QObject *parent = nullptr);
~ DB();
/* utils*/
QSqlQuery getQuery(const QString &queryTxt);
bool insert(const QString &tableName, const QVariantMap &insertData);
bool update(const QString &tableName, const FMH::MODEL &updateData, const QVariantMap &where);
bool update(const QString &table, const QString &column, const QVariant &newValue, const QVariant &op, const QString &id);
bool remove(const QString &tableName, const FMH::MODEL &removeData);
protected:
void init();
void openDB(const QString &name);
void prepareCollectionDB() const;
signals:
public slots:
bool checkExistance(const QString &tableName, const QString &searchId, const QString &search);
QVariantList get(const QString &queryTxt);
};
#endif // DB_H
/***
Pix Copyright (C) 2018 Camilo Higuita
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "dbactions.h"
#ifdef STATIC_MAUIKIT
#include "fm.h"
#else
#include <MauiKit/fm.h>
#endif
DBActions::DBActions(QObject *parent) : DB(parent) {}
DBActions::~DBActions() {}
void DBActions::init()
{
qDebug() << "Getting collectionDB info from: " << UNI::CollectionDBPath;
qDebug()<< "Starting DBActions";
}
DBActions *DBActions::instance = nullptr;
DBActions *DBActions::getInstance()
{
if(!instance)
{
instance = new DBActions();
qDebug() << "getInstance(): First DBActions instance\n";
instance->init();
return instance;
} else
{
qDebug()<< "getInstance(): previous DBActions instance\n";
return instance;
}
}
bool DBActions::execQuery(const QString &queryTxt)
{
auto query = this->getQuery(queryTxt);
return query.exec();
}
bool DBActions::insertContact(const FMH::MODEL &con)
{
auto contact = FM::toMap(con);
contact.insert(FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE], QDateTime::currentDateTime().toString(Qt::TextDate));
contact.insert(FMH::MODEL_NAME[FMH::MODEL_KEY::MODIFIED], QDateTime::currentDateTime().toString(Qt::TextDate));
return this->insert(UNI::TABLEMAP[UNI::TABLE::CONTACTS], contact);
}
bool DBActions::removeContact(const QString &id)
{
const auto queryTxt = QString("DELETE FROM contacts WHERE id = \"%1\"").arg(id);
return this->execQuery(queryTxt);
}
bool DBActions::updateContact(const FMH::MODEL &con)
{
auto contact = con;
contact.insert(FMH::MODEL_KEY::MODIFIED, QDateTime::currentDateTime().toString(Qt::TextDate));
QVariantMap where = {{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], con[FMH::MODEL_KEY::ID]}};
return this->update(UNI::TABLEMAP[UNI::TABLE::CONTACTS], con, where);
}
void DBActions::removeAll()
{
const auto queryTxt = QString("DELETE FROM contacts");
this->execQuery(queryTxt);
}
bool DBActions::favContact(const QString &id, const bool &fav )
{
if(!this->checkExistance(UNI::TABLEMAP[UNI::TABLE::CONTACTS], FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id))
return false;
const FMH::MODEL faved = {{FMH::MODEL_KEY::FAV, fav ? "1" : "0"}};
return this->update(UNI::TABLEMAP[UNI::TABLE::CONTACTS], faved, QVariantMap({{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id}}) );
}
bool DBActions::isFav(const QString &id)
{
const auto data = this->getDBData(QString("select * from contacts where id = '%1'").arg(id));
if (data.isEmpty()) return false;
return data.first()[FMH::MODEL_KEY::FAV] == "1" ? true : false;
}
FMH::MODEL_LIST DBActions::getDBData(const QString &queryTxt)
{
FMH::MODEL_LIST mapList;
auto query = this->getQuery(queryTxt);
if(query.exec())
{
while(query.next())
{
FMH::MODEL data;
for(auto key : FMH::MODEL_NAME.keys())
if(query.record().indexOf(FMH::MODEL_NAME[key]) > -1)
data.insert(key, query.value(FMH::MODEL_NAME[key]).toString());
mapList<< data;
}
}else qDebug()<< query.lastError()<< query.lastQuery();
return mapList;
}
/***
Pix Copyright (C) 2018 Camilo Higuita
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef DBACTIONS_H
#define DBACTIONS_H
#include <QObject>
#include "db.h"
#ifdef STATIC_MAUIKIT
#include "fmh.h"
#else
#include <MauiKit/fmh.h>
#endif
class DBActions : public DB
{
Q_OBJECT
public:
static DBActions *getInstance();
bool execQuery(const QString &queryTxt);
bool insertContact(const FMH::MODEL &con);
bool removeContact(const QString &id);
bool updateContact(const FMH::MODEL &con);
void removeAll();
/* utils */
FMH::MODEL_LIST getDBData(const QString &queryTxt);
public slots:
bool favContact(const QString &id, const bool &fav);
bool isFav(const QString &id);
private:
static DBActions* instance;
explicit DBActions(QObject *parent = nullptr);
~DBActions();
void init();
signals:
void contactRemoved();
};
#endif // DBACTIONS_H
CREATE TABLE IF NOT EXISTS CONTACTS (
id TEXT PRIMARY KEY,
photo TEXT,
n TEXT,
tel TEXT,
org TEXT,
email TEXT,
gender TEXT,
adr TEXT,
title TEXT,
account TEXT,
type TEXT,
fav INTEGER,
count INTEGER,
adddate DATE NOT NULL,
modified DATE NOT NULL
);
#ifndef ABSTRACTINTERFACE_H
#define ABSTRACTINTERFACE_H
#include <QObject>
#ifdef STATIC_MAUIKIT
#include "fmh.h"
#else
#include <MauiKit/fmh.h>
#endif
/**
* This is an abstract class for handling the contacts,
* it describes tha basic methods needed for Maui Dialer
* to fetch, edit and remove contacts.
* This abstraction is meant to be implemented on
* the android and linux specific interfaces... and any other future platform
*/
class AbstractInterface : public QObject
{
Q_OBJECT
private:
// /*
// * m_contacts might work as a cached list of the contacts
// * when fetching contacts all over again might be expensive
// */
// FMH::MODEL_LIST m_contacts;
public:
explicit AbstractInterface(QObject *parent =nullptr) : QObject(parent) {}
virtual ~AbstractInterface() {}
/**
* getContacts must be done async and
* emit a signal with FMH::MODEL_LIST representing the contacts
*/
virtual void getContacts() const {}
virtual void getContacts() {}
/**
* getAccounts returns a FMH::MODEL_LIST
* representing the avalible accounts handling the contacts
*/
virtual FMH::MODEL_LIST getAccounts(...) const {return FMH::MODEL_LIST();}
virtual FMH::MODEL_LIST getAccounts(...) {return FMH::MODEL_LIST();}
/**
* getContact returns a contact represented by a FMH::MODEL,
* to do so, it needs a valid id
*/
virtual FMH::MODEL getContact(const QString &id) const {Q_UNUSED(id) return FMH::MODEL();}
virtual FMH::MODEL getContact(const QString &id) {Q_UNUSED(id) return FMH::MODEL();}
/**
* insertContact takes a contact represented by a FMH::MODEL,
* and returns whether the contact was sucessfully inserted or not.
* To insert a contact to a specific account, use the fields:
* FMH::MODEL_KEY::ACCOUNT = name of the account
* FMH::MODEL_KEY::ACCOUNT_TYPE = type of the account
*/
virtual bool insertContact(const FMH::MODEL &contact) const {Q_UNUSED(contact) return false;}
virtual bool insertContact(const FMH::MODEL &contact) {Q_UNUSED(contact) return false;}
/**
* updateContact takes the id of the contact to be updated,
* and the up-to-date values represented as a FMH::MODEL,
* and returns whether the contact was sucessfulyl updated or not
*/
virtual bool updateContact(const QString &id, const FMH::MODEL &contact) const {Q_UNUSED(id) Q_UNUSED(contact) return false;}
virtual bool updateContact(const QString &id, const FMH::MODEL &contact) {Q_UNUSED(id) Q_UNUSED(contact) return false;}
/**
* removeContact takes the id of the contact to be removed and return
* whether the contact was sucesfully removed or not
*/
virtual bool removeContact(const QString &id) const {Q_UNUSED(id) return false;}
virtual bool removeContact(const QString &id) {Q_UNUSED(id) return false;}
signals:
/**
* contactsReady is emitted when all the contacts are ready,
* this signal is expected to be emitted by the getContacts method,
* which is supossed to work async.
* The contacts data is represented by FMH::MODEL_LIST
*/
void contactsReady(FMH::MODEL_LIST contacts);
};
#endif // ABSTRACTINTERFACE_H
#include "androidintents.h"
#include "androidinterface.h"
#include "./mauikit/src/android/mauiandroid.h"
#include <QDomDocument>
......@@ -8,32 +8,31 @@
#include <QFutureWatcher>
#include "fm.h"
AndroidIntents::AndroidIntents(QObject *parent) : QObject(parent) {}
AndroidIntents *AndroidIntents::instance = nullptr;
AndroidInterface *AndroidInterface::instance = nullptr;
AndroidIntents *AndroidIntents::getInstance()
AndroidInterface *AndroidInterface::getInstance()
{
if(!instance)
{
instance = new AndroidIntents();
qDebug() << "getInstance(AndroidIntents): First AndroidIntents instance\n";
instance = new AndroidInterface();
qDebug() << "getInstance(AndroidInterface): First AndroidInterface instance\n";
return instance;
} else
{
qDebug()<< "getInstance(AndroidIntents): previous AndroidIntents instance\n";
qDebug()<< "getInstance(AndroidInterface): previous AndroidInterface instance\n";
return instance;
}
}
void AndroidIntents::call(const QString &tel) const
void AndroidInterface::call(const QString &tel) const
{
MAUIAndroid::call(tel);
}