Merge pull request #57 from kdeng00/downloading
Downloading
This commit was merged in pull request #57.
This commit is contained in:
+71
-59
File diff suppressed because one or more lines are too long
+35
-14
@@ -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"
|
||||
@@ -38,6 +38,9 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "src/main/cpp/CMakeLists.txt"
|
||||
@@ -47,23 +50,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,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" />
|
||||
|
||||
+60
-24
@@ -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);
|
||||
@@ -285,11 +303,9 @@ void downloadSong(Song& song, const Token& token, const Str& path) {
|
||||
saveSong.write((char*)&downloadedSong.data[0], downloadedSong.data.size());
|
||||
saveSong.close();
|
||||
|
||||
song.path = downloadedSong.path;
|
||||
song.downloaded = true;
|
||||
repository::local::SongRepository localSongRepo(path);
|
||||
if (!localSongRepo.doesTableExist(path)) {
|
||||
localSongRepo.createSongTable(path);
|
||||
}
|
||||
|
||||
localSongRepo.saveSong(downloadedSong, path);
|
||||
}
|
||||
|
||||
@@ -524,6 +540,28 @@ Java_com_example_mear_repositories_TokenRepository_retrieveTokenRecord(
|
||||
return tokenObj;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject
|
||||
JNICALL
|
||||
Java_com_example_mear_repositories_TrackRepository_downloadSong(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jobject tokenObj,
|
||||
jobject songObj,
|
||||
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 song = ObjToSong<jobject, JNIEnv>(env, songObj);
|
||||
auto path = env->GetStringUTFChars(pathStr, nullptr);
|
||||
downloadSong(song, token, path);
|
||||
|
||||
return songToObj(env, song);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject
|
||||
JNICALL
|
||||
@@ -684,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
|
||||
@@ -764,26 +820,6 @@ Java_com_example_mear_repositories_TokenRepository_saveTokenRecord(
|
||||
saveToken(token, path);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void
|
||||
JNICALL
|
||||
Java_com_example_mear_repositories_TrackRepository_downloadSong(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jobject tokenObj,
|
||||
jobject songObj,
|
||||
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 song = ObjToSong<jobject, JNIEnv>(env, songObj);
|
||||
auto path = env->GetStringUTFChars(pathStr, nullptr);
|
||||
downloadSong(song, token, path);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void
|
||||
JNICALL
|
||||
|
||||
@@ -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();
|
||||
@@ -93,19 +93,18 @@ namespace manager {
|
||||
|
||||
template<typename Str = std::string, typename B = bool>
|
||||
B deleteSong(const Song& song, const Str& path) {
|
||||
auto s = fullSongPath(song, path);
|
||||
auto result = std::remove(s.c_str());
|
||||
const auto s = fullSongPath(song, path);
|
||||
|
||||
if (result == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return (remove(s.c_str()) == 0) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -117,27 +116,24 @@ 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);
|
||||
/**
|
||||
if (song.disc == 0) {
|
||||
albumPath.append("/");
|
||||
albumPath.append("disc1");
|
||||
} else {
|
||||
albumPath.append("/");
|
||||
albumPath.append("disc");
|
||||
albumPath.append(std::to_string(song.disc));
|
||||
}
|
||||
*/
|
||||
|
||||
DIR* dir = opendir(albumPath.c_str());
|
||||
|
||||
if (dir) {
|
||||
@@ -173,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());
|
||||
|
||||
@@ -187,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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -151,16 +151,6 @@ namespace repository {
|
||||
auto res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
downloadedSong.data = std::move(std::vector<char>(data.begin(), data.end()));
|
||||
/**
|
||||
downloadedSong.filename = "track";
|
||||
if (song.track < 10) {
|
||||
downloadedSong.filename.append("0");
|
||||
downloadedSong.filename.append(std::to_string(song.track));
|
||||
} else {
|
||||
downloadedSong.filename.append(std::to_string(song.track));
|
||||
}
|
||||
downloadedSong.filename.append(".mp3");
|
||||
*/
|
||||
|
||||
return downloadedSong;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,10 +5,9 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
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.*
|
||||
@@ -16,6 +16,7 @@ class LoginActivity : BaseServiceActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
window.statusBarColor = resources.getColor(R.color.track_seek)
|
||||
setContentView(R.layout.activity_login)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
|
||||
@@ -11,19 +11,20 @@ import kotlinx.android.synthetic.main.fragment_track_details.*
|
||||
import kotlinx.android.synthetic.main.fragment_track_elapsing.*
|
||||
import kotlinx.android.synthetic.main.fragment_track_flow.*
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
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 android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.Observer
|
||||
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,18 +33,14 @@ 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() {
|
||||
|
||||
private val ctx: Context? = this
|
||||
private var coverArtHandler: Handler? = Handler()
|
||||
private var musicHandler: Handler? = Handler()
|
||||
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
|
||||
|
||||
@@ -335,22 +332,6 @@ class MainActivity : BaseServiceActivity() {
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: Might need this down the road for playing songs off an external
|
||||
// storage
|
||||
private fun permissionPrompt() {
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||
}
|
||||
else {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPopup(view: View) {
|
||||
try {
|
||||
@@ -371,30 +352,64 @@ class MainActivity : BaseServiceActivity() {
|
||||
startActivity(Intent(this, IcarusSongActivity::class.java))
|
||||
}
|
||||
R.id.action_song_delete -> {
|
||||
// TODO: handle song deletion
|
||||
val ss = true
|
||||
val appPath = appDirectory()
|
||||
val trackRepo = TrackRepository()
|
||||
|
||||
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()
|
||||
val apiRepo = APIRepository()
|
||||
val tokenRepo = TokenRepository()
|
||||
val trackRepo = TrackRepository()
|
||||
val song = musicService!!.getCurrentSong()
|
||||
var song = musicService!!.getCurrentSong()
|
||||
|
||||
val token = tokenRepo.retrieveToken(appPath)
|
||||
val apiInfo = apiRepo.retrieveRecord(appPath)
|
||||
trackRepo.download(token, song, appPath)
|
||||
musicService!!.changeSongDownloadStatus()
|
||||
// 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 constraints = androidx.work.Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED).build()
|
||||
|
||||
val data = Data.Builder()
|
||||
data.putString("appPath", appPath)
|
||||
|
||||
data.putInt("songId", song.id)
|
||||
data.putString("songTitle", song.title)
|
||||
data.putString("songArtist", song.artist)
|
||||
data.putString("songAlbum", song.album)
|
||||
data.putString("songAlbumArtist", song.albumArtist)
|
||||
data.putString("songGenre", song.genre)
|
||||
data.putInt("songYear", song.year)
|
||||
data.putInt("songDuration", song.duration)
|
||||
data.putInt("songCoverArtId", song.coverArtId)
|
||||
data.putBoolean("songDownloaded", false)
|
||||
data.putInt("songDisc", song.disc)
|
||||
data.putInt("songTrack", song.track)
|
||||
|
||||
val task = OneTimeWorkRequest.Builder(IcarusSyncManager::class.java)
|
||||
.setInputData(data.build())
|
||||
.setConstraints(constraints)
|
||||
.build()
|
||||
WorkManager.getInstance().enqueue(task)
|
||||
|
||||
WorkManager.getInstance(this).getWorkInfoByIdLiveData(task.id)
|
||||
.observe(this, Observer { info ->
|
||||
if (info != null && info.state.isFinished) {
|
||||
song.path = info.outputData.getString("songPath")!!
|
||||
song.filename = info.outputData.getString("songFilename")!!
|
||||
song.downloaded = info.outputData.getBoolean("songDownloaded", true)!!
|
||||
musicService!!.changeSongDownloadStatus(song)
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
R.id.action_song_play_count-> {
|
||||
// TODO: not implemented
|
||||
val trk = musicService!!.getCurrentSong()
|
||||
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,6 +82,7 @@ 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()
|
||||
@@ -89,15 +95,29 @@ 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
|
||||
}
|
||||
// songQueue[currentSongIndex!!].downloaded = true
|
||||
currentSong = song
|
||||
currentSongIndex = songQueue.indexOfFirst { it.id == currentSong.id }
|
||||
songQueue[currentSongIndex!!] = currentSong
|
||||
|
||||
val curPosition = currentPositionOfTrack()
|
||||
trackPlayer!!.reset()
|
||||
trackPlayer!!.setDataSource(currentSong.path)
|
||||
trackPlayer!!.prepare()
|
||||
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) }
|
||||
@@ -142,11 +162,8 @@ class MusicService(var appPath: String = ""): Service() {
|
||||
if (retrieveShuffleMode()!! && !parseRepeatMode(repeatMode)) {
|
||||
currentSongIndex = Random.nextInt(0, songQueue.size - 1)
|
||||
} else if (!parseRepeatMode(repeatMode)) {
|
||||
if (currentSongIndex == 0) {
|
||||
currentSongIndex = songQueue.size - 1
|
||||
} else {
|
||||
currentSongIndex = currentSongIndex!! - 1
|
||||
}
|
||||
currentSongIndex = if (currentSongIndex == 0)
|
||||
songQueue.size - 1 else currentSongIndex!! - 1
|
||||
}
|
||||
|
||||
currentSong = songQueue[currentSongIndex!!]
|
||||
@@ -184,12 +201,8 @@ class MusicService(var appPath: String = ""): Service() {
|
||||
if (retrieveShuffleMode()!! && !parseRepeatMode(repeatMode)) {
|
||||
currentSongIndex = Random.nextInt(0, songQueue.size - 1)
|
||||
} else if (!parseRepeatMode(repeatMode)) {
|
||||
if ((currentSongIndex!! + 1) == songQueue.size) {
|
||||
currentSongIndex = 0
|
||||
}
|
||||
else {
|
||||
currentSongIndex = currentSongIndex!! + 1
|
||||
}
|
||||
currentSongIndex = if ((currentSongIndex!! + 1) == songQueue.size)
|
||||
0 else currentSongIndex!! + 1
|
||||
}
|
||||
|
||||
currentSong = songQueue[currentSongIndex!!]
|
||||
@@ -236,27 +249,23 @@ class MusicService(var appPath: String = ""): Service() {
|
||||
|
||||
val token = tokenRepo.retrieveToken(appPath)
|
||||
val apiInfo = apiRepo.retrieveRecord(appPath)
|
||||
// val songs = trackRepo.fetchSongs(token, apiInfo.uri)
|
||||
val songs = trackRepo.fetchSongsIncludingDownloaded(token, apiInfo.uri, appPath)
|
||||
songQueue = songs.toMutableList()
|
||||
|
||||
if (retrieveShuffleMode()!!) {
|
||||
currentSongIndex = Random.nextInt(0, songs.size - 1)
|
||||
} else {
|
||||
currentSongIndex = 0
|
||||
}
|
||||
currentSongIndex = if (retrieveShuffleMode()!!)
|
||||
Random.nextInt(0, songQueue.size - 1) else 0
|
||||
|
||||
currentSong = songQueue[currentSongIndex!!]
|
||||
if (currentSong.downloaded) {
|
||||
trackPlayer!!.setDataSource(currentSong.path)
|
||||
}
|
||||
else {
|
||||
|
||||
trackPlayer!!.setDataSource(this,
|
||||
APIRepository.retrieveSongStreamUri(apiInfo, currentSong),
|
||||
APIRepository.retrieveSongStreamHeader(token))
|
||||
}
|
||||
trackPlayer!!.prepareAsync()
|
||||
|
||||
trackPlayer!!.prepare()
|
||||
trackPlayer!!.setOnCompletionListener {
|
||||
playNextTrack()
|
||||
}
|
||||
@@ -269,37 +278,27 @@ class MusicService(var appPath: String = ""): Service() {
|
||||
|
||||
private fun retrieveShuffleMode(): Boolean? {
|
||||
val shuffleRepo = ShuffleRepository(null)
|
||||
val shuffleMode = shuffleRepo.shuffleMode(appPath)
|
||||
var shuffleOn = false
|
||||
|
||||
when (shuffleMode) {
|
||||
ShuffleTypes.ShuffleOn -> shuffleOn = true
|
||||
ShuffleTypes.ShuffleOff -> shuffleOn = false
|
||||
return when (shuffleRepo.shuffleMode(appPath)) {
|
||||
ShuffleTypes.ShuffleOn -> true
|
||||
ShuffleTypes.ShuffleOff -> false
|
||||
else -> false
|
||||
}
|
||||
|
||||
return shuffleOn
|
||||
}
|
||||
|
||||
private fun parseRepeatMode(repeatMode: RepeatTypes): Boolean {
|
||||
var repeatOn: Boolean? = null
|
||||
when (repeatMode) {
|
||||
RepeatTypes.RepeatOff -> repeatOn = false
|
||||
RepeatTypes.RepeatSong -> repeatOn = true
|
||||
return when (repeatMode) {
|
||||
RepeatTypes.RepeatOff -> false
|
||||
RepeatTypes.RepeatSong -> true
|
||||
}
|
||||
|
||||
return repeatOn!!
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
@@ -22,8 +21,9 @@ class TrackRepository(var context: Context? = null) {
|
||||
private external fun retrieveSongsIncludingDownloaded(token: Token, uri: String, path: String): Array<Song>
|
||||
|
||||
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 downloadSong(token: Token, song: Song, path: String)
|
||||
private external fun deleteSong(song: Song, path: String): Boolean
|
||||
|
||||
|
||||
fun fetchSongs(token: Token, uri: String): Array<Song> {
|
||||
@@ -43,8 +43,11 @@ class TrackRepository(var context: Context? = null) {
|
||||
downloadSong(token, song, uri)
|
||||
}
|
||||
|
||||
fun download(token: Token, song: Song, path: String) {
|
||||
downloadSong(token, song, path)
|
||||
val s = 4
|
||||
fun download(token: Token, song: Song, path: String): Song {
|
||||
return downloadSong(token, song, path)
|
||||
}
|
||||
|
||||
fun delete(song: Song, path: String): Boolean {
|
||||
return deleteSong(song, path)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.example.mear.workers
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Data
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
|
||||
import com.example.mear.models.Song
|
||||
import com.example.mear.repositories.TokenRepository
|
||||
import com.example.mear.repositories.TrackRepository
|
||||
|
||||
class IcarusSyncManager(context: Context, workerParams: WorkerParameters) :
|
||||
Worker(context, workerParams) {
|
||||
override fun doWork(): Result {
|
||||
val appPath: String = inputData.getString("appPath")!!
|
||||
val songId = inputData.getInt("songId", 0)
|
||||
if (songId == 0) {
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
val tokenRepo = TokenRepository()
|
||||
val trackRepo = TrackRepository()
|
||||
val tok = tokenRepo.retrieveToken(appPath)
|
||||
val song = Song()
|
||||
song.id = songId
|
||||
song.title = inputData.getString("songTitle")!!
|
||||
song.artist = inputData.getString("songArtist")!!
|
||||
song.album = inputData.getString("songAlbum")!!
|
||||
song.albumArtist = inputData.getString("songAlbumArtist")!!
|
||||
song.genre = inputData.getString("songGenre")!!
|
||||
song.year = inputData.getInt("songYear", 0)
|
||||
song.duration = inputData.getInt("songDuration", 0)
|
||||
song.coverArtId = inputData.getInt("songCoverArtId", 0)
|
||||
song.disc = inputData.getInt("songDisc", 0)
|
||||
song.track = inputData.getInt("songTrack", 0)
|
||||
|
||||
val downloadedSong = trackRepo.download(tok, song, appPath)
|
||||
|
||||
val output: Data = workDataOf("songPath" to downloadedSong.path,
|
||||
"songFilename" to downloadedSong.filename,
|
||||
"songDownloaded" to true)
|
||||
|
||||
return Result.success(output)
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -19,7 +19,6 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user