commit
b627b966c7
|
@ -52,14 +52,15 @@ set(SOURCES ${CMAKE_SOURCE_DIR}/src/main.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/handler/contextMenu.cpp
|
${CMAKE_SOURCE_DIR}/src/handler/contextMenu.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/handler/eventHandler.cpp
|
${CMAKE_SOURCE_DIR}/src/handler/eventHandler.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/handler/mainMenu.cpp
|
${CMAKE_SOURCE_DIR}/src/handler/mainMenu.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/util/nextcloud.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/listView/listView.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/util/item.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/listView/listViewEntry.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/listView.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/webDAVView/webDAVView.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/listViewEntry.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/webDAVView/webDAVViewEntry.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/loginView.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/loginView/loginView.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/util/util.cpp
|
${CMAKE_SOURCE_DIR}/src/util/util.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/util/log.cpp
|
${CMAKE_SOURCE_DIR}/src/util/log.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/api/webDAV.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/api/sqliteConnector.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(Nextcloud.app ${SOURCES})
|
add_executable(Nextcloud.app ${SOURCES})
|
||||||
|
@ -71,9 +72,13 @@ include_directories(
|
||||||
${CMAKE_SOURCE_DIR}/src/handler/
|
${CMAKE_SOURCE_DIR}/src/handler/
|
||||||
${CMAKE_SOURCE_DIR}/src/util/
|
${CMAKE_SOURCE_DIR}/src/util/
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/
|
${CMAKE_SOURCE_DIR}/src/ui/
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ui/listView/
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ui/webDAVView/
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ui/loginView/
|
||||||
|
${CMAKE_SOURCE_DIR}/src/api/
|
||||||
)
|
)
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES (Nextcloud.app PRIVATE inkview freetype curl)
|
TARGET_LINK_LIBRARIES (Nextcloud.app PRIVATE inkview freetype curl sqlite3)
|
||||||
|
|
||||||
INSTALL (TARGETS Nextcloud.app)
|
INSTALL (TARGETS Nextcloud.app)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ A basic client to access an existing nextcloud instance via Pocketbook.
|
||||||
* Remove files from local storage system
|
* Remove files from local storage system
|
||||||
* Show local files that are saved but no longer available in the cloud
|
* Show local files that are saved but no longer available in the cloud
|
||||||
* Open epub, pdf, text, html, word and mobi with default ebook reader application
|
* Open epub, pdf, text, html, word and mobi with default ebook reader application
|
||||||
* Set Start folder to custom path
|
|
||||||
* Offline Modus
|
* Offline Modus
|
||||||
* Navigaten via keys and touch
|
* Navigaten via keys and touch
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
LOGFILE="/mnt/Pocketbook/system/config/nextcloud/logfile.txt"
|
||||||
|
APPLOCATION="bin/Nextcloud.app"
|
||||||
|
APPDIR="/mnt/Pocketbook/applications/"
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Help #
|
||||||
|
############################################################
|
||||||
|
Help()
|
||||||
|
{
|
||||||
|
# Display Help
|
||||||
|
echo "Functions to interact with the PB"
|
||||||
|
echo
|
||||||
|
echo "Syntax: pb [h|c|l|u]"
|
||||||
|
echo "options:"
|
||||||
|
echo "-h Print this Help."
|
||||||
|
echo "-c Copy the app to the appfolder"
|
||||||
|
echo "-l Show a logfile, if it exists"
|
||||||
|
echo "-u Unmount PB"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# MOUNT #
|
||||||
|
############################################################
|
||||||
|
Mount()
|
||||||
|
{
|
||||||
|
MOUNTPOINT=$(sudo blkid | awk '/PB632/ {print $1;}' | tr -d ':')
|
||||||
|
if [ -n "$MOUNTPOINT" ]
|
||||||
|
then
|
||||||
|
if mount | grep $MOUNTPOINT > /dev/null; then
|
||||||
|
echo "Already mounted."
|
||||||
|
else
|
||||||
|
sudo mount $MOUNTPOINT /mnt/Pocketbook
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Could not find PB"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
############################################################
|
||||||
|
# Main program #
|
||||||
|
############################################################
|
||||||
|
############################################################
|
||||||
|
[ $# -eq 0 ] && Help
|
||||||
|
while getopts ":hclu" o; do
|
||||||
|
case $o in
|
||||||
|
h) #Display help
|
||||||
|
Help
|
||||||
|
exit;;
|
||||||
|
l)
|
||||||
|
Mount
|
||||||
|
if [ -f "$LOGFILE" ];
|
||||||
|
then
|
||||||
|
less $LOGFILE;
|
||||||
|
while true; do
|
||||||
|
read -p "Do you want to delete log?" yn
|
||||||
|
case $yn in
|
||||||
|
[Yy]* ) sudo rm -r $LOGFILE; break;;
|
||||||
|
[Nn]* ) exit;;
|
||||||
|
* ) echo "Y/N";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "No log file found."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
c)
|
||||||
|
Mount
|
||||||
|
if [ -d "$APPDIR" ]
|
||||||
|
then
|
||||||
|
make
|
||||||
|
sudo cp $APPLOCATION $APPDIR
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
u)
|
||||||
|
if mount | grep /mnt/Pocketbook > /dev/null; then
|
||||||
|
sudo umount /mnt/Pocketbook
|
||||||
|
echo "Pocketbook umounted"
|
||||||
|
else
|
||||||
|
echo "/mnt/Pocketbook not mounted."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid command. To see available commands add -h."
|
||||||
|
esac
|
||||||
|
done
|
|
@ -0,0 +1,15 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// model.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 23.04.2021
|
||||||
|
// Description: Base model
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef MODEL
|
||||||
|
#define MODEL
|
||||||
|
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,186 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// sqliteconnector.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 18.07.2021
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "sqliteConnector.h"
|
||||||
|
#include "sqlite3.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
SqliteConnector::SqliteConnector(const string &DBpath) : _dbpath(DBpath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SqliteConnector::~SqliteConnector()
|
||||||
|
{
|
||||||
|
sqlite3_close(_db);
|
||||||
|
Log::writeInfoLog("closed DB");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SqliteConnector::open()
|
||||||
|
{
|
||||||
|
int rs;
|
||||||
|
|
||||||
|
rs = sqlite3_open(_dbpath.c_str(), &_db);
|
||||||
|
|
||||||
|
if (rs)
|
||||||
|
{
|
||||||
|
Log::writeErrorLog("Could not open DB at " + _dbpath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs = sqlite3_exec(_db, "CREATE TABLE IF NOT EXISTS metadata (title VARCHAR, localPath VARCHAR, size VARCHAR, fileType VARCHAR, lasteditDate VARCHAR, type INT, state INT, etag VARCHAR, path VARCHAR, parentPath VARCHAR, key VARCHAR, PRIMARY KEY (key))", NULL, 0, NULL);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string SqliteConnector::getEtag(string path)
|
||||||
|
{
|
||||||
|
open();
|
||||||
|
|
||||||
|
int rs;
|
||||||
|
sqlite3_stmt *stmt = 0;
|
||||||
|
std::vector<WebDAVItem> items;
|
||||||
|
|
||||||
|
|
||||||
|
rs = sqlite3_prepare_v2(_db, "SELECT etag FROM 'metadata' WHERE path = ? LIMIT 1;", -1, &stmt, 0);
|
||||||
|
rs = sqlite3_bind_text(stmt, 1, path.c_str(), path.length(), NULL);
|
||||||
|
|
||||||
|
//TODO erase while
|
||||||
|
while (sqlite3_step(stmt) == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
path = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
sqlite3_close(_db);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<WebDAVItem> SqliteConnector::getItemsChildren(const string &parentPath)
|
||||||
|
{
|
||||||
|
open();
|
||||||
|
|
||||||
|
int rs;
|
||||||
|
sqlite3_stmt *stmt = 0;
|
||||||
|
std::vector<WebDAVItem> items;
|
||||||
|
|
||||||
|
|
||||||
|
rs = sqlite3_prepare_v2(_db, "SELECT title, localPath, path, size, etag, fileType, lastEditDate, type, state FROM 'metadata' WHERE parentPath = ?;", -1, &stmt, 0);
|
||||||
|
rs = sqlite3_bind_text(stmt, 1, parentPath.c_str(), parentPath.length(), NULL);
|
||||||
|
|
||||||
|
while (sqlite3_step(stmt) == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
|
||||||
|
WebDAVItem temp;
|
||||||
|
|
||||||
|
temp.title = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
|
||||||
|
temp.localPath = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
|
||||||
|
temp.path = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2));
|
||||||
|
temp.size = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 3));
|
||||||
|
temp.etag = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 4));
|
||||||
|
temp.fileType = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 5));
|
||||||
|
temp.lastEditDate = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 6));
|
||||||
|
temp.type = static_cast<Itemtype>(sqlite3_column_int(stmt,7));
|
||||||
|
temp.state = static_cast<FileState>(sqlite3_column_int(stmt,8));
|
||||||
|
|
||||||
|
items.push_back(temp);
|
||||||
|
//
|
||||||
|
//TODO also for folders
|
||||||
|
/*
|
||||||
|
if (iv_access(tempItem.localPath.c_str(), W_OK) != 0)
|
||||||
|
tempItem.state = FileState::ICLOUD;
|
||||||
|
else
|
||||||
|
tempItem.state = FileState::ISYNCED;
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
sqlite3_close(_db);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SqliteConnector::deleteChildren(const string &parentPath)
|
||||||
|
{
|
||||||
|
open();
|
||||||
|
int rs;
|
||||||
|
sqlite3_stmt *stmt = 0;
|
||||||
|
Log::writeInfoLog(parentPath);
|
||||||
|
rs = sqlite3_prepare_v2(_db, "DELETE FROM 'metadata' WHERE parentPath like ?", -1, &stmt, 0);
|
||||||
|
rs = sqlite3_bind_text(stmt, 1, parentPath.c_str(), parentPath.length(), NULL);
|
||||||
|
|
||||||
|
rs = sqlite3_step(stmt);
|
||||||
|
if (rs != SQLITE_DONE)
|
||||||
|
{
|
||||||
|
Log::writeErrorLog(std::string("An error ocurred trying to delete items of the path ") + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")");
|
||||||
|
}
|
||||||
|
rs = sqlite3_clear_bindings(stmt);
|
||||||
|
rs = sqlite3_reset(stmt);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO for folder write to all below folder or do singles?
|
||||||
|
// void SqliteConnector::updateState(const WebDAVItem
|
||||||
|
|
||||||
|
bool SqliteConnector::saveItemsChildren(const std::vector<WebDAVItem> &items)
|
||||||
|
{
|
||||||
|
open();
|
||||||
|
int rs;
|
||||||
|
string key;
|
||||||
|
sqlite3_stmt *stmt = 0;
|
||||||
|
string parent = items.at(0).path;
|
||||||
|
|
||||||
|
//Sqlite version to old... is 3.18, require 3.24
|
||||||
|
//Log::writeInfoLog(sqlite3_libversion());
|
||||||
|
//rs = sqlite3_prepare_v2(_db, "INSERT INTO 'metadata' (title, localPath, path, size, parentPath, etag, fileType, lastEditDate, type, state, key) VALUES (?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT(key) DO UPDATE SET etag=?, size=?, lastEditDate=? WHERE metadata.etag <> ?;", -1, &stmt, 0);
|
||||||
|
deleteChildren(parent);
|
||||||
|
|
||||||
|
|
||||||
|
rs = sqlite3_prepare_v2(_db, "INSERT INTO 'metadata' (title, localPath, path, size, parentPath, etag, fileType, lastEditDate, type, state, key) VALUES (?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt, 0);
|
||||||
|
rs = sqlite3_exec(_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
for (auto item : items)
|
||||||
|
{
|
||||||
|
Log::writeInfoLog("item :" + item.title);
|
||||||
|
rs = sqlite3_bind_text(stmt, 1, item.title.c_str(), item.title.length(), NULL);
|
||||||
|
rs = sqlite3_bind_text(stmt, 2, item.localPath.c_str(), item.localPath.length(), NULL);
|
||||||
|
rs = sqlite3_bind_text(stmt, 3, item.path.c_str(), item.path.length(), NULL);
|
||||||
|
rs = sqlite3_bind_text(stmt, 4, item.size.c_str(), item.size.length(), NULL);
|
||||||
|
rs = sqlite3_bind_text(stmt, 5, parent.c_str(), parent.length(), NULL);
|
||||||
|
rs = sqlite3_bind_text(stmt, 6, item.etag.c_str(), item.etag.length(), NULL);
|
||||||
|
rs = sqlite3_bind_text(stmt, 7, item.fileType.c_str(), item.fileType.length(), NULL);
|
||||||
|
rs = sqlite3_bind_text(stmt, 8, item.lastEditDate.c_str(), item.lastEditDate.length(), NULL);
|
||||||
|
rs = sqlite3_bind_int(stmt, 9, item.type);
|
||||||
|
rs = sqlite3_bind_int(stmt, 10, item.state);
|
||||||
|
key = parent + item.title;
|
||||||
|
rs = sqlite3_bind_text(stmt, 11, key.c_str(),key.length(),NULL);
|
||||||
|
|
||||||
|
rs = sqlite3_step(stmt);
|
||||||
|
if (rs == SQLITE_CONSTRAINT)
|
||||||
|
{
|
||||||
|
Log::writeInfoLog("item exists already: " + item.path);
|
||||||
|
}
|
||||||
|
else if (rs != SQLITE_DONE)
|
||||||
|
{
|
||||||
|
Log::writeErrorLog(std::string("error inserting into table ") + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")");
|
||||||
|
}
|
||||||
|
rs = sqlite3_clear_bindings(stmt);
|
||||||
|
rs = sqlite3_reset(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_exec(_db, "END TRANSACTION;", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
sqlite3_close(_db);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// sqliteconnector.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 18.07.2021
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef SQLITECONNECTOR
|
||||||
|
#define SQLITECONNECTOR
|
||||||
|
|
||||||
|
#include "webDAVModel.h"
|
||||||
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class SqliteConnector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SqliteConnector(const std::string &DBpath);
|
||||||
|
|
||||||
|
~SqliteConnector();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
std::string getEtag(std::string path);
|
||||||
|
|
||||||
|
std::vector<WebDAVItem> getItemsChildren(const std::string &parenthPath);
|
||||||
|
|
||||||
|
void deleteChildren(const std::string &parentPath);
|
||||||
|
|
||||||
|
bool saveItemsChildren(const std::vector<WebDAVItem> &children);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string _dbpath;
|
||||||
|
sqlite3 *_db;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,465 @@
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// webdav.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 06.07.2022
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "webDAV.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "eventHandler.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
using std::ifstream;
|
||||||
|
using std::ofstream;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
|
||||||
|
WebDAV::WebDAV()
|
||||||
|
{
|
||||||
|
|
||||||
|
//TODO update on first login only start and create update button, update others just if etag changed
|
||||||
|
//save all to sqlite
|
||||||
|
|
||||||
|
if (iv_access(NEXTCLOUD_PATH.c_str(), W_OK) != 0)
|
||||||
|
iv_mkdir(NEXTCLOUD_PATH.c_str(), 0777);
|
||||||
|
|
||||||
|
if (iv_access(NEXTCLOUD_FILE_PATH.c_str(), W_OK) != 0)
|
||||||
|
iv_mkdir(NEXTCLOUD_FILE_PATH.c_str(), 0777);
|
||||||
|
|
||||||
|
if (iv_access(CONFIG_PATH.c_str(), W_OK) == 0)
|
||||||
|
{
|
||||||
|
_username = Util::accessConfig(CONFIG_PATH,Action::IReadString,"username");
|
||||||
|
_password = Util::accessConfig(CONFIG_PATH,Action::IReadSecret,"password");
|
||||||
|
_url = Util::accessConfig(CONFIG_PATH, Action::IReadString, "url");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO pass in vector and change that one?
|
||||||
|
std::vector<WebDAVItem> WebDAV::login(const string &Url, const string &Username, const string &Pass)
|
||||||
|
{
|
||||||
|
string uuid;
|
||||||
|
std::size_t found = Url.find(NEXTCLOUD_ROOT_PATH);
|
||||||
|
|
||||||
|
if (found != std::string::npos)
|
||||||
|
{
|
||||||
|
_url = Url.substr(0, found);
|
||||||
|
uuid = Url.substr(found + NEXTCLOUD_ROOT_PATH.length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_url = Url;
|
||||||
|
uuid = Username;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tempPath = NEXTCLOUD_ROOT_PATH + uuid + "/";
|
||||||
|
std::vector<WebDAVItem> tempItems = getDataStructure(tempPath);
|
||||||
|
if (!tempItems.empty())
|
||||||
|
{
|
||||||
|
if (iv_access(CONFIG_PATH.c_str(), W_OK) != 0)
|
||||||
|
iv_buildpath(CONFIG_PATH.c_str());
|
||||||
|
Util::accessConfig(CONFIG_PATH, Action::IWriteString, "url", _url);
|
||||||
|
Util::accessConfig(CONFIG_PATH, Action::IWriteString, "username", Username);
|
||||||
|
Util::accessConfig(CONFIG_PATH, Action::IWriteString, "uuid", uuid);
|
||||||
|
Util::accessConfig(CONFIG_PATH, Action::IWriteSecret, "password", Pass);
|
||||||
|
}
|
||||||
|
return tempItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebDAV::logout(bool deleteFiles)
|
||||||
|
{
|
||||||
|
if (deleteFiles)
|
||||||
|
{
|
||||||
|
//string cmd = "rm -rf " + NEXTCLOUD_FILE_PATH + "/" + getUUID() + "/";
|
||||||
|
//system(cmd.c_str());
|
||||||
|
}
|
||||||
|
remove(CONFIG_PATH.c_str());
|
||||||
|
remove((CONFIG_PATH + ".back.").c_str());
|
||||||
|
|
||||||
|
//_url.clear();
|
||||||
|
//TODO where?
|
||||||
|
//tempItems.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO pas as reversne and no return
|
||||||
|
string WebDAV::getLocalPath(string path)
|
||||||
|
{
|
||||||
|
Util::decodeUrl(path);
|
||||||
|
if (path.find(NEXTCLOUD_ROOT_PATH) != string::npos)
|
||||||
|
path = path.substr(NEXTCLOUD_ROOT_PATH.length());
|
||||||
|
|
||||||
|
return NEXTCLOUD_FILE_PATH + "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO SQL CHeck before calling this function --> if is needed...
|
||||||
|
///TODO rename function
|
||||||
|
vector<WebDAVItem> WebDAV::getDataStructure(const string &pathUrl)
|
||||||
|
{
|
||||||
|
string xmlItem = propfind(pathUrl);
|
||||||
|
if(!xmlItem.empty())
|
||||||
|
{
|
||||||
|
string beginItem = "<d:response>";
|
||||||
|
string endItem = "</d:response>";
|
||||||
|
vector<WebDAVItem> tempItems;
|
||||||
|
WebDAVItem tempItem;
|
||||||
|
size_t begin = xmlItem.find(beginItem);
|
||||||
|
size_t end;
|
||||||
|
|
||||||
|
while (begin != std::string::npos)
|
||||||
|
{
|
||||||
|
end = xmlItem.find(endItem);
|
||||||
|
//TODO use xml lib?
|
||||||
|
|
||||||
|
//TODO fav is int?
|
||||||
|
//Log::writeInfoLog(Util::getXMLAttribute(xmlItem, "d:favorite"));
|
||||||
|
|
||||||
|
tempItem.etag = Util::getXMLAttribute(xmlItem, "d:getetag");
|
||||||
|
tempItem.path = Util::getXMLAttribute(xmlItem, "d:href");
|
||||||
|
tempItem.lastEditDate = Util::getXMLAttribute(xmlItem, "d:getlastmodified");
|
||||||
|
|
||||||
|
double size = atof(Util::getXMLAttribute(xmlItem, "oc:size").c_str());
|
||||||
|
if (size < 1024)
|
||||||
|
tempItem.size = "< 1 KB";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double departBy;
|
||||||
|
double tempSize;
|
||||||
|
string unit;
|
||||||
|
|
||||||
|
if (size < 1048576)
|
||||||
|
{
|
||||||
|
departBy = 1024;
|
||||||
|
unit = "KB";
|
||||||
|
}
|
||||||
|
else if (size < 1073741824)
|
||||||
|
{
|
||||||
|
departBy = 1048576;
|
||||||
|
unit = "MB";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
departBy = 1073741824;
|
||||||
|
unit = "GB";
|
||||||
|
}
|
||||||
|
tempSize = round((size / departBy) * 10.0) / 10.0;
|
||||||
|
std::ostringstream stringStream;
|
||||||
|
stringStream << tempSize;
|
||||||
|
tempItem.size = stringStream.str() + " " + unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
//replaces everthing in front of /remote.php as this is already part of the url
|
||||||
|
if(tempItem.path.find(NEXTCLOUD_START_PATH) != 0)
|
||||||
|
tempItem.path.erase(0,tempItem.path.find(NEXTCLOUD_START_PATH));
|
||||||
|
|
||||||
|
tempItem.title = tempItem.path;
|
||||||
|
tempItem.localPath = getLocalPath(tempItem.path);
|
||||||
|
|
||||||
|
if (tempItem.path.back() == '/')
|
||||||
|
{
|
||||||
|
tempItem.localPath = tempItem.localPath.substr(0, tempItem.localPath.length() - 1);
|
||||||
|
tempItem.type = Itemtype::IFOLDER;
|
||||||
|
tempItem.title = tempItem.title.substr(0, tempItem.path.length() - 1);
|
||||||
|
//TODO set sync status of folders --> use sqlite?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tempItem.type = Itemtype::IFILE;
|
||||||
|
tempItem.fileType = Util::getXMLAttribute(xmlItem, "d:getcontenttype");
|
||||||
|
|
||||||
|
if (iv_access(tempItem.localPath.c_str(), W_OK) != 0)
|
||||||
|
tempItem.state = FileState::ICLOUD;
|
||||||
|
else
|
||||||
|
tempItem.state = FileState::ISYNCED;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempItem.title = tempItem.title.substr(tempItem.title.find_last_of("/") + 1, tempItem.title.length());
|
||||||
|
Util::decodeUrl(tempItem.title);
|
||||||
|
|
||||||
|
tempItems.push_back(tempItem);
|
||||||
|
xmlItem = xmlItem.substr(end + endItem.length());
|
||||||
|
begin = xmlItem.find(beginItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO doppelt
|
||||||
|
if (tempItems.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
//resize item 1
|
||||||
|
string header = tempItems.at(0).path;
|
||||||
|
header = header.substr(0, header.find_last_of("/"));
|
||||||
|
header = header.substr(0, header.find_last_of("/") + 1);
|
||||||
|
tempItems.at(0).path = header;
|
||||||
|
tempItems.at(0).title += "\nclick to go back";
|
||||||
|
tempItems.at(0).lastEditDate = "";
|
||||||
|
if (tempItems.at(0).path.compare(NEXTCLOUD_ROOT_PATH) == 0)
|
||||||
|
tempItems.erase(tempItems.begin());
|
||||||
|
|
||||||
|
string localPath = getLocalPath(pathUrl);
|
||||||
|
|
||||||
|
//if the current folder does not exist locally, create it
|
||||||
|
if (iv_access(localPath.c_str(), W_OK) != 0)
|
||||||
|
iv_buildpath(localPath.c_str());
|
||||||
|
|
||||||
|
return tempItems;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
//TODO return empty items?
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void Nextcloud::downloadFolder(vector<Item> &tempItems, int itemID)
|
||||||
|
{
|
||||||
|
|
||||||
|
//TODO etag
|
||||||
|
BanSleep(2000);
|
||||||
|
|
||||||
|
if (tempItems.at(itemID).getState() == FileState::ILOCAL)
|
||||||
|
{
|
||||||
|
UpdateProgressbar(("Removing local item " + tempItems.at(itemID).getLocalPath()).c_str(), 0);
|
||||||
|
tempItems.at(itemID).removeFile();
|
||||||
|
if (_type == Itemtype::IFOLDER)
|
||||||
|
{
|
||||||
|
string cmd = "rm -rf " + _localPath + "/";
|
||||||
|
system(cmd.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove(_localPath.c_str()) != 0)
|
||||||
|
return false;
|
||||||
|
if (_state == FileState::ISYNCED || _state == FileState::IOUTSYNCED)
|
||||||
|
{
|
||||||
|
_state = FileState::ICLOUD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO applies if file is only local
|
||||||
|
//only show if person is inside this folder
|
||||||
|
Message(ICON_INFORMATION, "Warning", "The file will be shown until next folder update.", 1200);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check files; where modified date --> modified date of structure
|
||||||
|
//first check cloud, then check local
|
||||||
|
|
||||||
|
if (tempItems.at(itemID).getType() == Itemtype::IFOLDER)
|
||||||
|
{
|
||||||
|
//check etag
|
||||||
|
|
||||||
|
//for folders
|
||||||
|
//1. check etag --> if is different, cloud has been updated --> need to dig in deeper here;
|
||||||
|
//2. if is the same, only check local file system and dont show folder anymore
|
||||||
|
string temp = tempItems.at(itemID).getPath();
|
||||||
|
Log::writeInfoLog("Path to look for " + temp);
|
||||||
|
vector<Item> tempItems = getDataStructure(temp);
|
||||||
|
|
||||||
|
//first item of the vector is the root path itself
|
||||||
|
for (size_t i = 1; i < tempItems.size(); i++)
|
||||||
|
{
|
||||||
|
Log::writeInfoLog("Item: " + tempItems.at(i).getPath());
|
||||||
|
downloadFolder(tempItems, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//for files
|
||||||
|
//1. check etag --> if is differnt, cloud has been updated
|
||||||
|
//2. check modification date and file size locally --> if is different, local has been updated
|
||||||
|
|
||||||
|
//3. if both --> create conflict
|
||||||
|
//4. if first, renew file --> reset etag
|
||||||
|
//5. if second --> upload the local file; test if it has not been update in the cloud
|
||||||
|
Log::writeInfoLog("started download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath());
|
||||||
|
get(tempItems, itemID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nextcloud::download(int itemID)
|
||||||
|
{
|
||||||
|
if (!Util::connectToNetwork())
|
||||||
|
{
|
||||||
|
Message(ICON_WARNING, "Warning", "Can not connect to the Internet. Switching to offline modus.", 2000);
|
||||||
|
_workOffline = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->downloadFolder(tempItems, itemID);
|
||||||
|
|
||||||
|
UpdateProgressbar("Download completed", 100);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
string WebDAV::propfind(const string &pathUrl)
|
||||||
|
{
|
||||||
|
//TODO catch here pathUrl is empty!
|
||||||
|
if (pathUrl.empty())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
//where to test this??
|
||||||
|
//include error messsages
|
||||||
|
if(_username.empty() || _password.empty())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
//string localPath = getLocalPath(pathUrl);
|
||||||
|
|
||||||
|
if (!Util::connectToNetwork())
|
||||||
|
{
|
||||||
|
Message(ICON_WARNING, "Warning", "Cannot connect to the internet. Switching to offline modus. To work online turn on online modus in the menu.", 2000);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//get etag from current and then send request with FT_ENC_TAG
|
||||||
|
//need path url and also the etag
|
||||||
|
|
||||||
|
//can handle multiple etags --> * if exists
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
string readBuffer;
|
||||||
|
CURLcode res;
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
string post = _username + ":" + _password;
|
||||||
|
Log::writeInfoLog(_url + pathUrl);
|
||||||
|
|
||||||
|
struct curl_slist *headers = NULL;
|
||||||
|
headers = curl_slist_append(headers, "Depth: 1");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, (_url + pathUrl).c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "<\?xml version=\"1.0\" encoding=\"UTF-8\"\?> \
|
||||||
|
<d:propfind xmlns:d=\"DAV:\"><d:prop xmlns:oc=\"http://owncloud.org/ns\"> \
|
||||||
|
<d:getlastmodified/> \
|
||||||
|
<d:getcontenttype/> \
|
||||||
|
<oc:size/> \
|
||||||
|
<d:getetag/> \
|
||||||
|
<oc:favorite/> \
|
||||||
|
</d:prop></d:propfind>");
|
||||||
|
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
if (res == CURLE_OK)
|
||||||
|
{
|
||||||
|
long response_code;
|
||||||
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||||
|
|
||||||
|
switch (response_code)
|
||||||
|
{
|
||||||
|
case 404:
|
||||||
|
Message(ICON_ERROR, "Error", "The URL seems to be incorrect. You can look up the WebDav URL in the files app under settings. ", 4000);
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
Message(ICON_ERROR, "Error", "Username/password incorrect.", 4000);
|
||||||
|
break;
|
||||||
|
case 207:
|
||||||
|
return readBuffer;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Message(ICON_ERROR, "Error", ("An unknown error occured. Switching to offline modus. To work online turn on online modus in the menu. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 4000);
|
||||||
|
//TODO change default msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again.";
|
||||||
|
Log::writeErrorLog(response);
|
||||||
|
Message(ICON_ERROR, "Error", response.c_str(), 4000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void WebDAV::get(vector<Item> &tempItems, int itemID)
|
||||||
|
{
|
||||||
|
//CHECK id
|
||||||
|
if (tempItems.at(itemID).getState() == FileState::ISYNCED)
|
||||||
|
{
|
||||||
|
UpdateProgressbar(("The newest version of file " + tempItems.at(itemID).getLocalPath() + " is already downloaded.").c_str(), 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tempItems.at(itemID).getPath().empty())
|
||||||
|
{
|
||||||
|
Message(ICON_ERROR, "Error", "Download path is not set, therefore cannot download the file.", 2000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateProgressbar(("Starting Download of " + tempItems.at(itemID).getLocalPath()).c_str(), 0);
|
||||||
|
CURLcode res;
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
string post = this->getUsername() + std::string(":") + this->getPassword();
|
||||||
|
|
||||||
|
FILE *fp;
|
||||||
|
fp = iv_fopen(tempItems.at(itemID).getLocalPath().c_str(), "wb");
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, (_url + tempItems.at(itemID).getPath()).c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeData);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Util::progress_callback);
|
||||||
|
//in case that cacert is available use it
|
||||||
|
if (iv_access(CACERT_PATH.c_str(), W_OK) == 0)
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CAINFO, CACERT_PATH.c_str());
|
||||||
|
else
|
||||||
|
Log::writeErrorLog("could not find cacert");
|
||||||
|
//Follow redirects
|
||||||
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
iv_fclose(fp);
|
||||||
|
|
||||||
|
if (res == CURLE_OK)
|
||||||
|
{
|
||||||
|
long response_code;
|
||||||
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||||
|
|
||||||
|
switch (response_code)
|
||||||
|
{
|
||||||
|
case 200:
|
||||||
|
Log::writeInfoLog("finished download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath());
|
||||||
|
tempItems.at(itemID).setState(FileState::ISYNCED);
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
Message(ICON_ERROR, "Error", "Username/password incorrect.", 2000);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Message(ICON_ERROR, "Error", ("An unknown error occured. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 2000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again.";
|
||||||
|
if(res == 60)
|
||||||
|
response = "Seems as if you are using Let's Encrypt Certs. Please follow the guide on Github (https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client) to use a custom Cert Store on PB.";
|
||||||
|
Message(ICON_ERROR, "Error", response.c_str(), 4000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
|
@ -0,0 +1,59 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// webdav.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 06.07.2022
|
||||||
|
// Description: Interface to the webdav API
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef WEBDAV
|
||||||
|
#define WEBDAV
|
||||||
|
|
||||||
|
#include "webDAVModel.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//TODO rename
|
||||||
|
const std::string NEXTCLOUD_FILE_PATH = "/mnt/ext1/nextcloud";
|
||||||
|
const std::string NEXTCLOUD_ROOT_PATH = "/remote.php/dav/files/";
|
||||||
|
const std::string NEXTCLOUD_START_PATH = "/remote.php/";
|
||||||
|
const std::string CACERT_PATH = "/mnt/ext1/applications/cacert.pem";
|
||||||
|
const std::string NEXTCLOUD_PATH = "/mnt/ext1/system/config/nextcloud";
|
||||||
|
|
||||||
|
class WebDAV
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a new pocket object containing token to access the api
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
WebDAV();
|
||||||
|
|
||||||
|
std::vector<WebDAVItem> login(const std::string &Url, const std::string &Username, const std::string &Pass);
|
||||||
|
|
||||||
|
void logout(bool deleteFiles = false);
|
||||||
|
|
||||||
|
std::string getLocalPath(std::string path);
|
||||||
|
|
||||||
|
std::vector<WebDAVItem> getDataStructure(const std::string &pathUrl);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the dataStructure of the given URL and writes its WEBDAV items to the items vector
|
||||||
|
*
|
||||||
|
* @param pathUrl URL to get the dataStructure of
|
||||||
|
* @param Username the username of the Nextcloud instance
|
||||||
|
* @param Pass the pass of the Nextcloud instance
|
||||||
|
* @return vector of Items
|
||||||
|
*/
|
||||||
|
std::string propfind(const std::string &pathUrl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string _username;
|
||||||
|
std::string _password;
|
||||||
|
std::string _url;
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,42 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// webDAVItem.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 07.07.2022
|
||||||
|
// Description:
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef WEBDAVITEM
|
||||||
|
#define WEBDAVITEM
|
||||||
|
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
enum Itemtype
|
||||||
|
{
|
||||||
|
IFILE,
|
||||||
|
IFOLDER
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FileState
|
||||||
|
{
|
||||||
|
ICLOUD,
|
||||||
|
ISYNCED,
|
||||||
|
IOUTSYNCED,
|
||||||
|
ILOCAL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WebDAVItem : Entry{
|
||||||
|
std::string etag;
|
||||||
|
std::string path;
|
||||||
|
std::string title;
|
||||||
|
std::string localPath;
|
||||||
|
FileState state{FileState::ICLOUD};
|
||||||
|
Itemtype type;
|
||||||
|
std::string lastEditDate{"Error"};
|
||||||
|
std::string size;
|
||||||
|
std::string fileType;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -10,7 +10,7 @@
|
||||||
#define CONTEXT_MENU
|
#define CONTEXT_MENU
|
||||||
|
|
||||||
#include "inkview.h"
|
#include "inkview.h"
|
||||||
#include "item.h"
|
#include "webDAVModel.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,17 @@
|
||||||
#include "eventHandler.h"
|
#include "eventHandler.h"
|
||||||
#include "mainMenu.h"
|
#include "mainMenu.h"
|
||||||
#include "contextMenu.h"
|
#include "contextMenu.h"
|
||||||
#include "listView.h"
|
#include "webDAVView.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "webDAV.h"
|
||||||
|
#include "webDAVModel.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
std::unique_ptr<EventHandler> EventHandler::_eventHandlerStatic;
|
std::unique_ptr<EventHandler> EventHandler::_eventHandlerStatic;
|
||||||
|
|
||||||
|
@ -27,27 +30,63 @@ EventHandler::EventHandler()
|
||||||
_eventHandlerStatic = std::unique_ptr<EventHandler>(this);
|
_eventHandlerStatic = std::unique_ptr<EventHandler>(this);
|
||||||
|
|
||||||
_loginView = nullptr;
|
_loginView = nullptr;
|
||||||
_listView = nullptr;
|
_webDAVView = nullptr;
|
||||||
|
vector<WebDAVItem> fromDB;
|
||||||
|
std::vector<WebDAVItem> currentWebDAVItems;
|
||||||
|
|
||||||
if (iv_access(NEXTCLOUD_CONFIG_PATH.c_str(), W_OK) == 0)
|
if (iv_access(CONFIG_PATH.c_str(), W_OK) == 0)
|
||||||
{
|
{
|
||||||
if (_nextcloud.login())
|
//menubar
|
||||||
|
//explanation on first login?
|
||||||
|
//TODO here mark folders that are unsynced?
|
||||||
|
//compare both datasets, if fromDB etag is different, mark as unsycned
|
||||||
|
string tempPath = NEXTCLOUD_ROOT_PATH + Util::accessConfig(CONFIG_PATH, Action::IReadString,"UUID");
|
||||||
|
currentWebDAVItems = _webDAV.getDataStructure(tempPath);
|
||||||
|
fromDB = _sqllite.getItemsChildren(tempPath);
|
||||||
|
}
|
||||||
|
//TODO here or father below?
|
||||||
|
_menu = std::unique_ptr<MainMenu>(new MainMenu("Nextcloud"));
|
||||||
|
|
||||||
|
if(currentWebDAVItems.empty())
|
||||||
{
|
{
|
||||||
_listView = std::unique_ptr<ListView>(new ListView(_menu.getContentRect(), _nextcloud.getItems()));
|
//use from DB
|
||||||
|
//this one is always required --> if does not work -> say to the user that it did not work, to sync use
|
||||||
|
/*
|
||||||
|
vector<Item> Nextcloud::getOfflineStructure(const string &pathUrl)
|
||||||
|
{
|
||||||
|
if (pathUrl.compare(NEXTCLOUD_ROOT_PATH + getUUID() + "/") == 0)
|
||||||
|
{
|
||||||
|
Message(ICON_ERROR, "Error", "The root structure is not available offline. Please try again to login.", 2000);
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Message(ICON_ERROR, "Error", "Could not login, please try again.", 1200);
|
||||||
|
if(fromDB.empty())
|
||||||
|
{
|
||||||
|
int dialogResult = DialogSynchro(ICON_QUESTION, "Action", "Could not login and there is no DB available to restore information. What would you like to do?", "Logout", "Close App", NULL);
|
||||||
|
switch (dialogResult)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
_webDAV.logout();
|
||||||
|
_loginView = std::unique_ptr<LoginView>(new LoginView(_menu->getContentRect()));
|
||||||
FullUpdate();
|
FullUpdate();
|
||||||
return;
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
default:
|
||||||
|
CloseApp();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Message(ICON_ERROR, "Error", "Could not login, please try again.", 1200);
|
_webDAVView = std::unique_ptr<WebDAVView>(new WebDAVView(_menu->getContentRect(), _currentWebDAVItems,1));
|
||||||
_nextcloud.logout();
|
_sqllite.saveItemsChildren(_currentWebDAVItems);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_loginView = std::unique_ptr<LoginView>(new LoginView(_menu.getContentRect()));
|
|
||||||
|
|
||||||
FullUpdate();
|
FullUpdate();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int EventHandler::eventDistributor(const int type, const int par1, const int par2)
|
int EventHandler::eventDistributor(const int type, const int par1, const int par2)
|
||||||
{
|
{
|
||||||
|
@ -68,63 +107,39 @@ void EventHandler::mainMenuHandler(const int index)
|
||||||
{
|
{
|
||||||
switch (index)
|
switch (index)
|
||||||
{
|
{
|
||||||
//offlineModus
|
//TODO actualize current folder
|
||||||
case 101:
|
case 101:
|
||||||
{
|
{
|
||||||
if (_nextcloud.isWorkOffline())
|
|
||||||
{
|
|
||||||
if (Util::connectToNetwork())
|
|
||||||
{
|
|
||||||
_nextcloud.switchWorkOffline();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Message(ICON_WARNING, "Warning", "Could not connect to the internet.", 1200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_nextcloud.switchWorkOffline();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//Make startfolder
|
|
||||||
case 102:
|
|
||||||
{
|
|
||||||
_nextcloud.setStartFolder(_tempPath);
|
|
||||||
Message(ICON_INFORMATION, "Info", ("On the next startup the folder" + _tempPath + " will be shown.").c_str(), 1200);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//Logout
|
//Logout
|
||||||
case 103:
|
case 102:
|
||||||
{
|
{
|
||||||
int dialogResult = DialogSynchro(ICON_QUESTION, "Action", "Do you want to delete local files?", "Yes", "No", "Cancel");
|
int dialogResult = DialogSynchro(ICON_QUESTION, "Action", "Do you want to delete local files?", "Yes", "No", "Cancel");
|
||||||
switch (dialogResult)
|
switch (dialogResult)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
_nextcloud.logout(true);
|
_webDAV.logout(true);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
_nextcloud.logout();
|
_webDAV.logout();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_listView.release();
|
_webDAVView.release();
|
||||||
_loginView = std::unique_ptr<LoginView>(new LoginView(_menu.getContentRect()));
|
_loginView = std::unique_ptr<LoginView>(new LoginView(_menu->getContentRect()));
|
||||||
FullUpdate();
|
FullUpdate();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//Info
|
//Info
|
||||||
case 104:
|
case 103:
|
||||||
{
|
{
|
||||||
Message(ICON_INFORMATION, "Information", "Version 0.73 \n For support please open a ticket at https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client/issues", 1200);
|
Message(ICON_INFORMATION, "Information", "Version 0.73 \n For support please open a ticket at https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client/issues", 1200);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//Exit
|
//Exit
|
||||||
case 105:
|
case 104:
|
||||||
CloseApp();
|
CloseApp();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -146,7 +161,7 @@ void EventHandler::contextMenuHandler(const int index)
|
||||||
//Open
|
//Open
|
||||||
case 101:
|
case 101:
|
||||||
{
|
{
|
||||||
if (_nextcloud.getItems().at(_tempItemID).getType() == Itemtype::IFOLDER)
|
if (_webDAVView->getCurrentEntry().type == Itemtype::IFOLDER)
|
||||||
{
|
{
|
||||||
openFolder();
|
openFolder();
|
||||||
}
|
}
|
||||||
|
@ -167,22 +182,29 @@ void EventHandler::contextMenuHandler(const int index)
|
||||||
case 103:
|
case 103:
|
||||||
{
|
{
|
||||||
OpenProgressbar(1, "Removing...", "Removing Files.", 0, NULL);
|
OpenProgressbar(1, "Removing...", "Removing Files.", 0, NULL);
|
||||||
|
/*
|
||||||
|
Log::writeInfoLog("removing file " + _items.at(itemID).getPath());
|
||||||
|
if (!_items.at(itemID).removeFile())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
*/
|
||||||
|
/*
|
||||||
if (_nextcloud.removeItem(_tempItemID))
|
if (_nextcloud.removeItem(_tempItemID))
|
||||||
{
|
{
|
||||||
updatePBLibrary();
|
updatePBLibrary();
|
||||||
CloseProgressbar();
|
CloseProgressbar();
|
||||||
_listView->drawEntry(_tempItemID);
|
_webDAVView->reDrawCurrentEntry();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
*/
|
||||||
CloseProgressbar();
|
CloseProgressbar();
|
||||||
Message(ICON_WARNING, "Warning", "Could not delete the file, please try again.", 1200);
|
Message(ICON_WARNING, "Warning", "Could not delete the file, please try again.", 1200);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
_listView->invertEntryColor(_tempItemID);
|
_webDAVView->invertCurrentEntryColor();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,42 +217,36 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
|
||||||
//long press to open up context menu
|
//long press to open up context menu
|
||||||
if (type == EVT_POINTERLONG)
|
if (type == EVT_POINTERLONG)
|
||||||
{
|
{
|
||||||
if (_listView != nullptr)
|
if (_webDAVView != nullptr)
|
||||||
{
|
{
|
||||||
_tempItemID = _listView->listClicked(par1, par2);
|
_webDAVView->checkIfEntryClicked(par1, par2);
|
||||||
_listView->invertEntryColor(_tempItemID);
|
_webDAVView->invertCurrentEntryColor();
|
||||||
if (_tempItemID != -1)
|
if (_webDAVView->getCurrentEntry().title.compare("...") != 0)
|
||||||
{
|
|
||||||
if (_nextcloud.getItems().at(_tempItemID).getTitle().compare("...") != 0)
|
|
||||||
{
|
{
|
||||||
_contextMenu = std::unique_ptr<ContextMenu>(new ContextMenu());
|
_contextMenu = std::unique_ptr<ContextMenu>(new ContextMenu());
|
||||||
_contextMenu->createMenu(par2, _nextcloud.getItems().at(_tempItemID).getState(), EventHandler::contextMenuHandlerStatic);
|
_contextMenu->createMenu(par2, _webDAVView->getCurrentEntry().state, EventHandler::contextMenuHandlerStatic);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type == EVT_POINTERUP)
|
else if (type == EVT_POINTERUP)
|
||||||
{
|
{
|
||||||
//menu is clicked
|
if (IsInRect(par1, par2, &_menu->getMenuButtonRect()) == 1)
|
||||||
if (IsInRect(par1, par2, _menu.getMenuButtonRect()) == 1)
|
|
||||||
{
|
{
|
||||||
return _menu.createMenu(_nextcloud.isLoggedIn(), _nextcloud.isWorkOffline(), EventHandler::mainMenuHandlerStatic);
|
return _menu->createMenu((_webDAVView != nullptr), EventHandler::mainMenuHandlerStatic);
|
||||||
}
|
}
|
||||||
//if listView is shown
|
else if (_webDAVView != nullptr)
|
||||||
else if (_listView != nullptr)
|
|
||||||
{
|
{
|
||||||
_tempItemID = _listView->listClicked(par1, par2);
|
if(_webDAVView->checkIfEntryClicked(par1, par2))
|
||||||
if (_tempItemID != -1)
|
|
||||||
{
|
{
|
||||||
_listView->invertEntryColor(_tempItemID);
|
_webDAVView->invertCurrentEntryColor();
|
||||||
|
|
||||||
if (_nextcloud.getItems().at(_tempItemID).getType() == Itemtype::IFOLDER)
|
if (_webDAVView->getCurrentEntry().type == Itemtype::IFOLDER)
|
||||||
{
|
{
|
||||||
openFolder();
|
openFolder();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_nextcloud.getItems().at(_tempItemID).getState() == FileState::ISYNCED || (_nextcloud.isWorkOffline() && _nextcloud.getItems().at(_tempItemID).getState() == FileState::IOUTSYNCED))
|
if (_webDAVView->getCurrentEntry().state != FileState::ICLOUD)
|
||||||
{
|
{
|
||||||
openItem();
|
openItem();
|
||||||
}
|
}
|
||||||
|
@ -250,17 +266,17 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
|
||||||
{
|
{
|
||||||
ShowHourglassForce();
|
ShowHourglassForce();
|
||||||
|
|
||||||
if (_nextcloud.login(_loginView->getURL(), _loginView->getUsername(), _loginView->getPassword()))
|
std::vector<WebDAVItem> currentWebDAVItems = _webDAV.login(_loginView->getURL(), _loginView->getUsername(), _loginView->getPassword());
|
||||||
|
if(currentWebDAVItems.empty())
|
||||||
{
|
{
|
||||||
_listView = std::unique_ptr<ListView>(new ListView(_menu.getContentRect(), _nextcloud.getItems()));
|
HideHourglass();
|
||||||
_loginView.reset();
|
Log::writeErrorLog("login failed.");
|
||||||
|
|
||||||
FullUpdate();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HideHourglass();
|
_webDAVView = std::make_unique<WebDAVView>(WebDAVView(_menu->getContentRect(), currentWebDAVItems,1));
|
||||||
Log::writeLog("login failed.");
|
_loginView.reset();
|
||||||
|
FullUpdate();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -271,60 +287,96 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
|
||||||
|
|
||||||
void EventHandler::updatePBLibrary()
|
void EventHandler::updatePBLibrary()
|
||||||
{
|
{
|
||||||
if (_nextcloud.getItems().at(_tempItemID).getType() == Itemtype::IFOLDER)
|
if (_webDAVView->getCurrentEntry().type == Itemtype::IFOLDER)
|
||||||
{
|
{
|
||||||
Util::updatePBLibrary(15);
|
Util::updatePBLibrary(15);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_nextcloud.getItems().at(_tempItemID).isBook())
|
//if (_nextcloud.getItems().at(_tempItemID).isBook())
|
||||||
|
/*
|
||||||
|
* is needed twice!
|
||||||
|
if (_fileType.find("application/epub+zip") != string::npos ||
|
||||||
|
_fileType.find("application/pdf") != string::npos ||
|
||||||
|
_fileType.find("application/octet-stream") != string::npos ||
|
||||||
|
_fileType.find("text/plain") != string::npos ||
|
||||||
|
_fileType.find("text/html") != string::npos ||
|
||||||
|
_fileType.find("text/rtf") != string::npos ||
|
||||||
|
_fileType.find("application/msword") != string::npos ||
|
||||||
|
_fileType.find("application/x-mobipocket-ebook") != string::npos ||
|
||||||
|
_fileType.find("application/vnd.openxmlformats-officedocument.wordprocessingml.document") != string::npos ||
|
||||||
|
_fileType.find("application/x-fictionbook+xml") != string::npos)
|
||||||
Util::updatePBLibrary(5);
|
Util::updatePBLibrary(5);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandler::startDownload()
|
void EventHandler::startDownload()
|
||||||
{
|
{
|
||||||
if (_nextcloud.isWorkOffline())
|
|
||||||
{
|
|
||||||
int dialogResult = DialogSynchro(ICON_QUESTION, "Action", "You are in offline modus. Go back online?", "Yes", "No", "Cancel");
|
|
||||||
if (dialogResult == 2 || dialogResult == 3)
|
|
||||||
return; // 1;
|
|
||||||
_nextcloud.switchWorkOffline();
|
|
||||||
}
|
|
||||||
OpenProgressbar(1, "Downloading...", "Checking network connection", 0, NULL);
|
OpenProgressbar(1, "Downloading...", "Checking network connection", 0, NULL);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_nextcloud.download(_tempItemID);
|
//_nextcloud.download(_tempItemID);
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
Log::writeLog(e.what());
|
Log::writeErrorLog(e.what());
|
||||||
Message(ICON_ERROR, "Error", "Something has gone wrong. Please check the logs. (/system/config/nextcloud/)", 1200);
|
Message(ICON_ERROR, "Error", "Something has gone wrong. Please check the logs. (/system/config/nextcloud/)", 1200);
|
||||||
}
|
}
|
||||||
updatePBLibrary();
|
updatePBLibrary();
|
||||||
|
|
||||||
CloseProgressbar();
|
CloseProgressbar();
|
||||||
_listView->drawEntry(_tempItemID);
|
_webDAVView->reDrawCurrentEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandler::openItem()
|
void EventHandler::openItem()
|
||||||
{
|
{
|
||||||
_listView->invertEntryColor(_tempItemID);
|
_webDAVView->invertCurrentEntryColor();
|
||||||
_nextcloud.getItems().at(_tempItemID).open();
|
/*
|
||||||
|
if (_state == FileState::ICLOUD)
|
||||||
|
{
|
||||||
|
Message(ICON_ERROR, "File not found.", "Could not find file.", 1000);
|
||||||
|
}
|
||||||
|
else if(isBook())
|
||||||
|
{
|
||||||
|
|
||||||
|
OpenBook(_localPath.c_str(), "", 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message(ICON_INFORMATION, "Warning", "The filetype is currently not supported.", 1200);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
//webDAVView->getCurrentEntry
|
||||||
|
//_nextcloud.getItems().at(_tempItemID).open();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandler::openFolder()
|
void EventHandler::openFolder()
|
||||||
{
|
{
|
||||||
FillAreaRect(_menu.getContentRect(), WHITE);
|
|
||||||
ShowHourglassForce();
|
ShowHourglassForce();
|
||||||
|
//_nextcloud.setItems(_nextcloud.getDataStructure(_tempPath));
|
||||||
|
//TODO if folder is unsynced sync
|
||||||
|
std::vector<WebDAVItem> currentWebDAVItems = _webDAV.getDataStructure(_webDAVView->getCurrentEntry().path);
|
||||||
|
if(currentWebDAVItems.empty())
|
||||||
|
{
|
||||||
|
Log::writeErrorLog("items empty");
|
||||||
|
HideHourglass();
|
||||||
|
_webDAVView->invertCurrentEntryColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log::writeInfoLog("got new items");
|
||||||
|
_sqllite.saveItemsChildren(currentWebDAVItems);
|
||||||
|
|
||||||
_tempPath = _nextcloud.getItems().at(_tempItemID).getPath();
|
//if folder is synced, get only from DB
|
||||||
if (!_tempPath.empty())
|
//vector<WebDAVItem> fromDB = _sqllite.getItemsChildren(_tempPath);
|
||||||
_nextcloud.setItems(_nextcloud.getDataStructure(_tempPath));
|
//get etags from DB, if etag for path is unchanged, stays the same, same for foldersjj
|
||||||
_listView.release();
|
FillAreaRect(&_menu->getContentRect(), WHITE);
|
||||||
_listView = std::unique_ptr<ListView>(new ListView(_menu.getContentRect(), _nextcloud.getItems()));
|
_webDAVView.release();
|
||||||
_listView->drawHeader(_tempPath.substr(NEXTCLOUD_ROOT_PATH.length()));
|
_webDAVView = std::unique_ptr<WebDAVView>(new WebDAVView(_menu->getContentRect(), _currentWebDAVItems,1));
|
||||||
PartialUpdate(_menu.getContentRect()->x, _menu.getContentRect()->y, _menu.getContentRect()->w, _menu.getContentRect()->h);
|
//_sqllite.saveItemsChildren(_nextcloud.getItems());
|
||||||
|
PartialUpdate(_menu->getContentRect().x, _menu->getContentRect().y, _menu->getContentRect().w, _menu->getContentRect().h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int EventHandler::keyHandler(const int type, const int par1, const int par2)
|
int EventHandler::keyHandler(const int type, const int par1, const int par2)
|
||||||
|
@ -334,19 +386,19 @@ int EventHandler::keyHandler(const int type, const int par1, const int par2)
|
||||||
//menu button
|
//menu button
|
||||||
if (par1 == 23)
|
if (par1 == 23)
|
||||||
{
|
{
|
||||||
_listView->firstPage();
|
_webDAVView->firstPage();
|
||||||
}
|
}
|
||||||
else if (_listView != nullptr)
|
else if (_webDAVView != nullptr)
|
||||||
{
|
{
|
||||||
//left button
|
//left button
|
||||||
if (par1 == 24)
|
if (par1 == 24)
|
||||||
{
|
{
|
||||||
_listView->prevPage();
|
_webDAVView->prevPage();
|
||||||
}
|
}
|
||||||
//right button
|
//right button
|
||||||
else if (par1 == 25)
|
else if (par1 == 25)
|
||||||
{
|
{
|
||||||
_listView->nextPage();
|
_webDAVView->nextPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -358,3 +410,82 @@ int EventHandler::keyHandler(const int type, const int par1, const int par2)
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
void Nextcloud::getLocalFileStructure(vector<Item> &tempItems, const string &localPath)
|
||||||
|
{
|
||||||
|
//get local files, https://stackoverflow.com/questions/306533/how-do-i-get-a-list-of-files-in-a-directory-in-c
|
||||||
|
DIR *dir;
|
||||||
|
class dirent *ent;
|
||||||
|
class stat st;
|
||||||
|
|
||||||
|
dir = opendir(localPath.c_str());
|
||||||
|
while ((ent = readdir(dir)) != NULL)
|
||||||
|
{
|
||||||
|
const string fileName = ent->d_name;
|
||||||
|
const string fullFileName = localPath + fileName;
|
||||||
|
|
||||||
|
if (fileName[0] == '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (stat(fullFileName.c_str(), &st) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const bool isDirectory = (st.st_mode & S_IFDIR) != 0;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
//looks if files have been modified
|
||||||
|
for (unsigned int i = 1; i < tempItems.size(); i++)
|
||||||
|
{
|
||||||
|
if (tempItems.at(i).getLocalPath().compare(fullFileName) == 0)
|
||||||
|
{
|
||||||
|
//do via etag and not outsync !
|
||||||
|
if (!isDirectory)
|
||||||
|
{
|
||||||
|
//check if was changed on the cloud and here and then update...
|
||||||
|
//if etag ist different and last modifcated changed local --> create conflict
|
||||||
|
//compare by etag
|
||||||
|
//get last modification date and compare; if is different upload this
|
||||||
|
|
||||||
|
std::ifstream in(fullFileName, std::ifstream::binary | std::ifstream::ate);
|
||||||
|
Log::writeInfoLog(tempItems.at(i).getTitle());
|
||||||
|
Log::writeInfoLog(std::to_string(in.tellg()));
|
||||||
|
|
||||||
|
Log::writeInfoLog(std::to_string(tempItems.at(i).getSize()));
|
||||||
|
if (in.tellg() != tempItems.at(i).getSize())
|
||||||
|
{
|
||||||
|
tempItems.at(i).setState(FileState::IOUTSYNCED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
if (isDirectory)
|
||||||
|
{
|
||||||
|
//create new dir in cloud
|
||||||
|
tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFOLDER));
|
||||||
|
Item::Item(const string &localPath, FileState state, Itemtype type) : _localPath(localPath), _state(state), _type(type)
|
||||||
|
{
|
||||||
|
_title = _localPath;
|
||||||
|
_title = _title.substr(_title.find_last_of("/") + 1, _title.length());
|
||||||
|
Util::decodeUrl(_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//put to coud
|
||||||
|
tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFILE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,17 @@
|
||||||
|
|
||||||
#include "contextMenu.h"
|
#include "contextMenu.h"
|
||||||
#include "mainMenu.h"
|
#include "mainMenu.h"
|
||||||
#include "nextcloud.h"
|
#include "webDAV.h"
|
||||||
#include "listView.h"
|
#include "webDAVView.h"
|
||||||
#include "loginView.h"
|
#include "loginView.h"
|
||||||
|
#include "sqliteConnector.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
const std::string LOG_PATH = "/mnt/ext1/system/config/nextcloud";
|
const std::string CONFIG_FOLDER = "/mnt/ext1/system/config/nextcloud";
|
||||||
|
const std::string CONFIG_PATH = CONFIG_FOLDER + "/nextcloud.cfg";
|
||||||
|
//TODO use folder of nextcloud conifg temp
|
||||||
|
const std::string DB_PATH = CONFIG_FOLDER + "/data.db";
|
||||||
|
|
||||||
class EventHandler
|
class EventHandler
|
||||||
{
|
{
|
||||||
|
@ -39,13 +43,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::unique_ptr<EventHandler> _eventHandlerStatic;
|
static std::unique_ptr<EventHandler> _eventHandlerStatic;
|
||||||
std::unique_ptr<ListView> _listView;
|
std::unique_ptr<WebDAVView> _webDAVView;
|
||||||
std::unique_ptr<LoginView> _loginView;
|
std::unique_ptr<LoginView> _loginView;
|
||||||
std::unique_ptr<ContextMenu> _contextMenu;
|
std::unique_ptr<ContextMenu> _contextMenu;
|
||||||
MainMenu _menu = MainMenu("Nextcloud");
|
std::unique_ptr<MainMenu> _menu;
|
||||||
Nextcloud _nextcloud = Nextcloud();
|
|
||||||
std::string _tempPath;
|
WebDAV _webDAV = WebDAV();
|
||||||
int _tempItemID;
|
SqliteConnector _sqllite = SqliteConnector(DB_PATH);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function needed to call C function, redirects to real function
|
* Function needed to call C function, redirects to real function
|
||||||
|
|
|
@ -15,10 +15,9 @@ using std::string;
|
||||||
|
|
||||||
MainMenu::MainMenu(const string &name)
|
MainMenu::MainMenu(const string &name)
|
||||||
{
|
{
|
||||||
//Define panel size
|
|
||||||
_panelMenuHeight = ScreenHeight() / 18;
|
_panelMenuHeight = ScreenHeight() / 18;
|
||||||
_panelMenuBeginY = 0;
|
|
||||||
_mainMenuWidth = ScreenWidth() / 3;
|
_mainMenuWidth = ScreenWidth() / 3;
|
||||||
|
_panelMenuBeginY = 0;
|
||||||
_panelMenuBeginX = ScreenWidth() - _mainMenuWidth;
|
_panelMenuBeginX = ScreenWidth() - _mainMenuWidth;
|
||||||
|
|
||||||
_menuButtonRect = iRect(_mainMenuWidth * 2, _panelMenuBeginY, _mainMenuWidth, _panelMenuHeight, ALIGN_RIGHT);
|
_menuButtonRect = iRect(_mainMenuWidth * 2, _panelMenuBeginY, _mainMenuWidth, _panelMenuHeight, ALIGN_RIGHT);
|
||||||
|
@ -30,18 +29,17 @@ MainMenu::MainMenu(const string &name)
|
||||||
DrawTextRect2(&_menuButtonRect, "Menu");
|
DrawTextRect2(&_menuButtonRect, "Menu");
|
||||||
DrawLine(0, _panelMenuHeight - 1, ScreenWidth(), _panelMenuHeight - 1, BLACK);
|
DrawLine(0, _panelMenuHeight - 1, ScreenWidth(), _panelMenuHeight - 1, BLACK);
|
||||||
|
|
||||||
_contentRect = iRect(0, _panelMenuHeight, ScreenWidth(), (ScreenHeight() - PanelHeight() - _panelMenuHeight), 0);
|
_contentRect = iRect(0, _panelMenuHeight, ScreenWidth(), (ScreenHeight() - _panelMenuHeight), 0);
|
||||||
|
|
||||||
SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000);
|
SetPanelType(0);
|
||||||
DrawPanel(NULL, "", NULL, -1);
|
PartialUpdate(0, _panelMenuBeginY, ScreenWidth(), _panelMenuHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainMenu::~MainMenu()
|
MainMenu::~MainMenu()
|
||||||
{
|
{
|
||||||
CloseFont(_menuFont);
|
CloseFont(_menuFont);
|
||||||
free(_text);
|
free(_syncFolder);
|
||||||
free(_menu);
|
free(_menu);
|
||||||
free(_makeStartfolder);
|
|
||||||
free(_logout);
|
free(_logout);
|
||||||
free(_info);
|
free(_info);
|
||||||
free(_exit);
|
free(_exit);
|
||||||
|
@ -53,24 +51,17 @@ void MainMenu::panelHandlerStatic()
|
||||||
SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000);
|
SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MainMenu::createMenu(bool loggedIn, bool workOffline, iv_menuhandler handler)
|
int MainMenu::createMenu(bool loggedIn, iv_menuhandler handler)
|
||||||
{
|
{
|
||||||
string text = "Work offline";
|
|
||||||
if (workOffline)
|
|
||||||
text = "Work online";
|
|
||||||
|
|
||||||
_text = strdup(text.c_str());
|
|
||||||
|
|
||||||
imenu mainMenu[] =
|
imenu mainMenu[] =
|
||||||
{
|
{
|
||||||
{ITEM_HEADER, 0, _menu, NULL},
|
{ITEM_HEADER, 0, _menu, NULL},
|
||||||
//show logged in
|
//show logged in
|
||||||
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 101, _text, NULL},
|
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 101, _syncFolder, NULL},
|
||||||
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 102, _makeStartfolder, NULL},
|
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 102, _logout, NULL},
|
||||||
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 103, _logout, NULL},
|
|
||||||
//show always
|
//show always
|
||||||
{ITEM_ACTIVE, 104, _info, NULL},
|
{ITEM_ACTIVE, 103, _info, NULL},
|
||||||
{ITEM_ACTIVE, 105, _exit, NULL},
|
{ITEM_ACTIVE, 104, _exit, NULL},
|
||||||
{0, 0, NULL, NULL}};
|
{0, 0, NULL, NULL}};
|
||||||
|
|
||||||
OpenMenu(mainMenu, 0, _panelMenuBeginX, _panelMenuBeginY, handler);
|
OpenMenu(mainMenu, 0, _panelMenuBeginX, _panelMenuBeginY, handler);
|
||||||
|
|
|
@ -25,8 +25,8 @@ public:
|
||||||
|
|
||||||
~MainMenu();
|
~MainMenu();
|
||||||
|
|
||||||
irect *getContentRect() { return &_contentRect; };
|
irect &getContentRect() { return _contentRect; };
|
||||||
irect *getMenuButtonRect() { return &_menuButtonRect; };
|
irect &getMenuButtonRect() { return _menuButtonRect; };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the menu on the screen, lets the user choose menu options and then redirects the handler to the caller
|
* Shows the menu on the screen, lets the user choose menu options and then redirects the handler to the caller
|
||||||
|
@ -35,7 +35,7 @@ public:
|
||||||
* @param handler handles the clicks on the menu
|
* @param handler handles the clicks on the menu
|
||||||
* @return int returns if the event was handled
|
* @return int returns if the event was handled
|
||||||
*/
|
*/
|
||||||
int createMenu(bool loggedIn, bool workOffline, iv_menuhandler handler);
|
int createMenu(bool loggedIn, iv_menuhandler handler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ifont *_menuFont;
|
ifont *_menuFont;
|
||||||
|
@ -49,9 +49,8 @@ private:
|
||||||
imenu _mainMenu;
|
imenu _mainMenu;
|
||||||
irect _contentRect;
|
irect _contentRect;
|
||||||
|
|
||||||
char *_text;
|
|
||||||
char *_menu = strdup("Menu");
|
char *_menu = strdup("Menu");
|
||||||
char *_makeStartfolder = strdup("Make startfolder");
|
char *_syncFolder = strdup("Actualize folder");
|
||||||
char *_logout = strdup("Logout");
|
char *_logout = strdup("Logout");
|
||||||
char *_info = strdup("Info");
|
char *_info = strdup("Info");
|
||||||
char *_exit = strdup("Close App");
|
char *_exit = strdup("Close App");
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// fileModel.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 23.04.2021
|
||||||
|
// Description:
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef FILEMODEL
|
||||||
|
#define FILEMODEL
|
||||||
|
|
||||||
|
//#include "model.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
FOLDER,
|
||||||
|
FIL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct File : Entry{
|
||||||
|
std::string name;
|
||||||
|
std::string path;
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,44 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// fileView.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "fileView.h"
|
||||||
|
#include "fileViewEntry.h"
|
||||||
|
#include "fileModel.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
FileView::FileView(const irect &contentRect, const vector<File> &files, int page) : ListView(contentRect, page)
|
||||||
|
{
|
||||||
|
auto pageHeight = 0;
|
||||||
|
auto contentHeight = _contentRect->h - _footerHeight;
|
||||||
|
auto entrycount = files.size();
|
||||||
|
|
||||||
|
_entries.reserve(entrycount);
|
||||||
|
|
||||||
|
auto i = 0;
|
||||||
|
while (i < entrycount)
|
||||||
|
{
|
||||||
|
auto entrySize = TextRectHeight(contentRect->w, files.at(i).name.c_str(), 0) + 2.5 * _entryFontHeight;
|
||||||
|
if ((pageHeight + entrySize) > contentHeight)
|
||||||
|
{
|
||||||
|
pageHeight = 0;
|
||||||
|
_page++;
|
||||||
|
}
|
||||||
|
irect rect = iRect(_contentRect->x, _contentRect->y + pageHeight, _contentRect->w, entrySize, 0);
|
||||||
|
|
||||||
|
_entries.emplace_back(std::unique_ptr<FileViewEntry>(new FileViewEntry(_page, rect, files.at(i))));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
pageHeight = pageHeight + entrySize;
|
||||||
|
}
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// fileView.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
// Description: An UI class to display items in a listview
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef FILEVIEW
|
||||||
|
#define FILEVIEW
|
||||||
|
|
||||||
|
#include "fileModel.h"
|
||||||
|
#include "listView.h"
|
||||||
|
#include "fileViewEntry.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class FileView final : public ListView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Displays a list view
|
||||||
|
*
|
||||||
|
* @param ContentRect area of the screen where the list view is placed
|
||||||
|
* @param Items items that shall be shown in the listview
|
||||||
|
* @param page page that is shown, default is 1
|
||||||
|
*/
|
||||||
|
FileView(const irect &contentRect, const std::vector<File> &files, int page = 1);
|
||||||
|
|
||||||
|
File &getCurrentEntry() { return getEntry(_selectedEntry); };
|
||||||
|
|
||||||
|
File &getEntry(int entryID) { return std::dynamic_pointer_cast<FileViewEntry>(_entries.at(entryID))->get(); };
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,35 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// fileViewEntry.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "fileViewEntry.h"
|
||||||
|
#include "fileModel.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
FileViewEntry::FileViewEntry(int page, const irect &position, const File &entry) : ListViewEntry(page, position), _entry(entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileViewEntry::draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight)
|
||||||
|
{
|
||||||
|
SetFont(entryFontBold, BLACK);
|
||||||
|
int heightOfTitle = TextRectHeight(_position.w, _entry.name.c_str(), 0);
|
||||||
|
DrawTextRect(_position.x, _position.y, _position.w, heightOfTitle, _entry.name.c_str(), ALIGN_LEFT);
|
||||||
|
|
||||||
|
SetFont(entryFont, BLACK);
|
||||||
|
|
||||||
|
//DrawTextRect(_position.x, _position.y + heightOfTitle, _position.w, fontHeight, _entry.name.c_str(), ALIGN_LEFT);
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, _entry.path.c_str(), ALIGN_LEFT);
|
||||||
|
std::string type = "File";
|
||||||
|
if(_entry.type == Type::FOLDER)
|
||||||
|
type = "Folder";
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, type.c_str(), ALIGN_RIGHT);
|
||||||
|
|
||||||
|
int line = (_position.y + _position.h) - 1;
|
||||||
|
DrawLine(0, line, ScreenWidth(), line, BLACK);
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// fileViewEntry.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
// Description:
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef FILEVIEWENTRY
|
||||||
|
#define FILEVIEWENTRY
|
||||||
|
|
||||||
|
#include "listViewEntry.h"
|
||||||
|
#include "fileModel.h"
|
||||||
|
|
||||||
|
class FileViewEntry : public ListViewEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates an FileViewEntry
|
||||||
|
*
|
||||||
|
* @param Page site of the listView the Entry is shown
|
||||||
|
* @param Rect area of the screen the item is positioned
|
||||||
|
* @param entry entry that shall be drawn
|
||||||
|
*/
|
||||||
|
FileViewEntry(int page, const irect &position, const File &entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* draws the FileViewEntry to the screen
|
||||||
|
*
|
||||||
|
* @param entryFont font for the entry itself
|
||||||
|
* @param entryFontBold bold font for the header
|
||||||
|
* @param fontHeight height of the font
|
||||||
|
*/
|
||||||
|
void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) override;
|
||||||
|
|
||||||
|
File &get() { return _entry; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
File _entry;
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -1,186 +0,0 @@
|
||||||
//------------------------------------------------------------------
|
|
||||||
// listView.cpp
|
|
||||||
//
|
|
||||||
// Author: JuanJakobo
|
|
||||||
// Date: 04.08.2020
|
|
||||||
//
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include "inkview.h"
|
|
||||||
#include "item.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "listView.h"
|
|
||||||
#include "listViewEntry.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
ListView::ListView(const irect *contentRect, const vector<Item> &items) : _contentRect(contentRect), _items(&items)
|
|
||||||
{
|
|
||||||
FillAreaRect(_contentRect, WHITE);
|
|
||||||
|
|
||||||
_entries.clear();
|
|
||||||
|
|
||||||
int entrySize = _contentRect->h / (_itemCount + 1);
|
|
||||||
|
|
||||||
_headerHeight = 0.25 * entrySize;
|
|
||||||
_footerHeight = 0.75 * entrySize;
|
|
||||||
|
|
||||||
_headerFontHeight = 0.8 * _headerHeight;
|
|
||||||
_footerFontHeight = 0.3 * _footerHeight;
|
|
||||||
_entryFontHeight = 0.2 * entrySize;
|
|
||||||
|
|
||||||
_headerFont = OpenFont("LiberationMono", _headerFontHeight, FONT_STD);
|
|
||||||
_footerFont = OpenFont("LiberationMono", _footerFontHeight, FONT_STD);
|
|
||||||
_entryFont = OpenFont("LiberationMono", _entryFontHeight, FONT_STD);
|
|
||||||
_entryFontBold = OpenFont("LiberationMono-Bold", _entryFontHeight, FONT_BOLD);
|
|
||||||
|
|
||||||
_page = 1;
|
|
||||||
_shownPage = _page;
|
|
||||||
|
|
||||||
auto i = _items->size();
|
|
||||||
auto z = 0;
|
|
||||||
|
|
||||||
_entries.reserve(i);
|
|
||||||
|
|
||||||
while (i > 0)
|
|
||||||
{
|
|
||||||
if (z >= _itemCount)
|
|
||||||
{
|
|
||||||
_page++;
|
|
||||||
z = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
irect rect = iRect(_contentRect->x, z * entrySize + _headerHeight + _contentRect->y, _contentRect->w, entrySize, 0);
|
|
||||||
this->_entries.emplace_back(_page, rect);
|
|
||||||
i--;
|
|
||||||
z++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_pageIcon = iRect(_contentRect->w - 100, _contentRect->h + _contentRect->y - _footerHeight, 100, _footerHeight, ALIGN_CENTER);
|
|
||||||
|
|
||||||
_firstPageButton = iRect(_contentRect->x, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER);
|
|
||||||
_prevPageButton = iRect(_contentRect->x + 150, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER);
|
|
||||||
_nextPageButton = iRect(_contentRect->x + 300, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER);
|
|
||||||
_lastPageButton = iRect(_contentRect->x + 450, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER);
|
|
||||||
|
|
||||||
drawEntries();
|
|
||||||
drawFooter();
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView::~ListView()
|
|
||||||
{
|
|
||||||
CloseFont(_entryFont);
|
|
||||||
CloseFont(_entryFontBold);
|
|
||||||
CloseFont(_headerFont);
|
|
||||||
CloseFont(_footerFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::drawHeader(string headerText)
|
|
||||||
{
|
|
||||||
SetFont(_headerFont, BLACK);
|
|
||||||
Util::decodeUrl(headerText);
|
|
||||||
DrawTextRect(_contentRect->x, _contentRect->y, _contentRect->w, _headerHeight - 1, headerText.c_str(), ALIGN_LEFT);
|
|
||||||
|
|
||||||
int line = (_contentRect->y + _headerHeight) - 2;
|
|
||||||
DrawLine(0, line, ScreenWidth(), line, BLACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::drawEntry(int itemID)
|
|
||||||
{
|
|
||||||
FillAreaRect(_entries[itemID].getPosition(), WHITE);
|
|
||||||
_entries[itemID].draw(_items->at(itemID), _entryFont, _entryFontBold, _entryFontHeight);
|
|
||||||
updateEntry(itemID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::invertEntryColor(int itemID)
|
|
||||||
{
|
|
||||||
InvertAreaBW(_entries[itemID].getPosition()->x, _entries[itemID].getPosition()->y, _entries[itemID].getPosition()->w, _entries[itemID].getPosition()->h);
|
|
||||||
updateEntry(itemID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::drawEntries()
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < _entries.size(); i++)
|
|
||||||
{
|
|
||||||
if (_entries[i].getPage() == _shownPage)
|
|
||||||
_entries[i].draw(_items->at(i), _entryFont, _entryFontBold, _entryFontHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ListView::listClicked(int x, int y)
|
|
||||||
{
|
|
||||||
if (IsInRect(x, y, &_firstPageButton))
|
|
||||||
{
|
|
||||||
firstPage();
|
|
||||||
}
|
|
||||||
else if (IsInRect(x, y, &_nextPageButton))
|
|
||||||
{
|
|
||||||
nextPage();
|
|
||||||
}
|
|
||||||
else if (IsInRect(x, y, &_prevPageButton))
|
|
||||||
{
|
|
||||||
prevPage();
|
|
||||||
}
|
|
||||||
else if (IsInRect(x, y, &_lastPageButton))
|
|
||||||
{
|
|
||||||
actualizePage(_page);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < _entries.size(); i++)
|
|
||||||
{
|
|
||||||
if (_entries[i].getPage() == _shownPage && IsInRect(x, y, _entries[i].getPosition()) == 1)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::drawFooter()
|
|
||||||
{
|
|
||||||
SetFont(_footerFont, WHITE);
|
|
||||||
string footer = std::to_string(_shownPage) + "/" + std::to_string(_page);
|
|
||||||
FillAreaRect(&_pageIcon, BLACK);
|
|
||||||
|
|
||||||
DrawTextRect2(&_pageIcon, footer.c_str());
|
|
||||||
FillAreaRect(&_firstPageButton, BLACK);
|
|
||||||
DrawTextRect2(&_firstPageButton, "First");
|
|
||||||
FillAreaRect(&_prevPageButton, BLACK);
|
|
||||||
DrawTextRect2(&_prevPageButton, "Prev");
|
|
||||||
FillAreaRect(&_nextPageButton, BLACK);
|
|
||||||
DrawTextRect2(&_nextPageButton, "Next");
|
|
||||||
FillAreaRect(&_lastPageButton, BLACK);
|
|
||||||
DrawTextRect2(&_lastPageButton, "Last");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::updateEntry(int itemID)
|
|
||||||
{
|
|
||||||
PartialUpdate(_entries[itemID].getPosition()->x, _entries[itemID].getPosition()->y, _entries[itemID].getPosition()->w, _entries[itemID].getPosition()->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::actualizePage(int pageToShown)
|
|
||||||
{
|
|
||||||
if (pageToShown > _page)
|
|
||||||
{
|
|
||||||
Message(ICON_INFORMATION, "Info", "You have reached the last page, to return to the first, please click \"first.\"", 1200);
|
|
||||||
}
|
|
||||||
else if (pageToShown < 1)
|
|
||||||
{
|
|
||||||
Message(ICON_INFORMATION, "Info", "You are already on the first page.", 1200);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_shownPage = pageToShown;
|
|
||||||
FillArea(_contentRect->x, _contentRect->y + _headerHeight, _contentRect->w, _contentRect->h, WHITE);
|
|
||||||
drawEntries();
|
|
||||||
drawFooter();
|
|
||||||
PartialUpdate(_contentRect->x, _contentRect->y + _headerHeight, _contentRect->w, _contentRect->h);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// listView.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 04.08.2020
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "inkview.h"
|
||||||
|
#include "listView.h"
|
||||||
|
#include "listViewEntry.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
ListView::ListView(const irect &contentRect, int page) : _contentRect(contentRect), _shownPage(page)
|
||||||
|
{
|
||||||
|
_entries.clear();
|
||||||
|
|
||||||
|
_footerHeight = _contentRect.h / 15;
|
||||||
|
_footerFontHeight = 0.3 * _footerHeight;
|
||||||
|
_entryFontHeight = contentRect.h/45;
|
||||||
|
|
||||||
|
_footerFont = OpenFont("LiberationMono", _footerFontHeight, 1);
|
||||||
|
_entryFont = OpenFont("LiberationMono", _entryFontHeight, 1);
|
||||||
|
_entryFontBold = OpenFont("LiberationMono-Bold", _entryFontHeight, 1);
|
||||||
|
|
||||||
|
SetFont(_entryFont, BLACK);
|
||||||
|
|
||||||
|
int footerWidth = contentRect.w/20;
|
||||||
|
|
||||||
|
_pageIcon = iRect(_contentRect.w - footerWidth*2, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/10, _footerHeight, ALIGN_CENTER);
|
||||||
|
|
||||||
|
_firstPageButton = iRect(_contentRect.x, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER);
|
||||||
|
|
||||||
|
_prevPageButton = iRect(_contentRect.x + footerWidth*3, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER);
|
||||||
|
|
||||||
|
_nextPageButton = iRect(_contentRect.x + footerWidth*6, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER);
|
||||||
|
|
||||||
|
_lastPageButton = iRect(_contentRect.x + footerWidth*9, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView::~ListView()
|
||||||
|
{
|
||||||
|
CloseFont(_entryFont);
|
||||||
|
CloseFont(_entryFontBold);
|
||||||
|
CloseFont(_footerFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListView::draw()
|
||||||
|
{
|
||||||
|
FillAreaRect(&_contentRect, WHITE);
|
||||||
|
drawEntries();
|
||||||
|
drawFooter();
|
||||||
|
PartialUpdate(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListView::reDrawCurrentEntry()
|
||||||
|
{
|
||||||
|
FillAreaRect(&_entries.at(_selectedEntry)->getPosition(), WHITE);
|
||||||
|
_entries.at(_selectedEntry)->draw(_entryFont, _entryFontBold, _entryFontHeight);
|
||||||
|
updateEntry(_selectedEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListView::invertCurrentEntryColor()
|
||||||
|
{
|
||||||
|
InvertAreaBW(_entries.at(_selectedEntry)->getPosition().x, _entries.at(_selectedEntry)->getPosition().y, _entries.at(_selectedEntry)->getPosition().w, _entries.at(_selectedEntry)->getPosition().h);
|
||||||
|
updateEntry(_selectedEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListView::drawEntries()
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < _entries.size(); i++)
|
||||||
|
{
|
||||||
|
if (_entries.at(i)->getPage() == _shownPage)
|
||||||
|
_entries.at(i)->draw(_entryFont, _entryFontBold, _entryFontHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ListView::checkIfEntryClicked(int x, int y)
|
||||||
|
{
|
||||||
|
if (IsInRect(x, y, &_firstPageButton))
|
||||||
|
{
|
||||||
|
firstPage();
|
||||||
|
}
|
||||||
|
else if (IsInRect(x, y, &_nextPageButton))
|
||||||
|
{
|
||||||
|
nextPage();
|
||||||
|
}
|
||||||
|
else if (IsInRect(x, y, &_prevPageButton))
|
||||||
|
{
|
||||||
|
prevPage();
|
||||||
|
}
|
||||||
|
else if (IsInRect(x, y, &_lastPageButton))
|
||||||
|
{
|
||||||
|
actualizePage(_page);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < _entries.size(); i++)
|
||||||
|
{
|
||||||
|
if (_entries.at(i)->getPage() == _shownPage && IsInRect(x, y, &_entries.at(i)->getPosition()) == 1)
|
||||||
|
{
|
||||||
|
_selectedEntry = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListView::drawFooter()
|
||||||
|
{
|
||||||
|
SetFont(_footerFont, WHITE);
|
||||||
|
string footer = std::to_string(_shownPage) + "/" + std::to_string(_page);
|
||||||
|
FillAreaRect(&_pageIcon, BLACK);
|
||||||
|
|
||||||
|
DrawTextRect2(&_pageIcon, footer.c_str());
|
||||||
|
FillAreaRect(&_firstPageButton, BLACK);
|
||||||
|
DrawTextRect2(&_firstPageButton, "First");
|
||||||
|
FillAreaRect(&_prevPageButton, BLACK);
|
||||||
|
DrawTextRect2(&_prevPageButton, "Prev");
|
||||||
|
FillAreaRect(&_nextPageButton, BLACK);
|
||||||
|
DrawTextRect2(&_nextPageButton, "Next");
|
||||||
|
FillAreaRect(&_lastPageButton, BLACK);
|
||||||
|
DrawTextRect2(&_lastPageButton, "Last");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListView::updateEntry(int entryID)
|
||||||
|
{
|
||||||
|
PartialUpdate(_entries.at(entryID)->getPosition().x, _entries.at(entryID)->getPosition().y, _entries.at(entryID)->getPosition().w, _entries.at(entryID)->getPosition().h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListView::actualizePage(int pageToShow)
|
||||||
|
{
|
||||||
|
if (pageToShow > _page)
|
||||||
|
{
|
||||||
|
Message(ICON_INFORMATION, "Info", "You have reached the last page, to return to the first, please click \"first.\"", 1200);
|
||||||
|
}
|
||||||
|
else if (pageToShow < 1)
|
||||||
|
{
|
||||||
|
Message(ICON_INFORMATION, "Info", "You are already on the first page.", 1200);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_shownPage = pageToShow;
|
||||||
|
FillArea(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h, WHITE);
|
||||||
|
drawEntries();
|
||||||
|
drawFooter();
|
||||||
|
PartialUpdate(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,10 +10,9 @@
|
||||||
#define LISTVIEW
|
#define LISTVIEW
|
||||||
|
|
||||||
#include "inkview.h"
|
#include "inkview.h"
|
||||||
#include "item.h"
|
|
||||||
#include "listViewEntry.h"
|
#include "listViewEntry.h"
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -26,36 +25,11 @@ public:
|
||||||
* @param ContentRect area of the screen where the list view is placed
|
* @param ContentRect area of the screen where the list view is placed
|
||||||
* @param Items items that shall be shown in the listview
|
* @param Items items that shall be shown in the listview
|
||||||
*/
|
*/
|
||||||
ListView(const irect *contentRect, const std::vector<Item> &items);
|
ListView(const irect &contentRect, int page);
|
||||||
|
|
||||||
~ListView();
|
virtual ~ListView();
|
||||||
|
|
||||||
/**
|
int getShownPage(){return _shownPage;};
|
||||||
* Draws the header
|
|
||||||
*
|
|
||||||
* @param headerText the text that shall be displayed in the header
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void drawHeader(std::string headerText);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws an single entry to the screen
|
|
||||||
*
|
|
||||||
* @param itemID the id of the item that shall be drawn
|
|
||||||
*/
|
|
||||||
void drawEntry(int itemID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* inverts the color of an entry
|
|
||||||
*
|
|
||||||
* @param itemID the id of the item that shall be inverted
|
|
||||||
*/
|
|
||||||
void invertEntryColor(int itemID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates through the items and sends them to the listViewEntry Class for drawing
|
|
||||||
*/
|
|
||||||
void drawEntries();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates to the next page
|
* Navigates to the next page
|
||||||
|
@ -72,36 +46,56 @@ public:
|
||||||
*/
|
*/
|
||||||
void firstPage() { this->actualizePage(1); };
|
void firstPage() { this->actualizePage(1); };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws an single entry to the screen
|
||||||
|
*/
|
||||||
|
void reDrawCurrentEntry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inverts the color of the currently selected entry
|
||||||
|
*/
|
||||||
|
void invertCurrentEntryColor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checkes if the listview has been clicked and either changes the page or returns item ID
|
* Checkes if the listview has been clicked and either changes the page or returns item ID
|
||||||
*
|
*
|
||||||
* @param x x-coordinate
|
* @param x x-coordinate
|
||||||
* @param y y-coordinate
|
* @param y y-coordinate
|
||||||
* @return int Item ID that has been clicked, -1 if no Item was clicked
|
* @return true if was clicked
|
||||||
*/
|
*/
|
||||||
int listClicked(int x, int y);
|
bool checkIfEntryClicked(int x, int y);
|
||||||
|
|
||||||
private:
|
int getCurrentEntryItertator() const {return _selectedEntry;};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the screen and draws entries and footer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void draw();
|
||||||
|
|
||||||
|
protected:
|
||||||
int _footerHeight;
|
int _footerHeight;
|
||||||
int _headerHeight;
|
|
||||||
int _headerFontHeight;
|
|
||||||
int _footerFontHeight;
|
int _footerFontHeight;
|
||||||
int _entryFontHeight;
|
int _entryFontHeight;
|
||||||
const irect *_contentRect;
|
const irect _contentRect;
|
||||||
std::unique_ptr<const std::vector<Item>> _items;
|
std::vector<std::shared_ptr<ListViewEntry>> _entries;
|
||||||
std::vector<ListViewEntry> _entries;
|
|
||||||
ifont *_headerFont;
|
|
||||||
ifont *_footerFont;
|
ifont *_footerFont;
|
||||||
ifont *_entryFont;
|
ifont *_entryFont;
|
||||||
ifont *_entryFontBold;
|
ifont *_entryFontBold;
|
||||||
int _page;
|
int _page = 1;
|
||||||
int _shownPage;
|
int _shownPage;
|
||||||
irect _pageIcon;
|
irect _pageIcon;
|
||||||
irect _nextPageButton;
|
irect _nextPageButton;
|
||||||
irect _prevPageButton;
|
irect _prevPageButton;
|
||||||
irect _firstPageButton;
|
irect _firstPageButton;
|
||||||
irect _lastPageButton;
|
irect _lastPageButton;
|
||||||
int _itemCount = 7;
|
int _selectedEntry;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates through the items and sends them to the listViewEntry Class for drawing
|
||||||
|
*/
|
||||||
|
void drawEntries();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the footer including a page changer
|
* Draws the footer including a page changer
|
||||||
|
@ -111,15 +105,15 @@ private:
|
||||||
/**
|
/**
|
||||||
* updates an entry
|
* updates an entry
|
||||||
*
|
*
|
||||||
* @param itemID the id of the item that shall be inverted
|
* @param entryID the id of the item that shall be inverted
|
||||||
*/
|
*/
|
||||||
void updateEntry(int itemID);
|
void updateEntry(int entryID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates to the selected page
|
* Navigates to the selected page
|
||||||
*
|
*
|
||||||
* @param pageToShown page that shall be shown
|
* @param pageToShow page that shall be shown
|
||||||
*/
|
*/
|
||||||
void actualizePage(int pageToShown);
|
void actualizePage(int pageToShow);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,14 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// hnCommentViewEntry.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 04.08.2020
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "inkview.h"
|
||||||
|
#include "listViewEntry.h"
|
||||||
|
|
||||||
|
ListViewEntry::ListViewEntry(int page, const irect &rect) : _page(page), _position(rect)
|
||||||
|
{
|
||||||
|
}
|
|
@ -10,7 +10,7 @@
|
||||||
#define LISTVIEWENTRY
|
#define LISTVIEWENTRY
|
||||||
|
|
||||||
#include "inkview.h"
|
#include "inkview.h"
|
||||||
#include "item.h"
|
#include "model.h"
|
||||||
|
|
||||||
class ListViewEntry
|
class ListViewEntry
|
||||||
{
|
{
|
||||||
|
@ -21,22 +21,23 @@ public:
|
||||||
* @param Page site of the listView the Entry is shown
|
* @param Page site of the listView the Entry is shown
|
||||||
* @param Rect area of the screen the item is positioned
|
* @param Rect area of the screen the item is positioned
|
||||||
*/
|
*/
|
||||||
ListViewEntry(int page, irect position);
|
ListViewEntry(int page, const irect &position);
|
||||||
|
|
||||||
irect *getPosition() { return &_position; }
|
virtual ~ListViewEntry(){};
|
||||||
|
|
||||||
|
irect &getPosition() { return _position; }
|
||||||
int getPage() const { return _page; }
|
int getPage() const { return _page; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* draws the listViewEntry to the screen
|
* draws the listViewEntry to the screen
|
||||||
*
|
*
|
||||||
* @param item item that shall be drawn
|
|
||||||
* @param entryFont font for the entry itself
|
* @param entryFont font for the entry itself
|
||||||
* @param entryFontBold bold font for the header
|
* @param entryFontBold bold font for the header
|
||||||
* @param fontHeight height of the font
|
* @param fontHeight height of the font
|
||||||
*/
|
*/
|
||||||
void draw(const Item &item, ifont *entryFont, ifont *entryFontBold, int fontHeight);
|
virtual void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) = 0;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
int _page;
|
int _page;
|
||||||
irect _position;
|
irect _position;
|
||||||
};
|
};
|
|
@ -1,62 +0,0 @@
|
||||||
//------------------------------------------------------------------
|
|
||||||
// listViewEntry.cpp
|
|
||||||
//
|
|
||||||
// Author: JuanJakobo
|
|
||||||
// Date: 04.08.2020
|
|
||||||
//
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include "inkview.h"
|
|
||||||
#include "item.h"
|
|
||||||
#include "listViewEntry.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
ListViewEntry::ListViewEntry(int page, irect rect) : _page(page), _position(rect)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListViewEntry::draw(const Item &item, ifont *entryFont, ifont *entryFontBold, int fontHeight)
|
|
||||||
{
|
|
||||||
SetFont(entryFontBold, BLACK);
|
|
||||||
DrawTextRect(_position.x, _position.y, _position.w, fontHeight, item.getTitle().c_str(), ALIGN_LEFT);
|
|
||||||
|
|
||||||
SetFont(entryFont, BLACK);
|
|
||||||
|
|
||||||
if (item.getState() == FileState::ILOCAL)
|
|
||||||
{
|
|
||||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Local", ALIGN_RIGHT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (item.getType() == IFILE)
|
|
||||||
{
|
|
||||||
DrawTextRect(_position.x, _position.y + fontHeight, _position.w, fontHeight, item.getFiletype().c_str(), ALIGN_LEFT);
|
|
||||||
|
|
||||||
if (item.getState() == FileState::ISYNCED)
|
|
||||||
{
|
|
||||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Synced", ALIGN_RIGHT);
|
|
||||||
}
|
|
||||||
else if(item.getState() == FileState::IOUTSYNCED)
|
|
||||||
{
|
|
||||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Out of sync", ALIGN_RIGHT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Click to Download", ALIGN_RIGHT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (item.getState() == FileState::ISYNCED)
|
|
||||||
{
|
|
||||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Folder synced", ALIGN_RIGHT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawTextRect(_position.x, _position.y + 2 * fontHeight, _position.w, fontHeight, item.getLastEditDate().c_str(), ALIGN_LEFT);
|
|
||||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, item.getSizeString().c_str(), ALIGN_LEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
int line = (_position.y + _position.h) - 1;
|
|
||||||
DrawLine(0, line, ScreenWidth(), line, BLACK);
|
|
||||||
}
|
|
|
@ -14,17 +14,17 @@
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
LoginView *LoginView::_loginViewStatic;
|
std::unique_ptr<LoginView> LoginView::_loginViewStatic;
|
||||||
|
|
||||||
LoginView::LoginView(const irect *contentRect) : _contentRect(contentRect)
|
LoginView::LoginView(const irect &contentRect) : _contentRect(contentRect)
|
||||||
{
|
{
|
||||||
_loginViewStatic = this;
|
_loginViewStatic = std::unique_ptr<LoginView>(this);
|
||||||
|
|
||||||
int contentHeight = contentRect->h / 2;
|
int contentHeight = contentRect.h / 2;
|
||||||
int contentWidth = _contentRect->w * 0.9;
|
int contentWidth = _contentRect.w * 0.9;
|
||||||
|
|
||||||
int beginY = 0.4 * contentHeight;
|
int beginY = 0.4 * contentHeight;
|
||||||
int beginX = (_contentRect->w - contentWidth) / 2;
|
int beginX = (_contentRect.w - contentWidth) / 2;
|
||||||
|
|
||||||
int contents = contentHeight / 7;
|
int contents = contentHeight / 7;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ LoginView::LoginView(const irect *contentRect) : _contentRect(contentRect)
|
||||||
|
|
||||||
_loginFont = OpenFont("LiberationMono", _loginFontHeight, FONT_STD);
|
_loginFont = OpenFont("LiberationMono", _loginFontHeight, FONT_STD);
|
||||||
SetFont(_loginFont, BLACK);
|
SetFont(_loginFont, BLACK);
|
||||||
FillAreaRect(_contentRect, WHITE);
|
FillAreaRect(&_contentRect, WHITE);
|
||||||
|
|
||||||
_urlButton = iRect(beginX, beginY, contentWidth, contents, ALIGN_CENTER);
|
_urlButton = iRect(beginX, beginY, contentWidth, contents, ALIGN_CENTER);
|
||||||
DrawTextRect(_urlButton.x, _urlButton.y - _loginFontHeight - _loginFontHeight/2, _urlButton.w, _urlButton.h, "Server address:", ALIGN_LEFT);
|
DrawTextRect(_urlButton.x, _urlButton.y - _loginFontHeight - _loginFontHeight/2, _urlButton.w, _urlButton.h, "Server address:", ALIGN_LEFT);
|
|
@ -12,6 +12,7 @@
|
||||||
#include "inkview.h"
|
#include "inkview.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
enum KeyboardTarget
|
enum KeyboardTarget
|
||||||
{
|
{
|
||||||
|
@ -30,7 +31,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param contentRect area where the loginscreen shall be drawn
|
* @param contentRect area where the loginscreen shall be drawn
|
||||||
*/
|
*/
|
||||||
LoginView(const irect *contentRect);
|
LoginView(const irect &contentRect);
|
||||||
|
|
||||||
~LoginView();
|
~LoginView();
|
||||||
|
|
||||||
|
@ -48,10 +49,10 @@ public:
|
||||||
std::string getURL() { return _url; };
|
std::string getURL() { return _url; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static LoginView *_loginViewStatic;
|
static std::unique_ptr<LoginView> _loginViewStatic;
|
||||||
int _loginFontHeight;
|
int _loginFontHeight;
|
||||||
ifont *_loginFont;
|
ifont *_loginFont;
|
||||||
const irect *_contentRect;
|
const irect _contentRect;
|
||||||
irect _urlButton;
|
irect _urlButton;
|
||||||
irect _loginButton;
|
irect _loginButton;
|
||||||
irect _usernameButton;
|
irect _usernameButton;
|
|
@ -0,0 +1,62 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// webDAVView.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "webDAVView.h"
|
||||||
|
#include "webDAVModel.h"
|
||||||
|
#include "webDAV.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
WebDAVView::WebDAVView(const irect &contentRect, vector<WebDAVItem> &items, int page) : ListView(contentRect, page)
|
||||||
|
{
|
||||||
|
auto pageHeight = 0;
|
||||||
|
auto contentHeight = _contentRect.h - _footerHeight;
|
||||||
|
auto entrycount = items.size();
|
||||||
|
|
||||||
|
_entries.reserve(entrycount);
|
||||||
|
|
||||||
|
//resize item 1
|
||||||
|
std::string header = items.at(0).path;
|
||||||
|
header = header.substr(0, header.find_last_of("/"));
|
||||||
|
header = header.substr(0, header.find_last_of("/") + 1);
|
||||||
|
items.at(0).path = header;
|
||||||
|
items.at(0).title += "\nclick to go back";
|
||||||
|
items.at(0).lastEditDate = "";
|
||||||
|
if (items.at(0).path.compare(NEXTCLOUD_ROOT_PATH) == 0)
|
||||||
|
items.erase(items.begin());
|
||||||
|
|
||||||
|
for(auto item : items)
|
||||||
|
{
|
||||||
|
auto entrySize = TextRectHeight(contentRect.w, item.title.c_str(), 0);
|
||||||
|
|
||||||
|
if(item.type == IFILE)
|
||||||
|
entrySize += _entryFontHeight;
|
||||||
|
|
||||||
|
if(item.title.find("click to go back") != std::string::npos)
|
||||||
|
entrySize += 0.5 * _entryFontHeight;
|
||||||
|
else
|
||||||
|
entrySize += 2.5 * _entryFontHeight;
|
||||||
|
|
||||||
|
|
||||||
|
if ((pageHeight + entrySize) > contentHeight)
|
||||||
|
{
|
||||||
|
pageHeight = 0;
|
||||||
|
_page++;
|
||||||
|
}
|
||||||
|
irect rect = iRect(_contentRect.x, _contentRect.y + pageHeight, _contentRect.w, entrySize, 0);
|
||||||
|
|
||||||
|
_entries.emplace_back(std::unique_ptr<WebDAVViewEntry>(new WebDAVViewEntry(_page, rect, item)));
|
||||||
|
|
||||||
|
pageHeight = pageHeight + entrySize;
|
||||||
|
}
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// webDAVView.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
// Description: An UI class to display items in a listview
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef WEBDAVVIEW
|
||||||
|
#define WEBDAVVIEW
|
||||||
|
|
||||||
|
#include "webDAVModel.h"
|
||||||
|
#include "listView.h"
|
||||||
|
#include "webDAVViewEntry.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class WebDAVView final : public ListView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Displays a list view
|
||||||
|
*
|
||||||
|
* @param ContentRect area of the screen where the list view is placed
|
||||||
|
* @param Items items that shall be shown in the listview
|
||||||
|
* @param page page that is shown, default is 1
|
||||||
|
*/
|
||||||
|
WebDAVView(const irect &contentRect, std::vector<WebDAVItem> &items, int page = 1);
|
||||||
|
|
||||||
|
WebDAVItem &getCurrentEntry() { return getEntry(_selectedEntry); };
|
||||||
|
|
||||||
|
WebDAVItem &getEntry(int entryID) { return std::dynamic_pointer_cast<WebDAVViewEntry>(_entries.at(entryID))->get(); };
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,72 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// WebDAVViewEntry.cpp
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "webDAVViewEntry.h"
|
||||||
|
#include "webDAVModel.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
WebDAVViewEntry::WebDAVViewEntry(int page, const irect &position, const WebDAVItem &entry) : ListViewEntry(page, position), _entry(entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebDAVViewEntry::draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight)
|
||||||
|
{
|
||||||
|
|
||||||
|
SetFont(entryFontBold, BLACK);
|
||||||
|
int heightOfTitle = TextRectHeight(_position.w, _entry.title.c_str(), 0);
|
||||||
|
if(_entry.title.find("click to go back") != std::string::npos)
|
||||||
|
DrawTextRect(_position.x, _position.y, _position.w, heightOfTitle, _entry.title.c_str(), ALIGN_CENTER);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawTextRect(_position.x, _position.y, _position.w, heightOfTitle, _entry.title.c_str(), ALIGN_LEFT);
|
||||||
|
|
||||||
|
SetFont(entryFont, BLACK);
|
||||||
|
|
||||||
|
|
||||||
|
if (_entry.state == FileState::ILOCAL)
|
||||||
|
{
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Local", ALIGN_RIGHT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_entry.type == IFILE)
|
||||||
|
{
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle, _position.w, fontHeight, _entry.fileType.c_str(), ALIGN_LEFT);
|
||||||
|
|
||||||
|
switch(_entry.state)
|
||||||
|
{
|
||||||
|
case FileState::ISYNCED:
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Synced", ALIGN_RIGHT);
|
||||||
|
break;
|
||||||
|
case FileState::IOUTSYNCED:
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Out of sync", ALIGN_RIGHT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Click to Download", ALIGN_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, _entry.lastEditDate.c_str(), ALIGN_LEFT);
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, _entry.size.c_str(), ALIGN_LEFT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_entry.state == FileState::ISYNCED)
|
||||||
|
{
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, "Folder synced", ALIGN_RIGHT);
|
||||||
|
}
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle, _position.w, fontHeight, _entry.lastEditDate.c_str(), ALIGN_LEFT);
|
||||||
|
DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, _entry.size.c_str(), ALIGN_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
int line = (_position.y + _position.h) - 1;
|
||||||
|
DrawLine(0, line, ScreenWidth(), line, BLACK);
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// webDAVViewEntry.h
|
||||||
|
//
|
||||||
|
// Author: JuanJakobo
|
||||||
|
// Date: 08.09.2021
|
||||||
|
// Description:
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef WEBDAVVIEWENTRY
|
||||||
|
#define WEBDAVVIEWENTRY
|
||||||
|
|
||||||
|
#include "listViewEntry.h"
|
||||||
|
#include "webDAVModel.h"
|
||||||
|
|
||||||
|
class WebDAVViewEntry : public ListViewEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates an WebDAVViewEntry
|
||||||
|
*
|
||||||
|
* @param Page site of the listView the Entry is shown
|
||||||
|
* @param Rect area of the screen the item is positioned
|
||||||
|
* @param entry entry that shall be drawn
|
||||||
|
*/
|
||||||
|
WebDAVViewEntry(int page, const irect &position, const WebDAVItem &entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* draws the WebDAVViewEntry to the screen
|
||||||
|
*
|
||||||
|
* @param entryFont font for the entry itself
|
||||||
|
* @param entryFontBold bold font for the header
|
||||||
|
* @param fontHeight height of the font
|
||||||
|
*/
|
||||||
|
void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) override;
|
||||||
|
|
||||||
|
WebDAVItem &get() { return _entry; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
WebDAVItem _entry;
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -1,168 +0,0 @@
|
||||||
//------------------------------------------------------------------
|
|
||||||
// item.cpp
|
|
||||||
//
|
|
||||||
// Author: JuanJakobo
|
|
||||||
// Date: 04.08.2020
|
|
||||||
//
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include "item.h"
|
|
||||||
#include "inkview.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "nextcloud.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <string>
|
|
||||||
#include <curl/curl.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
Item::Item(const string &xmlItem)
|
|
||||||
{
|
|
||||||
_path = Util::getXMLAttribute(xmlItem, "d:href");
|
|
||||||
|
|
||||||
//replaces everthing in front of /remote.php as this is already part of the url
|
|
||||||
Log::writeLog("path before transformation " + _path);
|
|
||||||
if(_path.find(NEXTCLOUD_START_PATH) != 0)
|
|
||||||
{
|
|
||||||
_path.erase(0,_path.find(NEXTCLOUD_START_PATH));
|
|
||||||
Log::writeLog("path after transformation " + _path);
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastEditDate = Util::getXMLAttribute(xmlItem, "d:getlastmodified");
|
|
||||||
_title = _path;
|
|
||||||
_localPath = Nextcloud::getLocalPath(_path);
|
|
||||||
|
|
||||||
if (_path.back() == '/')
|
|
||||||
{
|
|
||||||
_localPath = _localPath.substr(0, _localPath.length() - 1);
|
|
||||||
_type = Itemtype::IFOLDER;
|
|
||||||
_title = _title.substr(0, _path.length() - 1);
|
|
||||||
_size = atof(Util::getXMLAttribute(xmlItem, "d:quota-used-bytes").c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_type = Itemtype::IFILE;
|
|
||||||
_size = atof(Util::getXMLAttribute(xmlItem, "d:getcontentlength").c_str());
|
|
||||||
_fileType = Util::getXMLAttribute(xmlItem, "d:getcontenttype");
|
|
||||||
|
|
||||||
if (iv_access(_localPath.c_str(), W_OK) != 0)
|
|
||||||
{
|
|
||||||
_state = FileState::ICLOUD;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_state = FileState::ISYNCED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_title = _title.substr(_title.find_last_of("/") + 1, _title.length());
|
|
||||||
Util::decodeUrl(_title);
|
|
||||||
}
|
|
||||||
|
|
||||||
Item::Item(const string &localPath, FileState state, Itemtype type) : _localPath(localPath), _state(state), _type(type)
|
|
||||||
{
|
|
||||||
_title = _localPath;
|
|
||||||
_title = _title.substr(_title.find_last_of("/") + 1, _title.length());
|
|
||||||
Util::decodeUrl(_title);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Item::isBook() const
|
|
||||||
{
|
|
||||||
if (_fileType.find("application/epub+zip") != string::npos ||
|
|
||||||
_fileType.find("application/pdf") != string::npos ||
|
|
||||||
_fileType.find("application/octet-stream") != string::npos ||
|
|
||||||
_fileType.find("text/plain") != string::npos ||
|
|
||||||
_fileType.find("text/html") != string::npos ||
|
|
||||||
_fileType.find("text/rtf") != string::npos ||
|
|
||||||
_fileType.find("application/msword") != string::npos ||
|
|
||||||
_fileType.find("application/x-mobipocket-ebook") != string::npos ||
|
|
||||||
_fileType.find("application/vnd.openxmlformats-officedocument.wordprocessingml.document") != string::npos ||
|
|
||||||
_fileType.find("application/x-fictionbook+xml") != string::npos)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Item::open() const
|
|
||||||
{
|
|
||||||
if (_state == FileState::ICLOUD)
|
|
||||||
{
|
|
||||||
Message(ICON_ERROR, "File not found.", "Could not find file.", 1000);
|
|
||||||
}
|
|
||||||
else if(isBook())
|
|
||||||
{
|
|
||||||
|
|
||||||
OpenBook(_localPath.c_str(), "", 0);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
else if (_fileType.find("audio/mpeg") != string::npos ||
|
|
||||||
_fileType.find("audio/ogg") != string::npos ||
|
|
||||||
_fileType.find("audio/mp4") != string::npos ||
|
|
||||||
_fileType.find("audio/m4b") != string::npos)
|
|
||||||
{
|
|
||||||
PlayFile(_localPath.c_str());
|
|
||||||
OpenPlayer();
|
|
||||||
}
|
|
||||||
else if (_fileType.find("image/jpeg") != string::npos)
|
|
||||||
{
|
|
||||||
Message(3, "Info", "Opening image", 600);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Message(ICON_INFORMATION, "Warning", "The filetype is currently not supported.", 1200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Item::removeFile()
|
|
||||||
{
|
|
||||||
if (_type == Itemtype::IFOLDER)
|
|
||||||
{
|
|
||||||
string cmd = "rm -rf " + _localPath + "/";
|
|
||||||
system(cmd.c_str());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remove(_localPath.c_str()) != 0)
|
|
||||||
return false;
|
|
||||||
if (_state == FileState::ISYNCED || _state == FileState::IOUTSYNCED)
|
|
||||||
{
|
|
||||||
_state = FileState::ICLOUD;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Message(ICON_INFORMATION, "Warning", "The file will be shown until next folder update.", 1200);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string Item::getSizeString() const
|
|
||||||
{
|
|
||||||
|
|
||||||
if (_size < 1024)
|
|
||||||
return "< 1 KB";
|
|
||||||
|
|
||||||
double departBy;
|
|
||||||
double tempSize;
|
|
||||||
string unit;
|
|
||||||
|
|
||||||
if (_size < 1048576)
|
|
||||||
{
|
|
||||||
departBy = 1024;
|
|
||||||
unit = "KB";
|
|
||||||
}
|
|
||||||
else if (_size < 1073741824)
|
|
||||||
{
|
|
||||||
departBy = 1048576;
|
|
||||||
unit = "MB";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
departBy = 1073741824;
|
|
||||||
unit = "GB";
|
|
||||||
}
|
|
||||||
|
|
||||||
tempSize = round((_size / departBy) * 10.0) / 10.0;
|
|
||||||
return std::to_string(tempSize) + " " + unit;
|
|
||||||
}
|
|
100
src/util/item.h
100
src/util/item.h
|
@ -1,100 +0,0 @@
|
||||||
//------------------------------------------------------------------
|
|
||||||
// item.h
|
|
||||||
//
|
|
||||||
// Author: JuanJakobo
|
|
||||||
// Date: 04.08.2020
|
|
||||||
// Description: Describes an WEBDAV item
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifndef ITEM
|
|
||||||
#define ITEM
|
|
||||||
|
|
||||||
#include "inkview.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
enum Itemtype
|
|
||||||
{
|
|
||||||
IFILE,
|
|
||||||
IFOLDER
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FileState
|
|
||||||
{
|
|
||||||
ICLOUD,
|
|
||||||
ISYNCED,
|
|
||||||
IOUTSYNCED,
|
|
||||||
ILOCAL
|
|
||||||
};
|
|
||||||
|
|
||||||
class Item
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Creates an item by receiving the xml from nextcloud and parses it into an object
|
|
||||||
*
|
|
||||||
* @param xmlItem result of the nextcloud request
|
|
||||||
*/
|
|
||||||
Item(const std::string &xmlItem);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new item by receiving localPath from the pocketbook
|
|
||||||
*
|
|
||||||
* @param localPath path where the file is placed
|
|
||||||
* @param state state of the file
|
|
||||||
* @param type type of the item (folder/file)
|
|
||||||
*/
|
|
||||||
Item(const std::string &localPath, FileState state, Itemtype type);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if item is a book
|
|
||||||
*/
|
|
||||||
bool isBook() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to open the item by checking the file format and then executes the fitting action
|
|
||||||
*/
|
|
||||||
void open() const;
|
|
||||||
|
|
||||||
bool removeFile();
|
|
||||||
|
|
||||||
void setPath(const std::string &path) { _path = path; };
|
|
||||||
std::string getPath() const { return _path; };
|
|
||||||
|
|
||||||
std::string getLocalPath() const { return _localPath; };
|
|
||||||
|
|
||||||
Itemtype getType() const { return _type; };
|
|
||||||
|
|
||||||
void setTitle(const std::string &title) { _title = title; };
|
|
||||||
std::string getTitle() const { return _title; };
|
|
||||||
|
|
||||||
void setState(FileState state) { _state = state; };
|
|
||||||
FileState getState() const { return _state; };
|
|
||||||
|
|
||||||
std::string getLastEditDate() const { return _lastEditDate; };
|
|
||||||
void setLastEditDate(const std::string &date) { _lastEditDate = date; };
|
|
||||||
|
|
||||||
double getSize() const { return _size; };
|
|
||||||
std::string getSizeString() const;
|
|
||||||
|
|
||||||
std::string getFiletype() const { return _fileType; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string _path;
|
|
||||||
std::string _title;
|
|
||||||
std::string _localPath;
|
|
||||||
FileState _state{FileState::ICLOUD};
|
|
||||||
Itemtype _type;
|
|
||||||
std::string _lastEditDate{"Error"};
|
|
||||||
double _size;
|
|
||||||
std::string _fileType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the size to an easier readble format
|
|
||||||
*
|
|
||||||
* @param tempSize Size of the item in bytes
|
|
||||||
*/
|
|
||||||
void setSize(double tempSize);
|
|
||||||
};
|
|
||||||
#endif
|
|
|
@ -12,9 +12,19 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
void Log::writeInfoLog(const std::string &text)
|
||||||
|
{
|
||||||
|
writeLog("Info:" + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::writeErrorLog(const std::string &text)
|
||||||
|
{
|
||||||
|
writeLog("Error:" + text);
|
||||||
|
}
|
||||||
|
|
||||||
void Log::writeLog(const std::string &text)
|
void Log::writeLog(const std::string &text)
|
||||||
{
|
{
|
||||||
std::ofstream log(LOG_PATH + std::string("/logfile.txt"), std::ios_base::app | std::ios_base::out);
|
std::ofstream log(CONFIG_FOLDER + std::string("/logfile.txt"), std::ios_base::app | std::ios_base::out);
|
||||||
|
|
||||||
time_t rawtime;
|
time_t rawtime;
|
||||||
struct tm *timeinfo;
|
struct tm *timeinfo;
|
||||||
|
@ -25,7 +35,7 @@ void Log::writeLog(const std::string &text)
|
||||||
|
|
||||||
strftime(buffer, sizeof(buffer), "%d/%b/%Y:%H:%M:%S %z", timeinfo);
|
strftime(buffer, sizeof(buffer), "%d/%b/%Y:%H:%M:%S %z", timeinfo);
|
||||||
|
|
||||||
log << buffer << ":" << text << "\n";
|
log << buffer << ':' << text << "\n";
|
||||||
|
|
||||||
log.close();
|
log.close();
|
||||||
}
|
}
|
|
@ -16,14 +16,28 @@
|
||||||
class Log
|
class Log
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Writes a error log entry to the log file
|
||||||
|
*
|
||||||
|
* @param text that shall be written to the log
|
||||||
|
*/
|
||||||
|
static void writeErrorLog(const std::string &text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a info log entry to the log file
|
||||||
|
*
|
||||||
|
* @param text that shall be written to the log
|
||||||
|
*/
|
||||||
|
static void writeInfoLog(const std::string &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Log() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a log entry to the log file
|
* Writes a log entry to the log file
|
||||||
*
|
*
|
||||||
* @param text that shall be written to the log
|
* @param text that shall be written to the log
|
||||||
*/
|
*/
|
||||||
static void writeLog(const std::string &text);
|
static void writeLog(const std::string &text);
|
||||||
|
|
||||||
private:
|
|
||||||
Log() {}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
|
@ -1,503 +0,0 @@
|
||||||
//------------------------------------------------------------------
|
|
||||||
// nextcloud.cpp
|
|
||||||
//
|
|
||||||
// Author: JuanJakobo
|
|
||||||
// Date: 04.08.2020
|
|
||||||
//
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include "inkview.h"
|
|
||||||
#include "nextcloud.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "item.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <curl/curl.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using std::ifstream;
|
|
||||||
using std::ofstream;
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
Nextcloud::Nextcloud()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (iv_access(NEXTCLOUD_PATH.c_str(), W_OK) != 0)
|
|
||||||
iv_mkdir(NEXTCLOUD_PATH.c_str(), 0777);
|
|
||||||
|
|
||||||
if (iv_access(NEXTCLOUD_FILE_PATH.c_str(), W_OK) != 0)
|
|
||||||
iv_mkdir(NEXTCLOUD_FILE_PATH.c_str(), 0777);
|
|
||||||
//create database
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Nextcloud::setItems(const vector<Item> &tempItems)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (tempItems.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!_items.empty())
|
|
||||||
_items.clear();
|
|
||||||
|
|
||||||
_items = tempItems;
|
|
||||||
|
|
||||||
//resize item 1
|
|
||||||
string header = _items.at(0).getPath();
|
|
||||||
header = header.substr(0, header.find_last_of("/"));
|
|
||||||
header = header.substr(0, header.find_last_of("/") + 1);
|
|
||||||
_items.at(0).setPath(header);
|
|
||||||
_items.at(0).setTitle("...");
|
|
||||||
_items.at(0).setLastEditDate("");
|
|
||||||
if (_items.at(0).getPath().compare(NEXTCLOUD_ROOT_PATH) == 0)
|
|
||||||
_items.erase(_items.begin());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Nextcloud::login()
|
|
||||||
{
|
|
||||||
string tempPath = getStartFolder();
|
|
||||||
|
|
||||||
if (tempPath.empty())
|
|
||||||
tempPath = NEXTCLOUD_ROOT_PATH + this->getUUID() + "/";
|
|
||||||
|
|
||||||
if (setItems(getDataStructure(tempPath)))
|
|
||||||
{
|
|
||||||
_loggedIn = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Nextcloud::login(const string &Url, const string &Username, const string &Pass)
|
|
||||||
{
|
|
||||||
string uuid;
|
|
||||||
std::size_t found = Url.find(NEXTCLOUD_ROOT_PATH);
|
|
||||||
|
|
||||||
if (found != std::string::npos)
|
|
||||||
{
|
|
||||||
_url = Url.substr(0, found);
|
|
||||||
uuid = Url.substr(found + NEXTCLOUD_ROOT_PATH.length());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_url = Url;
|
|
||||||
uuid = Username;
|
|
||||||
}
|
|
||||||
|
|
||||||
string tempPath = NEXTCLOUD_ROOT_PATH + uuid + "/";
|
|
||||||
if (setItems(getDataStructure(tempPath, Username, Pass)))
|
|
||||||
{
|
|
||||||
Log::writeLog("Got items");
|
|
||||||
|
|
||||||
if (iv_access(NEXTCLOUD_CONFIG_PATH.c_str(), W_OK) != 0)
|
|
||||||
iv_buildpath(NEXTCLOUD_CONFIG_PATH.c_str());
|
|
||||||
this->setUsername(Username);
|
|
||||||
this->setUUID(uuid);
|
|
||||||
this->setPassword(Pass);
|
|
||||||
this->setURL(_url);
|
|
||||||
this->setStartFolder(tempPath);
|
|
||||||
_loggedIn = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Nextcloud::logout(bool deleteFiles)
|
|
||||||
{
|
|
||||||
if (deleteFiles)
|
|
||||||
{
|
|
||||||
string cmd = "rm -rf " + NEXTCLOUD_FILE_PATH + "/" + getUUID() + "/";
|
|
||||||
system(cmd.c_str());
|
|
||||||
}
|
|
||||||
remove(NEXTCLOUD_CONFIG_PATH.c_str());
|
|
||||||
remove((NEXTCLOUD_CONFIG_PATH + ".back.").c_str());
|
|
||||||
|
|
||||||
_url.clear();
|
|
||||||
_items.clear();
|
|
||||||
_workOffline = false;
|
|
||||||
_loggedIn = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Nextcloud::downloadItem(vector<Item> &tempItems, int itemID)
|
|
||||||
{
|
|
||||||
if (tempItems.at(itemID).getState() == FileState::ISYNCED)
|
|
||||||
{
|
|
||||||
UpdateProgressbar(("The newest version of file " + tempItems.at(itemID).getLocalPath() + " is already downloaded.").c_str(), 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tempItems.at(itemID).getPath().empty())
|
|
||||||
{
|
|
||||||
Message(ICON_ERROR, "Error", "Download path is not set, therefore cannot download the file.", 2000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateProgressbar(("Starting Download of " + tempItems.at(itemID).getLocalPath()).c_str(), 0);
|
|
||||||
CURLcode res;
|
|
||||||
CURL *curl = curl_easy_init();
|
|
||||||
|
|
||||||
if (curl)
|
|
||||||
{
|
|
||||||
string post = this->getUsername() + std::string(":") + this->getPassword();
|
|
||||||
|
|
||||||
FILE *fp;
|
|
||||||
fp = iv_fopen(tempItems.at(itemID).getLocalPath().c_str(), "wb");
|
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, (_url + tempItems.at(itemID).getPath()).c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeData);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Util::progress_callback);
|
|
||||||
//in case that cacert is available use it
|
|
||||||
if (iv_access(CACERT_PATH.c_str(), W_OK) == 0)
|
|
||||||
curl_easy_setopt(curl, CURLOPT_CAINFO, CACERT_PATH.c_str());
|
|
||||||
else
|
|
||||||
Log::writeLog("could not find cacert");
|
|
||||||
//Follow redirects
|
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
|
||||||
res = curl_easy_perform(curl);
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
iv_fclose(fp);
|
|
||||||
|
|
||||||
if (res == CURLE_OK)
|
|
||||||
{
|
|
||||||
long response_code;
|
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
|
||||||
|
|
||||||
switch (response_code)
|
|
||||||
{
|
|
||||||
case 200:
|
|
||||||
Log::writeLog("finished download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath());
|
|
||||||
tempItems.at(itemID).setState(FileState::ISYNCED);
|
|
||||||
break;
|
|
||||||
case 401:
|
|
||||||
Message(ICON_ERROR, "Error", "Username/password incorrect.", 2000);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Message(ICON_ERROR, "Error", ("An unknown error occured. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 2000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again.";
|
|
||||||
if(res == 60)
|
|
||||||
response = "Seems as if you are using Let's Encrypt Certs. Please follow the guide on Github (https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client) to use a custom Cert Store on PB.";
|
|
||||||
Message(ICON_ERROR, "Error", response.c_str(), 4000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Nextcloud::downloadFolder(vector<Item> &tempItems, int itemID)
|
|
||||||
{
|
|
||||||
BanSleep(2000);
|
|
||||||
|
|
||||||
if (tempItems.at(itemID).getState() == FileState::ILOCAL)
|
|
||||||
{
|
|
||||||
UpdateProgressbar(("Removing local item " + tempItems.at(itemID).getLocalPath()).c_str(), 0);
|
|
||||||
tempItems.at(itemID).removeFile();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tempItems.at(itemID).getType() == Itemtype::IFOLDER)
|
|
||||||
{
|
|
||||||
string temp = tempItems.at(itemID).getPath();
|
|
||||||
Log::writeLog("Path to look for " + temp);
|
|
||||||
vector<Item> tempItems = getDataStructure(temp);
|
|
||||||
|
|
||||||
//first item of the vector is the root path itself
|
|
||||||
for (size_t i = 1; i < tempItems.size(); i++)
|
|
||||||
{
|
|
||||||
Log::writeLog("Item: " + tempItems.at(i).getPath());
|
|
||||||
downloadFolder(tempItems, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log::writeLog("started download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath());
|
|
||||||
downloadItem(tempItems, itemID);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Nextcloud::download(int itemID)
|
|
||||||
{
|
|
||||||
if (!Util::connectToNetwork())
|
|
||||||
{
|
|
||||||
Message(ICON_WARNING, "Warning", "Can not connect to the Internet. Switching to offline modus.", 2000);
|
|
||||||
_workOffline = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->downloadFolder(_items, itemID);
|
|
||||||
|
|
||||||
UpdateProgressbar("Download completed", 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Nextcloud::removeItem(int itemID)
|
|
||||||
{
|
|
||||||
Log::writeLog("removing file " + _items.at(itemID).getPath());
|
|
||||||
if (!_items.at(itemID).removeFile())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<Item> Nextcloud::getDataStructure(string &pathUrl)
|
|
||||||
{
|
|
||||||
return getDataStructure(pathUrl, this->getUsername(), this->getPassword());
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<Item> Nextcloud::getDataStructure(const string &pathUrl, const string &Username, const string &Pass)
|
|
||||||
{
|
|
||||||
if (_workOffline)
|
|
||||||
return getOfflineStructure(pathUrl);
|
|
||||||
|
|
||||||
if (!Util::connectToNetwork())
|
|
||||||
{
|
|
||||||
Message(ICON_WARNING, "Warning", "Cannot connect to the internet. Switching to offline modus. To work online turn on online modus in the menu.", 2000);
|
|
||||||
_workOffline = true;
|
|
||||||
return getOfflineStructure(pathUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_url.empty())
|
|
||||||
_url = this->getUrl();
|
|
||||||
|
|
||||||
if (Username.empty() || Pass.empty())
|
|
||||||
{
|
|
||||||
Message(ICON_ERROR, "Error", "Username/password not set.", 2000);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::writeLog("Starting download of DataStructure");
|
|
||||||
Log::writeLog(_url + pathUrl);
|
|
||||||
|
|
||||||
string readBuffer;
|
|
||||||
CURLcode res;
|
|
||||||
CURL *curl = curl_easy_init();
|
|
||||||
|
|
||||||
if (curl)
|
|
||||||
{
|
|
||||||
string post = Username + ":" + Pass;
|
|
||||||
|
|
||||||
struct curl_slist *headers = NULL;
|
|
||||||
headers = curl_slist_append(headers, "Depth: 1");
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, (_url + pathUrl).c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeCallback);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
|
||||||
|
|
||||||
if (iv_access(CACERT_PATH.c_str(), R_OK) == 0)
|
|
||||||
curl_easy_setopt(curl, CURLOPT_CAINFO, CACERT_PATH.c_str());
|
|
||||||
else
|
|
||||||
Log::writeLog("could not find cacert");
|
|
||||||
|
|
||||||
res = curl_easy_perform(curl);
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
|
|
||||||
if (res == CURLE_OK)
|
|
||||||
{
|
|
||||||
long response_code;
|
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
|
||||||
|
|
||||||
switch (response_code)
|
|
||||||
{
|
|
||||||
case 404:
|
|
||||||
Message(ICON_ERROR, "Error", "The URL seems to be incorrect. You can look up the WebDav URL in the files app under settings. ", 4000);
|
|
||||||
break;
|
|
||||||
case 401:
|
|
||||||
Message(ICON_ERROR, "Error", "Username/password incorrect.", 4000);
|
|
||||||
break;
|
|
||||||
case 207:
|
|
||||||
{
|
|
||||||
string localPath = this->getLocalPath(pathUrl);
|
|
||||||
|
|
||||||
//create items_
|
|
||||||
vector<Item> tempItems = readInXML(readBuffer);
|
|
||||||
if (tempItems.empty())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (iv_access(localPath.c_str(), W_OK) != 0)
|
|
||||||
{
|
|
||||||
//if the current folder does not exist locally, create it
|
|
||||||
iv_buildpath(localPath.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//get items from local path
|
|
||||||
if (iv_access(localPath.c_str(), R_OK) != 0)
|
|
||||||
{
|
|
||||||
Log::writeLog("Local structure of " + localPath + " found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocalFileStructure(tempItems, localPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
//update the .structure file acording to items in the folder
|
|
||||||
localPath = localPath + NEXTCLOUD_STRUCTURE_EXTENSION;
|
|
||||||
|
|
||||||
//save xml to make the structure available offline
|
|
||||||
ofstream outFile(localPath);
|
|
||||||
if (outFile)
|
|
||||||
{
|
|
||||||
outFile << readBuffer;
|
|
||||||
Log::writeLog("Saved local copy of tree structure to " + localPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log::writeLog(localPath + " Couldnt save copy of tree structure locally.");
|
|
||||||
}
|
|
||||||
|
|
||||||
outFile.close();
|
|
||||||
return tempItems;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Message(ICON_ERROR, "Error", ("An unknown error occured. Switching to offline modus. To work online turn on online modus in the menu. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 4000);
|
|
||||||
_workOffline = true;
|
|
||||||
return getOfflineStructure(pathUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again.";
|
|
||||||
if(res == 60)
|
|
||||||
response = "Seems as if you are using Let's Encrypt Certs. Please follow the guide on Github (https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client) to use a custom Cert Store on PB.";
|
|
||||||
Message(ICON_ERROR, "Error", response.c_str(), 4000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Do generic?
|
|
||||||
//use boost xml
|
|
||||||
vector<Item> Nextcloud::readInXML(string xml)
|
|
||||||
{
|
|
||||||
size_t begin;
|
|
||||||
size_t end;
|
|
||||||
string beginItem = "<d:response>";
|
|
||||||
string endItem = "</d:response>";
|
|
||||||
vector<Item> tempItems;
|
|
||||||
|
|
||||||
begin = xml.find(beginItem);
|
|
||||||
|
|
||||||
while (begin != std::string::npos)
|
|
||||||
{
|
|
||||||
end = xml.find(endItem);
|
|
||||||
|
|
||||||
tempItems.push_back(xml.substr(begin, end));
|
|
||||||
|
|
||||||
xml = xml.substr(end + endItem.length());
|
|
||||||
|
|
||||||
begin = xml.find(beginItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tempItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
string Nextcloud::getLocalPath(string path)
|
|
||||||
{
|
|
||||||
Util::decodeUrl(path);
|
|
||||||
if (path.find(NEXTCLOUD_ROOT_PATH) != string::npos)
|
|
||||||
path = path.substr(NEXTCLOUD_ROOT_PATH.length());
|
|
||||||
|
|
||||||
return NEXTCLOUD_FILE_PATH + "/" + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<Item> Nextcloud::getOfflineStructure(const string &pathUrl)
|
|
||||||
{
|
|
||||||
string localPath = this->getLocalPath(pathUrl) + NEXTCLOUD_STRUCTURE_EXTENSION;
|
|
||||||
if (iv_access(localPath.c_str(), W_OK) == 0)
|
|
||||||
{
|
|
||||||
ifstream inFile(localPath);
|
|
||||||
std::stringstream buffer;
|
|
||||||
buffer << inFile.rdbuf();
|
|
||||||
|
|
||||||
vector<Item> tempItems = readInXML(buffer.str());
|
|
||||||
|
|
||||||
if (tempItems.empty())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
getLocalFileStructure(tempItems, this->getLocalPath(pathUrl));
|
|
||||||
return tempItems;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pathUrl.compare(NEXTCLOUD_ROOT_PATH + getUUID() + "/") == 0)
|
|
||||||
{
|
|
||||||
Message(ICON_ERROR, "Error", "The root structure is not available offline. Please try again to login.", 2000);
|
|
||||||
logout();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Structure is not available offline, stay at the tree
|
|
||||||
Message(ICON_ERROR, "Error", "The selected structure is not available offline.", 2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Nextcloud::getLocalFileStructure(vector<Item> &tempItems, const string &localPath)
|
|
||||||
{
|
|
||||||
//get local files, https://stackoverflow.com/questions/306533/how-do-i-get-a-list-of-files-in-a-directory-in-c
|
|
||||||
DIR *dir;
|
|
||||||
class dirent *ent;
|
|
||||||
class stat st;
|
|
||||||
|
|
||||||
dir = opendir(localPath.c_str());
|
|
||||||
while ((ent = readdir(dir)) != NULL)
|
|
||||||
{
|
|
||||||
const string fileName = ent->d_name;
|
|
||||||
const string fullFileName = localPath + fileName;
|
|
||||||
|
|
||||||
if (fileName[0] == '.')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (stat(fullFileName.c_str(), &st) == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const bool isDirectory = (st.st_mode & S_IFDIR) != 0;
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
for (unsigned int i = 1; i < tempItems.size(); i++)
|
|
||||||
{
|
|
||||||
if (tempItems.at(i).getLocalPath().compare(fullFileName) == 0)
|
|
||||||
{
|
|
||||||
if (!isDirectory)
|
|
||||||
{
|
|
||||||
std::ifstream in(fullFileName, std::ifstream::binary | std::ifstream::ate);
|
|
||||||
Log::writeLog(tempItems.at(i).getTitle());
|
|
||||||
Log::writeLog(std::to_string(in.tellg()));
|
|
||||||
Log::writeLog(std::to_string(tempItems.at(i).getSize()));
|
|
||||||
if (in.tellg() != tempItems.at(i).getSize())
|
|
||||||
{
|
|
||||||
tempItems.at(i).setState(FileState::IOUTSYNCED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
if (isDirectory)
|
|
||||||
{
|
|
||||||
tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFOLDER));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFILE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
}
|
|
|
@ -1,172 +0,0 @@
|
||||||
//------------------------------------------------------------------
|
|
||||||
// nextcloud.h
|
|
||||||
//
|
|
||||||
// Author: JuanJakobo
|
|
||||||
// Date: 04.08.2020
|
|
||||||
// Description: Handles the userdata and issues, login and download of data structure for nextcloud WEBDAV
|
|
||||||
//
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifndef NEXTCLOUD
|
|
||||||
#define NEXTCLOUD
|
|
||||||
|
|
||||||
#include "inkview.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "item.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
const std::string NEXTCLOUD_PATH = "/mnt/ext1/system/config/nextcloud";
|
|
||||||
const std::string NEXTCLOUD_CONFIG_PATH = NEXTCLOUD_PATH + "/nextcloud.cfg";
|
|
||||||
const std::string NEXTCLOUD_FILE_PATH = "/mnt/ext1/nextcloud";
|
|
||||||
const std::string NEXTCLOUD_ROOT_PATH = "/remote.php/dav/files/";
|
|
||||||
const std::string NEXTCLOUD_STRUCTURE_EXTENSION = ".structure";
|
|
||||||
const std::string NEXTCLOUD_START_PATH = "/remote.php/";
|
|
||||||
const std::string CACERT_PATH = "/mnt/ext1/applications/cacert.pem";
|
|
||||||
|
|
||||||
class Nextcloud
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Nextcloud();
|
|
||||||
//TODO public?
|
|
||||||
void setURL(const std::string &Url) { Util::accessConfig(Action::IWriteString, "url", Url); };
|
|
||||||
void setUsername(const std::string &Username) { Util::accessConfig(Action::IWriteString, "username", Username); };
|
|
||||||
void setUUID(const std::string &UUID) { Util::accessConfig(Action::IWriteString, "UUID", UUID); };
|
|
||||||
void setPassword(const std::string &Pass) { Util::accessConfig(Action::IWriteSecret, "password", Pass); };
|
|
||||||
void setStartFolder(const std::string &Path) { Util::accessConfig(Action::IReadString, "startFolder", Path); };
|
|
||||||
|
|
||||||
std::string getUsername() { return Util::accessConfig(Action::IReadString, "username"); };
|
|
||||||
|
|
||||||
bool setItems(const std::vector<Item> &tempItems);
|
|
||||||
|
|
||||||
const std::vector<Item> &getItems() const { return _items; };
|
|
||||||
bool isLoggedIn() const { return _loggedIn; };
|
|
||||||
bool isWorkOffline() const { return _workOffline; };
|
|
||||||
void switchWorkOffline() { _workOffline = !_workOffline; };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles login by receiving userdat from config
|
|
||||||
*
|
|
||||||
* @return true - login succeeded, false - login failed
|
|
||||||
*/
|
|
||||||
bool login();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles first login to nextcloud, if sucessfull saves userdata
|
|
||||||
*
|
|
||||||
* @param Username the username of the Nextcloud instance
|
|
||||||
* @param Pass the pass of the Nextcloud instance
|
|
||||||
* @return true - login succeeded, false - login failed
|
|
||||||
*/
|
|
||||||
bool login(const std::string &Url, const std::string &Username, const std::string &Pass);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the config files and deletes are temp files
|
|
||||||
* @param deleteFiles default false, true - local files are deleted, false local files are kept
|
|
||||||
*/
|
|
||||||
void logout(bool deleteFiles = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a certain item from the Nextcloud and saves it locally
|
|
||||||
* @param tempItems set of items where the item is in
|
|
||||||
* @param itemID id of the item
|
|
||||||
*/
|
|
||||||
void downloadItem(std::vector<Item> &tempItems, int itemID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a certain folder from the Nextcloud and saves it locally
|
|
||||||
* @param tempItems set of items where the item is in
|
|
||||||
* @param itemID id of the item
|
|
||||||
*/
|
|
||||||
void downloadFolder(std::vector<Item> &tempItems, int itemId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the network connection and starts the download of the certain itemId
|
|
||||||
*
|
|
||||||
* @param itemID id of the item that shall be downloaded
|
|
||||||
*/
|
|
||||||
void download(int itemID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the item
|
|
||||||
*
|
|
||||||
* @param itemID id of the item that shall be removed
|
|
||||||
* @return bool true - success, false - failure
|
|
||||||
*/
|
|
||||||
bool removeItem(int itemID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the dataStructure of the given URL and writes its WEBDAV items to the items vector, reads Userdata from configfile
|
|
||||||
*
|
|
||||||
* @param pathUrl URL to get the dataStructure of
|
|
||||||
* @return vector of items
|
|
||||||
*/
|
|
||||||
std::vector<Item> getDataStructure(std::string &pathUrl);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* formats the pathUrl to a local path
|
|
||||||
*
|
|
||||||
* @param path online path
|
|
||||||
* @return local path
|
|
||||||
*/
|
|
||||||
static std::string getLocalPath(std::string path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* checks the local storage checks if the items are locally available
|
|
||||||
*
|
|
||||||
* @param tempItems items that shall be compared
|
|
||||||
* @param localPath path that has to be checked
|
|
||||||
*/
|
|
||||||
void getLocalFileStructure(std::vector<Item> &tempItems, const std::string &localPath);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Item> _items;
|
|
||||||
bool _loggedIn{false};
|
|
||||||
std::string _url;
|
|
||||||
std::string _username;
|
|
||||||
std::string _password;
|
|
||||||
bool _workOffline{false};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the dataStructure of the given URL and writes its WEBDAV items to the items vector
|
|
||||||
*
|
|
||||||
* @param pathUrl URL to get the dataStructure of
|
|
||||||
* @param Username the username of the Nextcloud instance
|
|
||||||
* @param Pass the pass of the Nextcloud instance
|
|
||||||
* @return vector of Items
|
|
||||||
*/
|
|
||||||
std::vector<Item> getDataStructure(const std::string &pathUrl, const std::string &Username, const std::string &Pass);
|
|
||||||
|
|
||||||
std::string getUrl() { return Util::accessConfig(Action::IReadString, "url"); };
|
|
||||||
std::string getUUID() { return Util::accessConfig(Action::IReadString, "UUID"); };
|
|
||||||
std::string getPassword() { return Util::accessConfig(Action::IReadSecret, "password"); };
|
|
||||||
std::string getStartFolder() { return Util::accessConfig(Action::IReadString, "startFolder"); };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the end of the game dialog and lets the user
|
|
||||||
* choose inbetween starting a new game or closing the app
|
|
||||||
*
|
|
||||||
* @param Button id of the button that was pressed
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
static void DialogHandlerStatic(int Button);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads in the xml and creates a vector of items of it
|
|
||||||
*
|
|
||||||
* @param xml xml formatted result from curl call
|
|
||||||
* @return vector<Item> the items that have been read from the xml
|
|
||||||
*/
|
|
||||||
std::vector<Item> readInXML(std::string xml);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a .structure file exists and if that is the case return a vector of items
|
|
||||||
* @param pathUrl path that shall be checked
|
|
||||||
* @return return the items for the structure if available offline
|
|
||||||
*/
|
|
||||||
std::vector<Item> getOfflineStructure(const std::string &pathUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "inkview.h"
|
#include "inkview.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nextcloud.h"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -54,12 +53,10 @@ bool Util::connectToNetwork()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//make template?
|
string Util::accessConfig(const string &path, const Action &action, const string &name, const string &value)
|
||||||
|
|
||||||
string Util::accessConfig(const Action &action, const string &name, const string &value)
|
|
||||||
{
|
{
|
||||||
iconfigedit *temp = nullptr;
|
iconfigedit *temp = nullptr;
|
||||||
iconfig *config = OpenConfig(NEXTCLOUD_CONFIG_PATH.c_str(), temp);
|
iconfig *config = OpenConfig(path.c_str(), temp);
|
||||||
string returnValue;
|
string returnValue;
|
||||||
|
|
||||||
switch (action)
|
switch (action)
|
||||||
|
|
|
@ -43,8 +43,8 @@ public:
|
||||||
*/
|
*/
|
||||||
static bool connectToNetwork();
|
static bool connectToNetwork();
|
||||||
|
|
||||||
//TODO Doku
|
static std::string accessConfig(const std::string &path, const Action &action, const std::string &name, const std::string &value = std::string());
|
||||||
static std::string accessConfig(const Action &action, const std::string &name, const std::string &value = std::string());
|
|
||||||
/**
|
/**
|
||||||
* Returns an integer representing the download progress
|
* Returns an integer representing the download progress
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue