Browse Source
Merge remote-tracking branch 'origin/master'
renovate/androidx.fragment-fragment-ktx-1.x
Merge remote-tracking branch 'origin/master'
renovate/androidx.fragment-fragment-ktx-1.x
Austin Huang
4 years ago
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
14 changed files with 431 additions and 482 deletions
-
129app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java
-
132app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.kt
-
9app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java
-
2app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemLinkViewHolder.java
-
216app/src/main/java/awais/instagrabber/dialogs/PostsLayoutPreferencesDialogFragment.java
-
180app/src/main/java/awais/instagrabber/dialogs/PostsLayoutPreferencesDialogFragment.kt
-
11app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.kt
-
2app/src/main/java/awais/instagrabber/repositories/responses/notification/Notification.kt
-
11app/src/main/java/awais/instagrabber/utils/Utils.java
-
113app/src/main/java/awais/instagrabber/viewmodels/DirectorySelectActivityViewModel.java
-
89app/src/main/java/awais/instagrabber/viewmodels/DirectorySelectActivityViewModel.kt
-
9app/src/main/res/navigation/more_nav_graph.xml
-
8app/src/main/res/navigation/settings_nav_graph.xml
-
2build.gradle
@ -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 |
|||
} |
|||
} |
@ -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) |
|||
} |
|||
} |
@ -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) |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue