mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 22:57:29 +00:00
Migrate File usage to DocumentFile
This commit is contained in:
parent
91c70b778a
commit
7c0acdbd6e
@ -14,6 +14,7 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.LocaleUtils;
|
import awais.instagrabber.utils.LocaleUtils;
|
||||||
import awais.instagrabber.utils.SettingsHelper;
|
import awais.instagrabber.utils.SettingsHelper;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
@ -86,5 +87,6 @@ public final class InstaGrabberApplication extends Application {
|
|||||||
if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) {
|
if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) {
|
||||||
settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString());
|
settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString());
|
||||||
}
|
}
|
||||||
|
DownloadUtils.init(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,12 +5,9 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.hardware.display.DisplayManager;
|
import android.hardware.display.DisplayManager;
|
||||||
import android.media.MediaScannerConnection;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.webkit.MimeTypeMap;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -21,11 +18,13 @@ import androidx.camera.core.ImageCaptureException;
|
|||||||
import androidx.camera.core.Preview;
|
import androidx.camera.core.Preview;
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@ -45,7 +44,7 @@ public class CameraActivity extends BaseLanguageActivity {
|
|||||||
|
|
||||||
private ActivityCameraBinding binding;
|
private ActivityCameraBinding binding;
|
||||||
private ImageCapture imageCapture;
|
private ImageCapture imageCapture;
|
||||||
private File outputDirectory;
|
private DocumentFile outputDirectory;
|
||||||
private ExecutorService cameraExecutor;
|
private ExecutorService cameraExecutor;
|
||||||
private int displayId = -1;
|
private int displayId = -1;
|
||||||
|
|
||||||
@ -113,7 +112,13 @@ public class CameraActivity extends BaseLanguageActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateUi() {
|
private void updateUi() {
|
||||||
binding.cameraCaptureButton.setOnClickListener(v -> takePhoto());
|
binding.cameraCaptureButton.setOnClickListener(v -> {
|
||||||
|
try {
|
||||||
|
takePhoto();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.e(TAG, "updateUi: ", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
// Disable the button until the camera is set up
|
// Disable the button until the camera is set up
|
||||||
binding.switchCamera.setEnabled(false);
|
binding.switchCamera.setEnabled(false);
|
||||||
// Listener for button used to switch cameras. Only called if the button is enabled
|
// Listener for button used to switch cameras. Only called if the button is enabled
|
||||||
@ -200,37 +205,44 @@ public class CameraActivity extends BaseLanguageActivity {
|
|||||||
preview.setSurfaceProvider(binding.viewFinder.getSurfaceProvider());
|
preview.setSurfaceProvider(binding.viewFinder.getSurfaceProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void takePhoto() {
|
private void takePhoto() throws FileNotFoundException {
|
||||||
if (imageCapture == null) return;
|
if (imageCapture == null) return;
|
||||||
final File photoFile = new File(outputDirectory, SIMPLE_DATE_FORMAT.format(System.currentTimeMillis()) + ".jpg");
|
final String extension = "jpg";
|
||||||
final ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build();
|
final String fileName = SIMPLE_DATE_FORMAT.format(System.currentTimeMillis()) + "." + extension;
|
||||||
|
// final File photoFile = new File(outputDirectory, fileName);
|
||||||
|
final String mimeType = Utils.mimeTypeMap.getMimeTypeFromExtension(extension);
|
||||||
|
final DocumentFile photoFile = outputDirectory.createFile(mimeType, fileName);
|
||||||
|
final OutputStream outputStream = getContentResolver().openOutputStream(photoFile.getUri());
|
||||||
|
final ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(outputStream).build();
|
||||||
imageCapture.takePicture(
|
imageCapture.takePicture(
|
||||||
outputFileOptions,
|
outputFileOptions,
|
||||||
cameraExecutor,
|
cameraExecutor,
|
||||||
new ImageCapture.OnImageSavedCallback() {
|
new ImageCapture.OnImageSavedCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onImageSaved(@NonNull final ImageCapture.OutputFileResults outputFileResults) {
|
public void onImageSaved(@NonNull final ImageCapture.OutputFileResults outputFileResults) {
|
||||||
final Uri uri = Uri.fromFile(photoFile);
|
if (outputStream != null) {
|
||||||
//noinspection UnstableApiUsage
|
try { outputStream.close(); } catch (IOException ignored) {}
|
||||||
final String mimeType = MimeTypeMap.getSingleton()
|
}
|
||||||
.getMimeTypeFromExtension(Files.getFileExtension(photoFile.getName()));
|
// final Uri uri = Uri.fromFile(photoFile);
|
||||||
MediaScannerConnection.scanFile(
|
// final String mimeType = MimeTypeMap.getSingleton()
|
||||||
CameraActivity.this,
|
// .getMimeTypeFromExtension(Files.getFileExtension(photoFile.getName()));
|
||||||
new String[]{photoFile.getAbsolutePath()},
|
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, photoFile.getUri()));
|
||||||
new String[]{mimeType},
|
Utils.scanDocumentFile(CameraActivity.this, photoFile, (path, uri1) -> {
|
||||||
(path, uri1) -> {
|
Log.d(TAG, "onImageSaved: scan complete");
|
||||||
Log.d(TAG, "onImageSaved: scan complete");
|
final Intent intent = new Intent();
|
||||||
final Intent intent = new Intent();
|
intent.setData(uri1);
|
||||||
intent.setData(uri1);
|
setResult(Activity.RESULT_OK, intent);
|
||||||
setResult(Activity.RESULT_OK, intent);
|
finish();
|
||||||
finish();
|
});
|
||||||
});
|
Log.d(TAG, "onImageSaved: " + photoFile.getUri());
|
||||||
Log.d(TAG, "onImageSaved: " + uri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(@NonNull final ImageCaptureException exception) {
|
public void onError(@NonNull final ImageCaptureException exception) {
|
||||||
Log.e(TAG, "onError: ", exception);
|
Log.e(TAG, "onError: ", exception);
|
||||||
|
if (outputStream != null) {
|
||||||
|
try { outputStream.close(); } catch (IOException ignored) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -102,7 +102,7 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
binding.typeIcon.setVisibility(View.VISIBLE);
|
binding.typeIcon.setVisibility(View.VISIBLE);
|
||||||
binding.typeIcon.setImageResource(typeIconRes);
|
binding.typeIcon.setImageResource(typeIconRes);
|
||||||
}
|
}
|
||||||
final DownloadedCheckerAsyncTask task = new DownloadedCheckerAsyncTask(result -> {
|
final DownloadedCheckerAsyncTask task = new DownloadedCheckerAsyncTask(itemView.getContext(), result -> {
|
||||||
final List<Boolean> checkList = result.get(media.getPk());
|
final List<Boolean> checkList = result.get(media.getPk());
|
||||||
if (checkList == null || checkList.isEmpty()) {
|
if (checkList == null || checkList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package awais.instagrabber.asyncs;
|
package awais.instagrabber.asyncs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -12,9 +14,12 @@ import awais.instagrabber.utils.DownloadUtils;
|
|||||||
public final class DownloadedCheckerAsyncTask extends AsyncTask<Media, Void, Map<String, List<Boolean>>> {
|
public final class DownloadedCheckerAsyncTask extends AsyncTask<Media, Void, Map<String, List<Boolean>>> {
|
||||||
private static final String TAG = "DownloadedCheckerAsyncTask";
|
private static final String TAG = "DownloadedCheckerAsyncTask";
|
||||||
|
|
||||||
|
private final WeakReference<Context> context;
|
||||||
private final OnCheckResultListener listener;
|
private final OnCheckResultListener listener;
|
||||||
|
|
||||||
public DownloadedCheckerAsyncTask(final OnCheckResultListener listener) {
|
public DownloadedCheckerAsyncTask(final Context context,
|
||||||
|
final OnCheckResultListener listener) {
|
||||||
|
this.context = new WeakReference<>(context);
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +30,9 @@ public final class DownloadedCheckerAsyncTask extends AsyncTask<Media, Void, Map
|
|||||||
}
|
}
|
||||||
final Map<String, List<Boolean>> map = new HashMap<>();
|
final Map<String, List<Boolean>> map = new HashMap<>();
|
||||||
for (final Media media : feedModels) {
|
for (final Media media : feedModels) {
|
||||||
map.put(media.getPk(), DownloadUtils.checkDownloaded(media));
|
final Context context = this.context.get();
|
||||||
|
if (context == null) return map;
|
||||||
|
map.put(media.getPk(), DownloadUtils.checkDownloaded(context, media));
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package awais.instagrabber.dialogs;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
@ -214,7 +213,7 @@ public class CreateBackupDialogFragment extends DialogFragment {
|
|||||||
// Optionally, specify a URI for the directory that should be opened in
|
// Optionally, specify a URI for the directory that should be opened in
|
||||||
// the system file picker when your app creates the document.
|
// the system file picker when your app creates the document.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.fromFile(DownloadUtils.getDownloadDir()));
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, DownloadUtils.getDownloadDir().getUri());
|
||||||
}
|
}
|
||||||
|
|
||||||
startActivityForResult(intent, CREATE_FILE_REQUEST_CODE);
|
startActivityForResult(intent, CREATE_FILE_REQUEST_CODE);
|
||||||
|
@ -7,7 +7,6 @@ import android.graphics.Color;
|
|||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -17,6 +16,7 @@ import android.widget.Toast;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
|
||||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||||
@ -24,15 +24,13 @@ import com.facebook.drawee.controller.BaseControllerListener;
|
|||||||
import com.facebook.drawee.interfaces.DraweeController;
|
import com.facebook.drawee.interfaces.DraweeController;
|
||||||
import com.facebook.imagepipeline.image.ImageInfo;
|
import com.facebook.imagepipeline.image.ImageInfo;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
|
||||||
import awais.instagrabber.databinding.DialogProfilepicBinding;
|
import awais.instagrabber.databinding.DialogProfilepicBinding;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
import awais.instagrabber.utils.DownloadUtils;
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.webservices.UserService;
|
import awais.instagrabber.webservices.UserService;
|
||||||
|
|
||||||
@ -182,14 +180,18 @@ public class ProfilePicDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
private void downloadProfilePicture() {
|
private void downloadProfilePicture() {
|
||||||
if (url == null) return;
|
if (url == null) return;
|
||||||
final File dir = new File(Environment.getExternalStorageDirectory(), "Download");
|
// final File dir = new File(Environment.getExternalStorageDirectory(), "Download");
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
if (dir.exists() || dir.mkdirs()) {
|
// if (dir.exists() || dir.mkdirs()) {
|
||||||
final File saveFile = new File(dir, name + '_' + System.currentTimeMillis() + ".jpg");
|
//
|
||||||
DownloadUtils.download(context, url, saveFile.getAbsolutePath());
|
// }
|
||||||
return;
|
final String fileName = name + '_' + System.currentTimeMillis() + ".jpg";
|
||||||
}
|
// final File saveFile = new File(dir, fileName);
|
||||||
Toast.makeText(context, R.string.downloader_error_creating_folder, Toast.LENGTH_SHORT).show();
|
final DocumentFile downloadDir = DownloadUtils.getDownloadDir();
|
||||||
|
final DocumentFile saveFile = downloadDir.createFile(Utils.mimeTypeMap.getMimeTypeFromExtension("jpg"), fileName);
|
||||||
|
DownloadUtils.download(context, url, saveFile);
|
||||||
|
// return;
|
||||||
|
// Toast.makeText(context, R.string.downloader_error_creating_folder, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,43 @@
|
|||||||
package awais.instagrabber.fragments.settings;
|
package awais.instagrabber.fragments.settings;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.widget.AppCompatButton;
|
||||||
|
import androidx.appcompat.widget.AppCompatTextView;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
import androidx.preference.PreferenceViewHolder;
|
||||||
import androidx.preference.SwitchPreferenceCompat;
|
import androidx.preference.SwitchPreferenceCompat;
|
||||||
|
|
||||||
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
|
||||||
|
import static android.app.Activity.RESULT_OK;
|
||||||
|
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
|
||||||
|
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
||||||
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
||||||
|
private static final String TAG = DownloadsPreferencesFragment.class.getSimpleName();
|
||||||
|
private static final int SELECT_DIR_REQUEST_CODE = 1;
|
||||||
|
private SaveToCustomFolderPreference.ResultCallback resultCallback;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setupPreferenceScreen(final PreferenceScreen screen) {
|
void setupPreferenceScreen(final PreferenceScreen screen) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
screen.addPreference(getDownloadUserFolderPreference(context));
|
screen.addPreference(getDownloadUserFolderPreference(context));
|
||||||
// screen.addPreference(getSaveToCustomFolderPreference(context));
|
screen.addPreference(getSaveToCustomFolderPreference(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Preference getDownloadUserFolderPreference(@NonNull final Context context) {
|
private Preference getDownloadUserFolderPreference(@NonNull final Context context) {
|
||||||
@ -27,63 +48,89 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
|||||||
return preference;
|
return preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private Preference getSaveToCustomFolderPreference(@NonNull final Context context) {
|
private Preference getSaveToCustomFolderPreference(@NonNull final Context context) {
|
||||||
// return new SaveToCustomFolderPreference(context, (resultCallback) -> new DirectoryChooser()
|
return new SaveToCustomFolderPreference(context, (resultCallback) -> {
|
||||||
// .setInitialDirectory(settingsHelper.getString(FOLDER_PATH))
|
// Choose a directory using the system's file picker.
|
||||||
// .setInteractionListener(file -> {
|
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
// settingsHelper.putString(FOLDER_PATH, file.getAbsolutePath());
|
startActivityForResult(intent, SELECT_DIR_REQUEST_CODE);
|
||||||
// resultCallback.onResult(file.getAbsolutePath());
|
this.resultCallback = resultCallback;
|
||||||
// })
|
|
||||||
// .show(getParentFragmentManager(), null));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public static class SaveToCustomFolderPreference extends Preference {
|
// new DirectoryChooser()
|
||||||
// private AppCompatTextView customPathTextView;
|
// .setInitialDirectory(settingsHelper.getString(FOLDER_PATH))
|
||||||
// private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener;
|
// .setInteractionListener(file -> {
|
||||||
// private final String key;
|
// settingsHelper.putString(FOLDER_PATH, file.getAbsolutePath());
|
||||||
//
|
// resultCallback.onResult(file.getAbsolutePath());
|
||||||
// public SaveToCustomFolderPreference(final Context context, final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener) {
|
// })
|
||||||
// super(context);
|
// .show(getParentFragmentManager(), null);
|
||||||
// this.onSelectFolderButtonClickListener = onSelectFolderButtonClickListener;
|
});
|
||||||
// key = Constants.FOLDER_SAVE_TO;
|
}
|
||||||
// setLayoutResource(R.layout.pref_custom_folder);
|
|
||||||
// setKey(key);
|
@Override
|
||||||
// setTitle(R.string.save_to_folder);
|
public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
||||||
// setIconSpaceReserved(false);
|
if (data == null || data.getData() == null) return;
|
||||||
// }
|
if (resultCode != RESULT_OK || requestCode != SELECT_DIR_REQUEST_CODE) return;
|
||||||
//
|
final Context context = getContext();
|
||||||
// @Override
|
if (context == null) return;
|
||||||
// public void onBindViewHolder(final PreferenceViewHolder holder) {
|
final Uri dirUri = data.getData();
|
||||||
// super.onBindViewHolder(holder);
|
Log.d(TAG, "onActivityResult: " + dirUri);
|
||||||
// final SwitchMaterial cbSaveTo = (SwitchMaterial) holder.findViewById(R.id.cbSaveTo);
|
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
// final View buttonContainer = holder.findViewById(R.id.button_container);
|
context.getContentResolver().takePersistableUriPermission(dirUri, takeFlags);
|
||||||
// customPathTextView = (AppCompatTextView) holder.findViewById(R.id.custom_path);
|
final DocumentFile root = DocumentFile.fromTreeUri(context, dirUri);
|
||||||
// cbSaveTo.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
settingsHelper.putString(FOLDER_PATH, data.getData().toString());
|
||||||
// settingsHelper.putBoolean(FOLDER_SAVE_TO, isChecked);
|
if (resultCallback != null) {
|
||||||
// buttonContainer.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
resultCallback.onResult(root.getName());
|
||||||
// final String customPath = settingsHelper.getString(FOLDER_PATH);
|
resultCallback = null;
|
||||||
// customPathTextView.setText(customPath);
|
}
|
||||||
// });
|
// Log.d(TAG, "onActivityResult: " + root);
|
||||||
// final boolean savedToEnabled = settingsHelper.getBoolean(key);
|
}
|
||||||
// holder.itemView.setOnClickListener(v -> cbSaveTo.toggle());
|
|
||||||
// cbSaveTo.setChecked(savedToEnabled);
|
public static class SaveToCustomFolderPreference extends Preference {
|
||||||
// buttonContainer.setVisibility(savedToEnabled ? View.VISIBLE : View.GONE);
|
private AppCompatTextView customPathTextView;
|
||||||
// final AppCompatButton btnSaveTo = (AppCompatButton) holder.findViewById(R.id.btnSaveTo);
|
private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener;
|
||||||
// btnSaveTo.setOnClickListener(v -> {
|
private final String key;
|
||||||
// if (onSelectFolderButtonClickListener == null) return;
|
|
||||||
// onSelectFolderButtonClickListener.onClick(result -> {
|
public SaveToCustomFolderPreference(final Context context, final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener) {
|
||||||
// if (TextUtils.isEmpty(result)) return;
|
super(context);
|
||||||
// customPathTextView.setText(result);
|
this.onSelectFolderButtonClickListener = onSelectFolderButtonClickListener;
|
||||||
// });
|
key = FOLDER_SAVE_TO;
|
||||||
// });
|
setLayoutResource(R.layout.pref_custom_folder);
|
||||||
// }
|
setKey(key);
|
||||||
//
|
setTitle(R.string.save_to_folder);
|
||||||
// public interface ResultCallback {
|
setIconSpaceReserved(false);
|
||||||
// void onResult(String result);
|
}
|
||||||
// }
|
|
||||||
//
|
@Override
|
||||||
// public interface OnSelectFolderButtonClickListener {
|
public void onBindViewHolder(final PreferenceViewHolder holder) {
|
||||||
// void onClick(ResultCallback resultCallback);
|
super.onBindViewHolder(holder);
|
||||||
// }
|
final SwitchMaterial cbSaveTo = (SwitchMaterial) holder.findViewById(R.id.cbSaveTo);
|
||||||
// }
|
final View buttonContainer = holder.findViewById(R.id.button_container);
|
||||||
|
customPathTextView = (AppCompatTextView) holder.findViewById(R.id.custom_path);
|
||||||
|
cbSaveTo.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
|
settingsHelper.putBoolean(FOLDER_SAVE_TO, isChecked);
|
||||||
|
buttonContainer.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||||
|
final String customPath = settingsHelper.getString(FOLDER_PATH);
|
||||||
|
customPathTextView.setText(customPath);
|
||||||
|
});
|
||||||
|
final boolean savedToEnabled = settingsHelper.getBoolean(key);
|
||||||
|
holder.itemView.setOnClickListener(v -> cbSaveTo.toggle());
|
||||||
|
cbSaveTo.setChecked(savedToEnabled);
|
||||||
|
buttonContainer.setVisibility(savedToEnabled ? View.VISIBLE : View.GONE);
|
||||||
|
final AppCompatButton btnSaveTo = (AppCompatButton) holder.findViewById(R.id.btnSaveTo);
|
||||||
|
btnSaveTo.setOnClickListener(v -> {
|
||||||
|
if (onSelectFolderButtonClickListener == null) return;
|
||||||
|
onSelectFolderButtonClickListener.onClick(result -> {
|
||||||
|
if (TextUtils.isEmpty(result)) return;
|
||||||
|
customPathTextView.setText(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultCallback {
|
||||||
|
void onResult(String result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnSelectFolderButtonClickListener {
|
||||||
|
void onClick(ResultCallback resultCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,14 @@ import android.app.IntentService;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
@ -39,7 +40,10 @@ public class DeleteImageIntentService extends IntentService {
|
|||||||
if (intent != null && Intent.ACTION_DELETE.equals(intent.getAction()) && intent.hasExtra(EXTRA_IMAGE_PATH)) {
|
if (intent != null && Intent.ACTION_DELETE.equals(intent.getAction()) && intent.hasExtra(EXTRA_IMAGE_PATH)) {
|
||||||
final String path = intent.getStringExtra(EXTRA_IMAGE_PATH);
|
final String path = intent.getStringExtra(EXTRA_IMAGE_PATH);
|
||||||
if (TextUtils.isEmpty(path)) return;
|
if (TextUtils.isEmpty(path)) return;
|
||||||
final File file = new File(path);
|
// final File file = new File(path);
|
||||||
|
final Uri parse = Uri.parse(path);
|
||||||
|
if (parse == null) return;
|
||||||
|
final DocumentFile file = DocumentFile.fromSingleUri(getApplicationContext(), parse);
|
||||||
boolean deleted;
|
boolean deleted;
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
deleted = file.delete();
|
deleted = file.delete();
|
||||||
@ -58,11 +62,11 @@ public class DeleteImageIntentService extends IntentService {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static PendingIntent pendingIntent(@NonNull final Context context,
|
public static PendingIntent pendingIntent(@NonNull final Context context,
|
||||||
@NonNull final String imagePath,
|
@NonNull final DocumentFile imagePath,
|
||||||
final int notificationId) {
|
final int notificationId) {
|
||||||
final Intent intent = new Intent(context, DeleteImageIntentService.class);
|
final Intent intent = new Intent(context, DeleteImageIntentService.class);
|
||||||
intent.setAction(Intent.ACTION_DELETE);
|
intent.setAction(Intent.ACTION_DELETE);
|
||||||
intent.putExtra(EXTRA_IMAGE_PATH, imagePath);
|
intent.putExtra(EXTRA_IMAGE_PATH, imagePath.getUri().toString());
|
||||||
intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId);
|
intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId);
|
||||||
return PendingIntent.getService(context, random.nextInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getService(context, random.nextInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,13 @@ import android.util.LruCache;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.util.Pair;
|
import androidx.core.util.Pair;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -247,12 +246,14 @@ public final class BitmapUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File convertToJpegAndSaveToFile(@NonNull final Bitmap bitmap, @Nullable final File file) throws IOException {
|
public static DocumentFile convertToJpegAndSaveToFile(@NonNull final ContentResolver contentResolver,
|
||||||
File tempFile = file;
|
@NonNull final Bitmap bitmap,
|
||||||
|
@Nullable final DocumentFile file) throws IOException {
|
||||||
|
DocumentFile tempFile = file;
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
tempFile = DownloadUtils.getTempFile();
|
tempFile = DownloadUtils.getTempFile(null, "jpg");
|
||||||
}
|
}
|
||||||
try (OutputStream output = new FileOutputStream(tempFile)) {
|
try (OutputStream output = contentResolver.openOutputStream(tempFile.getUri())) {
|
||||||
final boolean compressResult = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
|
final boolean compressResult = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
|
||||||
if (!compressResult) {
|
if (!compressResult) {
|
||||||
throw new RuntimeException("Compression failed!");
|
throw new RuntimeException("Compression failed!");
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Environment;
|
import android.net.Uri;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@ -11,6 +13,8 @@ import android.widget.Toast;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.core.util.Pair;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.work.Constraints;
|
import androidx.work.Constraints;
|
||||||
import androidx.work.Data;
|
import androidx.work.Data;
|
||||||
import androidx.work.NetworkType;
|
import androidx.work.NetworkType;
|
||||||
@ -21,9 +25,9 @@ import androidx.work.WorkRequest;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -41,31 +45,50 @@ import awais.instagrabber.repositories.responses.User;
|
|||||||
import awais.instagrabber.repositories.responses.VideoVersion;
|
import awais.instagrabber.repositories.responses.VideoVersion;
|
||||||
import awais.instagrabber.workers.DownloadWorker;
|
import awais.instagrabber.workers.DownloadWorker;
|
||||||
|
|
||||||
|
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
|
||||||
|
|
||||||
public final class DownloadUtils {
|
public final class DownloadUtils {
|
||||||
private static final String TAG = DownloadUtils.class.getSimpleName();
|
private static final String TAG = DownloadUtils.class.getSimpleName();
|
||||||
|
|
||||||
public static final String WRITE_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
public static final String WRITE_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||||
public static final String[] PERMS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
public static final String[] PERMS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||||
public static final String DIR_BARINSTA = "Barinsta";
|
private static final String DIR_BARINSTA = "Barinsta";
|
||||||
public static final String DIR_DOWNLOADS = "Downloads";
|
private static final String DIR_DOWNLOADS = "Downloads";
|
||||||
public static final String DIR_CAMERA = "Camera";
|
private static final String DIR_CAMERA = "Camera";
|
||||||
public static final String DIR_EDIT = "Edit";
|
private static final String DIR_EDIT = "Edit";
|
||||||
|
private static final String TEMP_DIR = "Temp";
|
||||||
|
|
||||||
public static File getDownloadDir(final String... dirs) {
|
private static DocumentFile root;
|
||||||
final File parent = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS);
|
|
||||||
File subDir = new File(parent, DIR_BARINSTA);
|
public static void init(@NonNull final Context context) {
|
||||||
|
// if (!Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) return;
|
||||||
|
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH);
|
||||||
|
if (TextUtils.isEmpty(customPath)) return;
|
||||||
|
// dir = new File(customPath);
|
||||||
|
root = DocumentFile.fromTreeUri(context, Uri.parse(customPath));
|
||||||
|
Log.d(TAG, "init: " + root);
|
||||||
|
// final File parent = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||||
|
// final DocumentFile documentFile = DocumentFile.fromFile(parent);
|
||||||
|
// Log.d(TAG, "init: " + documentFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DocumentFile getDownloadDir(final String... dirs) {
|
||||||
|
// final File parent = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS);
|
||||||
|
// File subDir = new File(parent, DIR_BARINSTA);
|
||||||
|
DocumentFile subDir = root;
|
||||||
if (dirs != null) {
|
if (dirs != null) {
|
||||||
for (final String dir : dirs) {
|
for (final String dir : dirs) {
|
||||||
subDir = new File(subDir, dir);
|
final DocumentFile subDirFile = subDir.findFile(dir);
|
||||||
//noinspection ResultOfMethodCallIgnored
|
if (subDirFile == null) {
|
||||||
subDir.mkdirs();
|
subDir = subDir.createDirectory(dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return subDir;
|
return subDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static File getDownloadDir() {
|
public static DocumentFile getDownloadDir() {
|
||||||
// final File parent = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS);
|
// final File parent = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS);
|
||||||
// final File dir = new File(new File(parent, "barinsta"), "downloads");
|
// final File dir = new File(new File(parent, "barinsta"), "downloads");
|
||||||
// if (!dir.exists()) {
|
// if (!dir.exists()) {
|
||||||
@ -83,37 +106,63 @@ public final class DownloadUtils {
|
|||||||
return getDownloadDir(DIR_DOWNLOADS);
|
return getDownloadDir(DIR_DOWNLOADS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getCameraDir() {
|
public static DocumentFile getCameraDir() {
|
||||||
return getDownloadDir(DIR_CAMERA);
|
return getDownloadDir(DIR_CAMERA);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getImageEditDir(final String sessionId) {
|
public static DocumentFile getImageEditDir(final String sessionId) {
|
||||||
return getDownloadDir(DIR_EDIT, sessionId);
|
return getDownloadDir(DIR_EDIT, sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
// @Nullable
|
||||||
private static File getDownloadDir(@NonNull final Context context, @Nullable final String username) {
|
// private static DocumentFile getDownloadDir(@NonNull final Context context, @Nullable final String username) {
|
||||||
return getDownloadDir(context, username, false);
|
// return getDownloadDir(context, username, false);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static File getDownloadDir(final Context context,
|
private static DocumentFile getDownloadDir(final Context context,
|
||||||
@Nullable final String username,
|
@Nullable final String username) {
|
||||||
final boolean skipCreateDir) {
|
final List<String> userFolderPaths = getSubPathForUserFolder(username);
|
||||||
File dir = getDownloadDir();
|
DocumentFile dir = root;
|
||||||
|
for (final String dirName : userFolderPaths) {
|
||||||
if (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER) && !TextUtils.isEmpty(username)) {
|
final DocumentFile file = dir.findFile(dirName);
|
||||||
final String finaleUsername = username.startsWith("@") ? username.substring(1) : username;
|
if (file != null) {
|
||||||
dir = new File(dir, finaleUsername);
|
dir = file;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dir = dir.createDirectory(dirName);
|
||||||
|
if (dir == null) break;
|
||||||
}
|
}
|
||||||
|
// final String joined = android.text.TextUtils.join("/", userFolderPaths);
|
||||||
if (context != null && !skipCreateDir && !dir.exists() && !dir.mkdirs()) {
|
// final Uri userFolderUri = DocumentsContract.buildDocumentUriUsingTree(root.getUri(), joined);
|
||||||
|
// final DocumentFile userFolder = DocumentFile.fromSingleUri(context, userFolderUri);
|
||||||
|
if (context != null && (dir == null || !dir.exists())) {
|
||||||
Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<String> getSubPathForUserFolder(final String username) {
|
||||||
|
final List<String> list = new ArrayList<>();
|
||||||
|
if (!Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER) || TextUtils.isEmpty(username)) {
|
||||||
|
list.add(DIR_DOWNLOADS);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
final String finalUsername = username.startsWith("@") ? username.substring(1) : username;
|
||||||
|
list.add(DIR_DOWNLOADS);
|
||||||
|
list.add(finalUsername);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DocumentFile getTempDir() {
|
||||||
|
DocumentFile file = root.findFile(TEMP_DIR);
|
||||||
|
if (file == null) {
|
||||||
|
file = root.createDirectory(TEMP_DIR);
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
// public static void dmDownload(@NonNull final Context context,
|
// public static void dmDownload(@NonNull final Context context,
|
||||||
// @Nullable final String username,
|
// @Nullable final String username,
|
||||||
// final String modelId,
|
// final String modelId,
|
||||||
@ -126,59 +175,71 @@ public final class DownloadUtils {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private static void dmDownloadImpl(@NonNull final Context context,
|
// private static void dmDownloadImpl(@NonNull final Context context,
|
||||||
@Nullable final String username,
|
// @Nullable final String username,
|
||||||
final String modelId,
|
// final String modelId,
|
||||||
final String url) {
|
// final String url) {
|
||||||
final File dir = getDownloadDir(context, username);
|
// final DocumentFile dir = getDownloadDir(context, username);
|
||||||
if (dir.exists() || dir.mkdirs()) {
|
// if (dir != null && dir.exists()) {
|
||||||
download(context,
|
// download(context, url, getDownloadSavePaths(dir, modelId, url));
|
||||||
url,
|
// return;
|
||||||
getDownloadSaveFile(dir, modelId, url).getAbsolutePath());
|
// }
|
||||||
return;
|
// Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show();
|
||||||
}
|
// }
|
||||||
Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static File getDownloadSaveFile(final File finalDir,
|
private static Pair<List<String>, String> getDownloadSavePaths(final List<String> paths,
|
||||||
final String postId,
|
final String postId,
|
||||||
final String displayUrl) {
|
final String displayUrl) {
|
||||||
return getDownloadSaveFile(finalDir, postId, "", displayUrl);
|
return getDownloadSavePaths(paths, postId, "", displayUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File getDownloadChildSaveFile(final File downloadDir,
|
private static Pair<List<String>, String> getDownloadChildSaveFile(final List<String> paths,
|
||||||
final String postId,
|
final String postId,
|
||||||
final int childPosition,
|
final int childPosition,
|
||||||
final String url) {
|
final String url) {
|
||||||
final String sliderPostfix = "_slide_" + childPosition;
|
final String sliderPostfix = "_slide_" + childPosition;
|
||||||
return getDownloadSaveFile(downloadDir, postId, sliderPostfix, url);
|
return getDownloadSavePaths(paths, postId, sliderPostfix, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@Nullable
|
||||||
private static File getDownloadSaveFile(final File finalDir,
|
private static Pair<List<String>, String> getDownloadSavePaths(final List<String> paths,
|
||||||
final String postId,
|
final String postId,
|
||||||
final String sliderPostfix,
|
final String sliderPostfix,
|
||||||
final String displayUrl) {
|
final String displayUrl) {
|
||||||
final String fileName = postId + sliderPostfix + getFileExtensionFromUrl(displayUrl);
|
if (paths == null) return null;
|
||||||
return new File(finalDir, fileName);
|
final String extension = getFileExtensionFromUrl(displayUrl);
|
||||||
|
final String fileName = postId + sliderPostfix + extension;
|
||||||
|
// return new File(finalDir, fileName);
|
||||||
|
// DocumentFile file = finalDir.findFile(fileName);
|
||||||
|
// if (file == null) {
|
||||||
|
final String mimeType = Utils.mimeTypeMap.getMimeTypeFromExtension(extension.startsWith(".") ? extension.substring(1) : extension);
|
||||||
|
// file = finalDir.createFile(mimeType, fileName);
|
||||||
|
// }
|
||||||
|
paths.add(fileName);
|
||||||
|
return new Pair<>(paths, mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
public static DocumentFile getTempFile() {
|
||||||
public static File getTempFile() {
|
|
||||||
return getTempFile(null, null);
|
return getTempFile(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getTempFile(final String fileName, final String extension) {
|
public static DocumentFile getTempFile(final String fileName, final String extension) {
|
||||||
final File dir = getDownloadDir();
|
final DocumentFile dir = getTempDir();
|
||||||
String name = fileName;
|
String name = fileName;
|
||||||
if (TextUtils.isEmpty(name)) {
|
if (TextUtils.isEmpty(name)) {
|
||||||
name = UUID.randomUUID().toString();
|
name = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
String mimeType = "application/octet-stream";
|
||||||
if (!TextUtils.isEmpty(extension)) {
|
if (!TextUtils.isEmpty(extension)) {
|
||||||
name += "." + extension;
|
name += "." + extension;
|
||||||
|
mimeType = Utils.mimeTypeMap.getMimeTypeFromExtension(extension);
|
||||||
}
|
}
|
||||||
return new File(dir, name);
|
DocumentFile file = dir.findFile(name);
|
||||||
|
if (file == null) {
|
||||||
|
file = dir.createFile(mimeType, name);
|
||||||
|
}
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,20 +282,21 @@ public final class DownloadUtils {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Boolean> checkDownloaded(@NonNull final Media media) {
|
public static List<Boolean> checkDownloaded(@NonNull final Context context,
|
||||||
|
@NonNull final Media media) {
|
||||||
final List<Boolean> checkList = new LinkedList<>();
|
final List<Boolean> checkList = new LinkedList<>();
|
||||||
final User user = media.getUser();
|
final User user = media.getUser();
|
||||||
String username = "username";
|
String username = "username";
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
username = user.getUsername();
|
username = user.getUsername();
|
||||||
}
|
}
|
||||||
final File downloadDir = getDownloadDir(null, "@" + username, true);
|
final List<String> userFolderPaths = getSubPathForUserFolder(username);
|
||||||
switch (media.getMediaType()) {
|
switch (media.getMediaType()) {
|
||||||
case MEDIA_TYPE_IMAGE:
|
case MEDIA_TYPE_IMAGE:
|
||||||
case MEDIA_TYPE_VIDEO: {
|
case MEDIA_TYPE_VIDEO: {
|
||||||
final String url = ResponseBodyUtils.getImageUrl(media);
|
final String url = ResponseBodyUtils.getImageUrl(media);
|
||||||
final File file = getDownloadSaveFile(downloadDir, media.getCode(), url);
|
final Pair<List<String>, String> pair = getDownloadSavePaths(userFolderPaths, media.getCode(), url);
|
||||||
checkList.add(file.exists());
|
checkList.add(checkPathExists(context, pair.first));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MEDIA_TYPE_SLIDER:
|
case MEDIA_TYPE_SLIDER:
|
||||||
@ -243,8 +305,8 @@ public final class DownloadUtils {
|
|||||||
final Media child = sliderItems.get(i);
|
final Media child = sliderItems.get(i);
|
||||||
if (child == null) continue;
|
if (child == null) continue;
|
||||||
final String url = ResponseBodyUtils.getImageUrl(child);
|
final String url = ResponseBodyUtils.getImageUrl(child);
|
||||||
final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url);
|
final Pair<List<String>, String> pair = getDownloadChildSaveFile(userFolderPaths, media.getCode(), i + 1, url);
|
||||||
checkList.add(file.exists());
|
checkList.add(checkPathExists(context, pair.first));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -252,6 +314,14 @@ public final class DownloadUtils {
|
|||||||
return checkList;
|
return checkList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean checkPathExists(@NonNull final Context context,
|
||||||
|
@NonNull final List<String> paths) {
|
||||||
|
final String joined = android.text.TextUtils.join("/", paths);
|
||||||
|
final Uri userFolderUri = DocumentsContract.buildDocumentUriUsingTree(root.getUri(), joined);
|
||||||
|
final DocumentFile userFolder = DocumentFile.fromSingleUri(context, userFolderUri);
|
||||||
|
return userFolder != null && userFolder.exists();
|
||||||
|
}
|
||||||
|
|
||||||
public static void showDownloadDialog(@NonNull Context context,
|
public static void showDownloadDialog(@NonNull Context context,
|
||||||
@NonNull final Media feedModel,
|
@NonNull final Media feedModel,
|
||||||
final int childPosition) {
|
final int childPosition) {
|
||||||
@ -286,15 +356,20 @@ public final class DownloadUtils {
|
|||||||
|
|
||||||
public static void download(@NonNull final Context context,
|
public static void download(@NonNull final Context context,
|
||||||
@NonNull final StoryModel storyModel) {
|
@NonNull final StoryModel storyModel) {
|
||||||
final File downloadDir = getDownloadDir(context, "@" + storyModel.getUsername());
|
final DocumentFile downloadDir = getDownloadDir(context, "@" + storyModel.getUsername());
|
||||||
final String url = storyModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO
|
final String url = storyModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO
|
||||||
? storyModel.getVideoUrl()
|
? storyModel.getVideoUrl()
|
||||||
: storyModel.getStoryUrl();
|
: storyModel.getStoryUrl();
|
||||||
final File saveFile = new File(downloadDir,
|
final String extension = DownloadUtils.getFileExtensionFromUrl(url);
|
||||||
storyModel.getStoryMediaId()
|
final String fileName = storyModel.getStoryMediaId() + "_" + storyModel.getTimestamp() + extension;
|
||||||
+ "_" + storyModel.getTimestamp()
|
DocumentFile saveFile = downloadDir.findFile(fileName);
|
||||||
+ DownloadUtils.getFileExtensionFromUrl(url));
|
if (saveFile == null) {
|
||||||
download(context, url, saveFile.getAbsolutePath());
|
saveFile = downloadDir.createFile(
|
||||||
|
Utils.mimeTypeMap.getMimeTypeFromExtension(extension.startsWith(".") ? extension.substring(1) : extension),
|
||||||
|
fileName);
|
||||||
|
}
|
||||||
|
// final File saveFile = new File(downloadDir, fileName);
|
||||||
|
download(context, url, saveFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void download(@NonNull final Context context,
|
public static void download(@NonNull final Context context,
|
||||||
@ -316,17 +391,19 @@ public final class DownloadUtils {
|
|||||||
private static void download(@NonNull final Context context,
|
private static void download(@NonNull final Context context,
|
||||||
@NonNull final List<Media> feedModels,
|
@NonNull final List<Media> feedModels,
|
||||||
final int childPositionIfSingle) {
|
final int childPositionIfSingle) {
|
||||||
final Map<String, String> map = new HashMap<>();
|
final Map<String, DocumentFile> map = new HashMap<>();
|
||||||
for (final Media media : feedModels) {
|
for (final Media media : feedModels) {
|
||||||
final User mediaUser = media.getUser();
|
final User mediaUser = media.getUser();
|
||||||
final File downloadDir = getDownloadDir(context, mediaUser == null ? "" : "@" + mediaUser.getUsername());
|
final List<String> userFolderPaths = getSubPathForUserFolder(mediaUser == null ? "" : "@" + mediaUser.getUsername());
|
||||||
if (downloadDir == null) return;
|
// final DocumentFile downloadDir = getDownloadDir(context, mediaUser == null ? "" : "@" + mediaUser.getUsername());
|
||||||
switch (media.getMediaType()) {
|
switch (media.getMediaType()) {
|
||||||
case MEDIA_TYPE_IMAGE:
|
case MEDIA_TYPE_IMAGE:
|
||||||
case MEDIA_TYPE_VIDEO: {
|
case MEDIA_TYPE_VIDEO: {
|
||||||
final String url = getUrlOfType(media);
|
final String url = getUrlOfType(media);
|
||||||
final File file = getDownloadSaveFile(downloadDir, media.getCode(), url);
|
final Pair<List<String>, String> pair = getDownloadSavePaths(userFolderPaths, media.getCode(), url);
|
||||||
map.put(url, file.getAbsolutePath());
|
final DocumentFile file = createFile(pair);
|
||||||
|
if (file == null) continue;
|
||||||
|
map.put(url, file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MEDIA_TYPE_VOICE: {
|
case MEDIA_TYPE_VOICE: {
|
||||||
@ -335,28 +412,48 @@ public final class DownloadUtils {
|
|||||||
if (mediaUser != null) {
|
if (mediaUser != null) {
|
||||||
fileName = mediaUser.getUsername() + "_" + fileName;
|
fileName = mediaUser.getUsername() + "_" + fileName;
|
||||||
}
|
}
|
||||||
final File file = getDownloadSaveFile(downloadDir, fileName, url);
|
final Pair<List<String>, String> pair = getDownloadSavePaths(userFolderPaths, fileName, url);
|
||||||
map.put(url, file.getAbsolutePath());
|
final DocumentFile file = createFile(pair);
|
||||||
|
if (file == null) continue;
|
||||||
|
map.put(url, file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MEDIA_TYPE_SLIDER:
|
case MEDIA_TYPE_SLIDER:
|
||||||
final List<Media> sliderItems = media.getCarouselMedia();
|
final List<Media> sliderItems = media.getCarouselMedia();
|
||||||
for (int i = 0; i < sliderItems.size(); i++) {
|
for (int i = 0; i < sliderItems.size(); i++) {
|
||||||
if (childPositionIfSingle >= 0 && feedModels.size() == 1 && i != childPositionIfSingle) {
|
if (childPositionIfSingle >= 0 && feedModels.size() == 1 && i != childPositionIfSingle) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final Media child = sliderItems.get(i);
|
final Media child = sliderItems.get(i);
|
||||||
final String url = getUrlOfType(child);
|
final String url = getUrlOfType(child);
|
||||||
final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url);
|
final Pair<List<String>, String> pair = getDownloadChildSaveFile(userFolderPaths, media.getCode(), i + 1, url);
|
||||||
map.put(url, file.getAbsolutePath());
|
final DocumentFile file = createFile(pair);
|
||||||
|
if (file == null) continue;
|
||||||
|
map.put(url, file);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (map.isEmpty()) return;
|
||||||
download(context, map);
|
download(context, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static DocumentFile createFile(@NonNull final Pair<List<String>, String> pair) {
|
||||||
|
if (pair.first == null || pair.second == null) return null;
|
||||||
|
DocumentFile dir = root;
|
||||||
|
final List<String> first = pair.first;
|
||||||
|
for (int i = 0; i < first.size(); i++) {
|
||||||
|
final String name = first.get(i);
|
||||||
|
final DocumentFile file = dir.findFile(name);
|
||||||
|
if (file != null) {
|
||||||
|
dir = file;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dir = i == first.size() - 1 ? dir.createFile(pair.second, name) : dir.createDirectory(name);
|
||||||
|
if (dir == null) break;
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getUrlOfType(@NonNull final Media media) {
|
private static String getUrlOfType(@NonNull final Media media) {
|
||||||
switch (media.getMediaType()) {
|
switch (media.getMediaType()) {
|
||||||
@ -388,12 +485,13 @@ public final class DownloadUtils {
|
|||||||
|
|
||||||
public static void download(final Context context,
|
public static void download(final Context context,
|
||||||
final String url,
|
final String url,
|
||||||
final String filePath) {
|
final DocumentFile filePath) {
|
||||||
if (context == null || url == null || filePath == null) return;
|
if (context == null || url == null || filePath == null) return;
|
||||||
download(context, Collections.singletonMap(url, filePath));
|
download(context, Collections.singletonMap(url, filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void download(final Context context, final Map<String, String> urlFilePathMap) {
|
private static void download(final Context context, final Map<String, DocumentFile> urlFilePathMap) {
|
||||||
|
if (context == null) return;
|
||||||
final Constraints constraints = new Constraints.Builder()
|
final Constraints constraints = new Constraints.Builder()
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.build();
|
.build();
|
||||||
@ -401,19 +499,25 @@ public final class DownloadUtils {
|
|||||||
.setUrlToFilePathMap(urlFilePathMap)
|
.setUrlToFilePathMap(urlFilePathMap)
|
||||||
.build();
|
.build();
|
||||||
final String requestJson = new Gson().toJson(request);
|
final String requestJson = new Gson().toJson(request);
|
||||||
final File tempFile = getTempFile();
|
final DocumentFile tempFile = getTempFile(null, "json");
|
||||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) {
|
if (tempFile == null) {
|
||||||
|
Log.e(TAG, "download: temp file is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Uri uri = tempFile.getUri();
|
||||||
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
if (contentResolver == null) return;
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(contentResolver.openOutputStream(uri)))) {
|
||||||
writer.write(requestJson);
|
writer.write(requestJson);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "download: Error writing request to file", e);
|
Log.e(TAG, "download: Error writing request to file", e);
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
tempFile.delete();
|
tempFile.delete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final WorkRequest downloadWorkRequest = new OneTimeWorkRequest.Builder(DownloadWorker.class)
|
final WorkRequest downloadWorkRequest = new OneTimeWorkRequest.Builder(DownloadWorker.class)
|
||||||
.setInputData(
|
.setInputData(
|
||||||
new Data.Builder()
|
new Data.Builder()
|
||||||
.putString(DownloadWorker.KEY_DOWNLOAD_REQUEST_JSON, tempFile.getAbsolutePath())
|
.putString(DownloadWorker.KEY_DOWNLOAD_REQUEST_JSON, tempFile.getUri().toString())
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
|
@ -6,11 +6,10 @@ import android.net.Uri;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -45,7 +44,7 @@ public final class MediaUploader {
|
|||||||
listener.onFailure(new RuntimeException("Bitmap result was null"));
|
listener.onFailure(new RuntimeException("Bitmap result was null"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uploadPhoto(bitmap, listener);
|
uploadPhoto(contentResolver, bitmap, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -55,13 +54,14 @@ public final class MediaUploader {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void uploadPhoto(@NonNull final Bitmap bitmap,
|
private static void uploadPhoto(@NonNull final ContentResolver contentResolver,
|
||||||
|
@NonNull final Bitmap bitmap,
|
||||||
@NonNull final OnMediaUploadCompleteListener listener) {
|
@NonNull final OnMediaUploadCompleteListener listener) {
|
||||||
appExecutors.tasksThread().submit(() -> {
|
appExecutors.tasksThread().submit(() -> {
|
||||||
final File file;
|
final DocumentFile file;
|
||||||
final long byteLength;
|
final long byteLength;
|
||||||
try {
|
try {
|
||||||
file = BitmapUtils.convertToJpegAndSaveToFile(bitmap, null);
|
file = BitmapUtils.convertToJpegAndSaveToFile(contentResolver, bitmap, null);
|
||||||
byteLength = file.length();
|
byteLength = file.length();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
listener.onFailure(e);
|
listener.onFailure(e);
|
||||||
@ -71,12 +71,11 @@ public final class MediaUploader {
|
|||||||
final Map<String, String> headers = MediaUploadHelper.getUploadPhotoHeaders(options);
|
final Map<String, String> headers = MediaUploadHelper.getUploadPhotoHeaders(options);
|
||||||
final String url = HOST + "/rupload_igphoto/" + options.getName() + "/";
|
final String url = HOST + "/rupload_igphoto/" + options.getName() + "/";
|
||||||
appExecutors.networkIO().execute(() -> {
|
appExecutors.networkIO().execute(() -> {
|
||||||
try (FileInputStream input = new FileInputStream(file)) {
|
try (InputStream input = contentResolver.openInputStream(file.getUri())) {
|
||||||
upload(input, url, headers, listener);
|
upload(input, url, headers, listener);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
listener.onFailure(e);
|
listener.onFailure(e);
|
||||||
} finally {
|
} finally {
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -15,8 +15,11 @@ import android.media.MediaScannerConnection;
|
|||||||
import android.media.MediaScannerConnection.OnScanCompletedListener;
|
import android.media.MediaScannerConnection.OnScanCompletedListener;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.storage.StorageManager;
|
||||||
import android.provider.Browser;
|
import android.provider.Browser;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@ -35,6 +38,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
||||||
@ -46,6 +50,8 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -71,6 +77,7 @@ public final class Utils {
|
|||||||
public static Handler applicationHandler;
|
public static Handler applicationHandler;
|
||||||
public static String cacheDir;
|
public static String cacheDir;
|
||||||
private static int defaultStatusBarColor;
|
private static int defaultStatusBarColor;
|
||||||
|
private static Object[] volumes;
|
||||||
|
|
||||||
public static int convertDpToPx(final float dp) {
|
public static int convertDpToPx(final float dp) {
|
||||||
return Math.round((dp * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT);
|
return Math.round((dp * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT);
|
||||||
@ -367,4 +374,51 @@ public final class Utils {
|
|||||||
if (window == null) return;
|
if (window == null) return;
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void scanDocumentFile(@NonNull final Context context,
|
||||||
|
@NonNull final DocumentFile documentFile,
|
||||||
|
@NonNull final OnScanCompletedListener callback) {
|
||||||
|
if (!documentFile.isFile()) return;
|
||||||
|
File file = null;
|
||||||
|
try {
|
||||||
|
file = getDocumentFileRealPath(context, documentFile);
|
||||||
|
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||||
|
Log.e(TAG, "scanDocumentFile: ", e);
|
||||||
|
}
|
||||||
|
if (file == null) return;
|
||||||
|
MediaScannerConnection.scanFile(context,
|
||||||
|
new String[]{file.getAbsolutePath()},
|
||||||
|
new String[]{documentFile.getType()},
|
||||||
|
callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getDocumentFileRealPath(Context context, DocumentFile documentFile)
|
||||||
|
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||||
|
final String docId = DocumentsContract.getDocumentId(documentFile.getUri());
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
final String type = split[0];
|
||||||
|
|
||||||
|
if (type.equalsIgnoreCase("primary")) {
|
||||||
|
return new File(Environment.getExternalStorageDirectory(), split[1]);
|
||||||
|
} else {
|
||||||
|
if (volumes == null) {
|
||||||
|
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||||
|
Method getVolumeListMethod = sm.getClass().getMethod("getVolumeList");
|
||||||
|
volumes = (Object[]) getVolumeListMethod.invoke(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object volume : volumes) {
|
||||||
|
Method getUuidMethod = volume.getClass().getMethod("getUuid");
|
||||||
|
String uuid = (String) getUuidMethod.invoke(volume);
|
||||||
|
|
||||||
|
if (uuid != null && uuid.equalsIgnoreCase(type)) {
|
||||||
|
Method getPathMethod = volume.getClass().getMethod("getPath");
|
||||||
|
String path = (String) getPathMethod.invoke(volume);
|
||||||
|
return new File(path, split[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
import android.media.MediaRecorder;
|
import android.media.MediaRecorder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -27,20 +29,20 @@ public class VoiceRecorder {
|
|||||||
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(FILE_FORMAT, Locale.US);
|
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(FILE_FORMAT, Locale.US);
|
||||||
|
|
||||||
private final List<Float> waveform = new ArrayList<>();
|
private final List<Float> waveform = new ArrayList<>();
|
||||||
private final File recordingsDir;
|
private final DocumentFile recordingsDir;
|
||||||
private final VoiceRecorderCallback callback;
|
private final VoiceRecorderCallback callback;
|
||||||
|
|
||||||
private MediaRecorder recorder;
|
private MediaRecorder recorder;
|
||||||
private File audioTempFile;
|
private DocumentFile audioTempFile;
|
||||||
private MaxAmpHandler maxAmpHandler;
|
private MaxAmpHandler maxAmpHandler;
|
||||||
private boolean stopped;
|
private boolean stopped;
|
||||||
|
|
||||||
public VoiceRecorder(@NonNull final File recordingsDir, final VoiceRecorderCallback callback) {
|
public VoiceRecorder(@NonNull final DocumentFile recordingsDir, final VoiceRecorderCallback callback) {
|
||||||
this.recordingsDir = recordingsDir;
|
this.recordingsDir = recordingsDir;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startRecording() {
|
public void startRecording(final Application application) {
|
||||||
stopped = false;
|
stopped = false;
|
||||||
try {
|
try {
|
||||||
recorder = new MediaRecorder();
|
recorder = new MediaRecorder();
|
||||||
@ -48,7 +50,8 @@ public class VoiceRecorder {
|
|||||||
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
|
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
|
||||||
deleteTempAudioFile();
|
deleteTempAudioFile();
|
||||||
audioTempFile = getAudioRecordFile();
|
audioTempFile = getAudioRecordFile();
|
||||||
recorder.setOutputFile(audioTempFile.getAbsolutePath());
|
final ParcelFileDescriptor parcelFileDescriptor = application.getContentResolver().openFileDescriptor(audioTempFile.getUri(), "rwt");
|
||||||
|
recorder.setOutputFile(parcelFileDescriptor.getFileDescriptor());
|
||||||
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
|
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
|
||||||
recorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
|
recorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
|
||||||
recorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
|
recorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
|
||||||
@ -140,9 +143,9 @@ public class VoiceRecorder {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private File getAudioRecordFile() {
|
private DocumentFile getAudioRecordFile() {
|
||||||
final String name = String.format("%s-%s.%s", FILE_PREFIX, SIMPLE_DATE_FORMAT.format(new Date()), EXTENSION);
|
final String name = String.format("%s-%s.%s", FILE_PREFIX, SIMPLE_DATE_FORMAT.format(new Date()), EXTENSION);
|
||||||
return new File(recordingsDir, name);
|
return recordingsDir.createFile(MIME_TYPE, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteTempAudioFile() {
|
private void deleteTempAudioFile() {
|
||||||
@ -160,11 +163,11 @@ public class VoiceRecorder {
|
|||||||
|
|
||||||
public static class VoiceRecordingResult {
|
public static class VoiceRecordingResult {
|
||||||
private final String mimeType;
|
private final String mimeType;
|
||||||
private final File file;
|
private final DocumentFile file;
|
||||||
private final List<Float> waveform;
|
private final List<Float> waveform;
|
||||||
private final int samplingFreq = 10;
|
private final int samplingFreq = 10;
|
||||||
|
|
||||||
public VoiceRecordingResult(final String mimeType, final File file, final List<Float> waveform) {
|
public VoiceRecordingResult(final String mimeType, final DocumentFile file, final List<Float> waveform) {
|
||||||
this.mimeType = mimeType;
|
this.mimeType = mimeType;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.waveform = waveform;
|
this.waveform = waveform;
|
||||||
@ -174,7 +177,7 @@ public class VoiceRecorder {
|
|||||||
return mimeType;
|
return mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getFile() {
|
public DocumentFile getFile() {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,18 +2,17 @@ package awais.instagrabber.viewmodels;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.media.MediaScannerConnection;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.Transformations;
|
import androidx.lifecycle.Transformations;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -38,6 +37,7 @@ import awais.instagrabber.utils.DownloadUtils;
|
|||||||
import awais.instagrabber.utils.MediaController;
|
import awais.instagrabber.utils.MediaController;
|
||||||
import awais.instagrabber.utils.MediaUtils;
|
import awais.instagrabber.utils.MediaUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.utils.VoiceRecorder;
|
import awais.instagrabber.utils.VoiceRecorder;
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
@ -47,7 +47,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
// private static final String ERROR_INVALID_THREAD = "Invalid thread";
|
// private static final String ERROR_INVALID_THREAD = "Invalid thread";
|
||||||
|
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
private final File recordingsDir;
|
private final DocumentFile recordingsDir;
|
||||||
private final Application application;
|
private final Application application;
|
||||||
private final long viewerId;
|
private final long viewerId;
|
||||||
private final String threadId;
|
private final String threadId;
|
||||||
@ -166,37 +166,32 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
@Override
|
@Override
|
||||||
public void onComplete(final VoiceRecorder.VoiceRecordingResult result) {
|
public void onComplete(final VoiceRecorder.VoiceRecordingResult result) {
|
||||||
Log.d(TAG, "onComplete: recording complete. Scanning file...");
|
Log.d(TAG, "onComplete: recording complete. Scanning file...");
|
||||||
MediaScannerConnection.scanFile(
|
Utils.scanDocumentFile(application, result.getFile(), (path, uri) -> {
|
||||||
application,
|
if (uri == null) {
|
||||||
new String[]{result.getFile().getAbsolutePath()},
|
final String msg = "Scan failed!";
|
||||||
new String[]{result.getMimeType()},
|
Log.e(TAG, msg);
|
||||||
(path, uri) -> {
|
data.postValue(Resource.error(msg, null));
|
||||||
if (uri == null) {
|
return;
|
||||||
final String msg = "Scan failed!";
|
}
|
||||||
Log.e(TAG, msg);
|
Log.d(TAG, "onComplete: scan complete");
|
||||||
data.postValue(Resource.error(msg, null));
|
MediaUtils.getVoiceInfo(contentResolver, uri, new MediaUtils.OnInfoLoadListener<MediaUtils.VideoInfo>() {
|
||||||
return;
|
@Override
|
||||||
}
|
public void onLoad(@Nullable final MediaUtils.VideoInfo videoInfo) {
|
||||||
Log.d(TAG, "onComplete: scan complete");
|
if (videoInfo == null) return;
|
||||||
MediaUtils.getVoiceInfo(contentResolver, uri, new MediaUtils.OnInfoLoadListener<MediaUtils.VideoInfo>() {
|
threadManager.sendVoice(data,
|
||||||
@Override
|
uri,
|
||||||
public void onLoad(@Nullable final MediaUtils.VideoInfo videoInfo) {
|
result.getWaveform(),
|
||||||
if (videoInfo == null) return;
|
result.getSamplingFreq(),
|
||||||
threadManager.sendVoice(data,
|
videoInfo == null ? 0 : videoInfo.duration,
|
||||||
uri,
|
videoInfo == null ? 0 : videoInfo.size);
|
||||||
result.getWaveform(),
|
|
||||||
result.getSamplingFreq(),
|
|
||||||
videoInfo == null ? 0 : videoInfo.duration,
|
|
||||||
videoInfo == null ? 0 : videoInfo.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(final Throwable t) {
|
|
||||||
data.postValue(Resource.error(t.getMessage(), null));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(final Throwable t) {
|
||||||
|
data.postValue(Resource.error(t.getMessage(), null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -204,7 +199,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
voiceRecorder.startRecording();
|
voiceRecorder.startRecording(application);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import android.graphics.RectF;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
@ -26,6 +27,7 @@ import awais.instagrabber.models.SavedImageEditState;
|
|||||||
import awais.instagrabber.utils.AppExecutors;
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.DownloadUtils;
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.SerializablePair;
|
import awais.instagrabber.utils.SerializablePair;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
import jp.co.cyberagent.android.gpuimage.GPUImage;
|
import jp.co.cyberagent.android.gpuimage.GPUImage;
|
||||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
|
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
|
||||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilterGroup;
|
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilterGroup;
|
||||||
@ -35,6 +37,7 @@ public class ImageEditViewModel extends AndroidViewModel {
|
|||||||
private static final String RESULT = "result";
|
private static final String RESULT = "result";
|
||||||
private static final String FILE_FORMAT = "yyyyMMddHHmmssSSS";
|
private static final String FILE_FORMAT = "yyyyMMddHHmmssSSS";
|
||||||
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(FILE_FORMAT, Locale.US);
|
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(FILE_FORMAT, Locale.US);
|
||||||
|
private static final String MIME_TYPE = Utils.mimeTypeMap.getMimeTypeFromExtension("jpg");
|
||||||
|
|
||||||
private Uri originalUri;
|
private Uri originalUri;
|
||||||
private SavedImageEditState savedImageEditState;
|
private SavedImageEditState savedImageEditState;
|
||||||
@ -48,18 +51,18 @@ public class ImageEditViewModel extends AndroidViewModel {
|
|||||||
private final MutableLiveData<Boolean> isCropped = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> isCropped = new MutableLiveData<>(false);
|
||||||
private final MutableLiveData<Boolean> isTuned = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> isTuned = new MutableLiveData<>(false);
|
||||||
private final MutableLiveData<Boolean> isFiltered = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> isFiltered = new MutableLiveData<>(false);
|
||||||
private final File outputDir;
|
private final DocumentFile outputDir;
|
||||||
private List<Filter<? extends GPUImageFilter>> tuningFilters;
|
private List<Filter<? extends GPUImageFilter>> tuningFilters;
|
||||||
private Filter<? extends GPUImageFilter> appliedFilter;
|
private Filter<? extends GPUImageFilter> appliedFilter;
|
||||||
private final File destinationFile;
|
private final DocumentFile destinationFile;
|
||||||
|
|
||||||
public ImageEditViewModel(final Application application) {
|
public ImageEditViewModel(final Application application) {
|
||||||
super(application);
|
super(application);
|
||||||
sessionId = SIMPLE_DATE_FORMAT.format(new Date());
|
sessionId = SIMPLE_DATE_FORMAT.format(new Date());
|
||||||
outputDir = DownloadUtils.getImageEditDir(sessionId);
|
outputDir = DownloadUtils.getImageEditDir(sessionId);
|
||||||
destinationFile = new File(outputDir, RESULT + ".jpg");
|
destinationFile = outputDir.createFile(MIME_TYPE, RESULT + ".jpg");
|
||||||
destinationUri = Uri.fromFile(destinationFile);
|
destinationUri = destinationFile.getUri();
|
||||||
cropDestinationUri = Uri.fromFile(new File(outputDir, CROP + ".jpg"));
|
cropDestinationUri = outputDir.createFile(MIME_TYPE, CROP + ".jpg").getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSessionId() {
|
public String getSessionId() {
|
||||||
@ -159,16 +162,15 @@ public class ImageEditViewModel extends AndroidViewModel {
|
|||||||
delete(outputDir);
|
delete(outputDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delete(@NonNull final File file) {
|
private void delete(@NonNull final DocumentFile file) {
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
final File[] files = file.listFiles();
|
final DocumentFile[] files = file.listFiles();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (File f : files) {
|
for (DocumentFile f : files) {
|
||||||
delete(f);
|
delete(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,9 +208,9 @@ public class ImageEditViewModel extends AndroidViewModel {
|
|||||||
return new SerializablePair<>(type, propertyValueMap);
|
return new SerializablePair<>(type, propertyValueMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getDestinationFile() {
|
// public File getDestinationFile() {
|
||||||
return destinationFile;
|
// return destinationFile;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public enum Tab {
|
public enum Tab {
|
||||||
RESULT,
|
RESULT,
|
||||||
|
@ -8,7 +8,6 @@ import android.content.Intent;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.media.MediaMetadataRetriever;
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.media.MediaScannerConnection;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -18,7 +17,7 @@ import android.util.Log;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.work.Data;
|
import androidx.work.Data;
|
||||||
import androidx.work.ForegroundInfo;
|
import androidx.work.ForegroundInfo;
|
||||||
import androidx.work.Worker;
|
import androidx.work.Worker;
|
||||||
@ -30,10 +29,8 @@ import com.google.gson.JsonSyntaxException;
|
|||||||
import org.apache.commons.imaging.formats.jpeg.iptc.JpegIptcRewriter;
|
import org.apache.commons.imaging.formats.jpeg.iptc.JpegIptcRewriter;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -44,6 +41,7 @@ import java.util.Map;
|
|||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import awais.instagrabber.BuildConfig;
|
import awais.instagrabber.BuildConfig;
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
@ -52,10 +50,11 @@ import awais.instagrabber.utils.Constants;
|
|||||||
import awais.instagrabber.utils.DownloadUtils;
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
//import awaisomereport.LogCollector;
|
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Constants.DOWNLOAD_CHANNEL_ID;
|
import static awais.instagrabber.utils.Constants.DOWNLOAD_CHANNEL_ID;
|
||||||
import static awais.instagrabber.utils.Constants.NOTIF_GROUP_NAME;
|
import static awais.instagrabber.utils.Constants.NOTIF_GROUP_NAME;
|
||||||
|
|
||||||
|
//import awaisomereport.LogCollector;
|
||||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
|
|
||||||
public class DownloadWorker extends Worker {
|
public class DownloadWorker extends Worker {
|
||||||
@ -85,8 +84,21 @@ public class DownloadWorker extends Worker {
|
|||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
final String downloadRequestString;
|
final String downloadRequestString;
|
||||||
final File requestFile = new File(downloadRequestFilePath);
|
// final File requestFile = new File(downloadRequestFilePath);
|
||||||
try (Scanner scanner = new Scanner(requestFile)) {
|
final Uri requestFile = Uri.parse(downloadRequestFilePath);
|
||||||
|
if (requestFile == null) {
|
||||||
|
return Result.failure(new Data.Builder()
|
||||||
|
.putString("error", "requestFile is null")
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
final Context context = getApplicationContext();
|
||||||
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
if (contentResolver == null) {
|
||||||
|
return Result.failure(new Data.Builder()
|
||||||
|
.putString("error", "contentResolver is null")
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
try (Scanner scanner = new Scanner(contentResolver.openInputStream(requestFile))) {
|
||||||
downloadRequestString = scanner.useDelimiter("\\A").next();
|
downloadRequestString = scanner.useDelimiter("\\A").next();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "doWork: ", e);
|
Log.e(TAG, "doWork: ", e);
|
||||||
@ -116,7 +128,7 @@ public class DownloadWorker extends Worker {
|
|||||||
final Map<String, String> urlToFilePathMap = downloadRequest.getUrlToFilePathMap();
|
final Map<String, String> urlToFilePathMap = downloadRequest.getUrlToFilePathMap();
|
||||||
download(urlToFilePathMap);
|
download(urlToFilePathMap);
|
||||||
new Handler(Looper.getMainLooper()).postDelayed(() -> showSummary(urlToFilePathMap), 500);
|
new Handler(Looper.getMainLooper()).postDelayed(() -> showSummary(urlToFilePathMap), 500);
|
||||||
final boolean deleted = requestFile.delete();
|
final boolean deleted = DocumentFile.fromSingleUri(context, requestFile).delete();
|
||||||
if (!deleted) {
|
if (!deleted) {
|
||||||
Log.w(TAG, "doWork: requestFile not deleted!");
|
Log.w(TAG, "doWork: requestFile not deleted!");
|
||||||
}
|
}
|
||||||
@ -131,7 +143,9 @@ public class DownloadWorker extends Worker {
|
|||||||
for (final Map.Entry<String, String> urlAndFilePath : entries) {
|
for (final Map.Entry<String, String> urlAndFilePath : entries) {
|
||||||
final String url = urlAndFilePath.getKey();
|
final String url = urlAndFilePath.getKey();
|
||||||
updateDownloadProgress(notificationId, count, total, 0);
|
updateDownloadProgress(notificationId, count, total, 0);
|
||||||
download(notificationId, count, total, url, urlAndFilePath.getValue());
|
final String uriString = urlAndFilePath.getValue();
|
||||||
|
final DocumentFile file = DocumentFile.fromSingleUri(getApplicationContext(), Uri.parse(uriString));
|
||||||
|
download(notificationId, count, total, url, file);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,17 +158,24 @@ public class DownloadWorker extends Worker {
|
|||||||
final int position,
|
final int position,
|
||||||
final int total,
|
final int total,
|
||||||
final String url,
|
final String url,
|
||||||
final String filePath) {
|
final DocumentFile filePath) {
|
||||||
final boolean isJpg = filePath.endsWith("jpg");
|
final Context context = getApplicationContext();
|
||||||
|
if (context == null) return;
|
||||||
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
if (contentResolver == null) return;
|
||||||
|
final String filePathType = filePath.getType();
|
||||||
|
if (filePathType == null) return;
|
||||||
|
// final String extension = Utils.mimeTypeMap.getExtensionFromMimeType(filePathType);
|
||||||
|
final boolean isJpg = filePathType.startsWith("image"); // extension.endsWith("jpg");
|
||||||
// using temp file approach to remove IPTC so that download progress can be reported
|
// using temp file approach to remove IPTC so that download progress can be reported
|
||||||
final File outFile = isJpg ? DownloadUtils.getTempFile() : new File(filePath);
|
final DocumentFile outFile = isJpg ? DownloadUtils.getTempFile(null, "jpg") : filePath;
|
||||||
try {
|
try {
|
||||||
final URLConnection urlConnection = new URL(url).openConnection();
|
final URLConnection urlConnection = new URL(url).openConnection();
|
||||||
final long fileSize = Build.VERSION.SDK_INT >= 24 ? urlConnection.getContentLengthLong() :
|
final long fileSize = Build.VERSION.SDK_INT >= 24 ? urlConnection.getContentLengthLong() :
|
||||||
urlConnection.getContentLength();
|
urlConnection.getContentLength();
|
||||||
float totalRead = 0;
|
float totalRead = 0;
|
||||||
try (final BufferedInputStream bis = new BufferedInputStream(urlConnection.getInputStream());
|
try (final BufferedInputStream bis = new BufferedInputStream(urlConnection.getInputStream());
|
||||||
final FileOutputStream fos = new FileOutputStream(outFile)) {
|
final OutputStream fos = contentResolver.openOutputStream(outFile.getUri())) {
|
||||||
final byte[] buffer = new byte[0x2000];
|
final byte[] buffer = new byte[0x2000];
|
||||||
int count;
|
int count;
|
||||||
while ((count = bis.read(buffer, 0, 0x2000)) != -1) {
|
while ((count = bis.read(buffer, 0, 0x2000)) != -1) {
|
||||||
@ -167,18 +188,17 @@ public class DownloadWorker extends Worker {
|
|||||||
}
|
}
|
||||||
fos.flush();
|
fos.flush();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.e(TAG, "Error while writing data from url: " + url + " to file: " + outFile.getAbsolutePath(), e);
|
Log.e(TAG, "Error while writing data from url: " + url + " to file: " + outFile.getName(), e);
|
||||||
}
|
}
|
||||||
if (isJpg) {
|
if (isJpg) {
|
||||||
final File finalFile = new File(filePath);
|
try (final InputStream fis = contentResolver.openInputStream(outFile.getUri());
|
||||||
try (FileInputStream fis = new FileInputStream(outFile);
|
final OutputStream fos = contentResolver.openOutputStream(filePath.getUri())) {
|
||||||
FileOutputStream fos = new FileOutputStream(finalFile)) {
|
|
||||||
final JpegIptcRewriter jpegIptcRewriter = new JpegIptcRewriter();
|
final JpegIptcRewriter jpegIptcRewriter = new JpegIptcRewriter();
|
||||||
jpegIptcRewriter.removeIPTC(fis, fos);
|
jpegIptcRewriter.removeIPTC(fis, fos);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Error while removing iptc: url: " + url
|
Log.e(TAG, "Error while removing iptc: url: " + url
|
||||||
+ ", tempFile: " + outFile.getAbsolutePath()
|
+ ", tempFile: " + outFile
|
||||||
+ ", finalFile: " + finalFile.getAbsolutePath(), e);
|
+ ", finalFile: " + filePath, e);
|
||||||
}
|
}
|
||||||
final boolean deleted = outFile.delete();
|
final boolean deleted = outFile.delete();
|
||||||
if (!deleted) {
|
if (!deleted) {
|
||||||
@ -243,57 +263,56 @@ public class DownloadWorker extends Worker {
|
|||||||
|
|
||||||
private void showSummary(final Map<String, String> urlToFilePathMap) {
|
private void showSummary(final Map<String, String> urlToFilePathMap) {
|
||||||
final Context context = getApplicationContext();
|
final Context context = getApplicationContext();
|
||||||
final Collection<String> filePaths = urlToFilePathMap.values();
|
final Collection<DocumentFile> filePaths = urlToFilePathMap.values()
|
||||||
|
.stream()
|
||||||
|
.map(s -> DocumentFile.fromSingleUri(context, Uri.parse(s)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
final List<NotificationCompat.Builder> notifications = new LinkedList<>();
|
final List<NotificationCompat.Builder> notifications = new LinkedList<>();
|
||||||
final List<Integer> notificationIds = new LinkedList<>();
|
final List<Integer> notificationIds = new LinkedList<>();
|
||||||
int count = 1;
|
int count = 1;
|
||||||
for (final String filePath : filePaths) {
|
for (final DocumentFile filePath : filePaths) {
|
||||||
final File file = new File(filePath);
|
// final File file = new File(filePath);
|
||||||
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
|
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, filePath.getUri()));
|
||||||
MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);
|
Utils.scanDocumentFile(context, filePath, (path, uri) -> {});
|
||||||
final Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
|
// final Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
|
||||||
final ContentResolver contentResolver = context.getContentResolver();
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
Bitmap bitmap = null;
|
Bitmap bitmap = null;
|
||||||
final String mimeType = Utils.getMimeType(uri, contentResolver);
|
final String mimeType = filePath.getType(); // Utils.getMimeType(uri, contentResolver);
|
||||||
if (!TextUtils.isEmpty(mimeType)) {
|
if (!TextUtils.isEmpty(mimeType)) {
|
||||||
if (mimeType.startsWith("image")) {
|
if (mimeType.startsWith("image")) {
|
||||||
try (final InputStream inputStream = contentResolver.openInputStream(uri)) {
|
try (final InputStream inputStream = contentResolver.openInputStream(filePath.getUri())) {
|
||||||
bitmap = BitmapFactory.decodeStream(inputStream);
|
bitmap = BitmapFactory.decodeStream(inputStream);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
// if (logCollector != null)
|
|
||||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_DOWNLOADER, "onPostExecute::bitmap_1");
|
|
||||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
||||||
}
|
}
|
||||||
} else if (mimeType.startsWith("video")) {
|
} else if (mimeType.startsWith("video")) {
|
||||||
final MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
final MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
retriever.setDataSource(context, uri);
|
retriever.setDataSource(context, filePath.getUri());
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
retriever.setDataSource(file.getAbsolutePath());
|
// retriever.setDataSource(file.getAbsolutePath());
|
||||||
|
Log.e(TAG, "showSummary: ", e);
|
||||||
}
|
}
|
||||||
bitmap = retriever.getFrameAtTime();
|
bitmap = retriever.getFrameAtTime();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
try {
|
try {
|
||||||
retriever.close();
|
retriever.close();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
// if (logCollector != null)
|
Log.e(TAG, "showSummary: ", e);
|
||||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_DOWNLOADER, "onPostExecute::bitmap_2");
|
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
Log.e(TAG, "", e);
|
||||||
// if (logCollector != null)
|
|
||||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_DOWNLOADER, "onPostExecute::bitmap_3");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String downloadComplete = context.getString(R.string.downloader_complete);
|
final String downloadComplete = context.getString(R.string.downloader_complete);
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
|
final Intent intent = new Intent(Intent.ACTION_VIEW, filePath.getUri())
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
| Intent.FLAG_FROM_BACKGROUND
|
| Intent.FLAG_FROM_BACKGROUND
|
||||||
| Intent.FLAG_GRANT_READ_URI_PERMISSION
|
| Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
.putExtra(Intent.EXTRA_STREAM, uri);
|
.putExtra(Intent.EXTRA_STREAM, filePath.getUri());
|
||||||
final PendingIntent pendingIntent = PendingIntent.getActivity(
|
final PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
DOWNLOAD_NOTIFICATION_INTENT_REQUEST_CODE,
|
DOWNLOAD_NOTIFICATION_INTENT_REQUEST_CODE,
|
||||||
@ -357,16 +376,22 @@ public class DownloadWorker extends Worker {
|
|||||||
public static class Builder {
|
public static class Builder {
|
||||||
private Map<String, String> urlToFilePathMap;
|
private Map<String, String> urlToFilePathMap;
|
||||||
|
|
||||||
public Builder setUrlToFilePathMap(final Map<String, String> urlToFilePathMap) {
|
public Builder setUrlToFilePathMap(final Map<String, DocumentFile> urlToFilePathMap) {
|
||||||
this.urlToFilePathMap = urlToFilePathMap;
|
if (urlToFilePathMap == null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
this.urlToFilePathMap = urlToFilePathMap.entrySet()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey,
|
||||||
|
o -> o.getValue().getUri().toString()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addUrl(@NonNull final String url, @NonNull final String filePath) {
|
public Builder addUrl(@NonNull final String url, @NonNull final DocumentFile filePath) {
|
||||||
if (urlToFilePathMap == null) {
|
if (urlToFilePathMap == null) {
|
||||||
urlToFilePathMap = new HashMap<>();
|
urlToFilePathMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
urlToFilePathMap.put(url, filePath);
|
urlToFilePathMap.put(url, filePath.getUri().toString());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user