implement download folder picker
This commit is contained in:
@@ -13,8 +13,10 @@ import static ru.vtosters.lite.utils.ThemesUtils.getAlertStyle;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getSTextAttr;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
@@ -40,41 +42,93 @@ import okhttp3.Request;
|
||||
import ru.vtosters.lite.downloaders.VideoDownloader;
|
||||
import ru.vtosters.lite.music.Scrobbler;
|
||||
import ru.vtosters.lite.ui.adapters.ImagineArrayAdapter;
|
||||
import ru.vtosters.lite.ui.dialogs.RoundingSeekbarDialog;
|
||||
import ru.vtosters.lite.utils.FileUriUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
|
||||
public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
public static void download(Context ctx) {
|
||||
AlertDialog.Builder alertDialog = new AlertDialog.Builder(ctx, getAlertStyle());
|
||||
alertDialog.setTitle("Введите ссылку на видео");
|
||||
private final int REQUEST_CODE_SET_DOWNLOAD_DIRECTORY = 665;
|
||||
|
||||
final EditText input = new EditText(ctx);
|
||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
input.setLayoutParams(lp);
|
||||
input.setTextColor(getTextAttr());
|
||||
input.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
|
||||
alertDialog.setView(input);
|
||||
alertDialog.setPositiveButton("Скачать", (dialog, which) -> VideoDownloader.parseVideoLink(input.getText().toString(), ctx));
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(getIdentifier("preferences_media", "xml"));
|
||||
prefs();
|
||||
}
|
||||
|
||||
private void logout(Context ctx) {
|
||||
VkAlertDialog.Builder alertDialog = new VkAlertDialog.Builder(ctx);
|
||||
alertDialog.setTitle("Вы уверены?");
|
||||
alertDialog.setMessage("Вы действительно хотите выйти из аккаунта?");
|
||||
alertDialog.setPositiveButton("Да", (dialog, which) -> {
|
||||
Scrobbler.logout();
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQUEST_CODE_SET_DOWNLOAD_DIRECTORY && resultCode == Activity.RESULT_OK) {
|
||||
var path = data.getData();
|
||||
if (path != null) {
|
||||
var prefs = getPreferences();
|
||||
var editor = prefs.edit();
|
||||
var actualPath = FileUriUtils.getFullPathFromTreeUri(path, getContext());
|
||||
editor.putString("downloads_directory", actualPath);
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
prefs();
|
||||
}
|
||||
|
||||
private void prefs() {
|
||||
findPreference("download_video").setOnPreferenceClickListener(new MediaFragment.download());
|
||||
findPreference("clearvideohistory").setOnPreferenceClickListener(preference -> {
|
||||
deleteVideoHistory();
|
||||
return true;
|
||||
});
|
||||
alertDialog.setNeutralButton("Нет", (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
findPreference("dateformat").setOnPreferenceChangeListener(new MediaFragment.restart());
|
||||
findPreference("lastfm_auth").setOnPreferenceClickListener(preference -> {
|
||||
if (isLoggedIn()) {
|
||||
logout(getContext());
|
||||
} else {
|
||||
lastfmAuth(getContext());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("downloads_directory").setSummary(
|
||||
"Текущая папка: " + Preferences.getDownloadsDir()
|
||||
);
|
||||
findPreference("downloads_directory").setOnPreferenceClickListener(preference -> {
|
||||
var intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
startActivityForResult(intent, REQUEST_CODE_SET_DOWNLOAD_DIRECTORY);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary("Вы авторизованы как " + Scrobbler.getUserName());
|
||||
} else {
|
||||
findPreference("lastfm_enabled").setEnabled(false);
|
||||
}
|
||||
|
||||
findPreference("select_photo_search_engine").setOnPreferenceClickListener(preference -> {
|
||||
var items = Arrays.asList(
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("yandex", "drawable"), "Yandex"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("google", "drawable"), "Google"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("microsoft", "drawable"), "Bing")
|
||||
);
|
||||
|
||||
var alert = new VkAlertDialog.Builder(getActivity())
|
||||
.create();
|
||||
|
||||
var listView = (ListView) LayoutInflater.from(getContext()).inflate(com.vtosters.lite.R.layout.abc_select_dialog_material, null, false);
|
||||
var adapter = new ImagineArrayAdapter(getContext(), items, i -> {
|
||||
getPreferences().edit().putInt("search_engine", i).apply();
|
||||
alert.dismiss();
|
||||
});
|
||||
adapter.setSelected(getPreferences().getInt("search_engine", 0));
|
||||
listView.setAdapter(adapter);
|
||||
alert.setView(listView);
|
||||
alert.show();
|
||||
|
||||
return true;
|
||||
});
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
alert.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor(getResources().getColor(com.vtosters.lite.R.color.red));
|
||||
}
|
||||
|
||||
private void lastfmAuth(Context ctx) {
|
||||
@@ -116,6 +170,22 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
}
|
||||
|
||||
private void logout(Context ctx) {
|
||||
VkAlertDialog.Builder alertDialog = new VkAlertDialog.Builder(ctx);
|
||||
alertDialog.setTitle("Вы уверены?");
|
||||
alertDialog.setMessage("Вы действительно хотите выйти из аккаунта?");
|
||||
alertDialog.setPositiveButton("Да", (dialog, which) -> {
|
||||
Scrobbler.logout();
|
||||
});
|
||||
alertDialog.setNeutralButton("Нет", (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
});
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
alert.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor(getResources().getColor(com.vtosters.lite.R.color.red));
|
||||
}
|
||||
|
||||
public static void deleteVideoHistory() {
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
@@ -140,57 +210,22 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
sendToast("История просмотра видео очищена");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(getIdentifier("preferences_media", "xml"));
|
||||
prefs();
|
||||
}
|
||||
public static void download(Context ctx) {
|
||||
AlertDialog.Builder alertDialog = new AlertDialog.Builder(ctx, getAlertStyle());
|
||||
alertDialog.setTitle("Введите ссылку на видео");
|
||||
|
||||
private void prefs() {
|
||||
findPreference("download_video").setOnPreferenceClickListener(new MediaFragment.download());
|
||||
findPreference("clearvideohistory").setOnPreferenceClickListener(preference -> {
|
||||
deleteVideoHistory();
|
||||
return true;
|
||||
});
|
||||
findPreference("dateformat").setOnPreferenceChangeListener(new MediaFragment.restart());
|
||||
findPreference("lastfm_auth").setOnPreferenceClickListener(preference -> {
|
||||
if (isLoggedIn()) {
|
||||
logout(getContext());
|
||||
} else {
|
||||
lastfmAuth(getContext());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary("Вы авторизованы как " + Scrobbler.getUserName());
|
||||
} else {
|
||||
findPreference("lastfm_enabled").setEnabled(false);
|
||||
}
|
||||
|
||||
findPreference("select_photo_search_engine").setOnPreferenceClickListener(preference -> {
|
||||
var items = Arrays.asList(
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("yandex", "drawable"), "Yandex"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("google", "drawable"), "Google"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("microsoft", "drawable"), "Bing")
|
||||
);
|
||||
|
||||
var alert = new VkAlertDialog.Builder(getActivity())
|
||||
.create();
|
||||
|
||||
var listView = (ListView) LayoutInflater.from(getContext()).inflate(com.vtosters.lite.R.layout.abc_select_dialog_material, null, false);
|
||||
var adapter = new ImagineArrayAdapter(getContext(), items, i -> {
|
||||
getPreferences().edit().putInt("search_engine", i).apply();
|
||||
alert.dismiss();
|
||||
});
|
||||
adapter.setSelected(getPreferences().getInt("search_engine", 0));
|
||||
listView.setAdapter(adapter);
|
||||
alert.setView(listView);
|
||||
alert.show();
|
||||
|
||||
return true;
|
||||
});
|
||||
final EditText input = new EditText(ctx);
|
||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
input.setLayoutParams(lp);
|
||||
input.setTextColor(getTextAttr());
|
||||
input.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
|
||||
alertDialog.setView(input);
|
||||
alertDialog.setPositiveButton("Скачать", (dialog, which) -> VideoDownloader.parseVideoLink(input.getText().toString(), ctx));
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
}
|
||||
|
||||
private class download implements Preference.OnPreferenceClickListener {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.StorageVolume;
|
||||
import android.provider.DocumentsContract;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
// https://stackoverflow.com/questions/34927748/android-5-0-documentfile-from-tree-uri/36162691#36162691
|
||||
|
||||
public final class FileUriUtils {
|
||||
|
||||
private static final String PRIMARY_VOLUME_NAME = "primary";
|
||||
|
||||
@Nullable
|
||||
public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) {
|
||||
if (treeUri == null) return null;
|
||||
String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri),con);
|
||||
if (volumePath == null) return File.separator;
|
||||
if (volumePath.endsWith(File.separator))
|
||||
volumePath = volumePath.substring(0, volumePath.length() - 1);
|
||||
|
||||
String documentPath = getDocumentPathFromTreeUri(treeUri);
|
||||
if (documentPath.endsWith(File.separator))
|
||||
documentPath = documentPath.substring(0, documentPath.length() - 1);
|
||||
|
||||
if (documentPath.length() > 0) {
|
||||
if (documentPath.startsWith(File.separator))
|
||||
return volumePath + documentPath;
|
||||
else
|
||||
return volumePath + File.separator + documentPath;
|
||||
}
|
||||
else return volumePath;
|
||||
}
|
||||
|
||||
|
||||
private static String getVolumePath(final String volumeId, Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||
return getVolumePathForAndroid11AndAbove(volumeId, context);
|
||||
else
|
||||
return getVolumePathBeforeAndroid11(volumeId, context);
|
||||
}
|
||||
|
||||
|
||||
private static String getVolumePathBeforeAndroid11(final String volumeId, Context context){
|
||||
try {
|
||||
StorageManager mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||
Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
|
||||
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
|
||||
Method getUuid = storageVolumeClazz.getMethod("getUuid");
|
||||
Method getPath = storageVolumeClazz.getMethod("getPath");
|
||||
Method isPrimary = storageVolumeClazz.getMethod("isPrimary");
|
||||
Object result = getVolumeList.invoke(mStorageManager);
|
||||
|
||||
final int length = Array.getLength(result);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object storageVolumeElement = Array.get(result, i);
|
||||
String uuid = (String) getUuid.invoke(storageVolumeElement);
|
||||
Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);
|
||||
|
||||
if (primary && PRIMARY_VOLUME_NAME.equals(volumeId)) // primary volume?
|
||||
return (String) getPath.invoke(storageVolumeElement);
|
||||
|
||||
if (uuid != null && uuid.equals(volumeId)) // other volumes?
|
||||
return (String) getPath.invoke(storageVolumeElement);
|
||||
}
|
||||
// not found.
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
private static String getVolumePathForAndroid11AndAbove(final String volumeId, Context context) {
|
||||
try {
|
||||
StorageManager mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||
List<StorageVolume> storageVolumes = mStorageManager.getStorageVolumes();
|
||||
for (StorageVolume storageVolume : storageVolumes) {
|
||||
// primary volume?
|
||||
if (storageVolume.isPrimary() && PRIMARY_VOLUME_NAME.equals(volumeId))
|
||||
return storageVolume.getDirectory().getPath();
|
||||
|
||||
// other volumes?
|
||||
String uuid = storageVolume.getUuid();
|
||||
if (uuid != null && uuid.equals(volumeId))
|
||||
return storageVolume.getDirectory().getPath();
|
||||
|
||||
}
|
||||
// not found.
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private static String getVolumeIdFromTreeUri(final Uri treeUri) {
|
||||
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||
final String[] split = docId.split(":");
|
||||
if (split.length > 0) return split[0];
|
||||
else return null;
|
||||
}
|
||||
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private static String getDocumentPathFromTreeUri(final Uri treeUri) {
|
||||
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||
final String[] split = docId.split(":");
|
||||
if ((split.length >= 2) && (split[1] != null)) return split[1];
|
||||
else return File.separator;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package ru.vtosters.lite.utils;
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
import static ru.vtosters.lite.utils.CacheUtils.getInstance;
|
||||
import static ru.vtosters.lite.utils.DeletedMessagesHandler.reloadMessagesList;
|
||||
@@ -17,11 +18,13 @@ import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.vtosters.lite.data.Users;
|
||||
import com.vtosters.lite.fragments.SettingsListFragment;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import ru.vtosters.lite.ui.fragments.VTSettings;
|
||||
@@ -383,4 +386,10 @@ public class Preferences {
|
||||
}
|
||||
return origquality;
|
||||
}
|
||||
|
||||
public static File getDownloadsDir() {
|
||||
return new File(getPreferences().getString(
|
||||
"downloads_directory",
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
android:summary="Показывать результаты в опросах без участия в них"
|
||||
android:title="Результаты опросов" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Загрузки">
|
||||
<Preference
|
||||
android:key="downloads_directory"
|
||||
android:summary="Текущая папка: "
|
||||
android:title="Папка для загрузок" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/sett_media">
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
|
||||
@@ -187,13 +187,17 @@
|
||||
.locals 2
|
||||
|
||||
.line 6
|
||||
invoke-static {}, Lb/h/g/m/FileUtils;->getVKDir()Ljava/io/File;
|
||||
# invoke-static {}, Lb/h/g/m/FileUtils;->getVKDir()Ljava/io/File;
|
||||
#
|
||||
# move-result-object v0
|
||||
#
|
||||
# const-string v1, "Downloads"
|
||||
#
|
||||
# invoke-static {v0, v1}, Lb/h/g/m/FileUtils;->a(Ljava/io/File;Ljava/lang/String;)Ljava/io/File;
|
||||
#
|
||||
# move-result-object v0
|
||||
|
||||
move-result-object v0
|
||||
|
||||
const-string v1, "Downloads"
|
||||
|
||||
invoke-static {v0, v1}, Lb/h/g/m/FileUtils;->a(Ljava/io/File;Ljava/lang/String;)Ljava/io/File;
|
||||
invoke-static {}, Lru/vtosters/lite/utils/Preferences;->getDownloadsDir()Ljava/io/File;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user