Merge pull request #6716 from TeamNewPipe/release_0.21.7
Hotfix release 0.21.7
This commit is contained in:
commit
b58f7856a1
|
@ -17,8 +17,8 @@ android {
|
||||||
resValue "string", "app_name", "NewPipe"
|
resValue "string", "app_name", "NewPipe"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 972
|
versionCode 973
|
||||||
versionName "0.21.6"
|
versionName "0.21.7"
|
||||||
|
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ dependencies {
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
implementation 'androidx.core:core-ktx:1.3.2'
|
implementation 'androidx.core:core-ktx:1.3.2'
|
||||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.3.4'
|
implementation 'androidx.fragment:fragment-ktx:1.3.5'
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
|
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
|
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
|
||||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||||
|
|
|
@ -589,9 +589,9 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
downloadDialog.setVideoStreams(sortedVideoStreams);
|
downloadDialog.setVideoStreams(sortedVideoStreams);
|
||||||
downloadDialog.setAudioStreams(result.getAudioStreams());
|
downloadDialog.setAudioStreams(result.getAudioStreams());
|
||||||
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
||||||
|
downloadDialog.setOnDismissListener(dialog -> finish());
|
||||||
downloadDialog.show(fm, "downloadDialog");
|
downloadDialog.show(fm, "downloadDialog");
|
||||||
fm.executePendingTransactions();
|
fm.executePendingTransactions();
|
||||||
downloadDialog.requireDialog().setOnDismissListener(dialog -> finish());
|
|
||||||
}, throwable ->
|
}, throwable ->
|
||||||
showUnsupportedUrlDialog(currentUrl)));
|
showUnsupportedUrlDialog(currentUrl)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package org.schabi.newpipe.download;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnDismissListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
@ -20,6 +22,9 @@ import android.widget.RadioGroup;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.annotation.IdRes;
|
import androidx.annotation.IdRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -35,7 +40,6 @@ import com.nononsenseapps.filepicker.Utils;
|
||||||
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.RouterActivity;
|
|
||||||
import org.schabi.newpipe.databinding.DownloadDialogBinding;
|
import org.schabi.newpipe.databinding.DownloadDialogBinding;
|
||||||
import org.schabi.newpipe.error.ErrorActivity;
|
import org.schabi.newpipe.error.ErrorActivity;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
|
@ -82,9 +86,6 @@ public class DownloadDialog extends DialogFragment
|
||||||
implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
||||||
private static final String TAG = "DialogFragment";
|
private static final String TAG = "DialogFragment";
|
||||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
|
|
||||||
private static final int REQUEST_DOWNLOAD_PICK_VIDEO_FOLDER = 0x789E;
|
|
||||||
private static final int REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER = 0x789F;
|
|
||||||
|
|
||||||
@State
|
@State
|
||||||
StreamInfo currentInfo;
|
StreamInfo currentInfo;
|
||||||
|
@ -101,6 +102,9 @@ public class DownloadDialog extends DialogFragment
|
||||||
@State
|
@State
|
||||||
int selectedSubtitleIndex = 0;
|
int selectedSubtitleIndex = 0;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private OnDismissListener onDismissListener = null;
|
||||||
|
|
||||||
private StoredDirectoryHelper mainStorageAudio = null;
|
private StoredDirectoryHelper mainStorageAudio = null;
|
||||||
private StoredDirectoryHelper mainStorageVideo = null;
|
private StoredDirectoryHelper mainStorageVideo = null;
|
||||||
private DownloadManager downloadManager = null;
|
private DownloadManager downloadManager = null;
|
||||||
|
@ -122,6 +126,21 @@ public class DownloadDialog extends DialogFragment
|
||||||
private String filenameTmp;
|
private String filenameTmp;
|
||||||
private String mimeTmp;
|
private String mimeTmp;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> requestDownloadSaveAsLauncher =
|
||||||
|
registerForActivityResult(
|
||||||
|
new StartActivityForResult(), this::requestDownloadSaveAsResult);
|
||||||
|
private final ActivityResultLauncher<Intent> requestDownloadPickAudioFolderLauncher =
|
||||||
|
registerForActivityResult(
|
||||||
|
new StartActivityForResult(), this::requestDownloadPickAudioFolderResult);
|
||||||
|
private final ActivityResultLauncher<Intent> requestDownloadPickVideoFolderLauncher =
|
||||||
|
registerForActivityResult(
|
||||||
|
new StartActivityForResult(), this::requestDownloadPickVideoFolderResult);
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Instance creation
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public static DownloadDialog newInstance(final StreamInfo info) {
|
public static DownloadDialog newInstance(final StreamInfo info) {
|
||||||
final DownloadDialog dialog = new DownloadDialog();
|
final DownloadDialog dialog = new DownloadDialog();
|
||||||
dialog.setInfo(info);
|
dialog.setInfo(info);
|
||||||
|
@ -143,6 +162,11 @@ public class DownloadDialog extends DialogFragment
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Setters
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void setInfo(final StreamInfo info) {
|
private void setInfo(final StreamInfo info) {
|
||||||
this.currentInfo = info;
|
this.currentInfo = info;
|
||||||
}
|
}
|
||||||
|
@ -184,6 +208,14 @@ public class DownloadDialog extends DialogFragment
|
||||||
this.selectedSubtitleIndex = ssi;
|
this.selectedSubtitleIndex = ssi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOnDismissListener(@Nullable final OnDismissListener onDismissListener) {
|
||||||
|
this.onDismissListener = onDismissListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Android lifecycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -194,7 +226,7 @@ public class DownloadDialog extends DialogFragment
|
||||||
|
|
||||||
if (!PermissionHelper.checkStoragePermissions(getActivity(),
|
if (!PermissionHelper.checkStoragePermissions(getActivity(),
|
||||||
PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
||||||
getDialog().dismiss();
|
dismiss();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,10 +285,6 @@ public class DownloadDialog extends DialogFragment
|
||||||
}, Context.BIND_AUTO_CREATE);
|
}, Context.BIND_AUTO_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Inits
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
|
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
|
||||||
final Bundle savedInstanceState) {
|
final Bundle savedInstanceState) {
|
||||||
|
@ -312,6 +340,60 @@ public class DownloadDialog extends DialogFragment
|
||||||
fetchStreamsSize();
|
fetchStreamsSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initToolbar(final Toolbar toolbar) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "initToolbar() called with: toolbar = [" + toolbar + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbar.setTitle(R.string.download_dialog_title);
|
||||||
|
toolbar.setNavigationIcon(R.drawable.ic_arrow_back);
|
||||||
|
toolbar.inflateMenu(R.menu.dialog_url);
|
||||||
|
toolbar.setNavigationOnClickListener(v -> dismiss());
|
||||||
|
toolbar.setNavigationContentDescription(R.string.cancel);
|
||||||
|
|
||||||
|
okButton = toolbar.findViewById(R.id.okay);
|
||||||
|
okButton.setEnabled(false); // disable until the download service connection is done
|
||||||
|
|
||||||
|
toolbar.setOnMenuItemClickListener(item -> {
|
||||||
|
if (item.getItemId() == R.id.okay) {
|
||||||
|
prepareSelectedDownload();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismiss(@NonNull final DialogInterface dialog) {
|
||||||
|
super.onDismiss(dialog);
|
||||||
|
if (onDismissListener != null) {
|
||||||
|
onDismissListener.onDismiss(dialog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
disposables.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
dialogBinding = null;
|
||||||
|
super.onDestroyView();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
Icepick.saveInstanceState(this, outState);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Video, audio and subtitle spinners
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void fetchStreamsSize() {
|
private void fetchStreamsSize() {
|
||||||
disposables.clear();
|
disposables.clear();
|
||||||
disposables.add(StreamSizeWrapper.fetchSizeForWrapper(wrappedVideoStreams)
|
disposables.add(StreamSizeWrapper.fetchSizeForWrapper(wrappedVideoStreams)
|
||||||
|
@ -346,126 +428,6 @@ public class DownloadDialog extends DialogFragment
|
||||||
currentInfo.getServiceId()))));
|
currentInfo.getServiceId()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
disposables.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
dialogBinding = null;
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Radio group Video&Audio options - Listener
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
Icepick.saveInstanceState(this, outState);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Streams Spinner Listener
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
|
|
||||||
if (resultCode != Activity.RESULT_OK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.getData() == null) {
|
|
||||||
showFailedDialog(R.string.general_error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestCode == REQUEST_DOWNLOAD_SAVE_AS) {
|
|
||||||
if (FilePickerActivityHelper.isOwnFileUri(context, data.getData())) {
|
|
||||||
final File file = Utils.getFileForUri(data.getData());
|
|
||||||
checkSelectedDownload(null, Uri.fromFile(file), file.getName(),
|
|
||||||
StoredFileHelper.DEFAULT_MIME);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
|
||||||
if (docFile == null) {
|
|
||||||
showFailedDialog(R.string.general_error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the selected file was previously used
|
|
||||||
checkSelectedDownload(null, data.getData(), docFile.getName(),
|
|
||||||
docFile.getType());
|
|
||||||
} else if (requestCode == REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER
|
|
||||||
|| requestCode == REQUEST_DOWNLOAD_PICK_VIDEO_FOLDER) {
|
|
||||||
Uri uri = data.getData();
|
|
||||||
if (FilePickerActivityHelper.isOwnFileUri(context, uri)) {
|
|
||||||
uri = Uri.fromFile(Utils.getFileForUri(uri));
|
|
||||||
} else {
|
|
||||||
context.grantUriPermission(context.getPackageName(), uri,
|
|
||||||
StoredDirectoryHelper.PERMISSION_FLAGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String key;
|
|
||||||
final String tag;
|
|
||||||
if (requestCode == REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER) {
|
|
||||||
key = getString(R.string.download_path_audio_key);
|
|
||||||
tag = DownloadManager.TAG_AUDIO;
|
|
||||||
} else {
|
|
||||||
key = getString(R.string.download_path_video_key);
|
|
||||||
tag = DownloadManager.TAG_VIDEO;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
|
||||||
.putString(key, uri.toString()).apply();
|
|
||||||
|
|
||||||
try {
|
|
||||||
final StoredDirectoryHelper mainStorage
|
|
||||||
= new StoredDirectoryHelper(context, uri, tag);
|
|
||||||
checkSelectedDownload(mainStorage, mainStorage.findFile(filenameTmp),
|
|
||||||
filenameTmp, mimeTmp);
|
|
||||||
} catch (final IOException e) {
|
|
||||||
showFailedDialog(R.string.general_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initToolbar(final Toolbar toolbar) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "initToolbar() called with: toolbar = [" + toolbar + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
toolbar.setTitle(R.string.download_dialog_title);
|
|
||||||
toolbar.setNavigationIcon(R.drawable.ic_arrow_back);
|
|
||||||
toolbar.inflateMenu(R.menu.dialog_url);
|
|
||||||
toolbar.setNavigationOnClickListener(v -> requireDialog().dismiss());
|
|
||||||
toolbar.setNavigationContentDescription(R.string.cancel);
|
|
||||||
|
|
||||||
okButton = toolbar.findViewById(R.id.okay);
|
|
||||||
okButton.setEnabled(false); // disable until the download service connection is done
|
|
||||||
|
|
||||||
toolbar.setOnMenuItemClickListener(item -> {
|
|
||||||
if (item.getItemId() == R.id.okay) {
|
|
||||||
prepareSelectedDownload();
|
|
||||||
if (getActivity() instanceof RouterActivity) {
|
|
||||||
getActivity().finish();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Utils
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void setupAudioSpinner() {
|
private void setupAudioSpinner() {
|
||||||
if (getContext() == null) {
|
if (getContext() == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -496,6 +458,88 @@ public class DownloadDialog extends DialogFragment
|
||||||
setRadioButtonsState(true);
|
setRadioButtonsState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Activity results
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void requestDownloadPickAudioFolderResult(final ActivityResult result) {
|
||||||
|
requestDownloadPickFolderResult(
|
||||||
|
result, getString(R.string.download_path_audio_key), DownloadManager.TAG_AUDIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestDownloadPickVideoFolderResult(final ActivityResult result) {
|
||||||
|
requestDownloadPickFolderResult(
|
||||||
|
result, getString(R.string.download_path_video_key), DownloadManager.TAG_VIDEO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestDownloadSaveAsResult(final ActivityResult result) {
|
||||||
|
if (result.getResultCode() != Activity.RESULT_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.getData() == null || result.getData().getData() == null) {
|
||||||
|
showFailedDialog(R.string.general_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FilePickerActivityHelper.isOwnFileUri(context, result.getData().getData())) {
|
||||||
|
final File file = Utils.getFileForUri(result.getData().getData());
|
||||||
|
checkSelectedDownload(null, Uri.fromFile(file), file.getName(),
|
||||||
|
StoredFileHelper.DEFAULT_MIME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final DocumentFile docFile
|
||||||
|
= DocumentFile.fromSingleUri(context, result.getData().getData());
|
||||||
|
if (docFile == null) {
|
||||||
|
showFailedDialog(R.string.general_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the selected file was previously used
|
||||||
|
checkSelectedDownload(null, result.getData().getData(), docFile.getName(),
|
||||||
|
docFile.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestDownloadPickFolderResult(final ActivityResult result,
|
||||||
|
final String key,
|
||||||
|
final String tag) {
|
||||||
|
if (result.getResultCode() != Activity.RESULT_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.getData() == null || result.getData().getData() == null) {
|
||||||
|
showFailedDialog(R.string.general_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri uri = result.getData().getData();
|
||||||
|
if (FilePickerActivityHelper.isOwnFileUri(context, uri)) {
|
||||||
|
uri = Uri.fromFile(Utils.getFileForUri(uri));
|
||||||
|
} else {
|
||||||
|
context.grantUriPermission(context.getPackageName(), uri,
|
||||||
|
StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
||||||
|
.putString(key, uri.toString()).apply();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final StoredDirectoryHelper mainStorage
|
||||||
|
= new StoredDirectoryHelper(context, uri, tag);
|
||||||
|
checkSelectedDownload(mainStorage, mainStorage.findFile(filenameTmp),
|
||||||
|
filenameTmp, mimeTmp);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
showFailedDialog(R.string.general_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Listeners
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(final RadioGroup group, @IdRes final int checkedId) {
|
public void onCheckedChanged(final RadioGroup group, @IdRes final int checkedId) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -545,6 +589,11 @@ public class DownloadDialog extends DialogFragment
|
||||||
public void onNothingSelected(final AdapterView<?> parent) {
|
public void onNothingSelected(final AdapterView<?> parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Download
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected void setupDownloadOptions() {
|
protected void setupDownloadOptions() {
|
||||||
setRadioButtonsState(false);
|
setRadioButtonsState(false);
|
||||||
|
|
||||||
|
@ -557,7 +606,7 @@ public class DownloadDialog extends DialogFragment
|
||||||
dialogBinding.subtitleButton.setVisibility(isSubtitleStreamsAvailable
|
dialogBinding.subtitleButton.setVisibility(isSubtitleStreamsAvailable
|
||||||
? View.VISIBLE : View.GONE);
|
? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||||
final String defaultMedia = prefs.getString(getString(R.string.last_used_download_type),
|
final String defaultMedia = prefs.getString(getString(R.string.last_used_download_type),
|
||||||
getString(R.string.last_download_type_video_key));
|
getString(R.string.last_download_type_video_key));
|
||||||
|
|
||||||
|
@ -585,7 +634,7 @@ public class DownloadDialog extends DialogFragment
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getContext(), R.string.no_streams_available_download,
|
Toast.makeText(getContext(), R.string.no_streams_available_download,
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
getDialog().dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,6 +686,10 @@ public class DownloadDialog extends DialogFragment
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void launchDirectoryPicker(final ActivityResultLauncher<Intent> launcher) {
|
||||||
|
launcher.launch(StoredDirectoryHelper.getPicker(context));
|
||||||
|
}
|
||||||
|
|
||||||
private void prepareSelectedDownload() {
|
private void prepareSelectedDownload() {
|
||||||
final StoredDirectoryHelper mainStorage;
|
final StoredDirectoryHelper mainStorage;
|
||||||
final MediaFormat format;
|
final MediaFormat format;
|
||||||
|
@ -691,11 +744,9 @@ public class DownloadDialog extends DialogFragment
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button) {
|
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button) {
|
||||||
startActivityForResult(StoredDirectoryHelper.getPicker(context),
|
launchDirectoryPicker(requestDownloadPickAudioFolderLauncher);
|
||||||
REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER);
|
|
||||||
} else {
|
} else {
|
||||||
startActivityForResult(StoredDirectoryHelper.getPicker(context),
|
launchDirectoryPicker(requestDownloadPickVideoFolderLauncher);
|
||||||
REQUEST_DOWNLOAD_PICK_VIDEO_FOLDER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -715,8 +766,8 @@ public class DownloadDialog extends DialogFragment
|
||||||
initialPath = Uri.parse(initialSavePath.getAbsolutePath());
|
initialPath = Uri.parse(initialSavePath.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
startActivityForResult(StoredFileHelper.getNewPicker(context,
|
requestDownloadSaveAsLauncher.launch(StoredFileHelper.getNewPicker(context,
|
||||||
filenameTmp, mimeTmp, initialPath), REQUEST_DOWNLOAD_SAVE_AS);
|
filenameTmp, mimeTmp, initialPath));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local;
|
package org.schabi.newpipe.local;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -26,6 +25,7 @@ import org.schabi.newpipe.fragments.list.ListViewContract;
|
||||||
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
|
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
|
||||||
|
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This fragment is design to be used with persistent data such as
|
* This fragment is design to be used with persistent data such as
|
||||||
|
@ -77,7 +77,7 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if (updateFlags != 0) {
|
if (updateFlags != 0) {
|
||||||
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
|
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
|
||||||
final boolean useGrid = isGridLayout();
|
final boolean useGrid = shouldUseGridLayout(requireContext());
|
||||||
itemsList.setLayoutManager(
|
itemsList.setLayoutManager(
|
||||||
useGrid ? getGridLayoutManager() : getListLayoutManager());
|
useGrid ? getGridLayoutManager() : getListLayoutManager());
|
||||||
itemListAdapter.setUseGridVariant(useGrid);
|
itemListAdapter.setUseGridVariant(useGrid);
|
||||||
|
@ -121,7 +121,7 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
|
|
||||||
itemListAdapter = new LocalItemListAdapter(activity);
|
itemListAdapter = new LocalItemListAdapter(activity);
|
||||||
|
|
||||||
final boolean useGrid = isGridLayout();
|
final boolean useGrid = shouldUseGridLayout(requireContext());
|
||||||
itemsList = rootView.findViewById(R.id.items_list);
|
itemsList = rootView.findViewById(R.id.items_list);
|
||||||
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
|
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
|
||||||
|
|
||||||
|
@ -260,17 +260,4 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
updateFlags |= LIST_MODE_UPDATE_FLAG;
|
updateFlags |= LIST_MODE_UPDATE_FLAG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isGridLayout() {
|
|
||||||
final String listMode = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
||||||
.getString(getString(R.string.list_view_mode_key),
|
|
||||||
getString(R.string.list_view_mode_value));
|
|
||||||
if ("auto".equals(listMode)) {
|
|
||||||
final Configuration configuration = getResources().getConfiguration();
|
|
||||||
return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
|
||||||
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
|
|
||||||
} else {
|
|
||||||
return "grid".equals(listMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -74,10 +73,10 @@ import org.schabi.newpipe.player.helper.PlayerHolder
|
||||||
import org.schabi.newpipe.util.Localization
|
import org.schabi.newpipe.util.Localization
|
||||||
import org.schabi.newpipe.util.NavigationHelper
|
import org.schabi.newpipe.util.NavigationHelper
|
||||||
import org.schabi.newpipe.util.StreamDialogEntry
|
import org.schabi.newpipe.util.StreamDialogEntry
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCount
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import kotlin.math.floor
|
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
class FeedFragment : BaseStateFragment<FeedState>() {
|
class FeedFragment : BaseStateFragment<FeedState>() {
|
||||||
private var _feedBinding: FragmentFeedBinding? = null
|
private var _feedBinding: FragmentFeedBinding? = null
|
||||||
|
@ -161,7 +160,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
|
||||||
|
|
||||||
fun setupListViewMode() {
|
fun setupListViewMode() {
|
||||||
// does everything needed to setup the layouts for grid or list modes
|
// does everything needed to setup the layouts for grid or list modes
|
||||||
groupAdapter.spanCount = if (shouldUseGridLayout()) getGridSpanCount() else 1
|
groupAdapter.spanCount = if (shouldUseGridLayout(context)) getGridSpanCount(context) else 1
|
||||||
feedBinding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply {
|
feedBinding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply {
|
||||||
spanSizeLookup = groupAdapter.spanSizeLookup
|
spanSizeLookup = groupAdapter.spanSizeLookup
|
||||||
}
|
}
|
||||||
|
@ -384,7 +383,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
|
||||||
@SuppressLint("StringFormatMatches")
|
@SuppressLint("StringFormatMatches")
|
||||||
private fun handleLoadedState(loadedState: FeedState.LoadedState) {
|
private fun handleLoadedState(loadedState: FeedState.LoadedState) {
|
||||||
|
|
||||||
val itemVersion = if (shouldUseGridLayout()) {
|
val itemVersion = if (shouldUseGridLayout(context)) {
|
||||||
StreamItem.ItemVersion.GRID
|
StreamItem.ItemVersion.GRID
|
||||||
} else {
|
} else {
|
||||||
StreamItem.ItemVersion.NORMAL
|
StreamItem.ItemVersion.NORMAL
|
||||||
|
@ -528,35 +527,6 @@ class FeedFragment : BaseStateFragment<FeedState>() {
|
||||||
listState = null
|
listState = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
|
||||||
// Grid Mode
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// TODO: Move these out of this class, as it can be reused
|
|
||||||
|
|
||||||
private fun shouldUseGridLayout(): Boolean {
|
|
||||||
val listMode = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
|
||||||
.getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value))
|
|
||||||
|
|
||||||
return when (listMode) {
|
|
||||||
getString(R.string.list_view_mode_auto_key) -> {
|
|
||||||
val configuration = resources.configuration
|
|
||||||
|
|
||||||
(
|
|
||||||
configuration.orientation == Configuration.ORIENTATION_LANDSCAPE &&
|
|
||||||
configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
getString(R.string.list_view_mode_grid_key) -> true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getGridSpanCount(): Int {
|
|
||||||
val minWidth = resources.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width)
|
|
||||||
return max(1, floor(resources.displayMetrics.widthPixels / minWidth.toDouble()).toInt())
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KEY_GROUP_ID = "ARG_GROUP_ID"
|
const val KEY_GROUP_ID = "ARG_GROUP_ID"
|
||||||
const val KEY_GROUP_NAME = "ARG_GROUP_NAME"
|
const val KEY_GROUP_NAME = "ARG_GROUP_NAME"
|
||||||
|
|
|
@ -68,6 +68,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
|
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
|
||||||
|
|
||||||
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> {
|
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> {
|
||||||
// Save the list 10 seconds after the last change occurred
|
// Save the list 10 seconds after the last change occurred
|
||||||
|
@ -678,7 +679,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
|
|
||||||
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
||||||
int directions = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
int directions = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||||
if (isGridLayout()) {
|
if (shouldUseGridLayout(requireContext())) {
|
||||||
directions |= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
directions |= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
||||||
}
|
}
|
||||||
return new ItemTouchHelper.SimpleCallback(directions,
|
return new ItemTouchHelper.SimpleCallback(directions,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -20,7 +19,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import com.xwray.groupie.Group
|
import com.xwray.groupie.Group
|
||||||
import com.xwray.groupie.GroupAdapter
|
import com.xwray.groupie.GroupAdapter
|
||||||
|
@ -60,12 +58,12 @@ import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService
|
||||||
import org.schabi.newpipe.streams.io.StoredFileHelper
|
import org.schabi.newpipe.streams.io.StoredFileHelper
|
||||||
import org.schabi.newpipe.util.NavigationHelper
|
import org.schabi.newpipe.util.NavigationHelper
|
||||||
import org.schabi.newpipe.util.OnClickGesture
|
import org.schabi.newpipe.util.OnClickGesture
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCount
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout
|
||||||
import org.schabi.newpipe.util.external_communication.ShareUtils
|
import org.schabi.newpipe.util.external_communication.ShareUtils
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.math.floor
|
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
|
class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
|
||||||
private var _binding: FragmentSubscriptionBinding? = null
|
private var _binding: FragmentSubscriptionBinding? = null
|
||||||
|
@ -279,8 +277,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
|
||||||
super.initViews(rootView, savedInstanceState)
|
super.initViews(rootView, savedInstanceState)
|
||||||
_binding = FragmentSubscriptionBinding.bind(rootView)
|
_binding = FragmentSubscriptionBinding.bind(rootView)
|
||||||
|
|
||||||
val shouldUseGridLayout = shouldUseGridLayout()
|
groupAdapter.spanCount = if (shouldUseGridLayout(context)) getGridSpanCount(context) else 1
|
||||||
groupAdapter.spanCount = if (shouldUseGridLayout) getGridSpanCount() else 1
|
|
||||||
binding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply {
|
binding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply {
|
||||||
spanSizeLookup = groupAdapter.spanSizeLookup
|
spanSizeLookup = groupAdapter.spanSizeLookup
|
||||||
}
|
}
|
||||||
|
@ -359,7 +356,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
|
||||||
override fun handleResult(result: SubscriptionState) {
|
override fun handleResult(result: SubscriptionState) {
|
||||||
super.handleResult(result)
|
super.handleResult(result)
|
||||||
|
|
||||||
val shouldUseGridLayout = shouldUseGridLayout()
|
val shouldUseGridLayout = shouldUseGridLayout(context)
|
||||||
when (result) {
|
when (result) {
|
||||||
is SubscriptionState.LoadedState -> {
|
is SubscriptionState.LoadedState -> {
|
||||||
result.subscriptions.forEach {
|
result.subscriptions.forEach {
|
||||||
|
@ -420,30 +417,4 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
|
||||||
super.hideLoading()
|
super.hideLoading()
|
||||||
binding.itemsList.animate(true, 200)
|
binding.itemsList.animate(true, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
|
||||||
// Grid Mode
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// TODO: Move these out of this class, as it can be reused
|
|
||||||
|
|
||||||
private fun shouldUseGridLayout(): Boolean {
|
|
||||||
val listMode = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
|
||||||
.getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value))
|
|
||||||
|
|
||||||
return when (listMode) {
|
|
||||||
getString(R.string.list_view_mode_auto_key) -> {
|
|
||||||
val configuration = resources.configuration
|
|
||||||
configuration.orientation == Configuration.ORIENTATION_LANDSCAPE &&
|
|
||||||
configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)
|
|
||||||
}
|
|
||||||
getString(R.string.list_view_mode_grid_key) -> true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getGridSpanCount(): Int {
|
|
||||||
val minWidth = resources.getDimensionPixelSize(R.dimen.channel_item_grid_min_width)
|
|
||||||
return max(1, floor(resources.displayMetrics.widthPixels / minWidth.toDouble()).toInt())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
@ -18,6 +21,7 @@ import androidx.preference.SwitchPreferenceCompat;
|
||||||
import com.nononsenseapps.filepicker.Utils;
|
import com.nononsenseapps.filepicker.Utils;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -27,14 +31,10 @@ import java.net.URI;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
public class DownloadSettingsFragment extends BasePreferenceFragment {
|
public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
public static final boolean IGNORE_RELEASE_ON_OLD_PATH = true;
|
public static final boolean IGNORE_RELEASE_ON_OLD_PATH = true;
|
||||||
private static final int REQUEST_DOWNLOAD_VIDEO_PATH = 0x1235;
|
|
||||||
private static final int REQUEST_DOWNLOAD_AUDIO_PATH = 0x1236;
|
|
||||||
private String downloadPathVideoPreference;
|
private String downloadPathVideoPreference;
|
||||||
private String downloadPathAudioPreference;
|
private String downloadPathAudioPreference;
|
||||||
private String storageUseSafPreference;
|
private String storageUseSafPreference;
|
||||||
|
@ -44,6 +44,12 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
private Preference prefStorageAsk;
|
private Preference prefStorageAsk;
|
||||||
|
|
||||||
private Context ctx;
|
private Context ctx;
|
||||||
|
private final ActivityResultLauncher<Intent> requestDownloadVideoPathLauncher =
|
||||||
|
registerForActivityResult(
|
||||||
|
new StartActivityForResult(), this::requestDownloadVideoPathResult);
|
||||||
|
private final ActivityResultLauncher<Intent> requestDownloadAudioPathLauncher =
|
||||||
|
registerForActivityResult(
|
||||||
|
new StartActivityForResult(), this::requestDownloadAudioPathResult);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||||
|
@ -185,7 +191,6 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
final String key = preference.getKey();
|
final String key = preference.getKey();
|
||||||
final int request;
|
|
||||||
|
|
||||||
if (key.equals(storageUseSafPreference)) {
|
if (key.equals(storageUseSafPreference)) {
|
||||||
if (!NewPipeSettings.useStorageAccessFramework(ctx)) {
|
if (!NewPipeSettings.useStorageAccessFramework(ctx)) {
|
||||||
|
@ -198,43 +203,39 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
updatePreferencesSummary();
|
updatePreferencesSummary();
|
||||||
return true;
|
return true;
|
||||||
} else if (key.equals(downloadPathVideoPreference)) {
|
} else if (key.equals(downloadPathVideoPreference)) {
|
||||||
request = REQUEST_DOWNLOAD_VIDEO_PATH;
|
launchDirectoryPicker(requestDownloadVideoPathLauncher);
|
||||||
} else if (key.equals(downloadPathAudioPreference)) {
|
} else if (key.equals(downloadPathAudioPreference)) {
|
||||||
request = REQUEST_DOWNLOAD_AUDIO_PATH;
|
launchDirectoryPicker(requestDownloadAudioPathLauncher);
|
||||||
} else {
|
} else {
|
||||||
return super.onPreferenceTreeClick(preference);
|
return super.onPreferenceTreeClick(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
startActivityForResult(StoredDirectoryHelper.getPicker(ctx), request);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void launchDirectoryPicker(final ActivityResultLauncher<Intent> launcher) {
|
||||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
launcher.launch(StoredDirectoryHelper.getPicker(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestDownloadVideoPathResult(final ActivityResult result) {
|
||||||
|
requestDownloadPathResult(result, downloadPathVideoPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestDownloadAudioPathResult(final ActivityResult result) {
|
||||||
|
requestDownloadPathResult(result, downloadPathAudioPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestDownloadPathResult(final ActivityResult result, final String key) {
|
||||||
assureCorrectAppLanguage(getContext());
|
assureCorrectAppLanguage(getContext());
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "onActivityResult() called with: "
|
|
||||||
+ "requestCode = [" + requestCode + "], "
|
|
||||||
+ "resultCode = [" + resultCode + "], data = [" + data + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultCode != Activity.RESULT_OK) {
|
if (result.getResultCode() != Activity.RESULT_OK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String key;
|
Uri uri = null;
|
||||||
if (requestCode == REQUEST_DOWNLOAD_VIDEO_PATH) {
|
if (result.getData() != null) {
|
||||||
key = downloadPathVideoPreference;
|
uri = result.getData().getData();
|
||||||
} else if (requestCode == REQUEST_DOWNLOAD_AUDIO_PATH) {
|
|
||||||
key = downloadPathAudioPreference;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri uri = data.getData();
|
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
showMessageDialog(R.string.general_error, R.string.invalid_directory);
|
showMessageDialog(R.string.general_error, R.string.invalid_directory);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -298,4 +298,43 @@ public final class ThemeHelper {
|
||||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the grid layout or the list layout should be used. If the user set "auto"
|
||||||
|
* mode in settings, decides based on screen orientation (landscape) and size.
|
||||||
|
*
|
||||||
|
* @param context the context to use
|
||||||
|
* @return true:use grid layout, false:use list layout
|
||||||
|
*/
|
||||||
|
public static boolean shouldUseGridLayout(final Context context) {
|
||||||
|
final String listMode = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
.getString(context.getString(R.string.list_view_mode_key),
|
||||||
|
context.getString(R.string.list_view_mode_value));
|
||||||
|
|
||||||
|
if (listMode.equals(context.getString(R.string.list_view_mode_list_key))) {
|
||||||
|
return false;
|
||||||
|
} else if (listMode.equals(context.getString(R.string.list_view_mode_grid_key))) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
final Configuration configuration = context.getResources().getConfiguration();
|
||||||
|
return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the number of grid items that can fit horizontally on the screen. The width of a
|
||||||
|
* grid item is obtained from the thumbnail width plus the right and left paddings.
|
||||||
|
*
|
||||||
|
* @param context the context to use
|
||||||
|
* @return the span count of grid list items
|
||||||
|
*/
|
||||||
|
public static int getGridSpanCount(final Context context) {
|
||||||
|
final Resources res = context.getResources();
|
||||||
|
final int minWidth
|
||||||
|
= res.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width)
|
||||||
|
+ res.getDimensionPixelSize(R.dimen.video_item_search_padding) * 2;
|
||||||
|
return Math.max(1, res.getDisplayMetrics().widthPixels / minWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
@ -44,7 +47,6 @@ import us.shandian.giga.ui.adapter.MissionAdapter;
|
||||||
public class MissionsFragment extends Fragment {
|
public class MissionsFragment extends Fragment {
|
||||||
|
|
||||||
private static final int SPAN_SIZE = 2;
|
private static final int SPAN_SIZE = 2;
|
||||||
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
|
|
||||||
|
|
||||||
private SharedPreferences mPrefs;
|
private SharedPreferences mPrefs;
|
||||||
private boolean mLinear;
|
private boolean mLinear;
|
||||||
|
@ -64,7 +66,8 @@ public class MissionsFragment extends Fragment {
|
||||||
private boolean mForceUpdate;
|
private boolean mForceUpdate;
|
||||||
|
|
||||||
private DownloadMission unsafeMissionTarget = null;
|
private DownloadMission unsafeMissionTarget = null;
|
||||||
|
private final ActivityResultLauncher<Intent> requestDownloadSaveAsLauncher =
|
||||||
|
registerForActivityResult(new StartActivityForResult(), this::requestDownloadSaveAsResult);
|
||||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -254,8 +257,9 @@ public class MissionsFragment extends Fragment {
|
||||||
initialPath = Uri.parse(initialSavePath.getAbsolutePath());
|
initialPath = Uri.parse(initialSavePath.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
startActivityForResult(StoredFileHelper.getNewPicker(mContext, mission.storage.getName(),
|
requestDownloadSaveAsLauncher.launch(
|
||||||
mission.storage.getType(), initialPath), REQUEST_DOWNLOAD_SAVE_AS);
|
StoredFileHelper.getNewPicker(mContext, mission.storage.getName(),
|
||||||
|
mission.storage.getType(), initialPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -289,18 +293,17 @@ public class MissionsFragment extends Fragment {
|
||||||
if (mBinder != null) mBinder.enableNotifications(true);
|
if (mBinder != null) mBinder.enableNotifications(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void requestDownloadSaveAsResult(final ActivityResult result) {
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
if (result.getResultCode() != Activity.RESULT_OK) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (requestCode != REQUEST_DOWNLOAD_SAVE_AS || resultCode != Activity.RESULT_OK) return;
|
if (unsafeMissionTarget == null || result.getData() == null) {
|
||||||
|
|
||||||
if (unsafeMissionTarget == null || data.getData() == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Uri fileUri = data.getData();
|
Uri fileUri = result.getData().getData();
|
||||||
if (fileUri.getAuthority() != null && FilePickerActivityHelper.isOwnFileUri(mContext, fileUri)) {
|
if (fileUri.getAuthority() != null && FilePickerActivityHelper.isOwnFileUri(mContext, fileUri)) {
|
||||||
fileUri = Uri.fromFile(Utils.getFileForUri(fileUri));
|
fileUri = Uri.fromFile(Utils.getFileForUri(fileUri));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Hotfix
|
||||||
|
• Fix thumbnails and titles being trimmed in grid layout, due to a wrong calculation of how many videos can fit in one row
|
||||||
|
• Fix download dialog disappearing without doing anything if opened from the share menu
|
||||||
|
• Update a library related to opening external activities such as the Storage Access Framework file picker
|
Loading…
Reference in New Issue