able to stream now, need to do some code clean up and refactoring. Also need to have a view for controls
This commit is contained in:
+3
-3
File diff suppressed because one or more lines are too long
+3
-1
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}}
|
||||
@@ -8,18 +8,31 @@
|
||||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
#include <SQLiteCpp/Database.h>
|
||||
|
||||
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:
|
||||
};
|
||||
} }
|
||||
|
||||
@@ -31,6 +31,7 @@ set (SOURCES
|
||||
set (HEADERS
|
||||
APIRepository.h
|
||||
BaseRepository.h
|
||||
Demo.h
|
||||
model/APIInfo.h
|
||||
model/Song.h
|
||||
model/Token.h
|
||||
|
||||
+150
-105
@@ -1,6 +1,7 @@
|
||||
//
|
||||
// Created by brahmix on 9/26/19.
|
||||
//
|
||||
#include "Demo.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -23,33 +24,12 @@
|
||||
#include <curl/curl.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#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<model::Song> 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<model::Song> 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, "<init>", "()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, "<init>", "()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, "<init>", "()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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// Created by brahmix on 10/12/19.
|
||||
//
|
||||
|
||||
#ifndef MEAR_DEMO_H
|
||||
#define MEAR_DEMO_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "model/APIInfo.h"
|
||||
#include "model/Song.h"
|
||||
#include "model/Token.h"
|
||||
#include "model/User.h"
|
||||
|
||||
|
||||
std::vector<model::Song> 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
|
||||
@@ -3,3 +3,73 @@
|
||||
//
|
||||
|
||||
#include "TokenRepository.h"
|
||||
|
||||
#include <SQLiteCpp/Database.h>
|
||||
|
||||
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"; }
|
||||
}}
|
||||
|
||||
@@ -5,10 +5,24 @@
|
||||
#ifndef MEAR_TOKENREPOSITORY_H
|
||||
#define MEAR_TOKENREPOSITORY_H
|
||||
|
||||
#include <string>
|
||||
|
||||
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
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace repository { namespace local {
|
||||
}
|
||||
|
||||
|
||||
[[deprecated("use the base class doesTableExist() function")]]
|
||||
bool UserRepository::doesUserTableExist(const std::string &appPath)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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<Song>? = 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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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<Song>) :
|
||||
RecyclerView.Adapter<SongAdapter.SongItemHolder>(), 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<Song>()
|
||||
|
||||
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<Song>
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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<String, String> = 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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
*/
|
||||
}
|
||||
Reference in New Issue
Block a user