diff --git a/app/app.iml b/app/app.iml
index d6d2051..c0ec6d8 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -19,7 +19,7 @@
-
+
@@ -29,7 +29,7 @@
-
+
@@ -133,7 +133,7 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index b80740c..f6fd9df 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,7 +11,7 @@ allprojects {
}
android {
- compileSdkVersion 28
+ compileSdkVersion 29
defaultConfig {
applicationId "com.example.mear"
minSdkVersion 23
@@ -31,6 +31,8 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ applicationIdSuffix = kotlin_version
+ versionNameSuffix = kotlin_version
}
}
compileOptions {
diff --git a/app/src/main/cpp/APIRepository.cpp b/app/src/main/cpp/APIRepository.cpp
index 44d76e1..213f08c 100644
--- a/app/src/main/cpp/APIRepository.cpp
+++ b/app/src/main/cpp/APIRepository.cpp
@@ -28,11 +28,10 @@ namespace repository { namespace local {
auto result = query.executeStep();
apiInfo.uri = query.getColumn(1).getString();
- apiInfo.endpoint = query.getColumn(2).getString();
- apiInfo.version = query.getColumn(3).getInt();
+ apiInfo.version = query.getColumn(2).getInt();
return apiInfo;
- } catch (std::exception ex) {
+ } catch (std::exception& ex) {
auto msg = ex.what();
}
@@ -40,6 +39,19 @@ namespace repository { namespace local {
}
+ bool APIRepository::doesAPIInfoTableExist(const std::string& path)
+ {
+ try {
+ const auto dbPath = pathOfDatabase(path);
+ SQLite::Database db(dbPath, SQLite::OPEN_READONLY);
+
+ return db.tableExists(m_tableName);
+ } catch (std::exception& ex) {
+ auto msg = ex.what();
+ }
+ }
+
+
void APIRepository::createAPiInfoTable(const std::string& path)
{
try {
@@ -48,7 +60,7 @@ namespace repository { namespace local {
std::string queryString("CREATE TABLE ");
queryString.append(m_tableName);
- queryString.append(" (Id INTEGER PRIMARY KEY, Uri TEXT, Endpoint TEXT, Version INT");
+ queryString.append(" (Id INTEGER PRIMARY KEY, Uri TEXT, Version INT)");
db.exec(queryString);
} catch (std::exception& ex) {
auto msg = ex.what();
@@ -77,12 +89,11 @@ namespace repository { namespace local {
SQLite::Database db(dbPath, SQLite::OPEN_READWRITE);
std::string queryString("INSERT INTO ");
queryString.append(m_tableName);
- queryString.append(" (Uri, Endpoint, Version) VALUES (?, ?, ?)");
+ queryString.append(" (Uri, Version) VALUES (?, ?)");
SQLite::Statement query(db, queryString);
query.bind(1, apiInfo.uri);
- query.bind(2, apiInfo.endpoint);
- query.bind(3, apiInfo.version);
+ query.bind(2, apiInfo.version);
query.exec();
} catch (std::exception& ex) {
diff --git a/app/src/main/cpp/APIRepository.h b/app/src/main/cpp/APIRepository.h
index 4699e2e..2969a0b 100644
--- a/app/src/main/cpp/APIRepository.h
+++ b/app/src/main/cpp/APIRepository.h
@@ -17,11 +17,13 @@ namespace repository { namespace local {
model::APIInfo retrieveAPIInfo(const std::string&);
+ [[deprecated("use the base class function")]]
+ bool doesAPIInfoTableExist(const std::string&);
+
void createAPiInfoTable(const std::string&);
void deleteAPIInfo(const model::APIInfo&, const std::string&);
void saveAPIInfo(const model::APIInfo&, const std::string&);
private:
- //std::string apiInfoTable();
std::string apiInfoTable() noexcept;
};
}}
diff --git a/app/src/main/cpp/BaseRepository.cpp b/app/src/main/cpp/BaseRepository.cpp
index 14f2ebe..2a1f01a 100644
--- a/app/src/main/cpp/BaseRepository.cpp
+++ b/app/src/main/cpp/BaseRepository.cpp
@@ -23,6 +23,18 @@ namespace repository { namespace local {
return false;
}
+ bool BaseRepository::doesTableExist(const std::string& appPath)
+ {
+ try {
+ const auto dbPath = pathOfDatabase(appPath);
+ SQLite::Database db(dbPath, SQLite::OPEN_READONLY);
+
+ return db.tableExists(m_tableName);
+ } catch (std::exception& ex) {
+ auto msg = ex.what();
+ }
+ }
+
bool BaseRepository::isTableEmpty(const std::string& appPath)
{
try {
@@ -33,7 +45,9 @@ namespace repository { namespace local {
SQLite::Statement query(db, queryStr);
- return query.hasRow();
+ const auto result = query.hasRow();
+
+ return result;
} catch (std::exception& ex) {
auto msg = ex.what();
}
@@ -53,6 +67,20 @@ namespace repository { namespace local {
}
}
+ void BaseRepository::deleteRecord(const std::string& appPath)
+ {
+ try {
+ auto db = getDbConn(appPath, ConnType::ReadWrite);
+
+ std::string queryString("DELETE FROM ");
+ queryString.append(m_tableName);
+
+ db.exec(queryString);
+ } catch (std::exception& ex) {
+ auto msg = ex.what();
+ }
+ }
+
std::string BaseRepository::pathOfDatabase(const std::string& appPath)
{
@@ -67,5 +95,20 @@ namespace repository { namespace local {
return dbPath;
}
+ SQLite::Database BaseRepository::getDbConn(const std::string& path, ConnType dbType)
+ {
+ auto dbPath = pathOfDatabase(path);
+ switch (dbType) {
+ case ConnType::ReadOnly:
+ return SQLite::Database(dbPath, SQLite::OPEN_READONLY);
+ case ConnType::ReadWrite:
+ return SQLite::Database(dbPath, SQLite::OPEN_READWRITE);
+ case ConnType::Create:
+ return SQLite::Database(dbPath, SQLite::OPEN_CREATE);
+ default:
+ break;
+ }
+ return SQLite::Database(dbPath);
+ }
}}
\ No newline at end of file
diff --git a/app/src/main/cpp/BaseRepository.h b/app/src/main/cpp/BaseRepository.h
index 52f804e..d5a2072 100644
--- a/app/src/main/cpp/BaseRepository.h
+++ b/app/src/main/cpp/BaseRepository.h
@@ -8,18 +8,31 @@
#include
#include
+#include
+
namespace repository { namespace local {
class BaseRepository {
public:
bool databaseExist(const std::string&);
+ bool doesTableExist(const std::string&);
bool isTableEmpty(const std::string&);
void initializedDatabase(const std::string&);
+ void deleteRecord(const std::string&);
protected:
+ enum class ConnType;
std::string pathOfDatabase(const std::string&);
+ SQLite::Database getDbConn(const std::string&, ConnType);
+
const std::string m_databaseName = "mear.db3";
std::string m_tableName;
+
+ enum class ConnType {
+ ReadOnly = 0,
+ ReadWrite,
+ Create
+ };
private:
};
} }
diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt
index acfa83c..03f8643 100644
--- a/app/src/main/cpp/CMakeLists.txt
+++ b/app/src/main/cpp/CMakeLists.txt
@@ -31,6 +31,7 @@ set (SOURCES
set (HEADERS
APIRepository.h
BaseRepository.h
+ Demo.h
model/APIInfo.h
model/Song.h
model/Token.h
diff --git a/app/src/main/cpp/Demo.cpp b/app/src/main/cpp/Demo.cpp
index 3016778..e2730a7 100644
--- a/app/src/main/cpp/Demo.cpp
+++ b/app/src/main/cpp/Demo.cpp
@@ -1,6 +1,7 @@
//
// Created by brahmix on 9/26/19.
//
+#include "Demo.h"
#include
#include
@@ -23,33 +24,12 @@
#include
#include
-#include "model/APIInfo.h"
-#include "model/Song.h"
-#include "model/Token.h"
-#include "model/User.h"
#include "APIRepository.h"
#include "SongRepository.h"
#include "Tok.h"
+#include "TokenRepository.h"
#include "UserRepository.h"
-std::vector retrieveSongs(const model::Token&, const std::string&);
-
-jobject songToObj(JNIEnv *env, const model::Song&);
-
-model::Song retrieveSong(const std::string&, const std::string&, const int);
-model::Song retrieveSong(const model::Token&, const model::Song&, const std::string&);
-
-model::Token fettchToken(const model::User&, const std::string&);
-
-model::User retrieveCredentials(const std::string&);
-
-std::string fetchToken(const std::string&, const std::string&, const std::string&);
-
-bool doesDatabaseExist(const std::string&);
-bool apiInformationExist(const std::string&);
-bool userCredentialExist(const std::string&);
-
-void saveCredentials(const model::User&, const std::string&);
std::vector retrieveSongs(const model::Token& token, const std::string& baseUri)
@@ -95,6 +75,14 @@ jobject songToObj(JNIEnv *env, const model::Song& song)
}
+model::APIInfo retrieveAPIInfo(const std::string& path)
+{
+ repository::local::APIRepository apiRepo;
+
+ return apiRepo.retrieveAPIInfo(path);
+}
+
+
model::Song retrieveSong(const std::string& token, const std::string& baseUri, const int songId)
{
repository::SongRepository songRepo;
@@ -121,6 +109,14 @@ model::Token fetchToken(const model::User& user, const std::string& apiUri)
return token;
}
+model::Token retrieveSavedToken(const std::string& path)
+{
+ repository::local::TokenRepository tokenRepo;
+ auto token = tokenRepo.retrieveToken(path);
+
+ return token;
+}
+
model::User retrieveCredentials(const std::string& dataPath)
{
@@ -131,20 +127,6 @@ model::User retrieveCredentials(const std::string& dataPath)
}
-[[deprecated("use fetchToken(const model::User, std::string&")]]
-std::string fetchToken(const std::string& username, const std::string& password,
- const std::string& apiUri)
-{
- model::User user(username, password);
- manager::Tok tokMgr;
-
- auto token = tokMgr.fetchToken(user, apiUri);
-
- return token;
-
-}
-
-
bool doesDatabaseExist(const std::string& dataPath)
{
repository::local::UserRepository userRepo;
@@ -160,6 +142,13 @@ bool apiInformationExist(const std::string& dataPath)
return apiRepo.isTableEmpty(dataPath);
}
+bool doesTokenExist(const std::string& dataPath)
+{
+ repository::local::TokenRepository tokenRepo;
+
+ return tokenRepo.isTableEmpty(dataPath);
+}
+
bool userCredentialExist(const std::string& dataPath)
{
repository::local::UserRepository userRepo;
@@ -168,20 +157,20 @@ bool userCredentialExist(const std::string& dataPath)
}
-[[deprecated("c++ 17 issues")]]
-void iterateDirectory(const std::string& path)
+void saveAPIInfo(const model::APIInfo& apiInfo, const std::string& path)
{
- /**
- auto somePath = std::filesystem::path(path);
- for (auto dir: std::filesystem::directory_iterator(somePath)) {
- auto foundPath = dir;
- if (foundPath.is_directory()) {
- auto dirPath = foundPath.path();
- } else {
- auto filePath = foundPath.path();
- }
+ repository::local::APIRepository apiRepo;
+ if (!apiRepo.databaseExist(path)) {
+ apiRepo.initializedDatabase(path);
}
- */
+ if (!apiRepo.doesAPIInfoTableExist(path)) {
+ apiRepo.createAPiInfoTable(path);
+ }
+ if (!apiRepo.isTableEmpty(path)) {
+ apiRepo.deleteAPIInfo(apiInfo, path);
+ }
+
+ apiRepo.saveAPIInfo(apiInfo, path);
}
void saveCredentials(const model::User& user, const std::string& appDirectory)
@@ -195,13 +184,29 @@ void saveCredentials(const model::User& user, const std::string& appDirectory)
userRepo.createUserTable(appDirectory);
}
- if (userRepo.isTableEmpty(appDirectory)) {
+ if (!userRepo.isTableEmpty(appDirectory)) {
userRepo.deleteUserTable(appDirectory);
}
userRepo.saveUserCred(user, appDirectory);
}
+void saveToken(const model::Token& token, const std::string& path)
+{
+ repository::local::TokenRepository tokenRepo;
+ if (!tokenRepo.databaseExist(path)) {
+ tokenRepo.initializedDatabase(path);
+ }
+ if (!tokenRepo.doesTableExist(path)) {
+ tokenRepo.createTokenTable(path);
+ }
+ if (!tokenRepo.isTableEmpty(path)) {
+ tokenRepo.deleteRecord(path);
+ }
+
+ tokenRepo.saveToken(token, path);
+}
+
extern "C"
JNIEXPORT jobjectArray
@@ -236,47 +241,52 @@ Java_com_example_mear_repositories_TrackRepository_retrieveSongs(
extern "C"
JNIEXPORT jobject
JNICALL
-Java_com_example_mear_activities_LoginActivity_retrieveSong(
+Java_com_example_mear_repositories_APIRepository_retrieveAPIInfoRecord(
JNIEnv *env,
jobject thisObj,
- jstring token,
- jstring apiUri,
- jint idOfSong
-)
-{
- const std::string tok = env->GetStringUTFChars(token, nullptr);
- const std::string baseUri = env->GetStringUTFChars(apiUri, nullptr);
- auto song = retrieveSong(tok, baseUri, idOfSong);
+ jstring pathStr ) {
+ const auto path = env->GetStringUTFChars(pathStr, nullptr);
- jclass songClass = env->FindClass( "com/example/mear/models/Song");
- jmethodID jconstructor = env->GetMethodID( songClass, "", "()V" );
- jobject songObj = env->NewObject( songClass, jconstructor );
+ auto apiInfo = retrieveAPIInfo(path);
- jmethodID songId = env->GetMethodID( songClass, "setId", "(I)V" );
- jmethodID songTitle = env->GetMethodID( songClass, "setTitle", "(Ljava/lang/String;)V" );
- jmethodID songAlbum = env->GetMethodID( songClass, "setAlbum", "(Ljava/lang/String;)V" );
- jmethodID songArtist = env->GetMethodID( songClass, "setArtist", "(Ljava/lang/String;)V" );
- jmethodID songGenre = env->GetMethodID( songClass, "setGenre", "(Ljava/lang/String;)V" );
- jmethodID songDuration = env->GetMethodID( songClass, "setDuration", "(I)V" );
- jmethodID songYear = env->GetMethodID( songClass, "setYear", "(I)V" );
+ jclass apiInfoClass = env->FindClass( "com/example/mear/models/APIInfo");
+ jmethodID jconstructor = env->GetMethodID( apiInfoClass, "", "()V" );
+ jobject apiInfoObj = env->NewObject( apiInfoClass, jconstructor );
- jint id = song.id;
- jstring title = env->NewStringUTF(song.title.c_str());
- jstring album = env->NewStringUTF(song.album.c_str());
- jstring artist = env->NewStringUTF(song.artist.c_str());
- jstring genre = env->NewStringUTF(song.genre.c_str());
- jint duration = song.duration;
- jint year = song.year;
+ jmethodID uriId = env->GetMethodID( apiInfoClass, "setUri", "(Ljava/lang/String;)V" );
+ jmethodID versionId = env->GetMethodID( apiInfoClass, "setVersion", "(I)V" );
- env->CallVoidMethod( songObj, songId, id );
- env->CallVoidMethod(songObj, songTitle, title);
- env->CallVoidMethod(songObj, songAlbum, album);
- env->CallVoidMethod(songObj, songArtist, artist);
- env->CallVoidMethod(songObj, songGenre, genre);
- env->CallVoidMethod(songObj, songDuration, duration);
- env->CallVoidMethod(songObj, songYear, year);
+ jint versionVal = apiInfo.version;
+ jstring uriVal = env->NewStringUTF(apiInfo.uri.c_str());
- return songObj;
+ env->CallVoidMethod(apiInfoObj, uriId, uriVal);
+ env->CallVoidMethod( apiInfoObj, versionId, versionVal);
+
+ return apiInfoObj;
+}
+
+extern "C"
+JNIEXPORT jobject
+JNICALL
+Java_com_example_mear_repositories_TokenRepository_retrieveTokenRecord(
+ JNIEnv *env,
+ jobject thisObj,
+ jstring pathStr
+ ) {
+ const auto path = env->GetStringUTFChars(pathStr, nullptr);
+ auto token = retrieveSavedToken(path);
+
+ auto tokenClass = env->FindClass("com/example/mear/models/Token");
+ auto jConstructor = env->GetMethodID(tokenClass, "", "()V");
+ auto tokenObj = env->NewObject(tokenClass, jConstructor);
+
+ auto accessTokenId = env->GetMethodID(tokenClass, "setAccessToken", "(Ljava/lang/String;)V");
+
+ auto accessTokenStr = env->NewStringUTF(token.accessToken.c_str());
+
+ env->CallVoidMethod(tokenObj, accessTokenId, accessTokenStr);
+
+ return tokenObj;
}
extern "C"
@@ -370,27 +380,6 @@ Java_com_example_mear_repositories_UserRepository_logUser(
}
-extern "C"
-JNIEXPORT jstring
-JNICALL
-Java_com_example_mear_activities_LoginActivity_logUser(
- JNIEnv *env,
- jobject thisObj,
- jstring username,
- jstring password,
- jstring apiUri ) {
- model::User user(env->GetStringUTFChars(username, nullptr),
- env->GetStringUTFChars(password, nullptr));
- const std::string usr = env->GetStringUTFChars(username, nullptr);
- const std::string pass = env->GetStringUTFChars(password, nullptr);
- const std::string api = env->GetStringUTFChars(apiUri, nullptr);
-
- auto token = fetchToken(usr, pass, api);
-
- return env->NewStringUTF(token.c_str());
-}
-
-
extern "C"
JNIEXPORT jboolean
JNICALL
@@ -399,9 +388,22 @@ Java_com_example_mear_repositories_APIRepository_isAPIInfoTableEmpty(
jobject thisObj,
jstring pathStr
) {
- const std::string datapath = env->GetStringUTFChars(pathStr, nullptr);
+ const auto dataPath = env->GetStringUTFChars(pathStr, nullptr);
- return apiInformationExist(datapath);
+ return apiInformationExist(dataPath);
+}
+
+extern "C"
+JNIEXPORT jboolean
+JNICALL
+Java_com_example_mear_repositories_TokenRepository_isTokenTableEmpty(
+ JNIEnv *env,
+ jobject thisObj,
+ jstring pathStr
+ ) {
+ const auto dataPath = env->GetStringUTFChars(pathStr, nullptr);
+
+ return doesTokenExist(dataPath);
}
extern "C"
@@ -456,3 +458,46 @@ Java_com_example_mear_repositories_UserRepository_saveUserCredentials(
saveCredentials(usr, appDirectoryStr);
}
+
+extern "C"
+JNIEXPORT void
+JNICALL
+Java_com_example_mear_repositories_APIRepository_saveAPIInfoRecord(
+ JNIEnv *env,
+ jobject thisObj,
+ jobject apiInfoObj,
+ jstring pathStr
+ ) {
+ auto apiInfoClass = env->GetObjectClass(apiInfoObj);
+ auto uriId = env->GetFieldID(apiInfoClass, "uri", "Ljava/lang/String;");
+ auto versionId = env->GetFieldID(apiInfoClass, "version", "I");
+
+ auto uriStr = (jstring) env->GetObjectField(apiInfoObj, uriId);
+ auto versionInt = env->GetIntField(apiInfoObj, versionId);
+
+ model::APIInfo apiInfo(env->GetStringUTFChars(uriStr, nullptr), versionInt);
+ auto path = env->GetStringUTFChars(pathStr, nullptr);
+
+ saveAPIInfo(apiInfo, path);
+}
+
+
+extern "C"
+JNIEXPORT void
+JNICALL
+Java_com_example_mear_repositories_TokenRepository_saveTokenRecord(
+ JNIEnv *env,
+ jobject thisObj,
+ jobject tokenObj,
+ jstring pathStr
+ ) {
+ auto tokenClass = env->GetObjectClass(tokenObj);
+ auto accessTokenId = env->GetFieldID(tokenClass, "accessToken", "Ljava/lang/String;");
+
+ auto accessTokenVal = (jstring) env->GetObjectField(tokenObj, accessTokenId);
+
+ model::Token token(env->GetStringUTFChars(accessTokenVal, nullptr));
+ auto path = env->GetStringUTFChars(pathStr, nullptr);
+
+ saveToken(token, path);
+}
diff --git a/app/src/main/cpp/Demo.h b/app/src/main/cpp/Demo.h
new file mode 100644
index 0000000..0d90039
--- /dev/null
+++ b/app/src/main/cpp/Demo.h
@@ -0,0 +1,42 @@
+//
+// Created by brahmix on 10/12/19.
+//
+
+#ifndef MEAR_DEMO_H
+#define MEAR_DEMO_H
+
+#include
+
+#include
+
+#include "model/APIInfo.h"
+#include "model/Song.h"
+#include "model/Token.h"
+#include "model/User.h"
+
+
+std::vector retrieveSongs(const model::Token&, const std::string&);
+
+jobject songToObj(JNIEnv *env, const model::Song&);
+
+model::APIInfo retrieveAPIInfo(const std::string&);
+
+model::Song retrieveSong(const std::string&, const std::string&, const int);
+model::Song retrieveSong(const model::Token&, const model::Song&, const std::string&);
+
+model::Token fettchToken(const model::User&, const std::string&);
+model::Token retrieveSavedToken(const std::string&);
+void saveToken(const model::Token&, const std::string&);
+
+model::User retrieveCredentials(const std::string&);
+
+bool doesDatabaseExist(const std::string&);
+bool apiInformationExist(const std::string&);
+bool doesTokenExist(const std::string&);
+bool userCredentialExist(const std::string&);
+
+void saveApiInfo(const model::APIInfo&, const std::string&);
+void saveCredentials(const model::User&, const std::string&);
+
+
+#endif //MEAR_DEMO_H
diff --git a/app/src/main/cpp/TokenRepository.cpp b/app/src/main/cpp/TokenRepository.cpp
index 7d670f2..ef2e39b 100644
--- a/app/src/main/cpp/TokenRepository.cpp
+++ b/app/src/main/cpp/TokenRepository.cpp
@@ -3,3 +3,73 @@
//
#include "TokenRepository.h"
+
+#include
+
+namespace repository { namespace local {
+ TokenRepository::TokenRepository()
+ {
+ m_tableName = tokenTable();
+ }
+
+
+ model::Token TokenRepository::retrieveToken(const std::string& path)
+ {
+ model::Token token;
+
+ try {
+ auto db = getDbConn(path, ConnType::ReadOnly);
+ std::string queryString("SELECT * FROM ");
+ queryString.append(m_tableName);
+ queryString.append(" LIMIT 1");
+
+ SQLite::Statement query(db, queryString);
+
+ auto result = query.executeStep();
+ model::Token token(query.getColumn(1).getString());
+
+ return token;
+ } catch (std::exception& ex) {
+ auto msg = ex.what();
+ }
+
+ return token;
+ }
+
+
+ void TokenRepository::createTokenTable(const std::string& path)
+ {
+ try {
+ auto db = getDbConn(path, ConnType::ReadWrite);
+
+ std::string queryString("CREATE TABLE ");
+ queryString.append(m_tableName);
+ queryString.append(" (Id INTEGER PRIMARY KEY, AccessToken TEXT)");
+
+ db.exec(queryString);
+ } catch (std::exception& ex) {
+ auto msg = ex.what();
+ }
+ }
+
+ void TokenRepository::saveToken(const model::Token& token, const std::string& path)
+ {
+ try {
+ auto db = getDbConn(path, ConnType::ReadWrite);
+
+ std::string queryString("INSERT INTO ");
+ queryString.append(m_tableName);
+ queryString.append(" (AccessToken) VALUES (?)");
+
+ SQLite::Statement query(db, queryString);
+ query.bind(1, token.accessToken);
+
+ query.exec();
+ } catch (std::exception& ex) {
+ auto msg = ex.what();
+ }
+ }
+
+
+ std::string TokenRepository::tokenTable() noexcept { return "Token"; }
+}}
diff --git a/app/src/main/cpp/TokenRepository.h b/app/src/main/cpp/TokenRepository.h
index 8fc8dfc..4a6e527 100644
--- a/app/src/main/cpp/TokenRepository.h
+++ b/app/src/main/cpp/TokenRepository.h
@@ -5,10 +5,24 @@
#ifndef MEAR_TOKENREPOSITORY_H
#define MEAR_TOKENREPOSITORY_H
+#include
-class TokenRepository {
+#include "model/Token.h"
+#include "BaseRepository.h"
-};
+namespace repository { namespace local {
+ class TokenRepository: public BaseRepository {
+ public:
+ TokenRepository();
+
+ model::Token retrieveToken(const std::string&);
+
+ void createTokenTable(const std::string&);
+ void saveToken(const model::Token&, const std::string&);
+ private:
+ std::string tokenTable() noexcept;
+ };
+}}
#endif //MEAR_TOKENREPOSITORY_H
diff --git a/app/src/main/cpp/UserRepository.cpp b/app/src/main/cpp/UserRepository.cpp
index 6fa4aeb..2387cc5 100644
--- a/app/src/main/cpp/UserRepository.cpp
+++ b/app/src/main/cpp/UserRepository.cpp
@@ -44,6 +44,7 @@ namespace repository { namespace local {
}
+ [[deprecated("use the base class doesTableExist() function")]]
bool UserRepository::doesUserTableExist(const std::string &appPath)
{
try {
diff --git a/app/src/main/cpp/model/APIInfo.h b/app/src/main/cpp/model/APIInfo.h
index 5790156..502e09a 100644
--- a/app/src/main/cpp/model/APIInfo.h
+++ b/app/src/main/cpp/model/APIInfo.h
@@ -11,6 +11,14 @@ namespace model {
class APIInfo
{
public:
+ APIInfo() = default;
+ APIInfo(const std::string& uri) :
+ uri(uri) { }
+ APIInfo(const std::string& uri, const int version) :
+ uri(uri), version(version) { }
+ APIInfo(const std::string& uri, const std::string& endpoint, const int version) :
+ uri(uri), endpoint(endpoint), version(version) { }
+
std::string uri;
std::string endpoint;
int version;
diff --git a/app/src/main/java/com/example/mear/activities/BaseServiceActivity.kt b/app/src/main/java/com/example/mear/activities/BaseServiceActivity.kt
index dd46234..c2c8233 100644
--- a/app/src/main/java/com/example/mear/activities/BaseServiceActivity.kt
+++ b/app/src/main/java/com/example/mear/activities/BaseServiceActivity.kt
@@ -5,9 +5,11 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
+import android.os.Environment
import android.os.IBinder
import android.support.v7.app.AppCompatActivity
import android.widget.Toast
+import com.example.mear.R
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@@ -31,6 +33,13 @@ open class BaseServiceActivity: AppCompatActivity() {
val d = "l"
}
+
+ protected fun appDirectory(): String {
+ return Environment.getDataDirectory().toString() + "/data/" +
+ resources.getString(R.string.app_relative_path)
+ }
+
+
protected fun isServiceRunning(serviceClass: Class<*>): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
diff --git a/app/src/main/java/com/example/mear/activities/IcarusSongActivity.kt b/app/src/main/java/com/example/mear/activities/IcarusSongActivity.kt
index 5b192f9..72da3bf 100644
--- a/app/src/main/java/com/example/mear/activities/IcarusSongActivity.kt
+++ b/app/src/main/java/com/example/mear/activities/IcarusSongActivity.kt
@@ -12,15 +12,19 @@ import kotlinx.android.synthetic.main.content_song_view.*
import com.example.mear.activities.BaseServiceActivity
import com.example.mear.adapters.RecyclerAdapter
+import com.example.mear.adapters.SongAdapter
import com.example.mear.models.TrackItems
+import com.example.mear.models.APIInfo
import com.example.mear.models.Song
+import com.example.mear.models.Token
import com.example.mear.R
-import com.example.mear.repositories.TrackRepository
+import com.example.mear.repositories.*
class IcarusSongActivity : BaseServiceActivity() {
- private lateinit var adapter: RecyclerAdapter
+ private lateinit var adapter: SongAdapter
+
private lateinit var linearLayoutManager: LinearLayoutManager
private var songs: ArrayList? = null
@@ -28,16 +32,16 @@ class IcarusSongActivity : BaseServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ try {
setContentView(R.layout.activity_icarus_song)
- setSupportActionBar(toolbar)
+ //setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
- try {
val colr = R.color.track_seek
window.statusBarColor = resources.getColor(R.color.track_seek)
doBindService()
initializeAdapter()
- //initializeSongSearchListener()
+ initializeSongSearchListener()
}
catch (ex: Exception) {
val msg = ex.message
@@ -45,15 +49,61 @@ class IcarusSongActivity : BaseServiceActivity() {
}
+ fun playSong(song: Song, token: Token, apiInfo: APIInfo) {
+ musicService!!.icarusPlaySong(token, song, apiInfo)
+ }
+
+
private fun initializeAdapter() {
try {
linearLayoutManager = LinearLayoutManager(this)
trackList.layoutManager = linearLayoutManager
+ val pa = appDirectory()
+ val trackRepo = TrackRepository()
+ val tokenRepo = TokenRepository()
+ val apiRepo = APIRepository()
+ val token = tokenRepo.retrieveToken(pa)
+ val apiInfo = apiRepo.retrieveRecord(pa)
+ val fetchedSongs = trackRepo.fetchSongs(token, apiInfo.uri).toCollection(ArrayList())
+ songs = fetchedSongs
+
songs!!.sortedWith(compareBy{it.title})
+
+ adapter = SongAdapter({songItems: Song -> playSong(songItems, token, apiInfo)}, songs!!)
+
+ trackList.adapter = adapter
+ trackList.setHasFixedSize(true)
+ trackList.setItemViewCacheSize(20)
}
catch (ex: Exception) {
val msg = ex.message
}
}
+
+ private fun initializeSongSearchListener() {
+ songSearch.setOnQueryTextListener(object: SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(p0: String?): Boolean {
+ try {
+ adapter.filter.filter(p0)
+ }
+ catch (ex: Exception) {
+ val msg = ex.message
+ }
+
+ return false
+ }
+
+ override fun onQueryTextChange(p0: String?): Boolean {
+ try {
+ adapter.filter.filter(p0)
+ }
+ catch (ex: Exception) {
+ val msg = ex.message
+ }
+
+ return false
+ }
+ })
+ }
}
diff --git a/app/src/main/java/com/example/mear/activities/LoginActivity.kt b/app/src/main/java/com/example/mear/activities/LoginActivity.kt
index d5f5faa..f62cfe7 100644
--- a/app/src/main/java/com/example/mear/activities/LoginActivity.kt
+++ b/app/src/main/java/com/example/mear/activities/LoginActivity.kt
@@ -12,10 +12,6 @@ import kotlinx.android.synthetic.main.content_login.*
import org.jetbrains.anko.toast
import com.example.mear.repositories.*
-import mear.com.example.mear.repositories.APIRepository
-
-//import com.example.mear.repositories.TrackRepository
-//import com.example.mear.repositories.UserRepository
class LoginActivity : BaseServiceActivity() {
@@ -45,29 +41,24 @@ class LoginActivity : BaseServiceActivity() {
val saveCred = saveUserCred.isChecked
var apiInfo = APIInfo(apiUri.text.toString(), 1)
- //var apiUriStr = apiUri.text.toString()
val usr = User(username.text.toString(), password.text.toString())
- if (apiInfo.uri.isEmpty()) {
- apiInfo.uri = ""
- }
-
val usrRepo = UserRepository()
- val trackRepo = TrackRepository()
+ val tokenRepo = TokenRepository()
val myToken = usrRepo.fetchToken(usr, apiInfo.uri)
try {
val pa = appDirectory()
- val so = Song(5)
- val song = trackRepo.fetchSong(myToken, so, apiInfo.uri)
+
if (saveCred && usrRepo.isTableEmpty(pa)) {
val api = APIRepository()
if (api.isTableEmpty(pa)) {
- api.SaveRecord(apiInfo, pa)
+ api.saveRecord(apiInfo, pa)
}
usrRepo.saveCredentials(usr, pa)
}
- //startActivity(Intent(this, IcarusSongActivity::class.java))
+ tokenRepo.saveToken(myToken, pa)
+ startActivity(Intent(this, IcarusSongActivity::class.java))
}
catch (ex: Exception) {
val msg = ex.message
@@ -88,18 +79,12 @@ class LoginActivity : BaseServiceActivity() {
}
if (!apiRepo.isTableEmpty(pa)) {
val api = apiRepo.retrieveRecord(pa)
- val s: String = "${api.uri}" + "${api.version} ${api.endpoint}"
- apiUri.setText(s)
+ apiUri.setText(api.uri)
}
doBindService()
}
- private fun appDirectory(): String {
- return Environment.getDataDirectory().toString() + "/data/" +
- resources.getString(R.string.app_relative_path)
- }
-
private fun validFields(): Boolean {
if (username.text.isEmpty()) {
diff --git a/app/src/main/java/com/example/mear/adapters/SongAdapter.kt b/app/src/main/java/com/example/mear/adapters/SongAdapter.kt
new file mode 100644
index 0000000..8df9e3c
--- /dev/null
+++ b/app/src/main/java/com/example/mear/adapters/SongAdapter.kt
@@ -0,0 +1,103 @@
+package com.example.mear.adapters
+
+import android.app.Activity
+import android.support.v7.widget.RecyclerView
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Filter
+import android.widget.Filterable
+
+import java.lang.Exception
+import kotlinx.android.synthetic.main.fragment_song_view.view.*
+import kotlinx.coroutines.GlobalScope
+
+import com.squareup.picasso.Picasso
+
+import com.example.mear.constants.Filenames
+import com.example.mear.inflate
+import com.example.mear.models.Song
+import com.example.mear.models.TrackItems
+import com.example.mear.R
+import com.example.mear.util.ConvertByteArray
+import com.example.mear.util.ExtractCover
+import org.jetbrains.anko.imageBitmap
+
+
+class SongAdapter(val mOnClickListener: (Song) -> Unit,
+ var songItemSource: ArrayList) :
+ RecyclerView.Adapter(), Filterable {
+
+ var allIcarusSongs = songItemSource
+ val adp = this
+
+
+ override fun onBindViewHolder(p0: SongItemHolder, p1: Int) {
+ val ph = songItemSource!![p1]
+ p0.bindSongItems(ph, mOnClickListener)
+ }
+
+
+ override fun onCreateViewHolder(p0: ViewGroup, p1: Int): SongItemHolder {
+ val inflatedView = p0.inflate(R.layout.fragment_song_view, false)
+ return SongItemHolder(inflatedView)
+ }
+
+
+ override fun getFilter(): Filter {
+ return object: Filter() {
+ override fun performFiltering(constraint: CharSequence?): FilterResults {
+ val fr = FilterResults()
+ val sortedList = mutableListOf()
+
+ for (song in allIcarusSongs) {
+ if (song.artist.contains(constraint!!, true) ||
+ song.title.contains(constraint!!, true)) {
+ sortedList.add(song)
+ }
+ }
+
+ fr.count = sortedList.size
+ fr.values = sortedList
+
+ return fr
+ }
+
+
+ override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
+ try {
+ val items = results!!.values as ArrayList
+ adp.songItemSource = items
+ }
+ catch (ex: Exception) {
+ val msg = ex.message
+ }
+ }
+ }
+ }
+
+
+ override fun getItemCount(): Int {
+ return songItemSource!!.size
+ }
+
+
+ class SongItemHolder(var v: View): RecyclerView.ViewHolder(v) {
+ private var songItem: Song? = null
+
+
+ fun bindSongItems(songItems: Song, clickList: (Song) -> Unit) {
+ try {
+ val context = v.context
+ this.songItem = songItems
+
+ v.trackTitle.setText(songItems.title)
+ v.trackArtist.setText(songItems.artist)
+
+ v.setOnClickListener { clickList(songItem!!)}
+ }
+ catch (ex: Exception) {
+ val msg = ex.message
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mear/management/MusicFiles.kt b/app/src/main/java/com/example/mear/management/MusicFiles.kt
index 1629369..5949724 100644
--- a/app/src/main/java/com/example/mear/management/MusicFiles.kt
+++ b/app/src/main/java/com/example/mear/management/MusicFiles.kt
@@ -1,5 +1,7 @@
package com.example.mear.management
+import android.os.Environment
+import com.example.mear.R
import java.io.File
import java.lang.Exception
@@ -13,6 +15,7 @@ class MusicFiles (private val demoPath: File) {
private val musicSongLimit = Int.MAX_VALUE
+
fun loadAllMusicPaths() {
try {
allSongs = mutableListOf()
diff --git a/app/src/main/java/com/example/mear/playback/service/MusicService.kt b/app/src/main/java/com/example/mear/playback/service/MusicService.kt
index d49116f..333b1cc 100644
--- a/app/src/main/java/com/example/mear/playback/service/MusicService.kt
+++ b/app/src/main/java/com/example/mear/playback/service/MusicService.kt
@@ -18,7 +18,9 @@ import com.example.mear.constants.Interval
import com.example.mear.management.MusicFiles
import com.example.mear.management.TrackManager
import com.example.mear.models.PlayControls
+import com.example.mear.models.APIInfo
import com.example.mear.models.Song
+import com.example.mear.models.Token
import com.example.mear.models.Track
import com.example.mear.repositories.RepeatRepository
import com.example.mear.repositories.ShuffleRepository
@@ -111,6 +113,23 @@ class MusicService: Service() {
}
}
+ fun icarusPlaySong(token: Token, song: Song, apiInfo: APIInfo) {
+ val uriStr = "${apiInfo.uri}/api/v${apiInfo.version}/song/stream/${song.id}"
+ val uri = Uri.parse(uriStr)
+ var hddr: MutableMap = mutableMapOf()
+ hddr["Authorization"] = "Bearer ${token.accessToken}"
+ hddr["Content-type"] = "Keep-alive"
+ try {
+ trackPlayer!!.reset()
+ trackPlayer!!.setDataSource(this, uri, hddr)
+ trackPlayer!!.prepare()
+ trackPlayer!!.start()
+ }
+ catch (ex: Exception) {
+ val msg = ex.message
+ }
+ }
+
fun icarusPlaySong(ctx: Context, token: String, uriBase: String, song: Song) {
var uriStr = uriBase
val id = song.id
diff --git a/app/src/main/java/com/example/mear/repositories/APIRepository.kt b/app/src/main/java/com/example/mear/repositories/APIRepository.kt
index 05f0f4a..dee2c73 100644
--- a/app/src/main/java/com/example/mear/repositories/APIRepository.kt
+++ b/app/src/main/java/com/example/mear/repositories/APIRepository.kt
@@ -1,7 +1,6 @@
-package mear.com.example.mear.repositories
+package com.example.mear.repositories
import com.example.mear.models.APIInfo
-import com.example.mear.repositories.BaseRepository
class APIRepository: BaseRepository() {
@@ -29,7 +28,7 @@ class APIRepository: BaseRepository() {
}
- fun SaveRecord(api: APIInfo, path: String) {
+ fun saveRecord(api: APIInfo, path: String) {
return saveAPIInfoRecord(api, path)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mear/repositories/TokenRepository.kt b/app/src/main/java/com/example/mear/repositories/TokenRepository.kt
index c910cff..6fc7eb0 100644
--- a/app/src/main/java/com/example/mear/repositories/TokenRepository.kt
+++ b/app/src/main/java/com/example/mear/repositories/TokenRepository.kt
@@ -13,11 +13,11 @@ class TokenRepository: BaseRepository() {
private external fun retrieveTokenRecord(path: String): Token
- private external fun isTokeTableEmpty(path: String): Boolean
+ private external fun isTokenTableEmpty(path: String): Boolean
private external fun saveTokenRecord(token: Token, path: String)
- private external fun deleteTokenRecord(path: String)
- private external fun updateTokenRecord(token: Token, path: String)
+ //private external fun deleteTokenRecord(path: String)
+ //private external fun updateTokenRecord(token: Token, path: String)
fun retrieveToken(path: String): Token {
@@ -26,7 +26,7 @@ class TokenRepository: BaseRepository() {
fun isTableEmpty(path: String): Boolean {
- return isTokeTableEmpty(path)
+ return isTokenTableEmpty(path)
}
@@ -34,6 +34,8 @@ class TokenRepository: BaseRepository() {
return saveTokenRecord(token, path)
}
+ // TODO: implement this
+ /**
fun deleteToken(path: String) {
return deleteTokenRecord(path)
}
@@ -41,4 +43,5 @@ class TokenRepository: BaseRepository() {
fun updateToken(token: Token, path: String) {
return updateTokenRecord(token, path)
}
+ */
}
\ No newline at end of file