Added feature to delete a song. Now working on downloading the song in the background

This commit is contained in:
kdeng00
2020-01-11 15:54:49 -05:00
parent 8755cb1137
commit c893a38192
41 changed files with 365 additions and 524 deletions
+69 -58
View File
File diff suppressed because one or more lines are too long
+32 -14
View File
@@ -18,7 +18,7 @@ android {
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared", "-DANDROID=true"
@@ -47,23 +47,41 @@ android {
}
dependencies {
def work_version = "2.2.0"
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation "org.jetbrains.anko:anko:0.10.8"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.ealva:ealvatag:0.4.3'
implementation 'com.ealva:ealvalog:0.5.0'
implementation 'com.ealva:ealvalog-core:0.5.0'
implementation 'com.ealva:ealvalog-android:0.5.0'
implementation 'com.google.guava:guava:23.0'
implementation 'com.squareup.okio:okio:2.4.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.github.XuDeveloper:XPopupWindow:1.0.1'
// implementation 'com.google.guava:guava:27.0'
implementation 'com.google.guava:guava:27.0.1-android'
implementation 'com.squareup.okio:okio:2.4.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation "org.jetbrains.anko:anko:0.10.8"
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
testImplementation 'junit:junit:4.12'
}
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '27.0.0'
}
}
}
}
@@ -1,7 +1,7 @@
package com.example.mear
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
+1
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.mear">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+37
View File
@@ -175,6 +175,24 @@ int retrieveShuffleMode(const std::string& path) {
}
template<class Song = model::Song, typename Str = std::string, typename B = bool>
B deleteSong(Song& song, const Str& path) {
manager::DirectoryManager dirMgr;
if (!dirMgr.doesSongExist(song, path)) {
return false;
}
auto result = dirMgr.deleteSong(song, path);
if (!result) {
return result;
}
repository::local::SongRepository songRepo(path);
songRepo.deleteSongFromTable(song, path);
return result;
}
bool doesDatabaseExist(const std::string& dataPath) {
repository::local::UserRepository userRepo;
const auto result = userRepo.databaseExist(dataPath);
@@ -286,6 +304,7 @@ void downloadSong(Song& song, const Token& token, const Str& path) {
saveSong.close();
song.path = downloadedSong.path;
song.downloaded = true;
repository::local::SongRepository localSongRepo(path);
localSongRepo.saveSong(downloadedSong, path);
}
@@ -703,6 +722,24 @@ Java_com_example_mear_repositories_TokenRepository_isTokenTableEmpty(
return doesTokenExist(dataPath);
}
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_example_mear_repositories_TrackRepository_deleteSong(
JNIEnv *env,
jobject thisObj,
jobject songObj,
jstring pathStr
) {
auto songClass = env->GetObjectClass(songObj);
auto path = env->GetStringUTFChars(pathStr, nullptr);
auto song = ObjToSong(env, songObj);
const auto result = deleteSong(song, path);
return result;
}
extern "C"
JNIEXPORT jboolean
JNICALL
+36 -10
View File
@@ -22,7 +22,7 @@ namespace manager {
public:
template<typename Str = std::string>
std::string fullSongPath(const Song& song, const Str& path) {
std::string s = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
std::string s = rootMusicDirectory(path);
s.append(song.albumArtist);
s.append("/");
s.append(song.album);
@@ -51,7 +51,7 @@ namespace manager {
template<typename Str = std::string>
Str albumPath(const Song& song, const Str& path) {
std::string s = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
auto s = rootMusicDirectory<std::string>(path);
s.append(song.albumArtist);
s.append("/");
s.append(song.album);
@@ -76,7 +76,7 @@ namespace manager {
template<typename Str = std::string>
Str artistPath(const Song& song, const Str& path) {
Str s = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
Str s = rootMusicDirectory(path);
s.append(song.albumArtist);
return s.c_str();
@@ -101,6 +101,10 @@ namespace manager {
template<typename Str = std::string>
void createSongDirectory(const Song& song, const Str& path) {
if (!rootMusicDirectoryExists<std::string>(path)) {
const std::string p(rootMusicDirectory<std::string>(path));
auto status = mkdir(p.c_str(), 0777);
}
if (!artistDirectoryExists(song, path)) {
auto status = mkdir(artistPath<std::string>(song, path).c_str(), 0777);
}
@@ -112,14 +116,20 @@ namespace manager {
}
}
template<typename Str = std::string>
void deleteSongDirectory(const Song& song, const Str& path) {
}
private:
template<typename Str = std::string>
static auto rootMusicDirectory(const Str& path) {
auto rootPath = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
rootPath.append("music/");
return rootPath;
}
template<typename Str = std::string, typename B = bool>
B albumDirectoryExists(const Song song, const Str& path) {
auto albumPath = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
// auto albumPath = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
auto albumPath = rootMusicDirectory<std::string>(path);
albumPath.append(song.albumArtist);
albumPath.append("/");
albumPath.append(song.album);
@@ -159,8 +169,9 @@ namespace manager {
}
template<typename Str = std::string, typename B = bool>
B artistDirectoryExists(const Song song, const Str& path) {
auto artistPath = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
B artistDirectoryExists(const Song& song, const Str& path) {
// auto artistPath = utility::GeneralUtility::appendForwardSlashToUri<std::string>(path);
auto artistPath = rootMusicDirectory<std::string>(path);
artistPath.append(song.albumArtist);
DIR* dir = opendir(artistPath.c_str());
@@ -173,6 +184,21 @@ namespace manager {
return true;
}
template<typename Str = std::string, typename B = bool>
B rootMusicDirectoryExists(const Str& path) {
auto rootPath = rootMusicDirectory<std::string>(path);
DIR *dir = opendir(rootPath.c_str());
if (dir) {
closedir(dir);
return true;
} else if (ENOENT == errno) {
return false;
}
return true;
}
};
}
@@ -3,10 +3,10 @@ package com.example.mear
import android.content.res.Configuration
import android.os.Bundle
import android.preference.PreferenceActivity
import android.support.annotation.LayoutRes
import android.support.v7.app.ActionBar
import android.support.v7.app.AppCompatDelegate
import android.support.v7.widget.Toolbar
import androidx.annotation.LayoutRes
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.Toolbar
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
@@ -8,7 +8,7 @@ import android.content.ServiceConnection
import android.os.Bundle
import android.os.Environment
import android.os.IBinder
import android.support.v7.app.AppCompatActivity
import androidx.appcompat.app.AppCompatActivity
import android.widget.Toast
import com.example.mear.R
@@ -1,8 +1,8 @@
package com.example.mear.activities
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.SearchView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.appcompat.widget.SearchView
import kotlinx.android.synthetic.main.content_song_view.*
@@ -48,7 +48,8 @@ class IcarusSongActivity : BaseServiceActivity() {
private fun initializeAdapter() {
try {
linearLayoutManager = LinearLayoutManager(this)
linearLayoutManager =
LinearLayoutManager(this)
trackList.layoutManager = linearLayoutManager
val pa = appDirectory()
@@ -57,7 +58,8 @@ class IcarusSongActivity : BaseServiceActivity() {
val apiRepo = APIRepository()
val token = tokenRepo.retrieveToken(pa)
val apiInfo = apiRepo.retrieveRecord(pa)
val fetchedSongs = trackRepo.fetchSongsIncludingDownloaded(token, apiInfo.uri, pa).toCollection(ArrayList())
val fetchedSongs = trackRepo.fetchSongsIncludingDownloaded(token, apiInfo.uri, pa)
.toCollection(ArrayList())
songs = fetchedSongs
songs!!.sortedWith(compareBy{it.title})
@@ -5,7 +5,7 @@ import kotlinx.android.synthetic.main.content_login.*
import android.content.Intent
import android.os.Bundle
import android.support.design.widget.Snackbar
import com.google.android.material.snackbar.Snackbar
import org.jetbrains.anko.toast
import com.example.mear.models.*
@@ -18,12 +18,19 @@ import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import android.view.MenuItem
import android.view.View
import android.widget.PopupMenu
import android.widget.Toast
/**
import androidx.work.Data
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
*/
import org.jetbrains.anko.image
import org.jetbrains.anko.imageBitmap
import com.example.mear.listeners.TrackElaspingChange
@@ -32,7 +39,7 @@ import com.example.mear.repositories.*
import com.example.mear.repositories.RepeatRepository.RepeatTypes
import com.example.mear.repositories.ShuffleRepository.ShuffleTypes
import com.example.mear.util.ConvertByteArray
import org.jetbrains.anko.image
// import com.example.mear.workers.IcarusSyncManager
class MainActivity : BaseServiceActivity() {
@@ -51,6 +58,18 @@ class MainActivity : BaseServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
/**
val workManager = WorkManager.getInstance()
val constraints = androidx.work.Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED).build()
val task = OneTimeWorkRequest.Builder(IcarusSyncManager::class.java)
.setConstraints(constraints).build()
workManager.enqueue(task)
*/
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
@@ -377,7 +396,12 @@ class MainActivity : BaseServiceActivity() {
val trackRepo = TrackRepository()
// The method I am calling has not been implemented on the C++
// side
trackRepo.delete(musicService!!.getCurrentSong(), appPath)
var currSong = musicService!!.getCurrentSong()
Toast.makeText(this, "Deleting song", Toast.LENGTH_SHORT).show()
val result = trackRepo.delete(currSong, appPath)
if (result) {
musicService!!.removeSongDownloadStatus(currSong)
}
}
R.id.action_song_download -> {
val appPath = appDirectory()
@@ -387,19 +411,43 @@ class MainActivity : BaseServiceActivity() {
var song = musicService!!.getCurrentSong()
val token = tokenRepo.retrieveToken(appPath)
val apiInfo = apiRepo.retrieveRecord(appPath)
song = trackRepo.download(token, song, appPath)
musicService!!.changeSongDownloadStatus()
// val apiInfo = apiRepo.retrieveRecord(appPath)
// song = trackRepo.download(token, song, appPath)
// musicService!!.changeSongDownloadStatus(song)
// TODO: implement something to include the downloaded song into the songQueue
// essentially replacing the song that already exists, that way one can
// actually access the file without having to restart the app
Toast.makeText(this, "Downloading song", Toast.LENGTH_SHORT).show()
// val dMgr = IcarusSyncManager
musicService!!.downloadSong(token, song, appPath)
//val workManager = WorkManager.getInstance()
/**
val constraints = androidx.work.Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED).build()
val task = OneTimeWorkRequest.Builder(IcarusSyncManager::class.java)
.setConstraints(constraints)
val data = Data.Builder()
data.putString("accessToken", token.accessToken)
data.putString("appPath", appPath)
data.putInt("songId", song.id)
task.setInputData(data.build())
*/
//workManager.enqueue(task)
//WorkManager.getInstance().enqueue(task.build())
}
/**
R.id.action_song_play_count-> {
// TODO: not implemented
val trk = musicService!!.getCurrentSong()
val pc = PlayCountRepository(this).getPlayCount(trk.id)
val playCount = pc.playCount
// val pc = PlayCountRepository(this).getPlayCount(trk.id)
// val playCount = pc.playCount
Toast.makeText(this, "Song played $playCount times", Toast.LENGTH_LONG).show()
}
*/
}
true
}
@@ -2,9 +2,7 @@ package com.example.mear.activities
import android.content.Context
import android.os.Bundle
import android.os.Environment
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.CardView
import androidx.appcompat.app.AppCompatActivity;
import android.view.View
import android.widget.LinearLayout
import android.widget.Toast
@@ -13,11 +11,8 @@ import java.lang.Exception
import kotlinx.android.synthetic.main.activity_settings.*
import kotlinx.android.synthetic.main.content_settings.*
import com.example.mear.adapters.SettingsAdapter
import com.example.mear.R
import com.example.mear.management.MusicFiles
import com.example.mear.ui.popups.AboutPopup
import com.example.mear.repositories.TrackRepository
import kotlinx.android.synthetic.main.popup_layout.*
@@ -47,16 +42,6 @@ class SettingsActivity : AppCompatActivity() {
window.statusBarColor = resources.getColor(R.color.track_seek)
}
private fun loadSongPaths(): MutableList<String> {
val demoPath = Environment.getExternalStorageDirectory()
val mfPaths = MusicFiles(demoPath)
mfPaths.loadAllMusicPaths()
val allSongs = mfPaths.allSongs
return allSongs!!
}
class AboutListener(var layout: LinearLayout?, val ctx: Context): View.OnClickListener {
override fun onClick(v: View?) {
@@ -1,7 +1,7 @@
package com.example.mear.adapters
import android.app.Activity
import android.support.v7.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
@@ -1,6 +1,6 @@
package com.example.mear.adapters
import android.support.v7.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
@@ -3,7 +3,7 @@ package com.example.mear.adapters
import java.lang.Exception
import kotlinx.android.synthetic.main.fragment_song_view.view.*
import android.support.v7.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
@@ -1,16 +1,11 @@
package com.example.mear
import android.content.Context
import android.support.annotation.LayoutRes
import androidx.annotation.LayoutRes
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.mear.management.DatabaseManager
val Context.database: DatabaseManager
get() = DatabaseManager.getInstance(applicationContext)
fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View {
return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
}
}
@@ -1,6 +1,6 @@
package com.example.mear.holders
import android.support.v7.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView
import android.view.View
import com.example.mear.models.SettingItems
@@ -1,93 +0,0 @@
package com.example.mear.management
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import com.example.mear.constants.ControlTypes
import java.lang.Exception
import org.jetbrains.anko.db.*
import org.jetbrains.anko.db.ManagedSQLiteOpenHelper
import com.example.mear.models.PlayControls
import com.example.mear.repositories.ShuffleRepository
class DatabaseManager(ctx: Context): ManagedSQLiteOpenHelper(ctx, "Mear",
null, 1) {
companion object {
private var instance: DatabaseManager? = null
@Synchronized
fun getInstance(ctx: Context): DatabaseManager {
if (instance == null) {
instance = DatabaseManager(ctx.applicationContext)
}
return instance!!
}
}
override fun onCreate(db: SQLiteDatabase?) {
try {
db!!.createTable(
"Track", true,
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
"Title" to TEXT, "Album" to TEXT, "Artist" to TEXT,
"Duration" to INTEGER, "FilePath" to TEXT
)
db!!.createTable(
"TrackCount", true,
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
"TotalSongs" to INTEGER
)
db!!.createTable(
"PlayCount", true,
"Id" to INTEGER + PRIMARY_KEY + AUTOINCREMENT,
"PlayCount" to INTEGER,
"TrackId" to INTEGER
)
db!!.createTable(
"Settings", true,
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
"DarkTheme" to org.jetbrains.anko.db.REAL
)
db!!.createTable(
"Shuffle", true,
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
"Mode" to TEXT
)
db!!.createTable(
"Repeat", true,
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
"Mode" to TEXT)
}
catch (ex: Exception) {
}
initializeShuffle(db)
initializeRepeat(db)
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
try {
db!!.dropTable("Track")
db!!.dropTable("TrackCount")
db!!.dropTable("PlayCount")
db!!.dropTable("Settings")
db!!.dropTable("Shuffle")
db!!.dropTable("Repeat")
}
catch (ex: Exception) {
}
}
private fun initializeShuffle(db: SQLiteDatabase?) {
db!!.insert("Shuffle",
"Mode" to ControlTypes.SHUFFLE_OFF)
}
private fun initializeRepeat(db: SQLiteDatabase?) {
db!!.insert("Repeat",
"Mode" to ControlTypes.REPEAT_OFF)
}
}
@@ -1,123 +0,0 @@
package com.example.mear.management
import android.os.Environment
import com.example.mear.R
import java.io.File
import java.lang.Exception
import com.example.mear.constants.DirectoryIgnore
import com.example.mear.constants.FileTypes
import com.example.mear.constants.SongSearch
class MusicFiles (private val demoPath: File) {
var allSongs: MutableList<String>?= null
private val musicSongLimit = Int.MAX_VALUE
fun loadAllMusicPaths() {
try {
allSongs = mutableListOf()
val demoPath = this.demoPath.absoluteFile.toString() + "/music/"
val f = File(demoPath)
var count = 0
val folder = f
val listOfFiles = folder.listFiles()
for (i in listOfFiles) {
for (j in i.listFiles()) {
if (j.absolutePath.toString().contains("zip")) {
}
for (k in j.listFiles()) {
if (k.absolutePath.toString().contains("mp3")) {
if (count < musicSongLimit) {
allSongs!!.add(k.absolutePath.toString())
count++
}
else
{
break
}
}
}
}
}
}
catch (ex: Exception) {
var exMsg = ex.message
}
}
fun initialMp3Search() {
try {
var pathList: MutableList<String>?
pathList = mutableListOf()
var songsAdded = 0
var fileSearch = File(demoPath.absolutePath)
fileSearch.walkTopDown().forEach {
println(it.absolutePath)
if (!ignoreThisDirectory(it.absolutePath)) {
if (it.isFile) {
if (it.extension == (FileTypes.Mp3)) {
if (songsAdded >= SongSearch.INITIAL_SEARCH_AMOUNT) {
return
}
pathList.add(it.absolutePath)
allSongs = pathList
songsAdded = songsAdded.inc()
}
}
}
}
}
catch (ex: Exception) {
val exMsg = ex.message
}
}
fun searchForMp3Songs() {
try {
var pathList: MutableList<String>?
pathList = mutableListOf()
var fileSearch = File(demoPath.absolutePath)
fileSearch.walkTopDown().forEach {
println(it.absolutePath)
if (!ignoreThisDirectory(it.absolutePath)) {
if (it.isFile) {
if (it.extension == (FileTypes.Mp3)) {
pathList.add(it.absolutePath)
}
}
}
}
allSongs = pathList
}
catch (ex: Exception) {
val exMsg = ex.message
}
}
private fun ignoreThisDirectory(path: String): Boolean {
var ignoreDirectory = false
try {
if (path.contains(DirectoryIgnore.Android_Root)) {
ignoreDirectory = true
}
if (path.contains(DirectoryIgnore.Notifications)) {
ignoreDirectory = true
}
if (path.contains(DirectoryIgnore.Ringtones)) {
ignoreDirectory = true
}
return ignoreDirectory
}
catch (ex: Exception) {
val exMsg = ex.message
}
return ignoreDirectory
}
}
@@ -68,6 +68,11 @@ class MusicService(var appPath: String = ""): Service() {
}
fun downloadSong(token: Token, song: Song, appPath: String) {
val trackRepo = TrackRepository()
val s = trackRepo.download(token, currentSong, appPath)
changeSongDownloadStatus(s)
}
fun icarusPlaySong(token: Token, song: Song, apiInfo: APIInfo) {
if (song.downloaded) {
offlinePlaySong(song)
@@ -77,11 +82,12 @@ class MusicService(var appPath: String = ""): Service() {
val uri = APIRepository.retrieveSongStreamUri(apiInfo, song)
val hddr = APIRepository.retrieveSongStreamHeader(token)
currentSong = song
currentSongIndex = songQueue.indexOfFirst { it.id == currentSong.id }
try {
trackPlayer!!.reset()
trackPlayer!!.setDataSource(this, uri, hddr)
trackPlayer!!.prepare()
trackPlayer!!.prepareAsync()
trackPlayer!!.start()
}
catch (ex: Exception) {
@@ -89,14 +95,30 @@ class MusicService(var appPath: String = ""): Service() {
}
}
fun changeSongDownloadStatus() {
currentSong.downloaded = true
songQueue.forEach {
s ->
if (s.id == currentSong.id) {
s.downloaded = true
}
fun changeSongDownloadStatus(song: Song) {
if (!song.downloaded) {
song.downloaded = true
}
currentSong = song
currentSongIndex = songQueue.indexOfFirst { it.id == currentSong.id }
songQueue[currentSongIndex!!] = currentSong
/**
val curPosition = currentPositionOfTrack()
trackPlayer!!.reset()
trackPlayer!!.setDataSource(currentSong.path)
trackPlayer!!.prepareAsync()
trackPlayer!!.seekTo(curPosition)
trackPlayer!!.start()
*/
}
fun removeSongDownloadStatus(song: Song) {
if (song.downloaded) {
song.downloaded = false
}
currentSong = song
currentSongIndex = songQueue.indexOfFirst { it.id == currentSong.id }
songQueue[currentSongIndex!!] = currentSong
}
fun goToPosition(progress: Int) { trackPlayer!!.seekTo(progress) }
@@ -157,7 +179,7 @@ class MusicService(var appPath: String = ""): Service() {
uri, hddr)
}
trackPlayer!!.prepare()
trackPlayer!!.prepareAsync()
trackPlayer!!.start()
}
}
@@ -194,7 +216,7 @@ class MusicService(var appPath: String = ""): Service() {
APIRepository.retrieveSongStreamUri(apiInfo, currentSong),
APIRepository.retrieveSongStreamHeader(token))
}
trackPlayer!!.prepare()
trackPlayer!!.prepareAsync()
trackPlayer!!.start()
}
catch (ex: Exception) {
@@ -275,16 +297,12 @@ class MusicService(var appPath: String = ""): Service() {
private fun offlinePlaySong(song: Song) {
try {
currentSong = song
songQueue.forEach{ s ->
if (s.id == currentSong.id) {
s.downloaded = currentSong.downloaded
s.filename = currentSong.filename
s.path = currentSong.path
}
}
currentSongIndex = songQueue.indexOfFirst { it.id == song.id }
songQueue[currentSongIndex!!] = currentSong
trackPlayer!!.reset()
trackPlayer!!.setDataSource(song.path)
trackPlayer!!.prepare()
trackPlayer!!.prepareAsync()
trackPlayer!!.start()
}
catch (ex: Exception) {
@@ -4,70 +4,8 @@ import android.content.Context
import org.jetbrains.anko.db.*
import com.example.mear.database
import com.example.mear.models.PlayCount
import com.example.mear.models.Track
class PlayCountRepository(val context: Context) {
fun getAll(): List<PlayCount> = context.database.use {
val playCounts = mutableListOf<PlayCount>()
select("PlayCount" )
.parseList(object : MapRowParser<PlayCount>{
override fun parseRow(columns: Map<String, Any?>): PlayCount {
val id = columns.getValue("Id").toString().toInt()
val songPlayedAmount = columns.getValue("PlayCount").toString().toInt()
val trackId = columns.getValue("TrackId").toString().toInt()
val playCount = PlayCount(id, songPlayedAmount, trackId)
playCounts.add(playCount)
return playCount
}
})
playCounts
}
fun getPlayCount(id: Int): PlayCount = context.database.use {
select("PlayCount").where("Id = $id")
.parseSingle(object: MapRowParser<PlayCount>{
override fun parseRow(columns: Map<String, Any?>): PlayCount {
val id = columns.getValue("Id").toString().toInt()
val songPlayedAmount = columns.getValue("PlayCount").toString().toInt()
val trackId = columns.getValue("TrackId").toString().toInt()
val playCount = PlayCount(id, songPlayedAmount, trackId)
return playCount
}
})
}
fun insertPlayCounts(tracks: List<Track>) = context.database.use {
transaction {
var i = 0
for (track in tracks) {
insert("PlayCount", "Id" to i++,
"PlayCount" to 0, "TrackId" to track.id)
}
}
}
fun insertPlayCount(track: Track) = context.database.use {
insert("PlayCount",
"Id" to track.id,
"PlayCount" to 0,
"TrackId" to track.id)
}
fun updatePlayCount(playCount: PlayCount) = context.database.use {
update("PlayCount",
"PlayCount" to playCount.playCount + 1)
.where("Id = {playCountId}", "playCountId" to playCount.id).exec()
}
fun delete(table: PlayCount?) = context.database.use {
delete("PlayCount", whereClause = "id = {$table.id}")
}
fun delete() = context.database.use {
delete("PlayCount")
}
}
@@ -1,41 +0,0 @@
package com.example.mear.repositories
import android.content.Context
import org.jetbrains.anko.db.*
import com.example.mear.database
import com.example.mear.models.Settings
class SettingRepository(val context: Context) {
fun getSettings(id: Int): Settings = context.database.use {
select("SettingsActivity").where("Id = $id")
.parseSingle(object: MapRowParser<Settings>{
override fun parseRow(columns: Map<String, Any?>): Settings {
val id = columns.getValue("Id").toString().toInt()
val darkTheme = columns.getValue("DarkTheme").toString().toBoolean()
val settings = Settings (id, darkTheme)
return settings
}
})
}
fun insertSettings(settings: Settings) = context.database.use {
insert("SettingsActivity",
"Id" to settings.id,
"DarkTheme" to false)
}
fun updateSettings(settings: Settings) = context.database.use {
update("SettingsActivity",
"DarkTheme" to settings.darkTheme)
.where("Id = {settingId}", "settingId" to settings.id).exec()
}
fun delete(table: Settings?) = context.database.use {
delete("SettingsActivity", whereClause = "id = {$table.id}")
}
fun delete() = context.database.use {
delete("SettingsActivity")
}
}
@@ -4,7 +4,6 @@ import android.content.Context
import org.jetbrains.anko.db.*
import com.example.mear.database
import com.example.mear.models.Song
import com.example.mear.models.Token
import com.example.mear.models.Track
@@ -24,7 +23,7 @@ class TrackRepository(var context: Context? = null) {
private external fun retrieveSong(token: Token, song: Song, uri: String): Song
private external fun downloadSong(token: Token, song: Song, path: String): Song
private external fun deleteSong(song: Song, path: String)
private external fun deleteSong(song: Song, path: String): Boolean
fun fetchSongs(token: Token, uri: String): Array<Song> {
@@ -48,7 +47,7 @@ class TrackRepository(var context: Context? = null) {
return downloadSong(token, song, path)
}
fun delete(song: Song, path: String) {
deleteSong(song, path)
fun delete(song: Song, path: String): Boolean {
return deleteSong(song, path)
}
}
@@ -0,0 +1,21 @@
package com.example.mear.workers
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
class IcarusSyncManager(context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) {
override fun doWork(): Result {
//TODO perform your async operational task here
/**
* We have performed download task here on above example
*/
val accessToken = inputData.getString("accessToken")
val appPath = inputData.getString("appPath")
//val songId = inputData.getInt("songId")
return Result.success()
}
}
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.IcarusSongActivity">
<android.support.design.widget.AppBarLayout
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -14,14 +14,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/color_background"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>
<include
@@ -34,4 +34,4 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
+6 -6
View File
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.LoginActivity">
<android.support.design.widget.AppBarLayout
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>
<android.support.design.widget.FloatingActionButton
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -30,4 +30,4 @@
<include layout="@layout/content_login" />
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
+5 -5
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
@@ -8,7 +8,7 @@
android:background="@color/color_background"
tools:context=".activities.MainActivity">
<android.support.design.widget.AppBarLayout
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -21,7 +21,7 @@
android:gravity="end"
android:orientation="horizontal">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="354dp"
android:layout_height="?attr/actionBarSize"
@@ -39,10 +39,10 @@
app:srcCompat="@drawable/ic_action_more_vert" />
</LinearLayout>
</android.support.design.widget.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="@+id/include"
layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -8,19 +8,19 @@
android:background="@color/color_background"
tools:context=".activities.SettingsActivity">
<android.support.design.widget.AppBarLayout
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/color_background"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="@+id/include3"
@@ -28,4 +28,4 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -76,4 +76,4 @@
app:layout_constraintBottom_toTopOf="@+id/login"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -22,4 +22,4 @@
layout="@layout/fragment_play_controls"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -105,4 +105,4 @@
</LinearLayout>
</FrameLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -14,7 +14,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.SearchView
<androidx.appcompat.widget.SearchView
android:id="@+id/songSearch"
style="@style/SongSearchViewStyle"
android:layout_width="match_parent"
@@ -26,7 +26,7 @@
app:layout_constraintTop_toBottomOf="@+id/space2"
tools:layout_editor_absoluteX="8dp" />
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/trackList"
marginTop="?android:attr/actionBarSize"
android:layout_width="wrap_content"
@@ -42,4 +42,4 @@
<!-- style="@style/SongSearchViewStyle" -->
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -43,4 +43,4 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_media_next" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/cv_settings"
android:layout_width="wrap_content"
@@ -70,7 +70,7 @@
</LinearLayout>
</android.support.v7.widget.CardView>
</androidx.cardview.widget.CardView>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/cv"
@@ -42,7 +42,7 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.AppCompatImageView
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/trackCover"
android:layout_width="45dp"
android:layout_height="45dp"
@@ -75,6 +75,6 @@
</LinearLayout>
</android.support.v7.widget.CardView>
</androidx.cardview.widget.CardView>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent">
@@ -19,4 +19,4 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.095"
tools:srcCompat="@tools:sample/backgrounds/scenic[1]" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent">
@@ -48,4 +48,4 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ArtistTitle"
app:layout_constraintVertical_bias="0.0" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent">
@@ -43,4 +43,4 @@
android:textColor="@color/track_details"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent">
@@ -33,4 +33,4 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.826" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -58,4 +58,4 @@
android:textAlignment="center"
android:textColor="@color/popup_text" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
-1
View File
@@ -19,7 +19,6 @@ allprojects {
repositories {
google()
jcenter()
}
}