Add support for downloading to internal storage and fix project build.
- Update outdated library com.github.QuadFlask:colorpicker in build.gradle - Update SettingsActivity with option to select download directory. - Add migration in PreferenceUtil to support download location storage. - Update MusicUtil to look for user-provided location when building locations. - Update DownloadService to download to specified location.
This commit is contained in:
parent
5f9f96e586
commit
5ca55a54d2
8 changed files with 100 additions and 36 deletions
|
|
@ -89,7 +89,7 @@ dependencies {
|
|||
implementation 'com.afollestad:material-cab:2.0.1'
|
||||
|
||||
implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1'
|
||||
implementation 'com.github.QuadFlask:colorpicker:ef73ced217'
|
||||
implementation 'com.github.QuadFlask:colorpicker:0.0.15'
|
||||
implementation 'com.github.codekidX:storage-chooser:2.0.4.4'
|
||||
implementation 'me.relex:circleindicator:2.1.6'
|
||||
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
package com.dkanada.gramophone.activities;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
|
@ -20,6 +27,8 @@ import com.dkanada.gramophone.dialogs.preferences.NowPlayingPreferenceDialog;
|
|||
import com.dkanada.gramophone.activities.base.AbsBaseActivity;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class SettingsActivity extends AbsBaseActivity {
|
||||
private ActivitySettingsBinding binding;
|
||||
|
||||
|
|
@ -43,6 +52,30 @@ public class SettingsActivity extends AbsBaseActivity {
|
|||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private ActivityResultLauncher<Intent> dirPickerLauncher;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
dirPickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK) {
|
||||
Intent data = result.getData();
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
requireContext().getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(requireContext()).edit();
|
||||
editor.putString(PreferenceUtil.LOCATION_DOWNLOAD, uri.toString());
|
||||
editor.apply();
|
||||
invalidateSettings();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle bundle, String s) {
|
||||
addPreferencesFromResource(R.xml.pref_library);
|
||||
|
|
@ -93,14 +126,6 @@ public class SettingsActivity extends AbsBaseActivity {
|
|||
blurAlbumCoverPreference.setEnabled(false);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
|
||||
downloadLocationPreference.setEnabled(false);
|
||||
|
||||
// stock Android 11 removed the album cover on lock screens
|
||||
// supported on LineageOS so we might want to add a check at some point
|
||||
showAlbumCoverPreference.setEnabled(false);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
|
||||
// custom notification layouts were removed entirely in Android 12
|
||||
classicNotification.setEnabled(false);
|
||||
|
|
@ -117,13 +142,32 @@ public class SettingsActivity extends AbsBaseActivity {
|
|||
return false;
|
||||
});
|
||||
|
||||
// use this to set default state for playback screen and notification style
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||
downloadLocationPreference.setOnPreferenceClickListener(preference -> {
|
||||
openDirectoryPicker();
|
||||
return true;
|
||||
});
|
||||
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||
String downloadLocation = preferences.getString(PreferenceUtil.LOCATION_DOWNLOAD, null);
|
||||
if (downloadLocation != null) {
|
||||
Uri uri = Uri.parse(downloadLocation);
|
||||
File file = new File(uri.getPath());
|
||||
downloadLocationPreference.setSummary(file.getPath());
|
||||
} else {
|
||||
downloadLocationPreference.setSummary(R.string.pref_title_download_location);
|
||||
}
|
||||
|
||||
|
||||
// use this to set default state for playback screen and notification style
|
||||
onSharedPreferenceChanged(preferences, PreferenceUtil.NOW_PLAYING_SCREEN);
|
||||
onSharedPreferenceChanged(preferences, PreferenceUtil.CLASSIC_NOTIFICATION);
|
||||
}
|
||||
|
||||
private void openDirectoryPicker() {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
dirPickerLauncher.launch(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package com.dkanada.gramophone.service;
|
|||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.BuildConfig;
|
||||
|
|
@ -13,8 +15,6 @@ import com.dkanada.gramophone.util.MusicUtil;
|
|||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
|
|
@ -76,17 +76,28 @@ public class DownloadService extends Service {
|
|||
URL url = new URL(MusicUtil.getDownloadUri(song));
|
||||
URLConnection connection = url.openConnection();
|
||||
|
||||
String cache = PreferenceUtil.getInstance(App.getInstance()).getLocationCache();
|
||||
File download = new File(cache, "download/" + song.id);
|
||||
File audio = new File(MusicUtil.getFileUri(song));
|
||||
String location = PreferenceUtil.getInstance(App.getInstance()).getLocationDownload();
|
||||
DocumentFile root;
|
||||
if (location.equals(getApplicationContext().getCacheDir().toString())) {
|
||||
root = DocumentFile.fromFile(new File(location));
|
||||
} else {
|
||||
root = DocumentFile.fromTreeUri(this, Uri.parse(location));
|
||||
}
|
||||
|
||||
download.getParentFile().mkdirs();
|
||||
download.createNewFile();
|
||||
audio.getParentFile().mkdirs();
|
||||
audio.createNewFile();
|
||||
DocumentFile artist = root.findFile(MusicUtil.ascii(song.artistName));
|
||||
if (artist == null) {
|
||||
artist = root.createDirectory(MusicUtil.ascii(song.artistName));
|
||||
}
|
||||
DocumentFile album = artist.findFile(MusicUtil.ascii(song.albumName));
|
||||
if (album == null) {
|
||||
album = artist.createDirectory(MusicUtil.ascii(song.albumName));
|
||||
}
|
||||
|
||||
String fileName = song.discNumber + "." + song.trackNumber + " - " + MusicUtil.ascii(song.title) + "." + song.container;
|
||||
DocumentFile audio = album.createFile("audio/" + song.container, fileName);
|
||||
|
||||
InputStream input = connection.getInputStream();
|
||||
OutputStream output = new FileOutputStream(download);
|
||||
OutputStream output = getContentResolver().openOutputStream(audio.getUri());
|
||||
|
||||
connection.connect();
|
||||
|
||||
|
|
@ -102,17 +113,6 @@ public class DownloadService extends Service {
|
|||
input.close();
|
||||
output.close();
|
||||
|
||||
input = new FileInputStream(download);
|
||||
output = new FileOutputStream(audio);
|
||||
|
||||
while ((count = input.read(data)) != -1) {
|
||||
output.write(data, 0, count);
|
||||
}
|
||||
|
||||
input.close();
|
||||
output.close();
|
||||
|
||||
download.delete();
|
||||
App.getDatabase().cacheDao().insertCache(new Cache(song));
|
||||
notification.stop(song);
|
||||
} catch (Exception e) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.dkanada.gramophone.util;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
|
@ -78,7 +79,12 @@ public class MusicUtil {
|
|||
}
|
||||
|
||||
public static String getFileUri(Song song) {
|
||||
File root = new File(PreferenceUtil.getInstance(App.getInstance()).getLocationDownload(), "music");
|
||||
String location = PreferenceUtil.getInstance(App.getInstance()).getLocationDownload();
|
||||
File root = new File(location, "music");
|
||||
if (!location.equals(App.getInstance().getCacheDir().toString())) {
|
||||
Uri uri = Uri.parse(location);
|
||||
return new File(uri.getPath()).getAbsolutePath();
|
||||
}
|
||||
|
||||
String path = "/" + ascii(song.artistName) + "/" + ascii(song.albumName);
|
||||
String name = "/" + song.discNumber + "." + song.trackNumber + " - " + ascii(song.title) + "." + song.container;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ public final class PreferenceUtil {
|
|||
public static final String GAIN_OFFSET = "gain_offset";
|
||||
|
||||
public static final String LOCATION_DOWNLOAD = "location_download";
|
||||
public static final String LOCATION_CACHE = "location_cache";
|
||||
public static final String IMAGE_CACHE_SIZE = "image_cache_size";
|
||||
public static final String MEDIA_CACHE_SIZE = "media_cache_size";
|
||||
|
||||
|
|
@ -97,7 +96,7 @@ public final class PreferenceUtil {
|
|||
|
||||
preferences.edit().putString(GENERAL_THEME, Theme.valueOf(theme.toUpperCase()).toString()).commit();
|
||||
preferences.edit().putString(IMAGE_CACHE_SIZE, imageSize.substring(0, imageSize.length() - 6)).commit();
|
||||
preferences.edit().putString(MEDIA_CACHE_SIZE, mediaSize.substring(0, imageSize.length() - 6)).commit();
|
||||
preferences.edit().putString(MEDIA_CACHE_SIZE, mediaSize.substring(0, mediaSize.length() - 6)).commit();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -424,7 +423,7 @@ public final class PreferenceUtil {
|
|||
}
|
||||
|
||||
public final String getLocationCache() {
|
||||
return mPreferences.getString(LOCATION_CACHE, mContext.getCacheDir().toString());
|
||||
return mContext.getCacheDir().toString();
|
||||
}
|
||||
|
||||
public final long getImageCacheSize() {
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@
|
|||
<string name="pref_header_library">Library</string>
|
||||
<string name="pref_header_lock_screen">Lock Screen</string>
|
||||
<string name="pref_header_notification">Notification</string>
|
||||
<string name="pref_header_storage">Storage</string>
|
||||
|
||||
<string name="pref_title_direct_play_codecs">Direct Play Codecs</string>
|
||||
<string name="pref_title_categories">Categories</string>
|
||||
|
|
@ -143,6 +144,9 @@
|
|||
<string name="pref_summary_categories">Configure visibility and order of display categories.</string>
|
||||
<string name="pref_summary_direct_play_codecs">Disable direct play codecs to force transcoding.</string>
|
||||
<string name="pref_summary_gain_adjustment">Adjust the gain of the music player\'s output</string>
|
||||
<string name="save_lyrics">Save Lyrics</string>
|
||||
<string name="cached_songs_location">Cached Songs Location</string>
|
||||
<string name="cached_songs_location_summary">Select where to store cached songs</string>
|
||||
|
||||
<string name="delete_action">Delete</string>
|
||||
<string name="remove_action">Remove</string>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<com.dkanada.gramophone.views.settings.JellyPreferenceCategory android:title="@string/pref_header_cache">
|
||||
|
||||
<com.dkanada.gramophone.views.settings.FilePreference
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="location_download"
|
||||
android:title="@string/pref_title_download_location" />
|
||||
|
|
|
|||
11
app/src/main/res/xml/pref_storage.xml
Normal file
11
app/src/main/res/xml/pref_storage.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<SwitchPreference
|
||||
app:key="save_lyrics"
|
||||
app:title="@string/save_lyrics"
|
||||
app:defaultValue="false" />
|
||||
<Preference
|
||||
app:key="cached_songs_location"
|
||||
app:title="@string/cached_songs_location"
|
||||
app:summary="@string/cached_songs_location_summary" />
|
||||
</androidx.preference.PreferenceScreen>
|
||||
Loading…
Add table
Add a link
Reference in a new issue