mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 06:37:30 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
0535df25b0
@ -1,129 +0,0 @@
|
|||||||
package awais.instagrabber.activities;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.provider.DocumentsContract;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
|
||||||
import awais.instagrabber.databinding.ActivityDirectorySelectBinding;
|
|
||||||
import awais.instagrabber.dialogs.ConfirmDialogFragment;
|
|
||||||
import awais.instagrabber.utils.AppExecutors;
|
|
||||||
import awais.instagrabber.viewmodels.DirectorySelectActivityViewModel;
|
|
||||||
|
|
||||||
public class DirectorySelectActivity extends BaseLanguageActivity {
|
|
||||||
private static final String TAG = DirectorySelectActivity.class.getSimpleName();
|
|
||||||
public static final int SELECT_DIR_REQUEST_CODE = 0x01;
|
|
||||||
private static final int ERROR_REQUEST_CODE = 0x02;
|
|
||||||
|
|
||||||
private Uri initialUri;
|
|
||||||
private ActivityDirectorySelectBinding binding;
|
|
||||||
private DirectorySelectActivityViewModel viewModel;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
binding = ActivityDirectorySelectBinding.inflate(getLayoutInflater());
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
viewModel = new ViewModelProvider(this).get(DirectorySelectActivityViewModel.class);
|
|
||||||
setupObservers();
|
|
||||||
binding.selectDir.setOnClickListener(v -> openDirectoryChooser());
|
|
||||||
AppExecutors.INSTANCE.getMainThread().execute(() -> viewModel.setInitialUri(getIntent()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupObservers() {
|
|
||||||
viewModel.getMessage().observe(this, message -> binding.message.setText(message));
|
|
||||||
viewModel.getPrevUri().observe(this, prevUri -> {
|
|
||||||
if (prevUri == null) {
|
|
||||||
binding.prevUri.setVisibility(View.GONE);
|
|
||||||
binding.message2.setVisibility(View.GONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
binding.prevUri.setText(prevUri);
|
|
||||||
binding.prevUri.setVisibility(View.VISIBLE);
|
|
||||||
binding.message2.setVisibility(View.VISIBLE);
|
|
||||||
});
|
|
||||||
viewModel.getDirSuccess().observe(this, success -> binding.selectDir.setVisibility(success ? View.GONE : View.VISIBLE));
|
|
||||||
viewModel.isLoading().observe(this, loading -> {
|
|
||||||
binding.message.setVisibility(loading ? View.GONE : View.VISIBLE);
|
|
||||||
binding.loadingIndicator.setVisibility(loading ? View.VISIBLE : View.GONE);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openDirectoryChooser() {
|
|
||||||
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && initialUri != null) {
|
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
startActivityForResult(intent, SELECT_DIR_REQUEST_CODE);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
Log.e(TAG, "openDirectoryChooser: ", e);
|
|
||||||
showErrorDialog(getString(R.string.no_directory_picker_activity));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "openDirectoryChooser: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("StringFormatInvalid")
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
if (requestCode != SELECT_DIR_REQUEST_CODE) return;
|
|
||||||
if (resultCode != RESULT_OK) {
|
|
||||||
showErrorDialog(getString(R.string.select_a_folder));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (data == null || data.getData() == null) {
|
|
||||||
showErrorDialog(getString(R.string.select_a_folder));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!"com.android.externalstorage.documents".equals(data.getData().getAuthority())) {
|
|
||||||
showErrorDialog(getString(R.string.dir_select_no_download_folder, data.getData().getAuthority()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
|
||||||
try {
|
|
||||||
viewModel.setupSelectedDir(data);
|
|
||||||
final Intent intent = new Intent(this, MainActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Should not come to this point.
|
|
||||||
// If it does, we have to show this error to the user so that they can report it.
|
|
||||||
try (final StringWriter sw = new StringWriter();
|
|
||||||
final PrintWriter pw = new PrintWriter(sw)) {
|
|
||||||
e.printStackTrace(pw);
|
|
||||||
showErrorDialog("Please report this error to the developers:\n\n" + sw.toString());
|
|
||||||
} catch (IOException ioException) {
|
|
||||||
Log.e(TAG, "onActivityResult: ", ioException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showErrorDialog(@NonNull final String message) {
|
|
||||||
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
|
|
||||||
ERROR_REQUEST_CODE,
|
|
||||||
R.string.error,
|
|
||||||
message,
|
|
||||||
R.string.ok,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
dialogFragment.show(getSupportFragmentManager(), ConfirmDialogFragment.class.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,132 @@
|
|||||||
|
package awais.instagrabber.activities
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import awais.instagrabber.R
|
||||||
|
import awais.instagrabber.databinding.ActivityDirectorySelectBinding
|
||||||
|
import awais.instagrabber.dialogs.ConfirmDialogFragment
|
||||||
|
import awais.instagrabber.utils.AppExecutors.mainThread
|
||||||
|
import awais.instagrabber.utils.Constants
|
||||||
|
import awais.instagrabber.utils.extensions.TAG
|
||||||
|
import awais.instagrabber.viewmodels.DirectorySelectActivityViewModel
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.io.StringWriter
|
||||||
|
|
||||||
|
class DirectorySelectActivity : BaseLanguageActivity() {
|
||||||
|
private var initialUri: Uri? = null
|
||||||
|
|
||||||
|
private lateinit var binding: ActivityDirectorySelectBinding
|
||||||
|
|
||||||
|
private val viewModel: DirectorySelectActivityViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityDirectorySelectBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
val intent = intent
|
||||||
|
viewModel.setInitialUri(intent)
|
||||||
|
setupObservers()
|
||||||
|
binding.selectDir.setOnClickListener { openDirectoryChooser() }
|
||||||
|
initialUri = intent.getParcelableExtra(Constants.EXTRA_INITIAL_URI)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers() {
|
||||||
|
viewModel.message.observe(this, { message: String? -> binding.message.text = message })
|
||||||
|
viewModel.prevUri.observe(this, { prevUri: String? ->
|
||||||
|
if (prevUri == null) {
|
||||||
|
binding.prevUri.visibility = View.GONE
|
||||||
|
binding.message2.visibility = View.GONE
|
||||||
|
return@observe
|
||||||
|
}
|
||||||
|
binding.prevUri.text = prevUri
|
||||||
|
binding.prevUri.visibility = View.VISIBLE
|
||||||
|
binding.message2.visibility = View.VISIBLE
|
||||||
|
})
|
||||||
|
viewModel.dirSuccess.observe(this, { success: Boolean -> binding.selectDir.visibility = if (success) View.GONE else View.VISIBLE })
|
||||||
|
viewModel.loading.observe(this, { loading: Boolean ->
|
||||||
|
binding.message.visibility = if (loading) View.GONE else View.VISIBLE
|
||||||
|
binding.loadingIndicator.visibility = if (loading) View.VISIBLE else View.GONE
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openDirectoryChooser() {
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && initialUri != null) {
|
||||||
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
startActivityForResult(intent, SELECT_DIR_REQUEST_CODE)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
Log.e(TAG, "openDirectoryChooser: ", e)
|
||||||
|
showErrorDialog(getString(R.string.no_directory_picker_activity))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "openDirectoryChooser: ", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("StringFormatInvalid")
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
if (requestCode != SELECT_DIR_REQUEST_CODE) return
|
||||||
|
if (resultCode != RESULT_OK) {
|
||||||
|
showErrorDialog(getString(R.string.select_a_folder))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (data == null || data.data == null) {
|
||||||
|
showErrorDialog(getString(R.string.select_a_folder))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val authority = data.data?.authority
|
||||||
|
if ("com.android.externalstorage.documents" != authority) {
|
||||||
|
showErrorDialog(getString(R.string.dir_select_no_download_folder, authority))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mainThread.execute({
|
||||||
|
try {
|
||||||
|
viewModel.setupSelectedDir(data)
|
||||||
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Should not come to this point.
|
||||||
|
// If it does, we have to show this error to the user so that they can report it.
|
||||||
|
try {
|
||||||
|
StringWriter().use { sw ->
|
||||||
|
PrintWriter(sw).use { pw ->
|
||||||
|
e.printStackTrace(pw)
|
||||||
|
showErrorDialog("Please report this error to the developers:\n\n$sw")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ioException: IOException) {
|
||||||
|
Log.e(TAG, "onActivityResult: ", ioException)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorDialog(message: String) {
|
||||||
|
val dialogFragment = ConfirmDialogFragment.newInstance(
|
||||||
|
ERROR_REQUEST_CODE,
|
||||||
|
R.string.error,
|
||||||
|
message,
|
||||||
|
R.string.ok,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
dialogFragment.show(supportFragmentManager, ConfirmDialogFragment::class.java.simpleName)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val SELECT_DIR_REQUEST_CODE = 0x01
|
||||||
|
private const val ERROR_REQUEST_CODE = 0x02
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import androidx.recyclerview.widget.ListAdapter;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import awais.instagrabber.adapters.viewholder.NotificationViewHolder;
|
import awais.instagrabber.adapters.viewholder.NotificationViewHolder;
|
||||||
@ -24,12 +25,12 @@ public final class NotificationsAdapter extends ListAdapter<Notification, Notifi
|
|||||||
private static final DiffUtil.ItemCallback<Notification> DIFF_CALLBACK = new DiffUtil.ItemCallback<Notification>() {
|
private static final DiffUtil.ItemCallback<Notification> DIFF_CALLBACK = new DiffUtil.ItemCallback<Notification>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean areItemsTheSame(final Notification oldItem, final Notification newItem) {
|
public boolean areItemsTheSame(final Notification oldItem, final Notification newItem) {
|
||||||
return oldItem.getPk().equals(newItem.getPk());
|
return Objects.requireNonNull(oldItem.getPk()).equals(newItem.getPk());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean areContentsTheSame(@NonNull final Notification oldItem, @NonNull final Notification newItem) {
|
public boolean areContentsTheSame(@NonNull final Notification oldItem, @NonNull final Notification newItem) {
|
||||||
return oldItem.getPk().equals(newItem.getPk()) && oldItem.getType() == newItem.getType();
|
return Objects.requireNonNull(oldItem.getPk()).equals(newItem.getPk()) && Objects.equals(oldItem.getType(), newItem.getType());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,8 +73,8 @@ public final class NotificationsAdapter extends ListAdapter<Notification, Notifi
|
|||||||
|
|
||||||
private List<Notification> sort(final List<Notification> list) {
|
private List<Notification> sort(final List<Notification> list) {
|
||||||
final List<Notification> listCopy = new ArrayList<>(list).stream()
|
final List<Notification> listCopy = new ArrayList<>(list).stream()
|
||||||
.filter(i -> i.getType() != null)
|
.filter(i -> i.getType() != null)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
Collections.sort(listCopy, (o1, o2) -> {
|
Collections.sort(listCopy, (o1, o2) -> {
|
||||||
// keep requests at top
|
// keep requests at top
|
||||||
if (o1.getType() == o2.getType()
|
if (o1.getType() == o2.getType()
|
||||||
|
@ -43,7 +43,9 @@ public class DirectItemLinkViewHolder extends DirectItemViewHolder {
|
|||||||
@Override
|
@Override
|
||||||
public void bindItem(final DirectItem item, final MessageDirection messageDirection) {
|
public void bindItem(final DirectItem item, final MessageDirection messageDirection) {
|
||||||
final DirectItemLink link = item.getLink();
|
final DirectItemLink link = item.getLink();
|
||||||
|
if (link == null) return;
|
||||||
final DirectItemLinkContext linkContext = link.getLinkContext();
|
final DirectItemLinkContext linkContext = link.getLinkContext();
|
||||||
|
if (linkContext == null) return;
|
||||||
final String linkImageUrl = linkContext.getLinkImageUrl();
|
final String linkImageUrl = linkContext.getLinkImageUrl();
|
||||||
if (TextUtils.isEmpty(linkImageUrl)) {
|
if (TextUtils.isEmpty(linkImageUrl)) {
|
||||||
binding.preview.setVisibility(View.GONE);
|
binding.preview.setVisibility(View.GONE);
|
||||||
|
@ -1,216 +0,0 @@
|
|||||||
package awais.instagrabber.dialogs;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.Window;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.DialogFragment;
|
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
|
||||||
import awais.instagrabber.databinding.DialogPostLayoutPreferencesBinding;
|
|
||||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
|
||||||
|
|
||||||
public class PostsLayoutPreferencesDialogFragment extends DialogFragment {
|
|
||||||
|
|
||||||
private final OnApplyListener onApplyListener;
|
|
||||||
private final PostsLayoutPreferences.Builder preferencesBuilder;
|
|
||||||
private final String layoutPreferenceKey;
|
|
||||||
private DialogPostLayoutPreferencesBinding binding;
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
public PostsLayoutPreferencesDialogFragment(final String layoutPreferenceKey,
|
|
||||||
@NonNull final OnApplyListener onApplyListener) {
|
|
||||||
this.layoutPreferenceKey = layoutPreferenceKey;
|
|
||||||
final PostsLayoutPreferences preferences = PostsLayoutPreferences.fromJson(settingsHelper.getString(layoutPreferenceKey));
|
|
||||||
this.preferencesBuilder = PostsLayoutPreferences.builder().mergeFrom(preferences);
|
|
||||||
this.onApplyListener = onApplyListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(@NonNull final Context context) {
|
|
||||||
super.onAttach(context);
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
|
|
||||||
binding = DialogPostLayoutPreferencesBinding.inflate(LayoutInflater.from(context), null, false);
|
|
||||||
init();
|
|
||||||
return new MaterialAlertDialogBuilder(context)
|
|
||||||
.setView(binding.getRoot())
|
|
||||||
.setPositiveButton(R.string.apply, (dialog, which) -> {
|
|
||||||
final PostsLayoutPreferences preferences = preferencesBuilder.build();
|
|
||||||
final String json = preferences.getJson();
|
|
||||||
settingsHelper.putString(layoutPreferenceKey, json);
|
|
||||||
onApplyListener.onApply(preferences);
|
|
||||||
})
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
final Dialog dialog = getDialog();
|
|
||||||
if (dialog == null) return;
|
|
||||||
final Window window = dialog.getWindow();
|
|
||||||
if (window == null) return;
|
|
||||||
window.setWindowAnimations(R.style.dialog_window_animation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
initLayoutToggle();
|
|
||||||
if (preferencesBuilder.getType() != PostsLayoutPreferences.PostsLayoutType.LINEAR) {
|
|
||||||
initStaggeredOrGridOptions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initStaggeredOrGridOptions() {
|
|
||||||
initColCountToggle();
|
|
||||||
initNamesToggle();
|
|
||||||
initAvatarsToggle();
|
|
||||||
initCornersToggle();
|
|
||||||
initGapToggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initLayoutToggle() {
|
|
||||||
final int selectedLayoutId = getSelectedLayoutId();
|
|
||||||
binding.layoutToggle.check(selectedLayoutId);
|
|
||||||
if (selectedLayoutId == R.id.layout_linear) {
|
|
||||||
binding.staggeredOrGridOptions.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
binding.layoutToggle.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
|
|
||||||
if (isChecked) {
|
|
||||||
if (checkedId == R.id.layout_linear) {
|
|
||||||
preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.LINEAR);
|
|
||||||
preferencesBuilder.setColCount(1);
|
|
||||||
binding.staggeredOrGridOptions.setVisibility(View.GONE);
|
|
||||||
} else if (checkedId == R.id.layout_staggered) {
|
|
||||||
preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.STAGGERED_GRID);
|
|
||||||
if (preferencesBuilder.getColCount() == 1) {
|
|
||||||
preferencesBuilder.setColCount(2);
|
|
||||||
}
|
|
||||||
binding.staggeredOrGridOptions.setVisibility(View.VISIBLE);
|
|
||||||
initStaggeredOrGridOptions();
|
|
||||||
} else {
|
|
||||||
preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.GRID);
|
|
||||||
if (preferencesBuilder.getColCount() == 1) {
|
|
||||||
preferencesBuilder.setColCount(2);
|
|
||||||
}
|
|
||||||
binding.staggeredOrGridOptions.setVisibility(View.VISIBLE);
|
|
||||||
initStaggeredOrGridOptions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initColCountToggle() {
|
|
||||||
binding.colCountToggle.check(getSelectedColCountId());
|
|
||||||
binding.colCountToggle.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
|
|
||||||
if (!isChecked) return;
|
|
||||||
if (checkedId == R.id.col_count_two) {
|
|
||||||
preferencesBuilder.setColCount(2);
|
|
||||||
} else {
|
|
||||||
preferencesBuilder.setColCount(3);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initAvatarsToggle() {
|
|
||||||
binding.showAvatarToggle.setChecked(preferencesBuilder.isAvatarVisible());
|
|
||||||
binding.avatarSizeToggle.check(getSelectedAvatarSizeId());
|
|
||||||
binding.showAvatarToggle.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
preferencesBuilder.setAvatarVisible(isChecked);
|
|
||||||
binding.labelAvatarSize.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
|
||||||
binding.avatarSizeToggle.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
|
||||||
});
|
|
||||||
binding.labelAvatarSize.setVisibility(preferencesBuilder.isAvatarVisible() ? View.VISIBLE : View.GONE);
|
|
||||||
binding.avatarSizeToggle.setVisibility(preferencesBuilder.isAvatarVisible() ? View.VISIBLE : View.GONE);
|
|
||||||
binding.avatarSizeToggle.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
|
|
||||||
if (!isChecked) return;
|
|
||||||
if (checkedId == R.id.avatar_size_tiny) {
|
|
||||||
preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.TINY);
|
|
||||||
} else if (checkedId == R.id.avatar_size_small) {
|
|
||||||
preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.SMALL);
|
|
||||||
} else {
|
|
||||||
preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.REGULAR);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initNamesToggle() {
|
|
||||||
binding.showNamesToggle.setChecked(preferencesBuilder.isNameVisible());
|
|
||||||
binding.showNamesToggle.setOnCheckedChangeListener((buttonView, isChecked) -> preferencesBuilder.setNameVisible(isChecked));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initCornersToggle() {
|
|
||||||
binding.cornersToggle.check(getSelectedCornersId());
|
|
||||||
binding.cornersToggle.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
|
|
||||||
if (!isChecked) return;
|
|
||||||
if (checkedId == R.id.corners_round) {
|
|
||||||
preferencesBuilder.setHasRoundedCorners(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
preferencesBuilder.setHasRoundedCorners(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGapToggle() {
|
|
||||||
binding.showGapToggle.setChecked(preferencesBuilder.getHasGap());
|
|
||||||
binding.showGapToggle.setOnCheckedChangeListener((buttonView, isChecked) -> preferencesBuilder.setHasGap(isChecked));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSelectedLayoutId() {
|
|
||||||
switch (preferencesBuilder.getType()) {
|
|
||||||
case STAGGERED_GRID:
|
|
||||||
return R.id.layout_staggered;
|
|
||||||
case LINEAR:
|
|
||||||
return R.id.layout_linear;
|
|
||||||
default:
|
|
||||||
case GRID:
|
|
||||||
return R.id.layout_grid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSelectedColCountId() {
|
|
||||||
switch (preferencesBuilder.getColCount()) {
|
|
||||||
case 2:
|
|
||||||
return R.id.col_count_two;
|
|
||||||
case 3:
|
|
||||||
default:
|
|
||||||
return R.id.col_count_three;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSelectedCornersId() {
|
|
||||||
if (preferencesBuilder.getHasRoundedCorners()) {
|
|
||||||
return R.id.corners_round;
|
|
||||||
}
|
|
||||||
return R.id.corners_square;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSelectedAvatarSizeId() {
|
|
||||||
switch (preferencesBuilder.getProfilePicSize()) {
|
|
||||||
case TINY:
|
|
||||||
return R.id.avatar_size_tiny;
|
|
||||||
case SMALL:
|
|
||||||
return R.id.avatar_size_small;
|
|
||||||
case REGULAR:
|
|
||||||
default:
|
|
||||||
return R.id.avatar_size_regular;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnApplyListener {
|
|
||||||
void onApply(final PostsLayoutPreferences preferences);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,180 @@
|
|||||||
|
package awais.instagrabber.dialogs
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.CompoundButton
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import awais.instagrabber.R
|
||||||
|
import awais.instagrabber.databinding.DialogPostLayoutPreferencesBinding
|
||||||
|
import awais.instagrabber.models.PostsLayoutPreferences
|
||||||
|
import awais.instagrabber.models.PostsLayoutPreferences.PostsLayoutType
|
||||||
|
import awais.instagrabber.models.PostsLayoutPreferences.ProfilePicSize
|
||||||
|
import awais.instagrabber.utils.Utils
|
||||||
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
|
||||||
|
class PostsLayoutPreferencesDialogFragment(
|
||||||
|
private val layoutPreferenceKey: String,
|
||||||
|
private val onApplyListener: OnApplyListener
|
||||||
|
) : DialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: DialogPostLayoutPreferencesBinding
|
||||||
|
|
||||||
|
private val preferencesBuilder: PostsLayoutPreferences.Builder
|
||||||
|
|
||||||
|
init {
|
||||||
|
val preferences = PostsLayoutPreferences.fromJson(Utils.settingsHelper.getString(layoutPreferenceKey))
|
||||||
|
preferencesBuilder = PostsLayoutPreferences.builder().mergeFrom(preferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
binding = DialogPostLayoutPreferencesBinding.inflate(layoutInflater)
|
||||||
|
init()
|
||||||
|
return MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setView(binding.getRoot())
|
||||||
|
.setPositiveButton(R.string.apply) { _: DialogInterface?, _: Int ->
|
||||||
|
val preferences = preferencesBuilder.build()
|
||||||
|
val json = preferences.json
|
||||||
|
Utils.settingsHelper.putString(layoutPreferenceKey, json)
|
||||||
|
onApplyListener.onApply(preferences)
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
initLayoutToggle()
|
||||||
|
if (preferencesBuilder.type != PostsLayoutType.LINEAR) {
|
||||||
|
initStaggeredOrGridOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initStaggeredOrGridOptions() {
|
||||||
|
initColCountToggle()
|
||||||
|
initNamesToggle()
|
||||||
|
initAvatarsToggle()
|
||||||
|
initCornersToggle()
|
||||||
|
initGapToggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initLayoutToggle() {
|
||||||
|
val selectedLayoutId = selectedLayoutId
|
||||||
|
binding.layoutToggle.check(selectedLayoutId)
|
||||||
|
if (selectedLayoutId == R.id.layout_linear) {
|
||||||
|
binding.staggeredOrGridOptions.visibility = View.GONE
|
||||||
|
}
|
||||||
|
binding.layoutToggle.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean ->
|
||||||
|
if (!isChecked) return@addOnButtonCheckedListener
|
||||||
|
when (checkedId) {
|
||||||
|
R.id.layout_linear -> {
|
||||||
|
preferencesBuilder.type = PostsLayoutType.LINEAR
|
||||||
|
preferencesBuilder.colCount = 1
|
||||||
|
binding.staggeredOrGridOptions.visibility = View.GONE
|
||||||
|
}
|
||||||
|
R.id.layout_staggered -> {
|
||||||
|
preferencesBuilder.type = PostsLayoutType.STAGGERED_GRID
|
||||||
|
if (preferencesBuilder.colCount == 1) {
|
||||||
|
preferencesBuilder.colCount = 2
|
||||||
|
}
|
||||||
|
binding.staggeredOrGridOptions.visibility = View.VISIBLE
|
||||||
|
initStaggeredOrGridOptions()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
preferencesBuilder.type = PostsLayoutType.GRID
|
||||||
|
if (preferencesBuilder.colCount == 1) {
|
||||||
|
preferencesBuilder.colCount = 2
|
||||||
|
}
|
||||||
|
binding.staggeredOrGridOptions.visibility = View.VISIBLE
|
||||||
|
initStaggeredOrGridOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initColCountToggle() {
|
||||||
|
binding.colCountToggle.check(selectedColCountId)
|
||||||
|
binding.colCountToggle.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean ->
|
||||||
|
if (!isChecked) return@addOnButtonCheckedListener
|
||||||
|
preferencesBuilder.colCount = (if (checkedId == R.id.col_count_two) 2 else 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initAvatarsToggle() {
|
||||||
|
binding.showAvatarToggle.isChecked = preferencesBuilder.isAvatarVisible
|
||||||
|
binding.avatarSizeToggle.check(selectedAvatarSizeId)
|
||||||
|
binding.showAvatarToggle.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||||
|
preferencesBuilder.isAvatarVisible = isChecked
|
||||||
|
binding.labelAvatarSize.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||||
|
binding.avatarSizeToggle.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
binding.labelAvatarSize.visibility = if (preferencesBuilder.isAvatarVisible) View.VISIBLE else View.GONE
|
||||||
|
binding.avatarSizeToggle.visibility = if (preferencesBuilder.isAvatarVisible) View.VISIBLE else View.GONE
|
||||||
|
binding.avatarSizeToggle.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean ->
|
||||||
|
if (!isChecked) return@addOnButtonCheckedListener
|
||||||
|
preferencesBuilder.profilePicSize = when (checkedId) {
|
||||||
|
R.id.avatar_size_tiny -> ProfilePicSize.TINY
|
||||||
|
R.id.avatar_size_small -> ProfilePicSize.SMALL
|
||||||
|
else -> ProfilePicSize.REGULAR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initNamesToggle() {
|
||||||
|
binding.showNamesToggle.isChecked = preferencesBuilder.isNameVisible
|
||||||
|
binding.showNamesToggle.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||||
|
preferencesBuilder.isNameVisible = isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initCornersToggle() {
|
||||||
|
binding.cornersToggle.check(selectedCornersId)
|
||||||
|
binding.cornersToggle.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean ->
|
||||||
|
if (!isChecked) return@addOnButtonCheckedListener
|
||||||
|
if (checkedId == R.id.corners_round) {
|
||||||
|
preferencesBuilder.hasRoundedCorners = true
|
||||||
|
return@addOnButtonCheckedListener
|
||||||
|
}
|
||||||
|
preferencesBuilder.hasRoundedCorners = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initGapToggle() {
|
||||||
|
binding.showGapToggle.isChecked = preferencesBuilder.hasGap
|
||||||
|
binding.showGapToggle.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||||
|
preferencesBuilder.hasGap = isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val selectedLayoutId: Int
|
||||||
|
get() = when (preferencesBuilder.type) {
|
||||||
|
PostsLayoutType.STAGGERED_GRID -> R.id.layout_staggered
|
||||||
|
PostsLayoutType.LINEAR -> R.id.layout_linear
|
||||||
|
PostsLayoutType.GRID -> R.id.layout_grid
|
||||||
|
else -> R.id.layout_grid
|
||||||
|
}
|
||||||
|
|
||||||
|
private val selectedColCountId: Int
|
||||||
|
get() = when (preferencesBuilder.colCount) {
|
||||||
|
2 -> R.id.col_count_two
|
||||||
|
3 -> R.id.col_count_three
|
||||||
|
else -> R.id.col_count_three
|
||||||
|
}
|
||||||
|
|
||||||
|
private val selectedCornersId: Int
|
||||||
|
get() = if (preferencesBuilder.hasRoundedCorners) {
|
||||||
|
R.id.corners_round
|
||||||
|
} else R.id.corners_square
|
||||||
|
|
||||||
|
private val selectedAvatarSizeId: Int
|
||||||
|
get() = when (preferencesBuilder.profilePicSize) {
|
||||||
|
ProfilePicSize.TINY -> R.id.avatar_size_tiny
|
||||||
|
ProfilePicSize.SMALL -> R.id.avatar_size_small
|
||||||
|
ProfilePicSize.REGULAR -> R.id.avatar_size_regular
|
||||||
|
else -> R.id.avatar_size_regular
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface OnApplyListener {
|
||||||
|
fun onApply(preferences: PostsLayoutPreferences)
|
||||||
|
}
|
||||||
|
}
|
@ -34,13 +34,10 @@ import awais.instagrabber.customviews.RamboTextViewV2
|
|||||||
import awais.instagrabber.customviews.RamboTextViewV2.*
|
import awais.instagrabber.customviews.RamboTextViewV2.*
|
||||||
import awais.instagrabber.databinding.FragmentProfileBinding
|
import awais.instagrabber.databinding.FragmentProfileBinding
|
||||||
import awais.instagrabber.db.repositories.FavoriteRepository
|
import awais.instagrabber.db.repositories.FavoriteRepository
|
||||||
import awais.instagrabber.dialogs.ConfirmDialogFragment
|
import awais.instagrabber.dialogs.*
|
||||||
import awais.instagrabber.dialogs.ConfirmDialogFragment.ConfirmDialogFragmentCallback
|
import awais.instagrabber.dialogs.ConfirmDialogFragment.ConfirmDialogFragmentCallback
|
||||||
import awais.instagrabber.dialogs.MultiOptionDialogFragment
|
|
||||||
import awais.instagrabber.dialogs.MultiOptionDialogFragment.MultiOptionDialogSingleCallback
|
import awais.instagrabber.dialogs.MultiOptionDialogFragment.MultiOptionDialogSingleCallback
|
||||||
import awais.instagrabber.dialogs.MultiOptionDialogFragment.Option
|
import awais.instagrabber.dialogs.MultiOptionDialogFragment.Option
|
||||||
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment
|
|
||||||
import awais.instagrabber.dialogs.ProfilePicDialogFragment
|
|
||||||
import awais.instagrabber.fragments.UserSearchMode
|
import awais.instagrabber.fragments.UserSearchMode
|
||||||
import awais.instagrabber.managers.DirectMessagesManager
|
import awais.instagrabber.managers.DirectMessagesManager
|
||||||
import awais.instagrabber.models.Resource
|
import awais.instagrabber.models.Resource
|
||||||
@ -1002,10 +999,10 @@ class ProfileFragment : Fragment(), OnRefreshListener, ConfirmDialogFragmentCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showPostsLayoutPreferences() {
|
private fun showPostsLayoutPreferences() {
|
||||||
val fragment = PostsLayoutPreferencesDialogFragment(Constants.PREF_PROFILE_POSTS_LAYOUT) { preferences ->
|
val fragment = PostsLayoutPreferencesDialogFragment(Constants.PREF_PROFILE_POSTS_LAYOUT) {
|
||||||
layoutPreferences = preferences
|
layoutPreferences = it
|
||||||
Handler(Looper.getMainLooper()).postDelayed(
|
Handler(Looper.getMainLooper()).postDelayed(
|
||||||
{ binding.postsRecyclerView.layoutPreferences = preferences },
|
{ binding.postsRecyclerView.layoutPreferences = it },
|
||||||
200
|
200
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import awais.instagrabber.models.enums.NotificationType.Companion.valueOfType
|
|||||||
|
|
||||||
class Notification(val args: NotificationArgs,
|
class Notification(val args: NotificationArgs,
|
||||||
private val storyType: Int,
|
private val storyType: Int,
|
||||||
val pk: String) {
|
val pk: String?) {
|
||||||
val type: NotificationType?
|
val type: NotificationType?
|
||||||
get() = valueOfType(storyType)
|
get() = valueOfType(storyType)
|
||||||
}
|
}
|
@ -195,10 +195,15 @@ public final class Utils {
|
|||||||
if (context == null || TextUtils.isEmpty(url)) {
|
if (context == null || TextUtils.isEmpty(url)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
|
||||||
i.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
|
||||||
i.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
|
|
||||||
try {
|
try {
|
||||||
|
String url1 = url;
|
||||||
|
// add http:// if string doesn't have http:// or https://
|
||||||
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||||
|
url1 = "http://" + url;
|
||||||
|
}
|
||||||
|
final Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url1));
|
||||||
|
i.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
||||||
|
i.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
|
||||||
context.startActivity(i);
|
context.startActivity(i);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
Log.e(TAG, "openURL: No activity found to handle URLs", e);
|
Log.e(TAG, "openURL: No activity found to handle URLs", e);
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
package awais.instagrabber.viewmodels;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.UriPermission;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
|
||||||
import awais.instagrabber.utils.Constants;
|
|
||||||
import awais.instagrabber.utils.DownloadUtils;
|
|
||||||
import awais.instagrabber.utils.TextUtils;
|
|
||||||
import awais.instagrabber.utils.Utils;
|
|
||||||
|
|
||||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.FOLDER_PATH;
|
|
||||||
|
|
||||||
public class DirectorySelectActivityViewModel extends AndroidViewModel {
|
|
||||||
private static final String TAG = DirectorySelectActivityViewModel.class.getSimpleName();
|
|
||||||
|
|
||||||
private final MutableLiveData<String> message = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<String> prevUri = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<Boolean> loading = new MutableLiveData<>(false);
|
|
||||||
private final MutableLiveData<Boolean> dirSuccess = new MutableLiveData<>(false);
|
|
||||||
|
|
||||||
public DirectorySelectActivityViewModel(final Application application) {
|
|
||||||
super(application);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getPrevUri() {
|
|
||||||
return prevUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Boolean> isLoading() {
|
|
||||||
return loading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Boolean> getDirSuccess() {
|
|
||||||
return dirSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitialUri(final Intent intent) {
|
|
||||||
if (intent == null) {
|
|
||||||
setMessage(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Parcelable initialUriParcelable = intent.getParcelableExtra(Constants.EXTRA_INITIAL_URI);
|
|
||||||
if (!(initialUriParcelable instanceof Uri)) {
|
|
||||||
setMessage(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setMessage((Uri) initialUriParcelable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setMessage(@Nullable final Uri initialUri) {
|
|
||||||
if (initialUri == null) {
|
|
||||||
final String prevVersionFolderPath = Utils.settingsHelper.getString(FOLDER_PATH);
|
|
||||||
if (TextUtils.isEmpty(prevVersionFolderPath)) {
|
|
||||||
// default message
|
|
||||||
message.postValue(getApplication().getString(R.string.dir_select_default_message));
|
|
||||||
prevUri.postValue(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
message.postValue(getApplication().getString(R.string.dir_select_reselect_message));
|
|
||||||
prevUri.postValue(prevVersionFolderPath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final List<UriPermission> existingPermissions = getApplication().getContentResolver().getPersistedUriPermissions();
|
|
||||||
final boolean anyMatch = existingPermissions.stream().anyMatch(uriPermission -> uriPermission.getUri().equals(initialUri));
|
|
||||||
final DocumentFile documentFile = DocumentFile.fromSingleUri(getApplication(), initialUri);
|
|
||||||
String path;
|
|
||||||
try {
|
|
||||||
path = URLDecoder.decode(initialUri.toString(), StandardCharsets.UTF_8.toString());
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
path = initialUri.toString();
|
|
||||||
}
|
|
||||||
if (!anyMatch) {
|
|
||||||
message.postValue(getApplication().getString(R.string.dir_select_permission_revoked_message));
|
|
||||||
prevUri.postValue(path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (documentFile == null || !documentFile.exists() || documentFile.lastModified() == 0) {
|
|
||||||
message.postValue(getApplication().getString(R.string.dir_select_folder_not_exist));
|
|
||||||
prevUri.postValue(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setupSelectedDir(@NonNull final Intent data) throws DownloadUtils.ReselectDocumentTreeException {
|
|
||||||
loading.postValue(true);
|
|
||||||
try {
|
|
||||||
Utils.setupSelectedDir(getApplication(), data);
|
|
||||||
message.postValue(getApplication().getString(R.string.dir_select_success_message));
|
|
||||||
dirSuccess.postValue(true);
|
|
||||||
} finally {
|
|
||||||
loading.postValue(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,89 @@
|
|||||||
|
package awais.instagrabber.viewmodels
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.UriPermission
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import awais.instagrabber.R
|
||||||
|
import awais.instagrabber.fragments.settings.PreferenceKeys
|
||||||
|
import awais.instagrabber.utils.Constants
|
||||||
|
import awais.instagrabber.utils.DownloadUtils.ReselectDocumentTreeException
|
||||||
|
import awais.instagrabber.utils.TextUtils.isEmpty
|
||||||
|
import awais.instagrabber.utils.Utils
|
||||||
|
import java.io.UnsupportedEncodingException
|
||||||
|
import java.net.URLDecoder
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
|
class DirectorySelectActivityViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
private val _message = MutableLiveData<String>()
|
||||||
|
private val _prevUri = MutableLiveData<String?>()
|
||||||
|
private val _loading = MutableLiveData(false)
|
||||||
|
private val _dirSuccess = MutableLiveData(false)
|
||||||
|
|
||||||
|
val message: LiveData<String> = _message
|
||||||
|
val prevUri: LiveData<String?> = _prevUri
|
||||||
|
val loading: LiveData<Boolean> = _loading
|
||||||
|
val dirSuccess: LiveData<Boolean> = _dirSuccess
|
||||||
|
|
||||||
|
fun setInitialUri(intent: Intent?) {
|
||||||
|
if (intent == null) {
|
||||||
|
setMessage(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val initialUriParcelable = intent.getParcelableExtra<Parcelable>(Constants.EXTRA_INITIAL_URI)
|
||||||
|
if (initialUriParcelable !is Uri) {
|
||||||
|
setMessage(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setMessage(initialUriParcelable as Uri?)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setMessage(initialUri: Uri?) {
|
||||||
|
if (initialUri == null) {
|
||||||
|
val prevVersionFolderPath = Utils.settingsHelper.getString(PreferenceKeys.FOLDER_PATH)
|
||||||
|
if (isEmpty(prevVersionFolderPath)) {
|
||||||
|
// default message
|
||||||
|
_message.postValue(getApplication<Application>().getString(R.string.dir_select_default_message))
|
||||||
|
_prevUri.postValue(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_message.postValue(getApplication<Application>().getString(R.string.dir_select_reselect_message))
|
||||||
|
_prevUri.postValue(prevVersionFolderPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val existingPermissions = getApplication<Application>().contentResolver.persistedUriPermissions
|
||||||
|
val anyMatch = existingPermissions.stream().anyMatch { uriPermission: UriPermission -> uriPermission.uri == initialUri }
|
||||||
|
val documentFile = DocumentFile.fromSingleUri(getApplication(), initialUri)
|
||||||
|
val path: String = try {
|
||||||
|
URLDecoder.decode(initialUri.toString(), StandardCharsets.UTF_8.toString())
|
||||||
|
} catch (e: UnsupportedEncodingException) {
|
||||||
|
initialUri.toString()
|
||||||
|
}
|
||||||
|
if (!anyMatch) {
|
||||||
|
_message.postValue(getApplication<Application>().getString(R.string.dir_select_permission_revoked_message))
|
||||||
|
_prevUri.postValue(path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (documentFile == null || !documentFile.exists() || documentFile.lastModified() == 0L) {
|
||||||
|
_message.postValue(getApplication<Application>().getString(R.string.dir_select_folder_not_exist))
|
||||||
|
_prevUri.postValue(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ReselectDocumentTreeException::class)
|
||||||
|
fun setupSelectedDir(data: Intent) {
|
||||||
|
_loading.postValue(true)
|
||||||
|
try {
|
||||||
|
Utils.setupSelectedDir(getApplication(), data)
|
||||||
|
_message.postValue(getApplication<Application>().getString(R.string.dir_select_success_message))
|
||||||
|
_dirSuccess.postValue(true)
|
||||||
|
} finally {
|
||||||
|
_loading.postValue(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -542,4 +542,13 @@
|
|||||||
android:id="@+id/action_to_profile"
|
android:id="@+id/action_to_profile"
|
||||||
app:destination="@id/profile_non_top" />
|
app:destination="@id/profile_non_top" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/aboutFragment"
|
||||||
|
android:name="awais.instagrabber.fragments.settings.AboutFragment"
|
||||||
|
android:label="@string/action_about" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/backupPreferencesFragment"
|
||||||
|
android:name="awais.instagrabber.fragments.settings.BackupPreferencesFragment"
|
||||||
|
android:label="@string/backup_and_restore" />
|
||||||
</navigation>
|
</navigation>
|
@ -33,18 +33,10 @@
|
|||||||
android:id="@+id/action_settings_to_post"
|
android:id="@+id/action_settings_to_post"
|
||||||
app:destination="@id/postPreferencesFragment" />
|
app:destination="@id/postPreferencesFragment" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
|
||||||
android:id="@+id/aboutFragment"
|
|
||||||
android:name="awais.instagrabber.fragments.settings.AboutFragment"
|
|
||||||
android:label="@string/action_about" />
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/themePreferencesFragment"
|
android:id="@+id/themePreferencesFragment"
|
||||||
android:name="awais.instagrabber.fragments.settings.ThemePreferencesFragment"
|
android:name="awais.instagrabber.fragments.settings.ThemePreferencesFragment"
|
||||||
android:label="@string/theme_settings" />
|
android:label="@string/theme_settings" />
|
||||||
<fragment
|
|
||||||
android:id="@+id/backupPreferencesFragment"
|
|
||||||
android:name="awais.instagrabber.fragments.settings.BackupPreferencesFragment"
|
|
||||||
android:label="@string/backup_and_restore" />
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/localePreferencesFragment"
|
android:id="@+id/localePreferencesFragment"
|
||||||
android:name="awais.instagrabber.fragments.settings.LocalePreferencesFragment"
|
android:name="awais.instagrabber.fragments.settings.LocalePreferencesFragment"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext{
|
ext{
|
||||||
kotlin_version = '1.5.20'
|
kotlin_version = '1.5.21'
|
||||||
nav_version = "2.4.0-alpha04"
|
nav_version = "2.4.0-alpha04"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user