Merge ccfb164abafe0a374b5bed806076381f5f84d180 into addf1e23b36d942aeb257c2be4d5d8ab82bdcc11
This commit is contained in:
commit
4a4a0f68b9
@ -299,7 +299,7 @@ public class DownloadDialog extends DialogFragment
|
||||
}
|
||||
|
||||
dialogBinding.fileName.setText(FilenameUtils.createFilename(getContext(),
|
||||
currentInfo.getName()));
|
||||
getFileName()));
|
||||
selectedAudioIndex = ListHelper.getDefaultAudioFormat(getContext(),
|
||||
getWrappedAudioStreams().getStreamsList());
|
||||
|
||||
@ -612,7 +612,7 @@ public class DownloadDialog extends DialogFragment
|
||||
}
|
||||
|
||||
private void onItemSelectedSetFileName() {
|
||||
final String fileName = FilenameUtils.createFilename(getContext(), currentInfo.getName());
|
||||
final String fileName = FilenameUtils.createFilename(getContext(), getFileName());
|
||||
final String prevFileName = Optional.ofNullable(dialogBinding.fileName.getText())
|
||||
.map(Object::toString)
|
||||
.orElse("");
|
||||
@ -743,7 +743,24 @@ public class DownloadDialog extends DialogFragment
|
||||
final String str = Objects.requireNonNull(dialogBinding.fileName.getText()).toString()
|
||||
.trim();
|
||||
|
||||
return FilenameUtils.createFilename(context, str.isEmpty() ? currentInfo.getName() : str);
|
||||
return FilenameUtils.createFilename(context, str.isEmpty() ? getFileName() : str);
|
||||
}
|
||||
|
||||
private String getFileName() {
|
||||
final SharedPreferences sharedPreferences = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
|
||||
final boolean includeUploader = sharedPreferences.getBoolean(
|
||||
context.getString(R.string.settings_file_name_include_uploader_key), false);
|
||||
|
||||
final String name = currentInfo.getName();
|
||||
if (includeUploader) {
|
||||
final String uploader = currentInfo.getUploaderName();
|
||||
if (uploader != null && !uploader.isEmpty()) {
|
||||
return name + " - " + uploader;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private void showFailedDialog(@StringRes final int msg) {
|
||||
|
||||
@ -14,6 +14,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.get.FinishedMission;
|
||||
@ -600,12 +601,25 @@ public class DownloadManager {
|
||||
|
||||
boolean hasFinished = false;
|
||||
|
||||
private boolean filteringEnabled = false;
|
||||
private String currentFilter = "";
|
||||
|
||||
private MissionIterator() {
|
||||
hidden = new ArrayList<>(2);
|
||||
current = null;
|
||||
snapshot = getSpecialItems();
|
||||
}
|
||||
|
||||
public void filter(String query) {
|
||||
currentFilter = query.trim().toLowerCase(Locale.getDefault());
|
||||
filteringEnabled = !currentFilter.isEmpty();
|
||||
}
|
||||
|
||||
public void clearFilter() {
|
||||
currentFilter = "";
|
||||
filteringEnabled = false;
|
||||
}
|
||||
|
||||
private ArrayList<Object> getSpecialItems() {
|
||||
synchronized (DownloadManager.this) {
|
||||
ArrayList<Mission> pending = new ArrayList<>(mMissionsPending);
|
||||
@ -620,6 +634,11 @@ public class DownloadManager {
|
||||
return pending.remove(mission) || finished.remove(mission);
|
||||
});
|
||||
|
||||
if (filteringEnabled && currentFilter != null && !currentFilter.isEmpty()) {
|
||||
pending.removeIf(m -> !matchesFilter(m, currentFilter));
|
||||
finished.removeIf(m -> !matchesFilter(m, currentFilter));
|
||||
}
|
||||
|
||||
int fakeTotal = pending.size();
|
||||
if (fakeTotal > 0) fakeTotal++;
|
||||
|
||||
@ -642,6 +661,11 @@ public class DownloadManager {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchesFilter(Mission mission, String query) {
|
||||
String name = mission.storage.getName().toLowerCase(Locale.getDefault());
|
||||
return name.contains(query);
|
||||
}
|
||||
|
||||
public MissionItem getItem(int position) {
|
||||
Object object = snapshot.get(position);
|
||||
|
||||
@ -729,6 +753,10 @@ public class DownloadManager {
|
||||
Object x = snapshot.get(oldItemPosition);
|
||||
Object y = current.get(newItemPosition);
|
||||
|
||||
// Necessary to avoid flickering of headers when filtering
|
||||
if (x == PENDING && y == PENDING) return true;
|
||||
if (x == FINISHED && y == FINISHED) return true;
|
||||
|
||||
if (x instanceof Mission && y instanceof Mission) {
|
||||
return ((Mission) x).storage.equals(((Mission) y).storage);
|
||||
}
|
||||
|
||||
@ -117,6 +117,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||
private final View mView;
|
||||
private final ArrayList<Mission> mHidden;
|
||||
private Snackbar mSnackbar;
|
||||
private boolean showButtons = true;
|
||||
|
||||
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
@ -186,7 +187,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||
str = R.string.missions_header_pending;
|
||||
} else {
|
||||
str = R.string.missions_header_finished;
|
||||
if (mClear != null) mClear.setVisible(true);
|
||||
if (mClear != null) mClear.setVisible(showButtons);
|
||||
}
|
||||
|
||||
((ViewHolderHeader) view).header.setText(str);
|
||||
@ -731,13 +732,25 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||
}
|
||||
}
|
||||
|
||||
public void filter(String query) {
|
||||
if (query == null) return;
|
||||
|
||||
String currentFilter = query.trim();
|
||||
if (currentFilter.isEmpty()) {
|
||||
mIterator.clearFilter();
|
||||
} else {
|
||||
mIterator.filter(currentFilter);
|
||||
}
|
||||
applyChanges();
|
||||
}
|
||||
|
||||
public void applyChanges() {
|
||||
mIterator.start();
|
||||
DiffUtil.calculateDiff(mIterator, true).dispatchUpdatesTo(this);
|
||||
mIterator.end();
|
||||
|
||||
checkEmptyMessageVisibility();
|
||||
if (mClear != null) mClear.setVisible(mIterator.hasFinishedMissions());
|
||||
if (mClear != null) mClear.setVisible(showButtons && mIterator.hasFinishedMissions());
|
||||
}
|
||||
|
||||
public void forceUpdate() {
|
||||
@ -757,7 +770,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||
|
||||
public void setClearButton(MenuItem clearButton) {
|
||||
if (mClear == null)
|
||||
clearButton.setVisible(mIterator.hasFinishedMissions());
|
||||
clearButton.setVisible(showButtons && mIterator.hasFinishedMissions());
|
||||
|
||||
mClear = clearButton;
|
||||
}
|
||||
@ -771,6 +784,18 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||
if (init) checkMasterButtonsVisibility();
|
||||
}
|
||||
|
||||
public void showMenuButtons() {
|
||||
showButtons = true;
|
||||
if (mClear != null) mClear.setVisible(mIterator.hasFinishedMissions());
|
||||
checkMasterButtonsVisibility();
|
||||
}
|
||||
|
||||
public void hideMenuButtons() {
|
||||
showButtons = false;
|
||||
if (mClear != null) mClear.setVisible(false);
|
||||
checkMasterButtonsVisibility();
|
||||
}
|
||||
|
||||
private void checkEmptyMessageVisibility() {
|
||||
int flag = mIterator.getOldListSize() > 0 ? View.GONE : View.VISIBLE;
|
||||
if (mEmptyMessage.getVisibility() != flag) mEmptyMessage.setVisibility(flag);
|
||||
@ -779,12 +804,12 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||
public void checkMasterButtonsVisibility() {
|
||||
boolean[] state = mIterator.hasValidPendingMissions();
|
||||
Log.d(TAG, "checkMasterButtonsVisibility() running=" + state[0] + " paused=" + state[1]);
|
||||
setButtonVisible(mPauseButton, state[0]);
|
||||
setButtonVisible(mStartButton, state[1]);
|
||||
setButtonVisible(mPauseButton, showButtons && state[0]);
|
||||
setButtonVisible(mStartButton, showButtons && state[1]);
|
||||
}
|
||||
|
||||
private static void setButtonVisible(MenuItem button, boolean visible) {
|
||||
if (button.isVisible() != visible)
|
||||
if (button != null && button.isVisible() != visible)
|
||||
button.setVisible(visible);
|
||||
}
|
||||
|
||||
|
||||
@ -10,24 +10,36 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.style.CharacterStyle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.TooltipCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.evernote.android.state.State;
|
||||
import com.livefront.bridge.Bridge;
|
||||
import com.nononsenseapps.filepicker.Utils;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
@ -35,6 +47,7 @@ import org.schabi.newpipe.settings.NewPipeSettings;
|
||||
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
|
||||
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||
import org.schabi.newpipe.util.KeyboardUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -52,6 +65,7 @@ public class MissionsFragment extends Fragment {
|
||||
|
||||
private SharedPreferences mPrefs;
|
||||
private boolean mLinear;
|
||||
private MenuItem mSearch;
|
||||
private MenuItem mSwitch;
|
||||
private MenuItem mClear = null;
|
||||
private MenuItem mStart = null;
|
||||
@ -64,9 +78,19 @@ public class MissionsFragment extends Fragment {
|
||||
private LinearLayoutManager mLinearManager;
|
||||
private Context mContext;
|
||||
|
||||
private View searchToolbarContainer;
|
||||
private EditText searchEditText;
|
||||
private View searchClear;
|
||||
private TextWatcher textWatcher;
|
||||
|
||||
private DownloadManagerBinder mBinder;
|
||||
private boolean mForceUpdate;
|
||||
|
||||
@State
|
||||
String searchString;
|
||||
@State
|
||||
boolean wasSearchActive;
|
||||
|
||||
private DownloadMission unsafeMissionTarget = null;
|
||||
private final ActivityResultLauncher<Intent> requestDownloadSaveAsLauncher =
|
||||
registerForActivityResult(new StartActivityForResult(), this::requestDownloadSaveAsResult);
|
||||
@ -87,6 +111,11 @@ public class MissionsFragment extends Fragment {
|
||||
mBinder.enableNotifications(false);
|
||||
|
||||
updateList();
|
||||
|
||||
if (isSearchActive()) {
|
||||
mAdapter.hideMenuButtons();
|
||||
mAdapter.filter(getSearchEditString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -132,6 +161,48 @@ public class MissionsFragment extends Fragment {
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
||||
super.onViewCreated(rootView, savedInstanceState);
|
||||
initSearchViews();
|
||||
initSearchListeners();
|
||||
|
||||
Bridge.restoreInstanceState(this, savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
if (wasSearchActive) {
|
||||
searchEditText.setText(searchString);
|
||||
showSearch();
|
||||
}
|
||||
}
|
||||
|
||||
requireActivity().getOnBackPressedDispatcher().addCallback(
|
||||
getViewLifecycleOwner(),
|
||||
new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
if (isSearchActive() && !TextUtils.isEmpty(getSearchEditString())) {
|
||||
hideSearch();
|
||||
} else {
|
||||
setEnabled(false);
|
||||
hideKeyboardSearch();
|
||||
requireActivity().onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull final Bundle bundle) {
|
||||
if (searchEditText != null) {
|
||||
searchString = getSearchEditString();
|
||||
wasSearchActive = isSearchActive();
|
||||
}
|
||||
|
||||
super.onSaveInstanceState(bundle);
|
||||
Bridge.saveInstanceState(this, bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Added in API level 23.
|
||||
*/
|
||||
@ -174,12 +245,14 @@ public class MissionsFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
mSearch = menu.findItem(R.id.action_search);
|
||||
mSwitch = menu.findItem(R.id.switch_mode);
|
||||
mClear = menu.findItem(R.id.clear_list);
|
||||
mStart = menu.findItem(R.id.start_downloads);
|
||||
mPause = menu.findItem(R.id.pause_downloads);
|
||||
|
||||
if (mAdapter != null) setAdapterButtons();
|
||||
if (mSearch != null) mSearch.setVisible(!isSearchActive());
|
||||
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
@ -200,6 +273,10 @@ public class MissionsFragment extends Fragment {
|
||||
case R.id.pause_downloads:
|
||||
mBinder.getDownloadManager().pauseAllMissions(false);
|
||||
mAdapter.refreshMissionItems();// update items view
|
||||
return true;
|
||||
case R.id.action_search:
|
||||
showSearch();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
@ -246,8 +323,8 @@ public class MissionsFragment extends Fragment {
|
||||
|
||||
if (mSwitch != null) {
|
||||
mSwitch.setIcon(mLinear
|
||||
? R.drawable.ic_apps
|
||||
: R.drawable.ic_list);
|
||||
? R.drawable.ic_apps
|
||||
: R.drawable.ic_list);
|
||||
mSwitch.setTitle(mLinear ? R.string.grid : R.string.list);
|
||||
mPrefs.edit().putBoolean("linear", mLinear).apply();
|
||||
}
|
||||
@ -338,4 +415,110 @@ public class MissionsFragment extends Fragment {
|
||||
Toast.makeText(mContext, R.string.general_error, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void initSearchViews() {
|
||||
searchToolbarContainer = requireActivity().findViewById(R.id.toolbar_search_container);
|
||||
searchEditText = searchToolbarContainer.findViewById(R.id.toolbar_search_edit_text);
|
||||
searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear);
|
||||
}
|
||||
|
||||
private void initSearchListeners() {
|
||||
searchClear.setOnClickListener(v -> {
|
||||
if (TextUtils.isEmpty(getSearchEditString())) {
|
||||
hideSearch();
|
||||
return;
|
||||
}
|
||||
searchEditText.setText("");
|
||||
showKeyboardSearch();
|
||||
});
|
||||
|
||||
TooltipCompat.setTooltipText(searchClear, getString(R.string.clear));
|
||||
|
||||
if (textWatcher != null) {
|
||||
searchEditText.removeTextChangedListener(textWatcher);
|
||||
}
|
||||
textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start,
|
||||
final int count, final int after) {
|
||||
// Do nothing, old text is already clean
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start,
|
||||
final int before, final int count) {
|
||||
// Changes are handled in afterTextChanged; CharSequence cannot be changed here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
// Remove rich text formatting
|
||||
for (final CharacterStyle span : s.getSpans(0, s.length(), CharacterStyle.class)) {
|
||||
s.removeSpan(span);
|
||||
}
|
||||
|
||||
if (mAdapter != null) mAdapter.filter(s.toString());
|
||||
}
|
||||
};
|
||||
searchEditText.addTextChangedListener(textWatcher);
|
||||
|
||||
searchEditText.setOnEditorActionListener((v, actionId, event) -> {
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
|
||||
(event != null
|
||||
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER
|
||||
&& event.getAction() == KeyEvent.ACTION_DOWN)) {
|
||||
hideKeyboardSearch();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void showSearch() {
|
||||
if (mSearch != null) mSearch.setVisible(false);
|
||||
if (mAdapter != null) mAdapter.hideMenuButtons();
|
||||
|
||||
showKeyboardSearch();
|
||||
|
||||
if (TextUtils.isEmpty(getSearchEditString())) {
|
||||
searchToolbarContainer.setTranslationX(100);
|
||||
searchToolbarContainer.setAlpha(0.0f);
|
||||
searchToolbarContainer.setVisibility(View.VISIBLE);
|
||||
searchToolbarContainer.animate()
|
||||
.translationX(0)
|
||||
.alpha(1.0f)
|
||||
.setDuration(200)
|
||||
.setInterpolator(new DecelerateInterpolator()).start();
|
||||
} else {
|
||||
searchToolbarContainer.setTranslationX(0);
|
||||
searchToolbarContainer.setAlpha(1.0f);
|
||||
searchToolbarContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideSearch() {
|
||||
hideKeyboardSearch();
|
||||
searchToolbarContainer.setVisibility(View.GONE);
|
||||
if (!TextUtils.isEmpty(getSearchEditString())) searchEditText.setText("");
|
||||
|
||||
if (mSearch != null) mSearch.setVisible(true);
|
||||
if (mAdapter != null) mAdapter.showMenuButtons();
|
||||
}
|
||||
|
||||
private boolean isSearchActive() {
|
||||
return searchToolbarContainer.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
private String getSearchEditString() {
|
||||
return searchEditText.getText().toString();
|
||||
}
|
||||
|
||||
private void showKeyboardSearch() {
|
||||
KeyboardUtil.showKeyboard(requireActivity(), searchEditText);
|
||||
}
|
||||
|
||||
private void hideKeyboardSearch() {
|
||||
KeyboardUtil.hideKeyboard(requireActivity(), searchEditText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,12 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_search"
|
||||
android:icon="@drawable/ic_search"
|
||||
android:title="@string/search"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/switch_mode"
|
||||
android:icon="@drawable/ic_apps"
|
||||
|
||||
@ -101,7 +101,7 @@
|
||||
<string name="popup_remember_size_pos_summary">Letzte Größe und Position des Pop-ups merken</string>
|
||||
<string name="show_search_suggestions_title">Suchvorschläge</string>
|
||||
<string name="show_search_suggestions_summary">Vorschläge auswählen, die bei der Suche angezeigt werden sollen</string>
|
||||
<string name="clear">löschen</string>
|
||||
<string name="clear">Löschen</string>
|
||||
<string name="best_resolution">Beste Auflösung</string>
|
||||
<string name="title_activity_about">Über NewPipe</string>
|
||||
<string name="tab_licenses">Lizenzen</string>
|
||||
@ -118,6 +118,8 @@
|
||||
<string name="settings_file_charset_title">Erlaubte Zeichen im Dateinamen</string>
|
||||
<string name="settings_file_replacement_character_summary">Ungültige Zeichen werden durch dieses Zeichen ersetzt</string>
|
||||
<string name="settings_file_replacement_character_title">Ersetzungszeichen</string>
|
||||
<string name="settings_file_name_include_uploader_key_summary">Name des Uploaders an den Dateinamen anhängen</string>
|
||||
<string name="settings_file_name_include_uploader_key_title">Uploader im Dateinamen</string>
|
||||
<string name="charset_letters_and_digits">Buchstaben und Zahlen</string>
|
||||
<string name="subscribe_button_title">Abonnieren</string>
|
||||
<string name="subscribed_button_title">Abonniert</string>
|
||||
|
||||
@ -432,6 +432,7 @@
|
||||
<string name="settings_file_charset_key">file_rename_charset</string>
|
||||
<string name="settings_file_replacement_character_key">file_replacement_character</string>
|
||||
<string name="settings_file_replacement_character_default_value">_</string>
|
||||
<string name="settings_file_name_include_uploader_key">file_include_uploader_name</string>
|
||||
|
||||
|
||||
<string name="charset_letters_and_digits_value">CHARSET_LETTERS_AND_DIGITS</string>
|
||||
|
||||
@ -365,6 +365,8 @@
|
||||
<string name="settings_file_charset_title">Allowed characters in filenames</string>
|
||||
<string name="settings_file_replacement_character_summary">Invalid characters are replaced with this value</string>
|
||||
<string name="settings_file_replacement_character_title">Replacement character</string>
|
||||
<string name="settings_file_name_include_uploader_key_summary">Append uploader name to filename</string>
|
||||
<string name="settings_file_name_include_uploader_key_title">Uploader in filename</string>
|
||||
<string name="charset_letters_and_digits">Letters and digits</string>
|
||||
<string name="charset_most_special_characters">Most special characters</string>
|
||||
<!-- About -->
|
||||
|
||||
@ -53,6 +53,14 @@
|
||||
app:singleLineTitle="false"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="@string/settings_file_name_include_uploader_key"
|
||||
android:summary="@string/settings_file_name_include_uploader_key_summary"
|
||||
android:title="@string/settings_file_name_include_uploader_key_title"
|
||||
app:singleLineTitle="false"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/downloads_maximum_retry_default"
|
||||
android:entries="@array/downloads_maximum_retry_list"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user