diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 8345304..875bdd1 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -21,6 +21,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3 -std=c++17 -DNDEBUG") set (SOURCES APIRepository.cpp BaseRepository.cpp + CoverArtRepository.cpp Demo.cpp RepeatRepository.cpp ShuffleRepository.cpp @@ -33,6 +34,8 @@ set (SOURCES set (HEADERS APIRepository.h BaseRepository.h + model/CoverArt.h + CoverArtRepository.h Demo.h model/APIInfo.h model/Song.h diff --git a/app/src/main/cpp/CoverArtRepository.cpp b/app/src/main/cpp/CoverArtRepository.cpp new file mode 100644 index 0000000..e7b0346 --- /dev/null +++ b/app/src/main/cpp/CoverArtRepository.cpp @@ -0,0 +1,86 @@ +// +// Created by brahmix on 11/8/19. +// + +#include "CoverArtRepository.h" + +#include + +namespace repository { + + /** + template + std::vector CoverArtRepository::retrieveCoverArtRecords(const model::Token& token, + const std::string& uri) { + std::vector vals; + + return vals; + } + + template + std::vector CoverArtRepository::retrieveCoverArtData(const model::Token& token, + const C& cover, + const std::string& uri) { + std::string fullUri(uri); + if (fullUri.at(fullUri.size() - 1) != '/') { + fullUri.append("/"); + } + fullUri.append(downloadEndpoint()); + fullUri.append(std::to_string(cover.id)); + + CURL *curl; + CURLcode res; + struct curl_slist *chunk = nullptr; + curl = curl_easy_init(); + + std::vector vals; + + if (!curl) { + return vals; + } + + std::string data; + std::string authHeader("Authorization: Bearer "); + authHeader.append(token.accessToken); + constexpr auto keepAliveHeader = "Content-type: Keep-alive"; + chunk = curl_slist_append(chunk, authHeader.c_str()); + chunk = curl_slist_append(chunk, keepAliveHeader); + + curl_easy_setopt(curl, CURLOPT_URL, fullUri.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + + std::copy(data.begin(), data.end(), vals); + + return vals; + } + + template + C CoverArtRepository::retrieveCoverArtRecord(const model::Token& token, + const C& cover, + const std::string& uri) { + model::CoverArt cov; + + return cov; + } + + + template + constexpr auto CoverArtRepository::downloadEndpoint() noexcept { + return "api/v1/coverart/download"; + } + template + constexpr auto CoverArtRepository::recordsEndpoint() noexcept { + return "api/v1/coverart/"; + } + + template + size_t CoverArtRepository::respBodyRetriever(void *ptr, size_t size, size_t nmemb, char *e) { + ((std::string*)e)->append((char*)ptr, size * nmemb); + + return size * nmemb; + } + */ +} diff --git a/app/src/main/cpp/CoverArtRepository.h b/app/src/main/cpp/CoverArtRepository.h new file mode 100644 index 0000000..9f20243 --- /dev/null +++ b/app/src/main/cpp/CoverArtRepository.h @@ -0,0 +1,122 @@ +// +// Created by brahmix on 11/8/19. +// + +#ifndef MEAR_COVERARTREPOSITORY_H +#define MEAR_COVERARTREPOSITORY_H + +#include +#include +#include +#include + +#include + +#include "model/CoverArt.h" +#include "model/Token.h" + +using data = char; + +namespace repository { + template + class CoverArtRepository { + public: + std::vector retrieveCoverArtRecords(const model::Token&, const std::string&); + std::vector retrieveCoverArtData(const model::Token&, const C&, const std::string&); + + C retrieveCoverArtRecord(const model::Token&, const C&, const std::string&); + + private: + constexpr auto downloadEndpoint() noexcept; + constexpr auto recordsEndpoint() noexcept; + + static size_t respBodyRetriever(void*, size_t, size_t, char*); + }; + + + template + std::vector CoverArtRepository::retrieveCoverArtRecords(const model::Token& token, + const std::string& uri) { + std::vector vals; + + return vals; + } + + template + std::vector CoverArtRepository::retrieveCoverArtData(const model::Token& token, + const C& cover, + const std::string& uri) { + std::string fullUri(uri); + if (fullUri.at(fullUri.size() - 1) != '/') { + fullUri.append("/"); + } + fullUri.append(downloadEndpoint()); + fullUri.append(std::to_string(cover.id)); + + CURL *curl; + CURLcode res; + struct curl_slist *chunk = nullptr; + curl = curl_easy_init(); + + if (!curl) { + return std::vector(); + } + + std::string data; + std::string authHeader("Authorization: Bearer "); + authHeader.append(token.accessToken); + constexpr auto keepAliveHeader = "Content-type: Keep-alive"; + chunk = curl_slist_append(chunk, authHeader.c_str()); + chunk = curl_slist_append(chunk, keepAliveHeader); + + curl_easy_setopt(curl, CURLOPT_URL, fullUri.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + std::stringstream buff(data); + std::vector vals(data.begin(), data.end()); + //vals.reserve(data.size()); + //vals.assign(data.begin(), data.end()); + /** + vals.assign(std::istream_iterator(buff), + std::istream_iterator()); + */ + //std::copy(data.begin(), data.end(), &vals); + + return vals; + } + + template + C CoverArtRepository::retrieveCoverArtRecord(const model::Token& token, + const C& cover, + const std::string& uri) { + model::CoverArt cov; + + return cov; + } + + + template + constexpr auto CoverArtRepository::downloadEndpoint() noexcept { + return "api/v1/coverart/download/"; + } + template + constexpr auto CoverArtRepository::recordsEndpoint() noexcept { + return "api/v1/coverart/"; + } + + template + size_t CoverArtRepository::respBodyRetriever(void *ptr, size_t size, size_t nmemb, char *e) { + ((std::string*)e)->append((char*)ptr, size * nmemb); + + return size * nmemb; + } +} + + +#endif //MEAR_COVERARTREPOSITORY_H diff --git a/app/src/main/cpp/Demo.cpp b/app/src/main/cpp/Demo.cpp index b715458..e7ae874 100644 --- a/app/src/main/cpp/Demo.cpp +++ b/app/src/main/cpp/Demo.cpp @@ -24,6 +24,7 @@ #include #include "APIRepository.h" +#include "CoverArtRepository.h" #include "RepeatRepository.h" #include "ShuffleRepository.h" #include "SongRepository.h" @@ -51,6 +52,7 @@ jobject songToObj(JNIEnv *env, const model::Song& song) 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 songAlbumArtist = env->GetMethodID(songClass, "setAlbumArtist", "(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" ); @@ -60,6 +62,7 @@ jobject songToObj(JNIEnv *env, const model::Song& song) jint id = song.id; jstring title = env->NewStringUTF(song.title.c_str()); jstring album = env->NewStringUTF(song.album.c_str()); + jstring albumArtist = env->NewStringUTF(song.albumArtist.c_str()); jstring artist = env->NewStringUTF(song.artist.c_str()); jstring genre = env->NewStringUTF(song.genre.c_str()); jint duration = song.duration; @@ -69,6 +72,7 @@ jobject songToObj(JNIEnv *env, const model::Song& song) env->CallVoidMethod( songObj, songId, id ); env->CallVoidMethod(songObj, songTitle, title); env->CallVoidMethod(songObj, songAlbum, album); + env->CallVoidMethod(songObj, songAlbumArtist, albumArtist); env->CallVoidMethod(songObj, songArtist, artist); env->CallVoidMethod(songObj, songGenre, genre); env->CallVoidMethod(songObj, songDuration, duration); @@ -113,6 +117,9 @@ model::Token fetchToken(const model::User& user, const std::string& apiUri) model::Token retrieveSavedToken(const std::string& path) { repository::local::TokenRepository tokenRepo; + if (!tokenRepo.databaseExist(path)) { + tokenRepo.initializedDatabase(path); + } auto token = tokenRepo.retrieveToken(path); return token; @@ -122,6 +129,9 @@ model::Token retrieveSavedToken(const std::string& path) model::User retrieveCredentials(const std::string& dataPath) { repository::local::UserRepository userRepo; + if (!userRepo.databaseExist(dataPath)) { + userRepo.initializedDatabase(dataPath); + } auto user = userRepo.retrieveUserCredentials(dataPath); return user; @@ -131,6 +141,9 @@ model::User retrieveCredentials(const std::string& dataPath) int retrieveRepeatMode(const std::string& path) { repository::local::RepeatRepository repeatRepo; + if (!repeatRepo.databaseExist(path)) { + repeatRepo.initializedDatabase(path); + } if (!repeatRepo.doesTableExist(path)) { repeatRepo.createRepeatTable(path); } @@ -143,6 +156,9 @@ int retrieveRepeatMode(const std::string& path) int retrieveShuffleMode(const std::string& path) { repository::local::ShuffleRepository shuffleRepo; + if (!shuffleRepo.databaseExist(path)) { + shuffleRepo.initializedDatabase(path); + } if (!shuffleRepo.doesTableExist(path)) { shuffleRepo.createShuffleTable(path); } @@ -236,12 +252,18 @@ void saveToken(const model::Token& token, const std::string& path) void updateRepeatMode(const std::string& path) { repository::local::RepeatRepository repeatRepo; + if (!repeatRepo.databaseExist(path)) { + repeatRepo.initializedDatabase(path); + } repeatRepo.updateRepeat(path); } void updateShuffleMode(const std::string& path) { repository::local::ShuffleRepository shuffleRepo; + if (!shuffleRepo.databaseExist(path)) { + shuffleRepo.initializedDatabase(path); + } shuffleRepo.updateShuffle(path); } @@ -418,6 +440,47 @@ Java_com_example_mear_repositories_UserRepository_logUser( } +extern "C" +JNIEXPORT jbyteArray +JNICALL +Java_com_example_mear_repositories_CoverArtRepository_retrieveCoverArtImage( + JNIEnv *env, + jobject thisObj, + jobject tokenObj, + jobject coverArt, + jstring apiUri + ) { + jclass coverArtClass = env->GetObjectClass(coverArt); + auto idField = env->GetFieldID(coverArtClass, "id", "I"); + auto titleField = env->GetFieldID(coverArtClass, "title", "Ljava/lang/String;"); + auto id = env->GetIntField(coverArt, idField); + auto title = (jstring)env->GetObjectField(coverArt, titleField); + + jclass tokenClass = env->GetObjectClass(tokenObj); + auto accessTokenId = env->GetFieldID(tokenClass, "accessToken", "Ljava/lang/String;"); + auto accessTokenVal = (jstring) env->GetObjectField(tokenObj, accessTokenId); + + model::Token token; + token.accessToken = env->GetStringUTFChars(accessTokenVal, nullptr); + + model::CoverArt cover(id, env->GetStringUTFChars(title, nullptr)); + repository::CoverArtRepository coverArtRepo; + auto data = coverArtRepo.retrieveCoverArtData(token, cover, env->GetStringUTFChars(apiUri, nullptr)); + + jbyteArray image = env->NewByteArray(data.size()); + //for (auto& b: data) { + env->SetByteArrayRegion(image, 0, data.size(), (jbyte*) data.data()); + //} + //constexpr auto testImagePath = "/data/data/com.example.mear/image.png"; + //std::ofstream out(testImagePath, std::ios::out | std::ios::binary); + //out.write(reinterpret_cast(data.data()), data.size()); + //out.close(); + + + return image; +} + + extern "C" JNIEXPORT jint JNICALL diff --git a/app/src/main/cpp/Demo.h b/app/src/main/cpp/Demo.h index 9c924d0..82a1512 100644 --- a/app/src/main/cpp/Demo.h +++ b/app/src/main/cpp/Demo.h @@ -10,6 +10,7 @@ #include #include "model/APIInfo.h" +#include "model/CoverArt.h" #include "model/Song.h" #include "model/Token.h" #include "model/User.h" diff --git a/app/src/main/cpp/SongRepository.cpp b/app/src/main/cpp/SongRepository.cpp index 6900dc2..33737ba 100644 --- a/app/src/main/cpp/SongRepository.cpp +++ b/app/src/main/cpp/SongRepository.cpp @@ -15,7 +15,8 @@ namespace repository { if (fullUri.at(fullUri.size()-1) != '/') { fullUri.append("/"); } - fullUri.append("api/v1/song"); + //fullUri.append("api/v1/song"); + fullUri.append(songRecordEndpoint()); std::vector songs; CURL *curl; @@ -27,29 +28,31 @@ namespace repository { return songs; } - constexpr auto EXPECTED_CHAR_AMOUNT = 100000; - auto resp = std::make_unique(EXPECTED_CHAR_AMOUNT); + std::string resp; std::string authInfo("Authorization: Bearer "); authInfo.append(token.accessToken); + constexpr auto contentType = "Content-type: Keep-alive"; chunk = curl_slist_append(chunk, authInfo.c_str()); + chunk = curl_slist_append(chunk, contentType); curl_easy_setopt(curl, CURLOPT_URL, fullUri.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp.get()); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res == CURLE_OK) { - auto songsJson = nlohmann::json::parse(resp.get()); + auto songsJson = nlohmann::json::parse(resp.c_str()); for (auto& songJson: songsJson) { model::Song song(songJson["id"].get(), songJson["title"].get(), songJson["artist"].get(), songJson["album"].get(), songJson["genre"].get(), songJson["duration"].get(), songJson["year"].get()); + song.albumArtist = songJson["album_artist"].get(); song.coverArtId = songJson["coverart_id"].get(); songs.push_back(song); @@ -63,13 +66,13 @@ namespace repository { model::Song SongRepository::retrieveSong(const model::Token& token, const model::Song& sng, const std::string& baseUri) { std::string uri(baseUri); - uri.append("/api/v1/song/"); + uri.append(songRecordEndpoint()); uri.append(std::to_string(sng.id)); model::Song song; CURL *curl; CURLcode res; - struct curl_slist *chunk = NULL; + struct curl_slist *chunk = nullptr; curl = curl_easy_init(); if (!curl) { @@ -80,7 +83,9 @@ namespace repository { std::string authInfo("Authorization: Bearer "); authInfo.append(token.accessToken); + constexpr auto contentType = "Content-type: Keep-alive"; chunk = curl_slist_append(chunk, authInfo.c_str()); + chunk = curl_slist_append(chunk, contentType); curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); @@ -96,6 +101,7 @@ namespace repository { song.id = s["id"].get(); song.title = s["title"].get(); song.album = s["album"].get(); + song.albumArtist = s["album_artist"].get(); song.artist = s["artist"].get(); song.genre = s["genre"].get(); song.duration = s["duration"].get(); @@ -111,9 +117,14 @@ namespace repository { size_t SongRepository::respBodyRetriever(void* ptr, size_t size, size_t nmemb, char *e) { - std::memcpy(e, ptr, nmemb); - e[nmemb] = '\0'; - - return nmemb; + ((std::string*)e)->append((char*)ptr, size * nmemb); + return size * nmemb; } + + + /** + constexpr auto SongRepository::songRecordEndpoint() noexcept { + return "api/v1/song"; + } + */ } diff --git a/app/src/main/cpp/SongRepository.h b/app/src/main/cpp/SongRepository.h index 1f88514..45f0016 100644 --- a/app/src/main/cpp/SongRepository.h +++ b/app/src/main/cpp/SongRepository.h @@ -20,7 +20,13 @@ namespace repository { model::Song retrieveSong(const model::Token&, const model::Song&, const std::string&); private: static size_t respBodyRetriever(void*, size_t, size_t, char*); + + constexpr auto songRecordEndpoint() noexcept; }; + + constexpr auto SongRepository::songRecordEndpoint() noexcept { + return "api/v1/song/"; + } } diff --git a/app/src/main/cpp/Tok.cpp b/app/src/main/cpp/Tok.cpp index 7697076..9346023 100644 --- a/app/src/main/cpp/Tok.cpp +++ b/app/src/main/cpp/Tok.cpp @@ -4,6 +4,7 @@ #include "Tok.h" +#include #include #include @@ -13,6 +14,7 @@ namespace manager { model::Token Tok::fetchTokenTrans(const model::User &user, const std::string& uri) { CURL *curl; + struct curl_slist *chunk = nullptr; CURLcode res; curl = curl_easy_init(); @@ -21,71 +23,49 @@ namespace manager { return model::Token("none"); } - auto resp = std::make_unique(10000); - + std::string resp; const auto loginUri = fetchLoginUri(uri); const auto obj = userJsonString(user); + constexpr auto contentType = "Content-type: Keep-alive"; + chunk = curl_slist_append(chunk , contentType); + curl_easy_setopt(curl, CURLOPT_URL, loginUri.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, obj.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp.get()); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res == CURLE_OK) { - auto s = nlohmann::json::parse(resp.get()); + auto s = nlohmann::json::parse(resp); + const auto tokenStr = std::move(s["token"].get()); - return model::Token(s["token"].get()); + return model::Token(std::move(tokenStr)); } return model::Token("failure"); } - std::string Tok::fetchToken(const model::User &user, const std::string& uri) { - CURL *curl; - CURLcode res; - - curl = curl_easy_init(); - - if (!curl) { - return "none"; - } - - auto resp = std::make_unique(10000); - - const auto loginUri = fetchLoginUri(uri); - const auto obj = userJsonString(user); - - curl_easy_setopt(curl, CURLOPT_URL, loginUri.c_str()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, obj.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp.get()); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - - if (res == CURLE_OK) { - auto s = nlohmann::json::parse(resp.get()); - return s["token"].get(); - } - - return "failure"; + constexpr auto Tok::loginEndpoint() noexcept + { + return "api/v1/login"; } - - std::string Tok::fetchLoginUri(const std::string& baseUri) + std::string Tok::fetchLoginUri(const std::string& uriBase) noexcept { - std::string uri(baseUri); - uri.append("/api/v1/login"); + std::string uri(uriBase); + if (uri.at(uri.size() - 1) != '/') { + uri.append("/"); + } + uri.append(loginEndpoint()); return uri; } - std::string Tok::userJsonString(const model::User& user) { nlohmann::json usr; @@ -98,9 +78,8 @@ namespace manager { size_t Tok::respBodyRetriever(void* ptr, size_t size, size_t nmemb, char *e) { - std::memcpy(e, ptr, nmemb); - e[nmemb] = '\0'; + ((std::string*)e)->append((char*)ptr, size * nmemb); - return nmemb; + return size * nmemb; } } diff --git a/app/src/main/cpp/Tok.h b/app/src/main/cpp/Tok.h index f959853..0d56fcd 100644 --- a/app/src/main/cpp/Tok.h +++ b/app/src/main/cpp/Tok.h @@ -16,10 +16,9 @@ namespace manager { class Tok { public: model::Token fetchTokenTrans(const model::User&, const std::string&); - - std::string fetchToken(const model::User&, const std::string&); private: - std::string fetchLoginUri(const std::string&); + std::string fetchLoginUri(const std::string&) noexcept; + constexpr auto loginEndpoint() noexcept; std::string userJsonString(const model::User&); static size_t respBodyRetriever(void*, size_t, size_t, char*); diff --git a/app/src/main/cpp/TokenRepository.cpp b/app/src/main/cpp/TokenRepository.cpp index ef2e39b..6f42485 100644 --- a/app/src/main/cpp/TokenRepository.cpp +++ b/app/src/main/cpp/TokenRepository.cpp @@ -26,7 +26,8 @@ namespace repository { namespace local { SQLite::Statement query(db, queryString); auto result = query.executeStep(); - model::Token token(query.getColumn(1).getString()); + //const std::string t(query.getColumn(1).getString()); + token.accessToken = std::move(query.getColumn(1).getString()); return token; } catch (std::exception& ex) { diff --git a/app/src/main/cpp/model/CoverArt.h b/app/src/main/cpp/model/CoverArt.h new file mode 100644 index 0000000..e5657f4 --- /dev/null +++ b/app/src/main/cpp/model/CoverArt.h @@ -0,0 +1,22 @@ +// +// Created by brahmix on 11/8/19. +// + +#ifndef MEAR_COVERART_H +#define MEAR_COVERART_H + +#include + +namespace model { + class CoverArt { + public: + CoverArt() = default; + CoverArt(const int id, const std::string& title) : + id(id), title(title) { } + + int id; + std::string title; + }; +} + +#endif //MEAR_COVERART_H diff --git a/app/src/main/cpp/model/Song.h b/app/src/main/cpp/model/Song.h index 2de8619..c288937 100644 --- a/app/src/main/cpp/model/Song.h +++ b/app/src/main/cpp/model/Song.h @@ -30,6 +30,7 @@ public: int id; std::string title; std::string artist; + std::string albumArtist; std::string album; std::string genre; int duration; diff --git a/app/src/main/cpp/model/Token.h b/app/src/main/cpp/model/Token.h index 2bb97d1..b59ea0b 100644 --- a/app/src/main/cpp/model/Token.h +++ b/app/src/main/cpp/model/Token.h @@ -15,7 +15,7 @@ namespace model { Token() = default; Token(const std::string& accessToken) : accessToken(accessToken) { } Token(const std::string&& accessToken) : - accessToken(std::move(accessToken)) { } + accessToken(accessToken) { } std::string accessToken; }; 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 0c83dc7..44d0feb 100644 --- a/app/src/main/java/com/example/mear/activities/IcarusSongActivity.kt +++ b/app/src/main/java/com/example/mear/activities/IcarusSongActivity.kt @@ -31,7 +31,6 @@ class IcarusSongActivity : BaseServiceActivity() { //setSupportActionBar(toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) - val colr = R.color.track_seek window.statusBarColor = resources.getColor(R.color.track_seek) doBindService() initializeAdapter() 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 ec865d0..2624448 100644 --- a/app/src/main/java/com/example/mear/activities/LoginActivity.kt +++ b/app/src/main/java/com/example/mear/activities/LoginActivity.kt @@ -1,15 +1,15 @@ package com.example.mear.activities +import kotlinx.android.synthetic.main.activity_login.* +import kotlinx.android.synthetic.main.content_login.* + import android.content.Intent import android.os.Bundle import android.support.design.widget.Snackbar -import com.example.mear.R -import com.example.mear.models.* - -import kotlinx.android.synthetic.main.activity_login.* -import kotlinx.android.synthetic.main.content_login.* import org.jetbrains.anko.toast +import com.example.mear.models.* +import com.example.mear.R import com.example.mear.repositories.* class LoginActivity : BaseServiceActivity() { diff --git a/app/src/main/java/com/example/mear/activities/MainActivity.kt b/app/src/main/java/com/example/mear/activities/MainActivity.kt index 33f8211..5eac42b 100644 --- a/app/src/main/java/com/example/mear/activities/MainActivity.kt +++ b/app/src/main/java/com/example/mear/activities/MainActivity.kt @@ -29,11 +29,11 @@ import org.jetbrains.anko.imageBitmap import com.example.mear.listeners.TrackElaspingChange import com.example.mear.models.Song import com.example.mear.R -import com.example.mear.repositories.PlayCountRepository -import com.example.mear.repositories.RepeatRepository +import com.example.mear.repositories.* import com.example.mear.repositories.RepeatRepository.RepeatTypes -import com.example.mear.repositories.ShuffleRepository import com.example.mear.repositories.ShuffleRepository.ShuffleTypes +import com.example.mear.util.ConvertByteArray +import org.jetbrains.anko.image class MainActivity : BaseServiceActivity() { @@ -44,6 +44,7 @@ class MainActivity : BaseServiceActivity() { private var updateLibraryHandler: Handler? = Handler() private var playCountUpdated: Boolean? = false private var serviceBinded: Boolean? = false + private var metadataInitialized: Boolean = false private var repeatOn: Boolean? = false private var shuffleOn: Boolean? = false @@ -262,12 +263,25 @@ class MainActivity : BaseServiceActivity() { (currSong.duration % 60) ) + val coverArtRepo = CoverArtRepository() + val apiRepo = APIRepository() + val tokenRepo = TokenRepository() + val path = appDirectory() + val apiUri = apiRepo.retrieveRecord(path) + val myToken = tokenRepo.retrieveToken(path) + val coverArt = CoverArtRepository.CoverArt(currSong.coverArtId, currSong.title) + val imgData = coverArtRepo.fetchCoverArtImage(myToken, coverArt, apiUri.uri) + val ImageConvByte = ConvertByteArray(imgData) + val convertedImage = ImageConvByte.convertToBmp(imgData) + + resetControls() TrackTitle.text = currSong.title ArtistTitle.text = currSong.artist AlbumTitle.text = currSong.album TrackDuration.text = dur + TrackCover.imageBitmap = convertedImage } } catch (ex: Exception) { @@ -298,6 +312,32 @@ class MainActivity : BaseServiceActivity() { } } + private fun songMetadataLoaded(): Boolean { + if (TrackTitle.text.isEmpty()) { + return false + } + if (ArtistTitle.text.isEmpty()) { + return false + } + if (AlbumTitle.text.isEmpty()) { + return false + } + if (TrackCover.image == null) { + return false + } + + val currSong = musicService!!.getCurrentSong() + + if (!TrackTitle.text.equals(currSong.title)) { + return false + } + if ((ArtistTitle.text != currSong.artist)) { + return false + } + + return true + } + // TODO: Might need this down the road for playing songs off an external // storage private fun permissionPrompt() { @@ -348,7 +388,9 @@ class MainActivity : BaseServiceActivity() { private var musicTrackTimeUpdateTask = object: Runnable { override fun run() { try { - configureTrackDisplay() + if (!songMetadataLoaded()) { + configureTrackDisplay() + } val currentPosition = musicService!!.currentPositionOfTrack() / 1000 val dur = String.format( "%02d:%02d", TimeUnit.SECONDS.toMinutes(currentPosition.toLong()), (currentPosition % 60) ) diff --git a/app/src/main/java/com/example/mear/adapters/SongAdapter.kt b/app/src/main/java/com/example/mear/adapters/SongAdapter.kt index 8df9e3c..007cf09 100644 --- a/app/src/main/java/com/example/mear/adapters/SongAdapter.kt +++ b/app/src/main/java/com/example/mear/adapters/SongAdapter.kt @@ -91,7 +91,7 @@ class SongAdapter(val mOnClickListener: (Song) -> Unit, this.songItem = songItems v.trackTitle.setText(songItems.title) - v.trackArtist.setText(songItems.artist) + v.trackArtist.setText(songItems.albumArtist) v.setOnClickListener { clickList(songItem!!)} } diff --git a/app/src/main/java/com/example/mear/models/Song.kt b/app/src/main/java/com/example/mear/models/Song.kt index 894b100..603eab5 100644 --- a/app/src/main/java/com/example/mear/models/Song.kt +++ b/app/src/main/java/com/example/mear/models/Song.kt @@ -1,5 +1,6 @@ package com.example.mear.models -class Song (var id: Int = 3, var title: String = "", var album: String = "", var artist: String = "", +class Song (var id: Int = 3, var title: String = "", var album: String = "", + var albumArtist: String = "", var artist: String = "", var genre: String = "", var year: Int = 0, var duration: Int = 0, var coverArtId: Int = 0) diff --git a/app/src/main/java/com/example/mear/repositories/CoverArtRepository.kt b/app/src/main/java/com/example/mear/repositories/CoverArtRepository.kt new file mode 100644 index 0000000..308fced --- /dev/null +++ b/app/src/main/java/com/example/mear/repositories/CoverArtRepository.kt @@ -0,0 +1,18 @@ +package com.example.mear.repositories + +import com.example.mear.models.Token + +class CoverArtRepository : BaseRepository() { + + private external fun retrieveCoverArtImage(token: Token, coverArt: CoverArt, apiUri: String): ByteArray + + + fun fetchCoverArtImage(token: Token, coverArt: CoverArt, apiUri: String): ByteArray { + val img = retrieveCoverArtImage(token, coverArt, apiUri) + + return img + } + + // TODO: Move this to it's own file later on + class CoverArt (var id: Int = 0, var title: String = "") +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mear/util/ConvertByteArray.kt b/app/src/main/java/com/example/mear/util/ConvertByteArray.kt index e2c9831..85b23be 100644 --- a/app/src/main/java/com/example/mear/util/ConvertByteArray.kt +++ b/app/src/main/java/com/example/mear/util/ConvertByteArray.kt @@ -7,7 +7,12 @@ class ConvertByteArray(private val byteArray: ByteArray?) { fun convertToBmp(): Bitmap { val songImage = BitmapFactory - .decodeByteArray(byteArray, 0, byteArray!!.size) + .decodeByteArray(byteArray!!, 0, byteArray!!.size) + + return songImage + } + fun convertToBmp(rawData: ByteArray): Bitmap { + val songImage = BitmapFactory.decodeByteArray(rawData, 0, rawData.size) return songImage }