diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java index 38d971a5..64a552cf 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java @@ -11,6 +11,8 @@ import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvicto import com.google.android.exoplayer2.upstream.cache.SimpleCache; import java.io.File; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.inject.Named; @@ -245,4 +247,10 @@ class AppModule { .build(); return ToroExo.with(mApplication).getCreator(config); } + + @Provides + @Singleton + Executor provideExecutor() { + return Executors.newFixedThreadPool(4); + } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java index 63260d1a..3ee75984 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java @@ -1,5 +1,7 @@ package ml.docilealligator.infinityforreddit; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; + public interface FragmentCommunicator { default void refresh() { } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java index aaa1450d..f90c814c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java @@ -16,6 +16,10 @@ import ml.docilealligator.infinityforreddit.customtheme.CustomTheme; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeDao; import ml.docilealligator.infinityforreddit.multireddit.MultiReddit; import ml.docilealligator.infinityforreddit.multireddit.MultiRedditDao; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.PostFilterDao; +import ml.docilealligator.infinityforreddit.postfilter.PostFilterUsage; +import ml.docilealligator.infinityforreddit.postfilter.PostFilterUsageDao; import ml.docilealligator.infinityforreddit.readpost.ReadPost; import ml.docilealligator.infinityforreddit.readpost.ReadPostDao; import ml.docilealligator.infinityforreddit.recentsearchquery.RecentSearchQuery; @@ -33,7 +37,7 @@ import ml.docilealligator.infinityforreddit.user.UserData; @Database(entities = {Account.class, SubredditData.class, SubscribedSubredditData.class, UserData.class, SubscribedUserData.class, MultiReddit.class, CustomTheme.class, RecentSearchQuery.class, - SubredditFilter.class, ReadPost.class}, version = 14) + SubredditFilter.class, ReadPost.class, PostFilter.class, PostFilterUsage.class}, version = 15) public abstract class RedditDataRoomDatabase extends RoomDatabase { private static RedditDataRoomDatabase INSTANCE; @@ -46,7 +50,7 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase { .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9, MIGRATION_9_10, MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13, - MIGRATION_13_14) + MIGRATION_13_14, MIGRATION_14_15) .build(); } } @@ -74,6 +78,10 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase { public abstract ReadPostDao readPostDao(); + public abstract PostFilterDao postFilterDao(); + + public abstract PostFilterUsageDao postFilterUsageDao(); + private static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(SupportSQLiteDatabase database) { @@ -281,4 +289,21 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase { database.execSQL("ALTER TABLE custom_themes ADD COLUMN read_post_card_view_background_color INTEGER DEFAULT " + Color.parseColor("#F5F5F5") + " NOT NULL"); } }; + + private static final Migration MIGRATION_14_15 = new Migration(14, 15) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + database.execSQL("CREATE TABLE post_filter" + + "(name TEXT NOT NULL PRIMARY KEY, max_vote INTEGER NOT NULL, min_vote INTEGER NOT NULL, " + + "max_comments INTEGER NOT NULL, min_comments INTEGER NOT NULL, max_awards INTEGER NOT NULL, " + + "min_awards INTEGER NOT NULL, only_nsfw INTEGER NOT NULL, only_spoiler INTEGER NOT NULL, " + + "post_title_excludes_regex TEXT, post_title_excludes_strings TEXT, exclude_subreddits TEXT, " + + "exclude_users TEXT, contain_flairs TEXT, exclude_flairs TEXT, contain_text_type INTEGER NOT NULL, " + + "contain_link_type INTEGER NOT NULL, contain_image_type INTEGER NOT NULL, " + + "contain_gif_type INTEGER NOT NULL, contain_video_type INTEGER NOT NULL, " + + "contain_gallery_type INTEGER NOT NULL)"); + database.execSQL("CREATE TABLE post_filter_usage (name TEXT NOT NULL, usage INTEGER NOT NULL, " + + "name_of_usage TEXT NOT NULL, PRIMARY KEY(name, usage, name_of_usage), FOREIGN KEY(name) REFERENCES post_filter(name) ON DELETE CASCADE)"); + } + }; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomThemeListingActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomThemeListingActivity.java index 03f6ae9e..edc3a2ac 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomThemeListingActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomThemeListingActivity.java @@ -154,8 +154,8 @@ public class CustomThemeListingActivity extends BaseActivity implements @Override public void changeName(String oldThemeName) { - View dialogView = getLayoutInflater().inflate(R.layout.dialog_edit_theme_name, null); - EditText themeNameEditText = dialogView.findViewById(R.id.theme_name_edit_text_edit_theme_name_dialog); + View dialogView = getLayoutInflater().inflate(R.layout.dialog_edit_name, null); + EditText themeNameEditText = dialogView.findViewById(R.id.theme_name_edit_text_edit_name_dialog); themeNameEditText.setText(oldThemeName); themeNameEditText.requestFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); @@ -293,8 +293,8 @@ public class CustomThemeListingActivity extends BaseActivity implements .setMessage(getString(R.string.duplicate_theme_name_dialog_message, customTheme.name)) .setPositiveButton(R.string.rename, (dialogInterface, i) -> { - View dialogView = getLayoutInflater().inflate(R.layout.dialog_edit_theme_name, null); - EditText themeNameEditText = dialogView.findViewById(R.id.theme_name_edit_text_edit_theme_name_dialog); + View dialogView = getLayoutInflater().inflate(R.layout.dialog_edit_name, null); + EditText themeNameEditText = dialogView.findViewById(R.id.theme_name_edit_text_edit_name_dialog); themeNameEditText.setText(customTheme.name); themeNameEditText.requestFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomizePostFilterActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomizePostFilterActivity.java index 61f7c57d..5a3d6185 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomizePostFilterActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CustomizePostFilterActivity.java @@ -1,15 +1,21 @@ package ml.docilealligator.infinityforreddit.activities; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.view.Menu; import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.widget.Toolbar; @@ -18,21 +24,25 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.checkbox.MaterialCheckBox; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.switchmaterial.SwitchMaterial; import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; import com.r0adkll.slidr.Slidr; +import java.util.concurrent.Executor; + import javax.inject.Inject; import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; import ml.docilealligator.infinityforreddit.Infinity; -import ml.docilealligator.infinityforreddit.PostFilter; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.SavePostFilter; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; public class CustomizePostFilterActivity extends BaseActivity { @@ -152,6 +162,8 @@ public class CustomizePostFilterActivity extends BaseActivity { SharedPreferences mSharedPreferences; @Inject CustomThemeWrapper mCustomThemeWrapper; + @Inject + Executor mExecutor; private PostFilter postFilter; @Override @@ -223,18 +235,18 @@ public class CustomizePostFilterActivity extends BaseActivity { } private void bindView() { - postTypeTextCheckBox.setChecked(postFilter.containsTextType); - postTypeLinkCheckBox.setChecked(postFilter.containsLinkType); - postTypeImageCheckBox.setChecked(postFilter.containsImageType); - postTypeGifCheckBox.setChecked(postFilter.containsGifType); - postTypeVideoCheckBox.setChecked(postFilter.containsVideoType); - postTypeGalleryCheckBox.setChecked(postFilter.containsGalleryType); + postTypeTextCheckBox.setChecked(postFilter.containTextType); + postTypeLinkCheckBox.setChecked(postFilter.containLinkType); + postTypeImageCheckBox.setChecked(postFilter.containImageType); + postTypeGifCheckBox.setChecked(postFilter.containGifType); + postTypeVideoCheckBox.setChecked(postFilter.containVideoType); + postTypeGalleryCheckBox.setChecked(postFilter.containGalleryType); titleExcludesStringsTextInputEditText.setText(postFilter.postTitleExcludesStrings); titleExcludesRegexTextInputEditText.setText(postFilter.postTitleExcludesRegex); - excludesSubredditsTextInputEditText.setText(postFilter.excludesSubreddits); - excludesUsersTextInputEditText.setText(postFilter.excludesUsers); - excludesFlairsTextInputEditText.setText(postFilter.excludesFlairs); - containsFlairsTextInputEditText.setText(postFilter.containsFlairs); + excludesSubredditsTextInputEditText.setText(postFilter.excludeSubreddits); + excludesUsersTextInputEditText.setText(postFilter.excludeUsers); + excludesFlairsTextInputEditText.setText(postFilter.excludeFlairs); + containsFlairsTextInputEditText.setText(postFilter.containFlairs); minVoteTextInputEditText.setText(Integer.toString(postFilter.minVote)); maxVoteTextInputEditText.setText(Integer.toString(postFilter.maxVote)); minCommentsTextInputEditText.setText(Integer.toString(postFilter.minComments)); @@ -317,38 +329,95 @@ public class CustomizePostFilterActivity extends BaseActivity { finish(); return true; } else if (item.getItemId() == R.id.action_save_customize_post_filter_activity) { - PostFilter postFilter = new PostFilter(); - postFilter.maxVote = maxVoteTextInputEditText.getText() == null || maxVoteTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(maxVoteTextInputEditText.getText().toString()); - postFilter.minVote = minVoteTextInputEditText.getText() == null || minVoteTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(minVoteTextInputEditText.getText().toString()); - postFilter.maxComments = maxCommentsTextInputEditText.getText() == null || maxCommentsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(maxCommentsTextInputEditText.getText().toString()); - postFilter.minComments = minCommentsTextInputEditText.getText() == null || minCommentsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(minCommentsTextInputEditText.getText().toString()); - postFilter.maxAwards = maxAwardsTextInputEditText.getText() == null || maxAwardsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(maxAwardsTextInputEditText.getText().toString()); - postFilter.minAwards = minAwardsTextInputEditText.getText() == null || minAwardsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(minAwardsTextInputEditText.getText().toString()); - postFilter.postTitleExcludesRegex = titleExcludesRegexTextInputEditText.getText().toString(); - postFilter.postTitleExcludesStrings = titleExcludesStringsTextInputEditText.getText().toString(); - postFilter.excludesSubreddits = excludesSubredditsTextInputEditText.getText().toString(); - postFilter.excludesUsers = excludesUsersTextInputEditText.getText().toString(); - postFilter.excludesFlairs = excludesUsersTextInputEditText.getText().toString(); - postFilter.containsFlairs = containsFlairsTextInputEditText.getText().toString(); - postFilter.containsTextType = postTypeTextCheckBox.isChecked(); - postFilter.containsLinkType = postTypeLinkCheckBox.isChecked(); - postFilter.containsImageType = postTypeImageCheckBox.isChecked(); - postFilter.containsGifType = postTypeGifCheckBox.isChecked(); - postFilter.containsVideoType = postTypeVideoCheckBox.isChecked(); - postFilter.containsGalleryType = postTypeGalleryCheckBox.isChecked(); - postFilter.onlyNSFW = onlyNSFWSwitch.isChecked(); - postFilter.onlySpoiler = onlySpoilerSwitch.isChecked(); - + PostFilter postFilter = constructPostFilter(); Intent returnIntent = new Intent(); returnIntent.putExtra(RETURN_EXTRA_POST_FILTER, postFilter); setResult(Activity.RESULT_OK, returnIntent); finish(); return true; + } else if (item.getItemId() == R.id.action_save_to_database_customize_post_filter_activity) { + PostFilter postFilter = constructPostFilter(); + + View dialogView = getLayoutInflater().inflate(R.layout.dialog_edit_name, null); + EditText nameEditText = dialogView.findViewById(R.id.theme_name_edit_text_edit_name_dialog); + nameEditText.setHint(R.string.post_filter_name_hint); + nameEditText.setText(postFilter.name); + nameEditText.requestFocus(); + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.edit_theme_name) + .setView(dialogView) + .setPositiveButton(R.string.ok, (dialogInterface, i) + -> { + if (imm != null) { + imm.hideSoftInputFromWindow(nameEditText.getWindowToken(), 0); + } + if (!nameEditText.getText().toString().equals("")) { + postFilter.name = nameEditText.getText().toString(); + Handler handler = new Handler(); + SavePostFilter.savePostFilter(mRedditDataRoomDatabase, mExecutor, postFilter, new SavePostFilter.SavePostFilterListener() { + @Override + public void success() { + handler.post(() -> { + Intent returnIntent = new Intent(); + returnIntent.putExtra(RETURN_EXTRA_POST_FILTER, postFilter); + setResult(Activity.RESULT_OK, returnIntent); + finish(); + }); + } + + @Override + public void failed(int errorCode) { + handler.post(() -> Toast.makeText(CustomizePostFilterActivity.this, R.string.duplicate_post_filter, Toast.LENGTH_LONG).show()); + } + }); + } + }) + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + if (imm != null) { + imm.hideSoftInputFromWindow(nameEditText.getWindowToken(), 0); + } + }) + .setOnDismissListener(dialogInterface -> { + if (imm != null) { + imm.hideSoftInputFromWindow(nameEditText.getWindowToken(), 0); + } + }) + .show(); } return false; } + private PostFilter constructPostFilter() { + PostFilter postFilter = new PostFilter(); + postFilter.maxVote = maxVoteTextInputEditText.getText() == null || maxVoteTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(maxVoteTextInputEditText.getText().toString()); + postFilter.minVote = minVoteTextInputEditText.getText() == null || minVoteTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(minVoteTextInputEditText.getText().toString()); + postFilter.maxComments = maxCommentsTextInputEditText.getText() == null || maxCommentsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(maxCommentsTextInputEditText.getText().toString()); + postFilter.minComments = minCommentsTextInputEditText.getText() == null || minCommentsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(minCommentsTextInputEditText.getText().toString()); + postFilter.maxAwards = maxAwardsTextInputEditText.getText() == null || maxAwardsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(maxAwardsTextInputEditText.getText().toString()); + postFilter.minAwards = minAwardsTextInputEditText.getText() == null || minAwardsTextInputEditText.getText().toString().equals("") ? -1 : Integer.parseInt(minAwardsTextInputEditText.getText().toString()); + postFilter.postTitleExcludesRegex = titleExcludesRegexTextInputEditText.getText().toString(); + postFilter.postTitleExcludesStrings = titleExcludesStringsTextInputEditText.getText().toString(); + postFilter.excludeSubreddits = excludesSubredditsTextInputEditText.getText().toString(); + postFilter.excludeUsers = excludesUsersTextInputEditText.getText().toString(); + postFilter.excludeFlairs = excludesUsersTextInputEditText.getText().toString(); + postFilter.containFlairs = containsFlairsTextInputEditText.getText().toString(); + postFilter.containTextType = postTypeTextCheckBox.isChecked(); + postFilter.containLinkType = postTypeLinkCheckBox.isChecked(); + postFilter.containImageType = postTypeImageCheckBox.isChecked(); + postFilter.containGifType = postTypeGifCheckBox.isChecked(); + postFilter.containVideoType = postTypeVideoCheckBox.isChecked(); + postFilter.containGalleryType = postTypeGalleryCheckBox.isChecked(); + postFilter.onlyNSFW = onlyNSFWSwitch.isChecked(); + postFilter.onlySpoiler = onlySpoilerSwitch.isChecked(); + + return postFilter; + } + @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FilteredPostsActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FilteredPostsActivity.java index e0ae0de2..a9040052 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FilteredPostsActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FilteredPostsActivity.java @@ -33,7 +33,7 @@ import ml.docilealligator.infinityforreddit.ActivityToolbarInterface; import ml.docilealligator.infinityforreddit.FragmentCommunicator; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.MarkPostAsReadInterface; -import ml.docilealligator.infinityforreddit.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; import ml.docilealligator.infinityforreddit.PostFragmentContentScrollingInterface; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; @@ -170,52 +170,52 @@ public class FilteredPostsActivity extends BaseActivity implements SortTypeSelec postFilter.onlyNSFW = true; break; case Post.TEXT_TYPE: - postFilter.containsTextType = true; - postFilter.containsLinkType = false; - postFilter.containsImageType = false; - postFilter.containsGifType = false; - postFilter.containsVideoType = false; - postFilter.containsGalleryType = false; + postFilter.containTextType = true; + postFilter.containLinkType = false; + postFilter.containImageType = false; + postFilter.containGifType = false; + postFilter.containVideoType = false; + postFilter.containGalleryType = false; break; case Post.LINK_TYPE: - postFilter.containsTextType = false; - postFilter.containsLinkType = true; - postFilter.containsImageType = false; - postFilter.containsGifType = false; - postFilter.containsVideoType = false; - postFilter.containsGalleryType = false; + postFilter.containTextType = false; + postFilter.containLinkType = true; + postFilter.containImageType = false; + postFilter.containGifType = false; + postFilter.containVideoType = false; + postFilter.containGalleryType = false; break; case Post.IMAGE_TYPE: - postFilter.containsTextType = false; - postFilter.containsLinkType = false; - postFilter.containsImageType = true; - postFilter.containsGifType = false; - postFilter.containsVideoType = false; - postFilter.containsGalleryType = false; + postFilter.containTextType = false; + postFilter.containLinkType = false; + postFilter.containImageType = true; + postFilter.containGifType = false; + postFilter.containVideoType = false; + postFilter.containGalleryType = false; break; case Post.GIF_TYPE: - postFilter.containsTextType = false; - postFilter.containsLinkType = false; - postFilter.containsImageType = false; - postFilter.containsGifType = true; - postFilter.containsVideoType = false; - postFilter.containsGalleryType = false; + postFilter.containTextType = false; + postFilter.containLinkType = false; + postFilter.containImageType = false; + postFilter.containGifType = true; + postFilter.containVideoType = false; + postFilter.containGalleryType = false; break; case Post.VIDEO_TYPE: - postFilter.containsTextType = false; - postFilter.containsLinkType = false; - postFilter.containsImageType = false; - postFilter.containsGifType = false; - postFilter.containsVideoType = true; - postFilter.containsGalleryType = false; + postFilter.containTextType = false; + postFilter.containLinkType = false; + postFilter.containImageType = false; + postFilter.containGifType = false; + postFilter.containVideoType = true; + postFilter.containGalleryType = false; break; case Post.GALLERY_TYPE: - postFilter.containsTextType = false; - postFilter.containsLinkType = false; - postFilter.containsImageType = false; - postFilter.containsGifType = false; - postFilter.containsVideoType = false; - postFilter.containsGalleryType = true; + postFilter.containTextType = false; + postFilter.containLinkType = false; + postFilter.containImageType = false; + postFilter.containGifType = false; + postFilter.containVideoType = false; + postFilter.containGalleryType = true; break; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CustomizeThemeRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CustomizeThemeRecyclerViewAdapter.java index eb8189dd..d41d318b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CustomizeThemeRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CustomizeThemeRecyclerViewAdapter.java @@ -87,8 +87,8 @@ public class CustomizeThemeRecyclerViewAdapter extends RecyclerView.Adapter { - View dialogView = activity.getLayoutInflater().inflate(R.layout.dialog_edit_theme_name, null); - EditText themeNameEditText = dialogView.findViewById(R.id.theme_name_edit_text_edit_theme_name_dialog); + View dialogView = activity.getLayoutInflater().inflate(R.layout.dialog_edit_name, null); + EditText themeNameEditText = dialogView.findViewById(R.id.theme_name_edit_text_edit_name_dialog); themeNameEditText.setText(themeName); themeNameEditText.requestFocus(); InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java index 60d7f907..0c4a0e4e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java @@ -66,7 +66,7 @@ import ml.docilealligator.infinityforreddit.ActivityToolbarInterface; import ml.docilealligator.infinityforreddit.FragmentCommunicator; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.NetworkState; -import ml.docilealligator.infinityforreddit.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; import ml.docilealligator.infinityforreddit.PostFragmentContentScrollingInterface; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java index b55c9277..6791dbdb 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java @@ -14,7 +14,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; -import ml.docilealligator.infinityforreddit.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; import ml.docilealligator.infinityforreddit.readpost.ReadPost; import ml.docilealligator.infinityforreddit.subredditfilter.SubredditFilter; import ml.docilealligator.infinityforreddit.utils.JSONUtils; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSource.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSource.java index fc7d1583..615df8f7 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSource.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSource.java @@ -11,7 +11,7 @@ import java.util.LinkedHashSet; import java.util.List; import ml.docilealligator.infinityforreddit.NetworkState; -import ml.docilealligator.infinityforreddit.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.apis.RedditAPI; import ml.docilealligator.infinityforreddit.readpost.ReadPost; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSourceFactory.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSourceFactory.java index 2d0e6d19..777fb8ae 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSourceFactory.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostDataSourceFactory.java @@ -9,7 +9,7 @@ import androidx.paging.DataSource; import java.util.List; -import ml.docilealligator.infinityforreddit.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.readpost.ReadPost; import ml.docilealligator.infinityforreddit.subredditfilter.SubredditFilter; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java index 716eabaf..29803616 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java @@ -16,7 +16,7 @@ import androidx.paging.PagedList; import java.util.List; import ml.docilealligator.infinityforreddit.NetworkState; -import ml.docilealligator.infinityforreddit.PostFilter; +import ml.docilealligator.infinityforreddit.postfilter.PostFilter; import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.readpost.ReadPost; import ml.docilealligator.infinityforreddit.subredditfilter.SubredditFilter; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFilter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilter.java similarity index 57% rename from app/src/main/java/ml/docilealligator/infinityforreddit/PostFilter.java rename to app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilter.java index 7e236624..b23db7a1 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFilter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilter.java @@ -1,35 +1,71 @@ -package ml.docilealligator.infinityforreddit; +package ml.docilealligator.infinityforreddit.postfilter; import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.Ignore; +import androidx.room.PrimaryKey; + import java.util.regex.Matcher; import java.util.regex.Pattern; import ml.docilealligator.infinityforreddit.post.Post; +@Entity(tableName = "post_filter") public class PostFilter implements Parcelable { + @PrimaryKey + @NonNull + @ColumnInfo(name = "name") + public String name = "New Filter"; + @ColumnInfo(name = "max_vote") public int maxVote = -1; + @ColumnInfo(name = "min_vote") public int minVote = -1; + @ColumnInfo(name = "max_comments") public int maxComments = -1; + @ColumnInfo(name = "min_comments") public int minComments = -1; + @ColumnInfo(name = "max_awards") public int maxAwards = -1; + @ColumnInfo(name = "min_awards") public int minAwards = -1; + @Ignore public boolean allowNSFW; + @ColumnInfo(name = "only_nsfw") public boolean onlyNSFW; + @ColumnInfo(name = "only_spoiler") public boolean onlySpoiler; + @ColumnInfo(name = "post_title_excludes_regex") public String postTitleExcludesRegex; + @ColumnInfo(name = "post_title_excludes_strings") public String postTitleExcludesStrings; - public String excludesSubreddits; - public String excludesUsers; - public String containsFlairs; - public String excludesFlairs; - public boolean containsTextType = true; - public boolean containsLinkType = true; - public boolean containsImageType = true; - public boolean containsGifType = true; - public boolean containsVideoType = true; - public boolean containsGalleryType = true; + @ColumnInfo(name = "exclude_subreddits") + public String excludeSubreddits; + @ColumnInfo(name = "exclude_users") + public String excludeUsers; + @ColumnInfo(name = "contain_flairs") + public String containFlairs; + @ColumnInfo(name = "exclude_flairs") + public String excludeFlairs; + @ColumnInfo(name = "contain_text_type") + public boolean containTextType = true; + @ColumnInfo(name = "contain_link_type") + public boolean containLinkType = true; + @ColumnInfo(name = "contain_image_type") + public boolean containImageType = true; + @ColumnInfo(name = "contain_gif_type") + public boolean containGifType = true; + @ColumnInfo(name = "contain_video_type") + public boolean containVideoType = true; + @ColumnInfo(name = "contain_gallery_type") + public boolean containGalleryType = true; + + public PostFilter() { + + } public static boolean isPostAllowed(Post post, PostFilter postFilter) { if (postFilter == null || post == null) { @@ -62,22 +98,22 @@ public class PostFilter implements Parcelable { if (postFilter.onlySpoiler && !post.isSpoiler()) { return false; } - if (!postFilter.containsTextType && post.getPostType() == Post.TEXT_TYPE) { + if (!postFilter.containTextType && post.getPostType() == Post.TEXT_TYPE) { return false; } - if (!postFilter.containsLinkType && (post.getPostType() == Post.LINK_TYPE || post.getPostType() == Post.NO_PREVIEW_LINK_TYPE)) { + if (!postFilter.containLinkType && (post.getPostType() == Post.LINK_TYPE || post.getPostType() == Post.NO_PREVIEW_LINK_TYPE)) { return false; } - if (!postFilter.containsImageType && post.getPostType() == Post.IMAGE_TYPE) { + if (!postFilter.containImageType && post.getPostType() == Post.IMAGE_TYPE) { return false; } - if (!postFilter.containsGifType && post.getPostType() == Post.GIF_TYPE) { + if (!postFilter.containGifType && post.getPostType() == Post.GIF_TYPE) { return false; } - if (!postFilter.containsVideoType && post.getPostType() == Post.VIDEO_TYPE) { + if (!postFilter.containVideoType && post.getPostType() == Post.VIDEO_TYPE) { return false; } - if (!postFilter.containsGalleryType && post.getPostType() == Post.GALLERY_TYPE) { + if (!postFilter.containGalleryType && post.getPostType() == Post.GALLERY_TYPE) { return false; } if (postFilter.postTitleExcludesRegex != null && !postFilter.postTitleExcludesRegex.equals("")) { @@ -95,32 +131,32 @@ public class PostFilter implements Parcelable { } } } - if (postFilter.excludesSubreddits != null && !postFilter.excludesSubreddits.equals("")) { - String[] subreddits = postFilter.excludesSubreddits.split(",", 0); + if (postFilter.excludeSubreddits != null && !postFilter.excludeSubreddits.equals("")) { + String[] subreddits = postFilter.excludeSubreddits.split(",", 0); for (String s : subreddits) { if (post.getSubredditName().equalsIgnoreCase(s)) { return false; } } } - if (postFilter.excludesUsers != null && !postFilter.excludesUsers.equals("")) { - String[] users = postFilter.excludesUsers.split(",", 0); + if (postFilter.excludeUsers != null && !postFilter.excludeUsers.equals("")) { + String[] users = postFilter.excludeUsers.split(",", 0); for (String u : users) { if (post.getAuthor().equalsIgnoreCase(u)) { return false; } } } - if (postFilter.excludesFlairs != null && !postFilter.excludesFlairs.equals("")) { - String[] flairs = postFilter.excludesFlairs.split(",", 0); + if (postFilter.excludeFlairs != null && !postFilter.excludeFlairs.equals("")) { + String[] flairs = postFilter.excludeFlairs.split(",", 0); for (String f : flairs) { if (post.getFlair().equalsIgnoreCase(f)) { return false; } } } - if (postFilter.containsFlairs != null && !postFilter.containsFlairs.equals("")) { - String[] flairs = postFilter.containsFlairs.split(",", 0); + if (postFilter.containFlairs != null && !postFilter.containFlairs.equals("")) { + String[] flairs = postFilter.containFlairs.split(",", 0); for (String f : flairs) { if (post.getFlair().equalsIgnoreCase(f)) { return false; @@ -131,10 +167,6 @@ public class PostFilter implements Parcelable { return true; } - public PostFilter() { - - } - protected PostFilter(Parcel in) { maxVote = in.readInt(); minVote = in.readInt(); @@ -147,15 +179,15 @@ public class PostFilter implements Parcelable { onlySpoiler = in.readByte() != 0; postTitleExcludesRegex = in.readString(); postTitleExcludesStrings = in.readString(); - excludesSubreddits = in.readString(); - excludesUsers = in.readString(); - containsFlairs = in.readString(); - excludesFlairs = in.readString(); - containsTextType = in.readByte() != 0; - containsLinkType = in.readByte() != 0; - containsImageType = in.readByte() != 0; - containsVideoType = in.readByte() != 0; - containsGalleryType = in.readByte() != 0; + excludeSubreddits = in.readString(); + excludeUsers = in.readString(); + containFlairs = in.readString(); + excludeFlairs = in.readString(); + containTextType = in.readByte() != 0; + containLinkType = in.readByte() != 0; + containImageType = in.readByte() != 0; + containVideoType = in.readByte() != 0; + containGalleryType = in.readByte() != 0; } public static final Creator CREATOR = new Creator() { @@ -188,14 +220,14 @@ public class PostFilter implements Parcelable { parcel.writeByte((byte) (onlySpoiler ? 1 : 0)); parcel.writeString(postTitleExcludesRegex); parcel.writeString(postTitleExcludesStrings); - parcel.writeString(excludesSubreddits); - parcel.writeString(excludesUsers); - parcel.writeString(containsFlairs); - parcel.writeString(excludesFlairs); - parcel.writeByte((byte) (containsTextType ? 1 : 0)); - parcel.writeByte((byte) (containsLinkType ? 1 : 0)); - parcel.writeByte((byte) (containsImageType ? 1 : 0)); - parcel.writeByte((byte) (containsVideoType ? 1 : 0)); - parcel.writeByte((byte) (containsGalleryType ? 1 : 0)); + parcel.writeString(excludeSubreddits); + parcel.writeString(excludeUsers); + parcel.writeString(containFlairs); + parcel.writeString(excludeFlairs); + parcel.writeByte((byte) (containTextType ? 1 : 0)); + parcel.writeByte((byte) (containLinkType ? 1 : 0)); + parcel.writeByte((byte) (containImageType ? 1 : 0)); + parcel.writeByte((byte) (containVideoType ? 1 : 0)); + parcel.writeByte((byte) (containGalleryType ? 1 : 0)); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterDao.java b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterDao.java new file mode 100644 index 00000000..baddaa8f --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterDao.java @@ -0,0 +1,22 @@ +package ml.docilealligator.infinityforreddit.postfilter; + +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; + +@Dao +public interface PostFilterDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insert(PostFilter postFilter); + + @Query("DELETE FROM post_filter") + void deleteAllPostFilters(); + + @Query("SELECT * FROM post_filter WHERE name = :name LIMIT 1") + PostFilter getPostFilter(String name); + + @Query("SELECT * FROM post_filter") + LiveData getAllPostFiltersLiveData(); +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterUsage.java b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterUsage.java new file mode 100644 index 00000000..05cf05cc --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterUsage.java @@ -0,0 +1,26 @@ +package ml.docilealligator.infinityforreddit.postfilter; + +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.ForeignKey; + +@Entity(tableName = "post_filter_usage", primaryKeys = {"name", "usage", "name_of_usage"}, + foreignKeys = @ForeignKey(entity = PostFilter.class, parentColumns = "name", + childColumns = "name", onDelete = ForeignKey.CASCADE)) +public class PostFilterUsage { + @NonNull + @ColumnInfo(name = "name") + public String name; + @ColumnInfo(name = "usage") + public int usage; + @NonNull + @ColumnInfo(name = "name_of_usage") + public String nameOfUsage; + + public PostFilterUsage(@NonNull String name, int usage, String nameOfUsage) { + this.name = name; + this.usage = usage; + this.nameOfUsage = nameOfUsage; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterUsageDao.java b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterUsageDao.java new file mode 100644 index 00000000..165df55a --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/PostFilterUsageDao.java @@ -0,0 +1,7 @@ +package ml.docilealligator.infinityforreddit.postfilter; + +import androidx.room.Dao; + +@Dao +public interface PostFilterUsageDao { +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/SavePostFilter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/SavePostFilter.java new file mode 100644 index 00000000..f129a4dd --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/postfilter/SavePostFilter.java @@ -0,0 +1,27 @@ +package ml.docilealligator.infinityforreddit.postfilter; + +import java.util.concurrent.Executor; + +import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; + +public class SavePostFilter { + public static final int ERROR_DUPLICATE_NAME = 1; + + public interface SavePostFilterListener { + //Need to make sure it is running in the UI thread. + void success(); + void failed(int errorCode); + } + + public static void savePostFilter(RedditDataRoomDatabase redditDataRoomDatabase, Executor executor, + PostFilter postFilter, SavePostFilterListener savePostFilterListener) { + executor.execute(() -> { + if (redditDataRoomDatabase.postFilterDao().getPostFilter(postFilter.name) == null) { + redditDataRoomDatabase.postFilterDao().insert(postFilter); + savePostFilterListener.success(); + } else { + savePostFilterListener.failed(ERROR_DUPLICATE_NAME); + } + }); + } +} diff --git a/app/src/main/res/drawable-night/ic_save_to_database_24dp.xml b/app/src/main/res/drawable-night/ic_save_to_database_24dp.xml new file mode 100644 index 00000000..b10b206f --- /dev/null +++ b/app/src/main/res/drawable-night/ic_save_to_database_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_save_to_database_24dp.xml b/app/src/main/res/drawable/ic_save_to_database_24dp.xml new file mode 100644 index 00000000..4402c5df --- /dev/null +++ b/app/src/main/res/drawable/ic_save_to_database_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/dialog_edit_theme_name.xml b/app/src/main/res/layout/dialog_edit_name.xml similarity index 86% rename from app/src/main/res/layout/dialog_edit_theme_name.xml rename to app/src/main/res/layout/dialog_edit_name.xml index 9e126bc5..bfd0cc8c 100644 --- a/app/src/main/res/layout/dialog_edit_theme_name.xml +++ b/app/src/main/res/layout/dialog_edit_name.xml @@ -1,6 +1,6 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c683d45e..afeeb6f4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -73,6 +73,7 @@ Block User Select User Flair Give Award + Save to Database Error occurred when parsing the JSON response Error Retrieving the token @@ -974,5 +975,8 @@ Max comments Min awards Max awards + Post Filter Name + Duplicate post filter found. Please use another name. +