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:
kdeng00
2019-10-12 13:16:05 -04:00
parent f9304a52e2
commit cc97123908
21 changed files with 577 additions and 154 deletions
+3 -3
View File
File diff suppressed because one or more lines are too long
+3 -1
View File
@@ -11,7 +11,7 @@ allprojects {
} }
android { android {
compileSdkVersion 28 compileSdkVersion 29
defaultConfig { defaultConfig {
applicationId "com.example.mear" applicationId "com.example.mear"
minSdkVersion 23 minSdkVersion 23
@@ -31,6 +31,8 @@ android {
release { release {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
applicationIdSuffix = kotlin_version
versionNameSuffix = kotlin_version
} }
} }
compileOptions { compileOptions {
+18 -7
View File
@@ -28,11 +28,10 @@ namespace repository { namespace local {
auto result = query.executeStep(); auto result = query.executeStep();
apiInfo.uri = query.getColumn(1).getString(); apiInfo.uri = query.getColumn(1).getString();
apiInfo.endpoint = query.getColumn(2).getString(); apiInfo.version = query.getColumn(2).getInt();
apiInfo.version = query.getColumn(3).getInt();
return apiInfo; return apiInfo;
} catch (std::exception ex) { } catch (std::exception& ex) {
auto msg = ex.what(); 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) void APIRepository::createAPiInfoTable(const std::string& path)
{ {
try { try {
@@ -48,7 +60,7 @@ namespace repository { namespace local {
std::string queryString("CREATE TABLE "); std::string queryString("CREATE TABLE ");
queryString.append(m_tableName); 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); db.exec(queryString);
} catch (std::exception& ex) { } catch (std::exception& ex) {
auto msg = ex.what(); auto msg = ex.what();
@@ -77,12 +89,11 @@ namespace repository { namespace local {
SQLite::Database db(dbPath, SQLite::OPEN_READWRITE); SQLite::Database db(dbPath, SQLite::OPEN_READWRITE);
std::string queryString("INSERT INTO "); std::string queryString("INSERT INTO ");
queryString.append(m_tableName); queryString.append(m_tableName);
queryString.append(" (Uri, Endpoint, Version) VALUES (?, ?, ?)"); queryString.append(" (Uri, Version) VALUES (?, ?)");
SQLite::Statement query(db, queryString); SQLite::Statement query(db, queryString);
query.bind(1, apiInfo.uri); query.bind(1, apiInfo.uri);
query.bind(2, apiInfo.endpoint); query.bind(2, apiInfo.version);
query.bind(3, apiInfo.version);
query.exec(); query.exec();
} catch (std::exception& ex) { } catch (std::exception& ex) {
+3 -1
View File
@@ -17,11 +17,13 @@ namespace repository { namespace local {
model::APIInfo retrieveAPIInfo(const std::string&); model::APIInfo retrieveAPIInfo(const std::string&);
[[deprecated("use the base class function")]]
bool doesAPIInfoTableExist(const std::string&);
void createAPiInfoTable(const std::string&); void createAPiInfoTable(const std::string&);
void deleteAPIInfo(const model::APIInfo&, const std::string&); void deleteAPIInfo(const model::APIInfo&, const std::string&);
void saveAPIInfo(const model::APIInfo&, const std::string&); void saveAPIInfo(const model::APIInfo&, const std::string&);
private: private:
//std::string apiInfoTable();
std::string apiInfoTable() noexcept; std::string apiInfoTable() noexcept;
}; };
}} }}
+44 -1
View File
@@ -23,6 +23,18 @@ namespace repository { namespace local {
return false; 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) bool BaseRepository::isTableEmpty(const std::string& appPath)
{ {
try { try {
@@ -33,7 +45,9 @@ namespace repository { namespace local {
SQLite::Statement query(db, queryStr); SQLite::Statement query(db, queryStr);
return query.hasRow(); const auto result = query.hasRow();
return result;
} catch (std::exception& ex) { } catch (std::exception& ex) {
auto msg = ex.what(); 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) std::string BaseRepository::pathOfDatabase(const std::string& appPath)
{ {
@@ -67,5 +95,20 @@ namespace repository { namespace local {
return dbPath; 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);
}
}} }}
+13
View File
@@ -8,18 +8,31 @@
#include <string> #include <string>
#include <exception> #include <exception>
#include <SQLiteCpp/Database.h>
namespace repository { namespace local { namespace repository { namespace local {
class BaseRepository { class BaseRepository {
public: public:
bool databaseExist(const std::string&); bool databaseExist(const std::string&);
bool doesTableExist(const std::string&);
bool isTableEmpty(const std::string&); bool isTableEmpty(const std::string&);
void initializedDatabase(const std::string&); void initializedDatabase(const std::string&);
void deleteRecord(const std::string&);
protected: protected:
enum class ConnType;
std::string pathOfDatabase(const std::string&); std::string pathOfDatabase(const std::string&);
SQLite::Database getDbConn(const std::string&, ConnType);
const std::string m_databaseName = "mear.db3"; const std::string m_databaseName = "mear.db3";
std::string m_tableName; std::string m_tableName;
enum class ConnType {
ReadOnly = 0,
ReadWrite,
Create
};
private: private:
}; };
} } } }
+1
View File
@@ -31,6 +31,7 @@ set (SOURCES
set (HEADERS set (HEADERS
APIRepository.h APIRepository.h
BaseRepository.h BaseRepository.h
Demo.h
model/APIInfo.h model/APIInfo.h
model/Song.h model/Song.h
model/Token.h model/Token.h
+150 -105
View File
@@ -1,6 +1,7 @@
// //
// Created by brahmix on 9/26/19. // Created by brahmix on 9/26/19.
// //
#include "Demo.h"
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@@ -23,33 +24,12 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <sqlite3.h> #include <sqlite3.h>
#include "model/APIInfo.h"
#include "model/Song.h"
#include "model/Token.h"
#include "model/User.h"
#include "APIRepository.h" #include "APIRepository.h"
#include "SongRepository.h" #include "SongRepository.h"
#include "Tok.h" #include "Tok.h"
#include "TokenRepository.h"
#include "UserRepository.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) 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) model::Song retrieveSong(const std::string& token, const std::string& baseUri, const int songId)
{ {
repository::SongRepository songRepo; repository::SongRepository songRepo;
@@ -121,6 +109,14 @@ model::Token fetchToken(const model::User& user, const std::string& apiUri)
return token; 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) 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) bool doesDatabaseExist(const std::string& dataPath)
{ {
repository::local::UserRepository userRepo; repository::local::UserRepository userRepo;
@@ -160,6 +142,13 @@ bool apiInformationExist(const std::string& dataPath)
return apiRepo.isTableEmpty(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) bool userCredentialExist(const std::string& dataPath)
{ {
repository::local::UserRepository userRepo; repository::local::UserRepository userRepo;
@@ -168,20 +157,20 @@ bool userCredentialExist(const std::string& dataPath)
} }
[[deprecated("c++ 17 issues")]] void saveAPIInfo(const model::APIInfo& apiInfo, const std::string& path)
void iterateDirectory(const std::string& path)
{ {
/** repository::local::APIRepository apiRepo;
auto somePath = std::filesystem::path(path); if (!apiRepo.databaseExist(path)) {
for (auto dir: std::filesystem::directory_iterator(somePath)) { apiRepo.initializedDatabase(path);
auto foundPath = dir;
if (foundPath.is_directory()) {
auto dirPath = foundPath.path();
} else {
auto filePath = foundPath.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) 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); userRepo.createUserTable(appDirectory);
} }
if (userRepo.isTableEmpty(appDirectory)) { if (!userRepo.isTableEmpty(appDirectory)) {
userRepo.deleteUserTable(appDirectory); userRepo.deleteUserTable(appDirectory);
} }
userRepo.saveUserCred(user, 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" extern "C"
JNIEXPORT jobjectArray JNIEXPORT jobjectArray
@@ -236,47 +241,52 @@ Java_com_example_mear_repositories_TrackRepository_retrieveSongs(
extern "C" extern "C"
JNIEXPORT jobject JNIEXPORT jobject
JNICALL JNICALL
Java_com_example_mear_activities_LoginActivity_retrieveSong( Java_com_example_mear_repositories_APIRepository_retrieveAPIInfoRecord(
JNIEnv *env, JNIEnv *env,
jobject thisObj, jobject thisObj,
jstring token, jstring pathStr ) {
jstring apiUri, const auto path = env->GetStringUTFChars(pathStr, nullptr);
jint idOfSong
)
{
const std::string tok = env->GetStringUTFChars(token, nullptr);
const std::string baseUri = env->GetStringUTFChars(apiUri, nullptr);
auto song = retrieveSong(tok, baseUri, idOfSong);
jclass songClass = env->FindClass( "com/example/mear/models/Song"); auto apiInfo = retrieveAPIInfo(path);
jmethodID jconstructor = env->GetMethodID( songClass, "<init>", "()V" );
jobject songObj = env->NewObject( songClass, jconstructor );
jmethodID songId = env->GetMethodID( songClass, "setId", "(I)V" ); jclass apiInfoClass = env->FindClass( "com/example/mear/models/APIInfo");
jmethodID songTitle = env->GetMethodID( songClass, "setTitle", "(Ljava/lang/String;)V" ); jmethodID jconstructor = env->GetMethodID( apiInfoClass, "<init>", "()V" );
jmethodID songAlbum = env->GetMethodID( songClass, "setAlbum", "(Ljava/lang/String;)V" ); jobject apiInfoObj = env->NewObject( apiInfoClass, jconstructor );
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" );
jint id = song.id; jmethodID uriId = env->GetMethodID( apiInfoClass, "setUri", "(Ljava/lang/String;)V" );
jstring title = env->NewStringUTF(song.title.c_str()); jmethodID versionId = env->GetMethodID( apiInfoClass, "setVersion", "(I)V" );
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;
env->CallVoidMethod( songObj, songId, id ); jint versionVal = apiInfo.version;
env->CallVoidMethod(songObj, songTitle, title); jstring uriVal = env->NewStringUTF(apiInfo.uri.c_str());
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);
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" 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" extern "C"
JNIEXPORT jboolean JNIEXPORT jboolean
JNICALL JNICALL
@@ -399,9 +388,22 @@ Java_com_example_mear_repositories_APIRepository_isAPIInfoTableEmpty(
jobject thisObj, jobject thisObj,
jstring pathStr 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" extern "C"
@@ -456,3 +458,46 @@ Java_com_example_mear_repositories_UserRepository_saveUserCredentials(
saveCredentials(usr, appDirectoryStr); 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);
}
+42
View File
@@ -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
+70
View File
@@ -3,3 +3,73 @@
// //
#include "TokenRepository.h" #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"; }
}}
+15 -1
View File
@@ -5,10 +5,24 @@
#ifndef MEAR_TOKENREPOSITORY_H #ifndef MEAR_TOKENREPOSITORY_H
#define 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 #endif //MEAR_TOKENREPOSITORY_H
+1
View File
@@ -44,6 +44,7 @@ namespace repository { namespace local {
} }
[[deprecated("use the base class doesTableExist() function")]]
bool UserRepository::doesUserTableExist(const std::string &appPath) bool UserRepository::doesUserTableExist(const std::string &appPath)
{ {
try { try {
+8
View File
@@ -11,6 +11,14 @@ namespace model {
class APIInfo class APIInfo
{ {
public: 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 uri;
std::string endpoint; std::string endpoint;
int version; int version;
@@ -5,9 +5,11 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.os.Environment
import android.os.IBinder import android.os.IBinder
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.widget.Toast import android.widget.Toast
import com.example.mear.R
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@@ -31,6 +33,13 @@ open class BaseServiceActivity: AppCompatActivity() {
val d = "l" 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 { protected fun isServiceRunning(serviceClass: Class<*>): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager 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.activities.BaseServiceActivity
import com.example.mear.adapters.RecyclerAdapter import com.example.mear.adapters.RecyclerAdapter
import com.example.mear.adapters.SongAdapter
import com.example.mear.models.TrackItems import com.example.mear.models.TrackItems
import com.example.mear.models.APIInfo
import com.example.mear.models.Song import com.example.mear.models.Song
import com.example.mear.models.Token
import com.example.mear.R import com.example.mear.R
import com.example.mear.repositories.TrackRepository import com.example.mear.repositories.*
class IcarusSongActivity : BaseServiceActivity() { class IcarusSongActivity : BaseServiceActivity() {
private lateinit var adapter: RecyclerAdapter private lateinit var adapter: SongAdapter
private lateinit var linearLayoutManager: LinearLayoutManager private lateinit var linearLayoutManager: LinearLayoutManager
private var songs: ArrayList<Song>? = null private var songs: ArrayList<Song>? = null
@@ -28,16 +32,16 @@ class IcarusSongActivity : BaseServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
try {
setContentView(R.layout.activity_icarus_song) setContentView(R.layout.activity_icarus_song)
setSupportActionBar(toolbar) //setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
try {
val colr = R.color.track_seek val colr = R.color.track_seek
window.statusBarColor = resources.getColor(R.color.track_seek) window.statusBarColor = resources.getColor(R.color.track_seek)
doBindService() doBindService()
initializeAdapter() initializeAdapter()
//initializeSongSearchListener() initializeSongSearchListener()
} }
catch (ex: Exception) { catch (ex: Exception) {
val msg = ex.message 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() { private fun initializeAdapter() {
try { try {
linearLayoutManager = LinearLayoutManager(this) linearLayoutManager = LinearLayoutManager(this)
trackList.layoutManager = linearLayoutManager 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}) 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) { catch (ex: Exception) {
val msg = ex.message 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 org.jetbrains.anko.toast
import com.example.mear.repositories.* 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() { class LoginActivity : BaseServiceActivity() {
@@ -45,29 +41,24 @@ class LoginActivity : BaseServiceActivity() {
val saveCred = saveUserCred.isChecked val saveCred = saveUserCred.isChecked
var apiInfo = APIInfo(apiUri.text.toString(), 1) var apiInfo = APIInfo(apiUri.text.toString(), 1)
//var apiUriStr = apiUri.text.toString()
val usr = User(username.text.toString(), password.text.toString()) val usr = User(username.text.toString(), password.text.toString())
if (apiInfo.uri.isEmpty()) {
apiInfo.uri = ""
}
val usrRepo = UserRepository() val usrRepo = UserRepository()
val trackRepo = TrackRepository() val tokenRepo = TokenRepository()
val myToken = usrRepo.fetchToken(usr, apiInfo.uri) val myToken = usrRepo.fetchToken(usr, apiInfo.uri)
try { try {
val pa = appDirectory() val pa = appDirectory()
val so = Song(5)
val song = trackRepo.fetchSong(myToken, so, apiInfo.uri)
if (saveCred && usrRepo.isTableEmpty(pa)) { if (saveCred && usrRepo.isTableEmpty(pa)) {
val api = APIRepository() val api = APIRepository()
if (api.isTableEmpty(pa)) { if (api.isTableEmpty(pa)) {
api.SaveRecord(apiInfo, pa) api.saveRecord(apiInfo, pa)
} }
usrRepo.saveCredentials(usr, pa) usrRepo.saveCredentials(usr, pa)
} }
//startActivity(Intent(this, IcarusSongActivity::class.java)) tokenRepo.saveToken(myToken, pa)
startActivity(Intent(this, IcarusSongActivity::class.java))
} }
catch (ex: Exception) { catch (ex: Exception) {
val msg = ex.message val msg = ex.message
@@ -88,18 +79,12 @@ class LoginActivity : BaseServiceActivity() {
} }
if (!apiRepo.isTableEmpty(pa)) { if (!apiRepo.isTableEmpty(pa)) {
val api = apiRepo.retrieveRecord(pa) val api = apiRepo.retrieveRecord(pa)
val s: String = "${api.uri}" + "${api.version} ${api.endpoint}" apiUri.setText(api.uri)
apiUri.setText(s)
} }
doBindService() doBindService()
} }
private fun appDirectory(): String {
return Environment.getDataDirectory().toString() + "/data/" +
resources.getString(R.string.app_relative_path)
}
private fun validFields(): Boolean { private fun validFields(): Boolean {
if (username.text.isEmpty()) { 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 package com.example.mear.management
import android.os.Environment
import com.example.mear.R
import java.io.File import java.io.File
import java.lang.Exception import java.lang.Exception
@@ -13,6 +15,7 @@ class MusicFiles (private val demoPath: File) {
private val musicSongLimit = Int.MAX_VALUE private val musicSongLimit = Int.MAX_VALUE
fun loadAllMusicPaths() { fun loadAllMusicPaths() {
try { try {
allSongs = mutableListOf() allSongs = mutableListOf()
@@ -18,7 +18,9 @@ import com.example.mear.constants.Interval
import com.example.mear.management.MusicFiles import com.example.mear.management.MusicFiles
import com.example.mear.management.TrackManager import com.example.mear.management.TrackManager
import com.example.mear.models.PlayControls import com.example.mear.models.PlayControls
import com.example.mear.models.APIInfo
import com.example.mear.models.Song import com.example.mear.models.Song
import com.example.mear.models.Token
import com.example.mear.models.Track import com.example.mear.models.Track
import com.example.mear.repositories.RepeatRepository import com.example.mear.repositories.RepeatRepository
import com.example.mear.repositories.ShuffleRepository 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) { fun icarusPlaySong(ctx: Context, token: String, uriBase: String, song: Song) {
var uriStr = uriBase var uriStr = uriBase
val id = song.id 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.models.APIInfo
import com.example.mear.repositories.BaseRepository
class APIRepository: 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) return saveAPIInfoRecord(api, path)
} }
} }
@@ -13,11 +13,11 @@ class TokenRepository: BaseRepository() {
private external fun retrieveTokenRecord(path: String): Token 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 saveTokenRecord(token: Token, path: String)
private external fun deleteTokenRecord(path: String) //private external fun deleteTokenRecord(path: String)
private external fun updateTokenRecord(token: Token, path: String) //private external fun updateTokenRecord(token: Token, path: String)
fun retrieveToken(path: String): Token { fun retrieveToken(path: String): Token {
@@ -26,7 +26,7 @@ class TokenRepository: BaseRepository() {
fun isTableEmpty(path: String): Boolean { fun isTableEmpty(path: String): Boolean {
return isTokeTableEmpty(path) return isTokenTableEmpty(path)
} }
@@ -34,6 +34,8 @@ class TokenRepository: BaseRepository() {
return saveTokenRecord(token, path) return saveTokenRecord(token, path)
} }
// TODO: implement this
/**
fun deleteToken(path: String) { fun deleteToken(path: String) {
return deleteTokenRecord(path) return deleteTokenRecord(path)
} }
@@ -41,4 +43,5 @@ class TokenRepository: BaseRepository() {
fun updateToken(token: Token, path: String) { fun updateToken(token: Token, path: String) {
return updateTokenRecord(token, path) return updateTokenRecord(token, path)
} }
*/
} }