Merge pull request #1639 from mfietz/issue/975-no-external-storage

No external storage / Choose Data Folder redo
This commit is contained in:
Tom Hennen 2016-02-06 11:19:13 -05:00
commit 6e6a452a4d
28 changed files with 440 additions and 293 deletions

View File

@ -6,8 +6,8 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileObserver;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@ -34,7 +34,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
* Let's the user choose a directory on the storage device. The selected folder
* will be sent back to the starting activity as an activity result.
*/
public class DirectoryChooserActivity extends ActionBarActivity {
public class DirectoryChooserActivity extends AppCompatActivity {
private static final String TAG = "DirectoryChooserActivit";
private static final String CREATE_DIRECTORY_NAME = "AntennaPod";
@ -250,8 +251,7 @@ public class DirectoryChooserActivity extends ActionBarActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.new_folder_item)
.setVisible(isValidFile(selectedDir));
menu.findItem(R.id.new_folder_item).setVisible(isValidFile(selectedDir));
return true;
}
@ -333,4 +333,5 @@ public class DirectoryChooserActivity extends ActionBarActivity {
private boolean isValidFile(File file) {
return file != null && file.isDirectory() && file.canRead() && file.canWrite();
}
}

View File

@ -1,30 +1,109 @@
package de.danoeh.antennapod.activity;
import android.Manifest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
import com.afollestad.materialdialogs.MaterialDialog;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.StorageUtils;
/** Is show if there is now external storage available. */
public class StorageErrorActivity extends ActionBarActivity {
public class StorageErrorActivity extends AppCompatActivity {
private static final String TAG = "StorageErrorActivity";
private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 42;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
setContentView(R.layout.storage_error);
}
Button btnChooseDataFolder = (Button) findViewById(R.id.btnChooseDataFolder);
btnChooseDataFolder.setOnClickListener(v -> {
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
showChooseDataFolderDialog();
} else {
openDirectoryChooser();
}
});
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
int readPermission = ActivityCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE);
int writePermission = ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (readPermission != PackageManager.PERMISSION_GRANTED ||
writePermission != PackageManager.PERMISSION_GRANTED) {
requestPermission();
}
}
}
private void requestPermission() {
ActivityCompat.requestPermissions(this, EXTERNAL_STORAGE_PERMISSIONS,
PERMISSION_REQUEST_EXTERNAL_STORAGE);
}
private void openDirectoryChooser() {
Intent intent = new Intent(this, DirectoryChooserActivity.class);
startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
}
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions,
int[] grantResults) {
if (requestCode != PERMISSION_REQUEST_EXTERNAL_STORAGE || grantResults.length != 2) {
return;
}
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED) {
new MaterialDialog.Builder(this)
.content(R.string.choose_data_directory_permission_rationale)
.positiveText(android.R.string.ok)
.onPositive((dialog, which) -> requestPermission())
.onNegative((dialog, which) -> finish())
.show();
}
}
@Override
protected void onResume() {
super.onResume();
if (StorageUtils.storageAvailable()) {
leaveErrorState();
} else {
registerReceiver(mediaUpdate, new IntentFilter(Intent.ACTION_MEDIA_MOUNTED));
}
}
@Override
protected void onPause() {
@ -32,18 +111,102 @@ public class StorageErrorActivity extends ActionBarActivity {
try {
unregisterReceiver(mediaUpdate);
} catch (IllegalArgumentException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
}
@Override
protected void onResume() {
super.onResume();
if (StorageUtils.storageAvailable()) {
leaveErrorState();
} else {
registerReceiver(mediaUpdate, new IntentFilter(
Intent.ACTION_MEDIA_MOUNTED));
// see PreferenceController.showChooseDataFolderDialog()
private void showChooseDataFolderDialog() {
File dataFolder = UserPreferences.getDataFolder(null);
if(dataFolder == null) {
new MaterialDialog.Builder(this)
.title(R.string.error_label)
.content(R.string.external_storage_error_msg)
.neutralText(android.R.string.ok)
.show();
return;
}
String dataFolderPath = dataFolder.getAbsolutePath();
int selectedIndex = -1;
File[] mediaDirs = ContextCompat.getExternalFilesDirs(this, null);
List<String> folders = new ArrayList<>(mediaDirs.length);
List<CharSequence> choices = new ArrayList<>(mediaDirs.length);
for(int i=0; i < mediaDirs.length; i++) {
if(mediaDirs[i] == null) {
continue;
}
String path = mediaDirs[i].getAbsolutePath();
folders.add(path);
if(dataFolderPath.equals(path)) {
selectedIndex = i;
}
int index = path.indexOf("Android");
String choice;
if(index >= 0) {
choice = path.substring(0, index);
} else {
choice = path;
}
long bytes = StorageUtils.getFreeSpaceAvailable(path);
String freeSpace = String.format(getString(R.string.free_space_label),
Converter.byteToString(bytes));
choices.add(Html.fromHtml("<html><small>" + choice + " [" + freeSpace + "]"
+ "</small></html>"));
}
if(choices.size() == 0) {
new MaterialDialog.Builder(this)
.title(R.string.error_label)
.content(R.string.external_storage_error_msg)
.neutralText(android.R.string.ok)
.show();
return;
}
MaterialDialog dialog = new MaterialDialog.Builder(this)
.title(R.string.choose_data_directory)
.content(R.string.choose_data_directory_message)
.items(choices.toArray(new CharSequence[choices.size()]))
.itemsCallbackSingleChoice(selectedIndex, (dialog1, itemView, which, text) -> {
String folder = folders.get(which);
UserPreferences.setDataFolder(folder);
leaveErrorState();
return true;
})
.negativeText(R.string.cancel_label)
.cancelable(true)
.build();
dialog.show();
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK &&
requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
File path;
if (dir != null) {
path = new File(dir);
} else {
path = getExternalFilesDir(null);
}
String message = null;
if(!path.exists()) {
message = String.format(getString(R.string.folder_does_not_exist_error), dir);
} else if(!path.canRead()) {
message = String.format(getString(R.string.folder_not_readable_error), dir);
} else if(!path.canWrite()) {
message = String.format(getString(R.string.folder_not_writable_error), dir);
}
if(message == null) {
Log.d(TAG, "Setting data folder: " + dir);
UserPreferences.setDataFolder(dir);
leaveErrorState();
} else {
AlertDialog.Builder ab = new AlertDialog.Builder(this);
ab.setMessage(message);
ab.setPositiveButton(android.R.string.ok, null);
ab.show();
}
}
}
@ -58,13 +221,10 @@ public class StorageErrorActivity extends ActionBarActivity {
public void onReceive(Context context, Intent intent) {
if (TextUtils.equals(intent.getAction(), Intent.ACTION_MEDIA_MOUNTED)) {
if (intent.getBooleanExtra("read-only", true)) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Media was mounted; Finishing activity");
Log.d(TAG, "Media was mounted; Finishing activity");
leaveErrorState();
} else {
if (BuildConfig.DEBUG)
Log.d(TAG,
"Media seemed to have been mounted read only");
Log.d(TAG, "Media seemed to have been mounted read only");
}
}
}

View File

@ -1,12 +1,13 @@
package de.danoeh.antennapod.preferences;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
@ -18,6 +19,7 @@ import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
@ -85,6 +87,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
private CheckBoxPreference[] selectedNetworks;
private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
public PreferenceController(PreferenceUI ui) {
this.ui = ui;
PreferenceManager.getDefaultSharedPreferences(ui.getActivity().getApplicationContext())
@ -121,54 +128,51 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
// disable expanded notification option on unsupported android versions
ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setEnabled(false);
ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Toast toast = Toast.makeText(activity, R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT);
toast.show();
return true;
}
preference -> {
Toast toast = Toast.makeText(activity,
R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT);
toast.show();
return true;
}
);
}
ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
FlattrUtils.revokeAccessToken(activity);
checkItemVisibility();
return true;
}
preference -> {
FlattrUtils.revokeAccessToken(activity);
checkItemVisibility();
return true;
}
);
ui.findPreference(PreferenceController.PREF_ABOUT).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
activity.startActivity(new Intent(
activity, AboutActivity.class));
return true;
}
preference -> {
activity.startActivity(new Intent(activity, AboutActivity.class));
return true;
}
);
ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
new OpmlExportWorker(activity)
.executeAsync();
return true;
preference -> {
new OpmlExportWorker(activity).executeAsync();
return true;
}
);
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
preference -> {
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
showChooseDataFolderDialog();
} else {
int readPermission = ActivityCompat.checkSelfPermission(
activity, Manifest.permission.READ_EXTERNAL_STORAGE);
int writePermission = ActivityCompat.checkSelfPermission(
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (readPermission == PackageManager.PERMISSION_GRANTED &&
writePermission == PackageManager.PERMISSION_GRANTED) {
openDirectoryChooser();
} else {
requestPermission();
}
}
return true;
}
);
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR)
@ -185,40 +189,29 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
return true;
}
}
);
}
);
ui.findPreference(UserPreferences.PREF_THEME)
.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(
Preference preference, Object newValue) {
Intent i = new Intent(activity, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NEW_TASK);
activity.finish();
activity.startActivity(i);
return true;
}
(preference, newValue) -> {
Intent i = new Intent(activity, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NEW_TASK);
activity.finish();
activity.startActivity(i);
return true;
}
);
ui.findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS)
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showDrawerPreferencesDialog();
return true;
}
.setOnPreferenceClickListener(preference -> {
showDrawerPreferencesDialog();
return true;
});
ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showUpdateIntervalTimePreferencesDialog();
return true;
}
.setOnPreferenceClickListener(preference -> {
showUpdateIntervalTimePreferencesDialog();
return true;
});
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL).setOnPreferenceChangeListener(
@ -234,38 +227,30 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
});
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(
Preference preference, Object newValue) {
if (newValue instanceof Boolean) {
setSelectedNetworksEnabled((Boolean) newValue);
return true;
} else {
return false;
}
(preference, newValue) -> {
if (newValue instanceof Boolean) {
setSelectedNetworksEnabled((Boolean) newValue);
return true;
} else {
return false;
}
}
);
ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
if (o instanceof String) {
try {
int value = Integer.valueOf((String) o);
if (1 <= value && value <= 50) {
setParallelDownloadsText(value);
return true;
}
} catch (NumberFormatException e) {
return false;
(preference, o) -> {
if (o instanceof String) {
try {
int value = Integer.valueOf((String) o);
if (1 <= value && value <= 50) {
setParallelDownloadsText(value);
return true;
}
} catch (NumberFormatException e) {
return false;
}
return false;
}
return false;
}
);
// validate and set correct value: number of downloads between 1 and 50 (inclusive)
@ -298,102 +283,79 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
});
ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
if (o instanceof String) {
setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o));
}
return true;
(preference, o) -> {
if (o instanceof String) {
setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o));
}
return true;
}
);
ui.findPreference(PreferenceController.PREF_PLAYBACK_SPEED_LAUNCHER)
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
VariableSpeedDialog.showDialog(activity);
.setOnPreferenceClickListener(preference -> {
VariableSpeedDialog.showDialog(activity);
return true;
});
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION)
.setOnPreferenceClickListener(preference -> {
AuthenticationDialog dialog = new AuthenticationDialog(activity,
R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(),
null) {
@Override
protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
GpodnetPreferences.setPassword(password);
}
};
dialog.show();
return true;
});
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
preference -> {
GpodnetPreferences.logout();
Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT);
toast.show();
updateGpodnetPreferenceScreen();
return true;
});
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(
preference -> {
GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen());
return true;
});
ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
.setOnPreferenceClickListener(preference -> {
AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
@Override
public void onCancelled() {
}
@Override
public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
checkItemVisibility();
}
});
return true;
});
ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
(preference, o) -> {
if (o instanceof String) {
int newValue = Integer.valueOf((String) o) * 1024 * 1024;
if (newValue != UserPreferences.getImageCacheSize()) {
AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
dialog.setTitle(android.R.string.dialog_alert_title);
dialog.setMessage(R.string.pref_restart_required);
dialog.setPositiveButton(android.R.string.ok, null);
dialog.show();
}
return true;
}
});
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
AuthenticationDialog dialog = new AuthenticationDialog(activity,
R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(),
null) {
@Override
protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
GpodnetPreferences.setPassword(password);
}
};
dialog.show();
return true;
}
});
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
GpodnetPreferences.logout();
Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT);
toast.show();
updateGpodnetPreferenceScreen();
return true;
}
});
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
updateGpodnetPreferenceScreen();
}
});
return true;
}
});
ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
@Override
public void onCancelled() {
}
@Override
public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
checkItemVisibility();
}
});
return true;
}
});
ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE)
.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
if (o instanceof String) {
int newValue = Integer.valueOf((String) o) * 1024 * 1024;
if (newValue != UserPreferences.getImageCacheSize()) {
AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
dialog.setTitle(android.R.string.dialog_alert_title);
dialog.setMessage(R.string.pref_restart_required);
dialog.setPositiveButton(android.R.string.ok, null);
dialog.show();
}
return true;
}
return false;
}
}
);
return false;
}
);
ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
@ -427,7 +389,12 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
File path = new File(dir);
File path;
if(dir != null) {
path = new File(dir);
} else {
path = ui.getActivity().getExternalFilesDir(null);
}
String message = null;
final Context context= ui.getActivity().getApplicationContext();
if(!path.exists()) {
@ -628,35 +595,31 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
List<String> prefValues = Arrays.asList(UserPreferences
.getAutodownloadSelectedNetworks());
PreferenceScreen prefScreen = (PreferenceScreen) ui.findPreference(PreferenceController.AUTO_DL_PREF_SCREEN);
Preference.OnPreferenceClickListener clickListener = new Preference.OnPreferenceClickListener() {
Preference.OnPreferenceClickListener clickListener = preference -> {
if (preference instanceof CheckBoxPreference) {
String key = preference.getKey();
ArrayList<String> prefValuesList = new ArrayList<String>(
Arrays.asList(UserPreferences
.getAutodownloadSelectedNetworks())
);
boolean newValue = ((CheckBoxPreference) preference)
.isChecked();
Log.d(TAG, "Selected network " + key + ". New state: " + newValue);
@Override
public boolean onPreferenceClick(Preference preference) {
if (preference instanceof CheckBoxPreference) {
String key = preference.getKey();
ArrayList<String> prefValuesList = new ArrayList<String>(
Arrays.asList(UserPreferences
.getAutodownloadSelectedNetworks())
);
boolean newValue = ((CheckBoxPreference) preference)
.isChecked();
Log.d(TAG, "Selected network " + key + ". New state: " + newValue);
int index = prefValuesList.indexOf(key);
if (index >= 0 && newValue == false) {
// remove network
prefValuesList.remove(index);
} else if (index < 0 && newValue == true) {
prefValuesList.add(key);
}
UserPreferences.setAutodownloadSelectedNetworks(
prefValuesList.toArray(new String[prefValuesList.size()])
);
return true;
} else {
return false;
int index = prefValuesList.indexOf(key);
if (index >= 0 && newValue == false) {
// remove network
prefValuesList.remove(index);
} else if (index < 0 && newValue == true) {
prefValuesList.add(key);
}
UserPreferences.setAutodownloadSelectedNetworks(
prefValuesList.toArray(new String[prefValuesList.size()])
);
return true;
} else {
return false;
}
};
// create preference for each known network. attach listener and set
@ -703,7 +666,6 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
checked[i] = true;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.drawer_preferences);
builder.setMultiChoiceItems(navTitles, checked, (dialog, which, isChecked) -> {
@ -713,16 +675,26 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
}
});
builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
}
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.create().show();
}
// CHOOSE DATA FOLDER
private void requestPermission() {
ActivityCompat.requestPermissions(ui.getActivity(), EXTERNAL_STORAGE_PERMISSIONS,
PERMISSION_REQUEST_EXTERNAL_STORAGE);
}
private void openDirectoryChooser() {
Activity activity = ui.getActivity();
Intent intent = new Intent(activity, DirectoryChooserActivity.class);
activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
}
private void showChooseDataFolderDialog() {
Context context = ui.getActivity();
File dataFolder = UserPreferences.getDataFolder(null);
@ -786,6 +758,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
dialog.show();
}
// UPDATE TIME/INTERVAL DIALOG
private void showUpdateIntervalTimePreferencesDialog() {
final Context context = ui.getActivity();
@ -795,38 +769,34 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
builder.positiveText(R.string.pref_autoUpdateIntervallOrTime_Interval);
builder.negativeText(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay);
builder.neutralText(R.string.pref_autoUpdateIntervallOrTime_Disable);
builder.callback(new MaterialDialog.ButtonCallback() {
@Override
public void onPositive(MaterialDialog dialog) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
final String[] entries = getUpdateIntervalEntries(values);
long currInterval = UserPreferences.getUpdateInterval();
int checkedItem = -1;
if(currInterval > 0) {
String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval));
checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
}
builder.setSingleChoiceItems(entries, checkedItem, (dialog1, which) -> {
int hours = Integer.valueOf(values[which]);
UserPreferences.setUpdateInterval(hours);
dialog1.dismiss();
setUpdateIntervalText();
});
builder.setNegativeButton(context.getString(R.string.cancel_label), null);
builder.show();
builder.onPositive((dialog, which) -> {
AlertDialog.Builder builder1 = new AlertDialog.Builder(context);
builder1.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
final String[] entries = getUpdateIntervalEntries(values);
long currInterval = UserPreferences.getUpdateInterval();
int checkedItem = -1;
if(currInterval > 0) {
String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval));
checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
}
@Override
public void onNegative(MaterialDialog dialog) {
int hourOfDay = 7, minute = 0;
int[] updateTime = UserPreferences.getUpdateTimeOfDay();
if (updateTime.length == 2) {
hourOfDay = updateTime[0];
minute = updateTime[1];
}
TimePickerDialog timePickerDialog = new TimePickerDialog(context,
builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
int hours = Integer.valueOf(values[which1]);
UserPreferences.setUpdateInterval(hours);
dialog1.dismiss();
setUpdateIntervalText();
});
builder1.setNegativeButton(context.getString(R.string.cancel_label), null);
builder1.show();
});
builder.onNegative((dialog, which) -> {
int hourOfDay = 7, minute = 0;
int[] updateTime = UserPreferences.getUpdateTimeOfDay();
if (updateTime.length == 2) {
hourOfDay = updateTime[0];
minute = updateTime[1];
}
TimePickerDialog timePickerDialog = new TimePickerDialog(context,
(view, selectedHourOfDay, selectedMinute) -> {
if (view.getTag() == null) { // onTimeSet() may get called twice!
view.setTag("TAGGED");
@ -834,17 +804,13 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
setUpdateIntervalText();
}
}, hourOfDay, minute, DateFormat.is24HourFormat(context));
timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
timePickerDialog.show();
}
@Override
public void onNeutral(MaterialDialog dialog) {
UserPreferences.setUpdateInterval(0);
setUpdateIntervalText();
}
timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
timePickerDialog.show();
});
builder.onNeutral((dialog, which) -> {
UserPreferences.setUpdateInterval(0);
setUpdateIntervalText();
});
builder.forceStacking(true);
builder.show();
}

View File

@ -1,25 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:id="@+id/imageView1"
android:contentDescription="@string/external_storage_error_msg"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_margin="16dp"
android:src="@android:drawable/stat_notify_sdcard_usb" />
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_margin="8dp"
android:src="?attr/ic_sd_storage" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imageView1"
android:layout_centerHorizontal="true"
android:layout_margin="8dp"
android:text="@string/external_storage_error_msg" />
</RelativeLayout>
<Button
android:id="@+id/btnChooseDataFolder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/choose_data_directory"/>
</LinearLayout>

View File

@ -1,14 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto">
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/new_folder_item"
android:title="@string/create_folder_label"
custom:showAsAction="ifRoom|withText"/>
android:icon="?attr/ic_create_new_folder"
custom:showAsAction="ifRoom|withText" />
<item
android:id="@+id/set_to_default_folder_item"
custom:showAsAction="collapseActionView"
android:title="@string/set_to_default_folder"/>
android:title="@string/set_to_default_folder"
custom:showAsAction="collapseActionView" />
</menu>
</menu>

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

View File

@ -50,6 +50,8 @@
<attr name="ic_check_box_outline" format="reference"/>
<attr name="ic_indeterminate_check_box" format="reference"/>
<attr name="ic_sort" format="reference"/>
<attr name="ic_sd_storage" format="reference"/>
<attr name="ic_create_new_folder" format="reference"/>
<!-- Used in itemdescription -->
<attr name="non_transparent_background" format="reference"/>

View File

@ -485,6 +485,7 @@
<string name="create_folder_label">Create folder</string>
<string name="choose_data_directory">Choose Data Folder</string>
<string name="choose_data_directory_message">Please choose the base of your data folder. AntennaPod will create the appropriate sub-directories.</string>
<string name="choose_data_directory_permission_rationale">Access to external storage is required to change the data folder</string>
<string name="create_folder_msg">Create new folder with name "%1$s"?</string>
<string name="create_folder_success">Created new folder</string>
<string name="create_folder_error_no_write_access">Cannot write to this folder</string>

View File

@ -57,6 +57,8 @@
<item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_grey600_24dp</item>
<item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_grey600_24dp</item>
<item name="attr/ic_sort">@drawable/ic_sort_grey600_24dp</item>
<item name="attr/ic_sd_storage">@drawable/ic_sd_storage_grey600_36dp</item>
<item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_grey600_24dp</item>
</style>
<style name="Theme.AntennaPod.Dark" parent="Theme.AppCompat">
@ -114,6 +116,8 @@
<item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_white_24dp</item>
<item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_white_24dp</item>
<item name="attr/ic_sort">@drawable/ic_sort_white_24dp</item>
<item name="attr/ic_sd_storage">@drawable/ic_sd_storage_white_36dp</item>
<item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_white_24dp</item>
</style>
<style name="Theme.AntennaPod.Light.NoTitle" parent="Theme.AppCompat.Light.NoActionBar">
@ -173,6 +177,8 @@
<item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_grey600_24dp</item>
<item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_grey600_24dp</item>
<item name="attr/ic_sort">@drawable/ic_sort_grey600_24dp</item>
<item name="attr/ic_sd_storage">@drawable/ic_sd_storage_grey600_36dp</item>
<item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_grey600_24dp</item>
</style>
<style name="Theme.AntennaPod.Dark.NoTitle" parent="Theme.AppCompat.NoActionBar">
@ -231,6 +237,8 @@
<item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_white_24dp</item>
<item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_white_24dp</item>
<item name="attr/ic_sort">@drawable/ic_sort_white_24dp</item>
<item name="attr/ic_sd_storage">@drawable/ic_sd_storage_white_36dp</item>
<item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_white_24dp</item>
</style>
<style name="Theme.AntennaPod.VideoPlayer" parent="@style/Theme.AntennaPod.Dark">