diff options
Diffstat (limited to 'app/src/main/java')
64 files changed, 3399 insertions, 948 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/API/DownloadRedditVideo.java b/app/src/main/java/ml/docilealligator/infinityforreddit/API/DownloadFile.java index 7e51123d..10a8dda4 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/API/DownloadRedditVideo.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/API/DownloadFile.java @@ -6,7 +6,7 @@ import retrofit2.http.GET; import retrofit2.http.Streaming; import retrofit2.http.Url; -public interface DownloadRedditVideo { +public interface DownloadFile { @Streaming @GET() Call<ResponseBody> downloadFile(@Url String fileUrl); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/API/RedditAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/API/RedditAPI.java index 8bdcbbfa..003ad955 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/API/RedditAPI.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/API/RedditAPI.java @@ -313,4 +313,9 @@ public interface RedditAPI { @FormUrlEncoded @POST("/api/compose") Call<String> composePrivateMessage(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params); + + + @FormUrlEncoded + @POST("api/block_user") + Call<String> blockUser(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountPostsActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountPostsActivity.java index 805674de..e88d70ce 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountPostsActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountPostsActivity.java @@ -191,6 +191,7 @@ public class AccountPostsActivity extends BaseActivity implements SortTypeSelect bundle.putString(PostFragment.EXTRA_USER_WHERE, mUserWhere); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); mFragment.setArguments(bundle); getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_account_posts_activity, mFragment).commit(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountSavedThingActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountSavedThingActivity.java index 5a2ed18c..818e5c0f 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountSavedThingActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/AccountSavedThingActivity.java @@ -338,6 +338,7 @@ public class AccountSavedThingActivity extends BaseActivity implements ActivityT bundle.putString(PostFragment.EXTRA_USER_WHERE, PostDataSource.USER_WHERE_SAVED); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/CommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/CommentActivity.java index 6bf1b3ab..1c14defd 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/CommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/CommentActivity.java @@ -27,7 +27,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; -import com.r0adkll.slidr.Slidr; import org.commonmark.ext.gfm.tables.TableBlock; import org.greenrobot.eventbus.EventBus; @@ -41,23 +40,22 @@ import butterknife.ButterKnife; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.Markwon; import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.linkify.LinkifyPlugin; import io.noties.markwon.recycler.MarkwonAdapter; import io.noties.markwon.recycler.table.TableEntry; import io.noties.markwon.recycler.table.TableEntryPlugin; import io.noties.markwon.simple.ext.SimpleExtPlugin; -import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import ml.docilealligator.infinityforreddit.AsyncTask.GetCurrentAccountAsyncTask; +import ml.docilealligator.infinityforreddit.BottomSheetFragment.CopyTextBottomSheetFragment; import ml.docilealligator.infinityforreddit.Comment.Comment; +import ml.docilealligator.infinityforreddit.Comment.SendComment; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.Event.SwitchAccountEvent; -import ml.docilealligator.infinityforreddit.BottomSheetFragment.CopyTextBottomSheetFragment; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; -import ml.docilealligator.infinityforreddit.Comment.SendComment; -import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.Utils.Utils; import retrofit2.Retrofit; @@ -124,10 +122,6 @@ public class CommentActivity extends BaseActivity { applyCustomTheme(); - if (mSharedPreferences.getBoolean(SharedPreferencesUtils.SWIPE_RIGHT_TO_GO_BACK, true)) { - Slidr.attach(this); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && isChangeStatusBarIconColor()) { addOnOffsetChangedListener(appBarLayout); } @@ -146,6 +140,8 @@ public class CommentActivity extends BaseActivity { String parentTextMarkdown = intent.getStringExtra(EXTRA_COMMENT_PARENT_TEXT_MARKDOWN_KEY); String parentText = intent.getStringExtra(EXTRA_COMMENT_PARENT_TEXT_KEY); CopyTextBottomSheetFragment copyTextBottomSheetFragment = new CopyTextBottomSheetFragment(); + + int linkColor = mCustomThemeWrapper.getLinkColor(); Markwon markwon = Markwon.builder(this) .usePlugin(new AbstractMarkwonPlugin() { @Override @@ -161,6 +157,11 @@ public class CommentActivity extends BaseActivity { startActivity(intent); }); } + + @Override + public void configureTheme(@NonNull MarkwonTheme.Builder builder) { + builder.linkColor(linkColor); + } }) .usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS)) .usePlugin(SimpleExtPlugin.create(plugin -> @@ -218,7 +219,12 @@ public class CommentActivity extends BaseActivity { intent.setData(uri); } startActivity(intent); - }).urlProcessor(new UrlProcessorRelativeToAbsolute("https://www.reddit.com")); + }); + } + + @Override + public void configureTheme(@NonNull MarkwonTheme.Builder builder) { + builder.linkColor(linkColor); } }) .usePlugin(StrikethroughPlugin.create()) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditCommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditCommentActivity.java index ccb2f1af..b3ece3d2 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditCommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditCommentActivity.java @@ -18,7 +18,6 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; -import com.r0adkll.slidr.Slidr; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -31,13 +30,12 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; +import ml.docilealligator.infinityforreddit.API.RedditAPI; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.Event.SwitchAccountEvent; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; -import ml.docilealligator.infinityforreddit.API.RedditAPI; import ml.docilealligator.infinityforreddit.Utils.APIUtils; -import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.Utils.Utils; import retrofit2.Call; import retrofit2.Callback; @@ -89,10 +87,6 @@ public class EditCommentActivity extends BaseActivity { applyCustomTheme(); - if (mSharedPreferences.getBoolean(SharedPreferencesUtils.SWIPE_RIGHT_TO_GO_BACK, true)) { - Slidr.attach(this); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && isChangeStatusBarIconColor()) { addOnOffsetChangedListener(appBarLayout); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditMultiRedditActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditMultiRedditActivity.java index 60945420..421b495d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditMultiRedditActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/EditMultiRedditActivity.java @@ -226,7 +226,7 @@ public class EditMultiRedditActivity extends BaseActivity { if (requestCode == SUBREDDIT_SELECTION_REQUEST_CODE && resultCode == RESULT_OK) { if (data != null) { multiReddit.setSubreddits(data.getStringArrayListExtra( - SubredditMultiselectionActivity.EXTRA_RETURN_SELECTED_SUBREDDITS)); + SelectedSubredditsActivity.EXTRA_RETURN_SELECTED_SUBREDDITS)); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/FilteredThingActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/FilteredThingActivity.java index a0b8bd47..1a3bfa31 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/FilteredThingActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/FilteredThingActivity.java @@ -58,6 +58,7 @@ public class FilteredThingActivity extends BaseActivity implements SortTypeSelec private static final String IS_IN_LAZY_MODE_STATE = "IILMS"; private static final String NULL_ACCESS_TOKEN_STATE = "NATS"; private static final String ACCESS_TOKEN_STATE = "ATS"; + private static final String ACCOUNT_NAME_STATE = "ANS"; private static final String FRAGMENT_OUT_STATE = "FOS"; @BindView(R.id.coordinator_layout_filtered_thing_activity) @@ -81,6 +82,7 @@ public class FilteredThingActivity extends BaseActivity implements SortTypeSelec private boolean isInLazyMode = false; private boolean mNullAccessToken = false; private String mAccessToken; + private String mAccountName; private String name; private String userWhere; private int postType; @@ -148,6 +150,7 @@ public class FilteredThingActivity extends BaseActivity implements SortTypeSelec isInLazyMode = savedInstanceState.getBoolean(IS_IN_LAZY_MODE_STATE); mNullAccessToken = savedInstanceState.getBoolean(NULL_ACCESS_TOKEN_STATE); mAccessToken = savedInstanceState.getString(ACCESS_TOKEN_STATE); + mAccountName = savedInstanceState.getString(ACCOUNT_NAME_STATE); mFragment = getSupportFragmentManager().getFragment(savedInstanceState, FRAGMENT_OUT_STATE); getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_filtered_posts_activity, mFragment).commit(); @@ -195,6 +198,7 @@ public class FilteredThingActivity extends BaseActivity implements SortTypeSelec mNullAccessToken = true; } else { mAccessToken = account.getAccessToken(); + mAccountName = account.getUsername(); } bindView(filter, true); }).execute(); @@ -248,7 +252,6 @@ public class FilteredThingActivity extends BaseActivity implements SortTypeSelec multiRedditSortTypeBottomSheetFragment = new SortTypeBottomSheetFragment(); Bundle multiRedditBundle = new Bundle(); multiRedditBundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, true); - multiRedditBundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_RANDOM_TYPE, true); multiRedditSortTypeBottomSheetFragment.setArguments(multiRedditBundle); break; case PostDataSource.TYPE_USER: @@ -291,6 +294,7 @@ public class FilteredThingActivity extends BaseActivity implements SortTypeSelec bundle.putInt(PostFragment.EXTRA_POST_TYPE, postType); bundle.putInt(PostFragment.EXTRA_FILTER, filter); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); if (postType == PostDataSource.TYPE_USER) { bundle.putString(PostFragment.EXTRA_USER_NAME, name); bundle.putString(PostFragment.EXTRA_USER_WHERE, userWhere); @@ -393,6 +397,7 @@ public class FilteredThingActivity extends BaseActivity implements SortTypeSelec getSupportFragmentManager().putFragment(outState, FRAGMENT_OUT_STATE, mFragment); outState.putBoolean(IS_IN_LAZY_MODE_STATE, isInLazyMode); outState.putString(ACCESS_TOKEN_STATE, mAccessToken); + outState.putString(ACCOUNT_NAME_STATE, mAccountName); outState.putBoolean(NULL_ACCESS_TOKEN_STATE, mNullAccessToken); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/LinkResolverActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/LinkResolverActivity.java index 15a072d8..f318c1b5 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/LinkResolverActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/LinkResolverActivity.java @@ -33,8 +33,8 @@ public class LinkResolverActivity extends AppCompatActivity { private static final String POST_PATTERN = "/r/\\w+/comments/\\w+/?\\w+/?"; private static final String COMMENT_PATTERN = "/(r|u|U|user)/\\w+/comments/\\w+/?\\w+/\\w+/?"; - private static final String SUBREDDIT_PATTERN = "/[rR]/\\w+/?"; - private static final String USER_PATTERN = "/(u|U|user)/\\w+/?"; + private static final String SUBREDDIT_PATTERN = "/[rR]/[\\w-]+/?"; + private static final String USER_PATTERN = "/(u|U|user)/[\\w-]+/?"; private static final String SIDEBAR_PATTERN = "/[rR]/\\w+/about/sidebar"; private static final String MULTIREDDIT_PATTERN = "/user/\\w+/m/\\w+/?"; private static final String MULTIREDDIT_PATTERN_2 = "/[rR]/(\\w+\\+?)+/?"; @@ -262,7 +262,17 @@ public class LinkResolverActivity extends AppCompatActivity { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); - List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0); + try { + startActivity(intent); + } catch (ActivityNotFoundException e) { + if (handleError) { + openInCustomTabs(uri, pm, false); + } else { + Toast.makeText(this, R.string.no_browser_found, Toast.LENGTH_SHORT).show(); + } + } + + /*List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0); ArrayList<String> packageNames = new ArrayList<>(); String currentPackageName = getApplicationContext().getPackageName(); @@ -289,10 +299,9 @@ public class LinkResolverActivity extends AppCompatActivity { } else { Toast.makeText(this, R.string.no_browser_found, Toast.LENGTH_SHORT).show(); } - } + }*/ } - private ArrayList<ResolveInfo> getCustomTabsPackages(PackageManager pm) { // Get default VIEW intent handler. Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.example.com")); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/MainActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/MainActivity.java index bc15b896..d86168ee 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/MainActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/MainActivity.java @@ -169,12 +169,14 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb @Named("post_layout") SharedPreferences mPostLayoutSharedPreferences; @Inject + @Named("main_activity_tabs") + SharedPreferences mMainActivityTabsSharedPreferences; + @Inject CustomThemeWrapper mCustomThemeWrapper; private SectionsPagerAdapter sectionsPagerAdapter; private AppBarLayout.LayoutParams params; private PostTypeBottomSheetFragment postTypeBottomSheetFragment; - private SortTypeBottomSheetFragment bestSortTypeBottomSheetFragment; - private SortTypeBottomSheetFragment popularAndAllSortTypeBottomSheetFragment; + private SortTypeBottomSheetFragment sortTypeBottomSheetFragment; private SortTimeBottomSheetFragment sortTimeBottomSheetFragment; private PostLayoutBottomSheetFragment postLayoutBottomSheetFragment; private NavigationDrawerRecyclerViewAdapter adapter; @@ -234,17 +236,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb } postTypeBottomSheetFragment = new PostTypeBottomSheetFragment(); - - bestSortTypeBottomSheetFragment = new SortTypeBottomSheetFragment(); - Bundle bestBundle = new Bundle(); - bestBundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, false); - bestSortTypeBottomSheetFragment.setArguments(bestBundle); - - popularAndAllSortTypeBottomSheetFragment = new SortTypeBottomSheetFragment(); - Bundle popularBundle = new Bundle(); - popularBundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, true); - popularAndAllSortTypeBottomSheetFragment.setArguments(popularBundle); - + sortTypeBottomSheetFragment = new SortTypeBottomSheetFragment(); sortTimeBottomSheetFragment = new SortTimeBottomSheetFragment(); postLayoutBottomSheetFragment = new PostLayoutBottomSheetFragment(); @@ -727,11 +719,15 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.action_sort_main_activity: - if (viewPager.getCurrentItem() == 1 || viewPager.getCurrentItem() == 2) { - popularAndAllSortTypeBottomSheetFragment.show(getSupportFragmentManager(), popularAndAllSortTypeBottomSheetFragment.getTag()); + int currentPostType = sectionsPagerAdapter.getCurrentPostType(); + Bundle bundle = new Bundle(); + if (currentPostType != PostDataSource.TYPE_FRONT_PAGE) { + bundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, true); } else { - bestSortTypeBottomSheetFragment.show(getSupportFragmentManager(), bestSortTypeBottomSheetFragment.getTag()); + bundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, false); } + sortTypeBottomSheetFragment.setArguments(bundle); + sortTypeBottomSheetFragment.show(getSupportFragmentManager(), sortTypeBottomSheetFragment.getTag()); return true; case R.id.action_search_main_activity: Intent intent = new Intent(this, SearchActivity.class); @@ -945,6 +941,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb bundle.putString(PostFragment.EXTRA_NAME, "popular"); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; } else { @@ -954,63 +951,69 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb bundle.putString(PostFragment.EXTRA_NAME, "all"); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; } } if (position == 0) { - String postType = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_1_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME); - String name = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_1_NAME, ""); + int postType = mMainActivityTabsSharedPreferences.getInt((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME); + String name = mMainActivityTabsSharedPreferences.getString((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_NAME, ""); return generatePostFragment(postType, name); } else if (position == 1) { - String postType = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_2_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_POPULAR); - String name = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_2_NAME, ""); + int postType = mMainActivityTabsSharedPreferences.getInt((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_POPULAR); + String name = mMainActivityTabsSharedPreferences.getString((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_NAME, ""); return generatePostFragment(postType, name); } else { - String postType = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_3_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL); - String name = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_3_NAME, ""); + int postType = mMainActivityTabsSharedPreferences.getInt((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL); + String name = mMainActivityTabsSharedPreferences.getString((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_NAME, ""); return generatePostFragment(postType, name); } } - private Fragment generatePostFragment(String postType, String name) { - if (postType.equals(SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME)) { + private Fragment generatePostFragment(int postType, String name) { + + if (postType == SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME) { PostFragment fragment = new PostFragment(); Bundle bundle = new Bundle(); bundle.putInt(PostFragment.EXTRA_POST_TYPE, PostDataSource.TYPE_FRONT_PAGE); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; - } else if (postType.equals(SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL)) { + } else if (postType == SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL) { PostFragment fragment = new PostFragment(); Bundle bundle = new Bundle(); bundle.putInt(PostFragment.EXTRA_POST_TYPE, PostDataSource.TYPE_SUBREDDIT); bundle.putString(PostFragment.EXTRA_NAME, "all"); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; - } else if (postType.equals(SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT)) { + } else if (postType == SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT) { PostFragment fragment = new PostFragment(); Bundle bundle = new Bundle(); bundle.putInt(PostFragment.EXTRA_POST_TYPE, PostDataSource.TYPE_SUBREDDIT); bundle.putString(PostFragment.EXTRA_NAME, name); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; - } else if (postType.equals(SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT)) { + } else if (postType == SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT) { PostFragment fragment = new PostFragment(); Bundle bundle = new Bundle(); bundle.putString(PostFragment.EXTRA_NAME, name); bundle.putInt(PostFragment.EXTRA_POST_TYPE, PostDataSource.TYPE_MULTI_REDDIT); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; - } else if (postType.equals(SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER)) { + } else if (postType == SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER) { PostFragment fragment = new PostFragment(); Bundle bundle = new Bundle(); bundle.putInt(PostFragment.EXTRA_POST_TYPE, PostDataSource.TYPE_USER); @@ -1018,6 +1021,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb bundle.putString(PostFragment.EXTRA_USER_WHERE, PostDataSource.USER_WHERE_SUBMITTED); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; } else { @@ -1027,6 +1031,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb bundle.putString(PostFragment.EXTRA_NAME, "popular"); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; } @@ -1052,11 +1057,11 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb } else { switch (position) { case 0: - return mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_1_TITLE, getString(R.string.home)); + return mMainActivityTabsSharedPreferences.getString((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_TITLE, getString(R.string.home)); case 1: - return mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_2_TITLE, getString(R.string.popular)); + return mMainActivityTabsSharedPreferences.getString((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_TITLE, getString(R.string.popular)); case 2: - return mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_3_TITLE, getString(R.string.all)); + return mMainActivityTabsSharedPreferences.getString((mAccountName == null ? "" : mAccountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_TITLE, getString(R.string.all)); } } return null; @@ -1232,6 +1237,25 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb } } + int getCurrentPostType() { + if (mAccessToken == null) { + if (viewPager.getCurrentItem() == 0) { + return tab2.getPostType(); + } else { + return tab3.getPostType(); + } + } else { + switch (viewPager.getCurrentItem()) { + case 1: + return tab2.getPostType(); + case 2: + return tab3.getPostType(); + default: + return tab1.getPostType(); + } + } + } + void changeSortType(SortType sortType) { if (mAccessToken == null) { if (viewPager.getCurrentItem() == 0) { @@ -1242,27 +1266,12 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb } else { switch (viewPager.getCurrentItem()) { case 0: - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_BEST_POST, sortType.getType().name()).apply(); - if (sortType.getTime() != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_BEST_POST, sortType.getTime().name()).apply(); - } - tab1.changeSortType(sortType); break; case 1: - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_POPULAR_POST, sortType.getType().name()).apply(); - if (sortType.getTime() != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_POPULAR_POST, sortType.getTime().name()).apply(); - } - tab2.changeSortType(sortType); break; case 2: - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_ALL_POST, sortType.getType().name()).apply(); - if (sortType.getTime() != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_ALL_POST, sortType.getTime().name()).apply(); - } - tab3.changeSortType(sortType); } } @@ -1365,6 +1374,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb tab3.goBackToTop(); } } + void displaySortTypeInToolbar() { switch (viewPager.getCurrentItem()) { case 0: diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/PostTextActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/PostTextActivity.java index 2a666d5b..69568d88 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/PostTextActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/PostTextActivity.java @@ -129,7 +129,7 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr private boolean isSpoiler = false; private boolean isNSFW = false; private Resources resources; - private Menu mMemu; + private Menu mMenu; private RequestManager mGlide; private FlairBottomSheetFragment flairSelectionBottomSheetFragment; private Snackbar mPostingSnackbar; @@ -391,10 +391,10 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.post_text_activity, menu); applyMenuItemTheme(menu); - mMemu = menu; + mMenu = menu; if (isPosting) { - mMemu.findItem(R.id.action_send_post_text_activity).setEnabled(false); - mMemu.findItem(R.id.action_send_post_text_activity).getIcon().setAlpha(130); + mMenu.findItem(R.id.action_send_post_text_activity).setEnabled(false); + mMenu.findItem(R.id.action_send_post_text_activity).getIcon().setAlpha(130); } return true; } @@ -539,8 +539,8 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr startActivity(intent); finish(); } else { - mMemu.findItem(R.id.action_send_post_text_activity).setEnabled(true); - mMemu.findItem(R.id.action_send_post_text_activity).getIcon().setAlpha(255); + mMenu.findItem(R.id.action_send_post_text_activity).setEnabled(true); + mMenu.findItem(R.id.action_send_post_text_activity).getIcon().setAlpha(255); if (submitTextOrLinkPostEvent.errorMessage == null || submitTextOrLinkPostEvent.errorMessage.equals("")) { Snackbar.make(coordinatorLayout, R.string.post_failed, Snackbar.LENGTH_SHORT).show(); } else { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SearchResultActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SearchResultActivity.java index c905cdfc..fa5f14fc 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SearchResultActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SearchResultActivity.java @@ -419,11 +419,6 @@ public class SearchResultActivity extends BaseActivity implements SortTypeSelect } void changeSortType(SortType sortType) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_SEARCH_POST, sortType.getType().name()).apply(); - if(sortType.getTime() != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_SEARCH_POST, sortType.getTime().name()).apply(); - } - postFragment.changeSortType(sortType); displaySortTypeInToolbar(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SettingsActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SettingsActivity.java index 4e59c42b..325e8e91 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SettingsActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SettingsActivity.java @@ -21,11 +21,14 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; +import ml.docilealligator.infinityforreddit.AsyncTask.GetCurrentAccountAsyncTask; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.Event.RecreateActivityEvent; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.Settings.AboutPreferenceFragment; +import ml.docilealligator.infinityforreddit.Settings.CustomizeMainPageTabsFragment; import ml.docilealligator.infinityforreddit.Settings.FontPreferenceFragment; import ml.docilealligator.infinityforreddit.Settings.InterfacePreferenceFragment; import ml.docilealligator.infinityforreddit.Settings.MainPreferenceFragment; @@ -39,11 +42,15 @@ public class SettingsActivity extends BaseActivity implements AppBarLayout appBarLayout; @BindView(R.id.toolbar_settings_activity) Toolbar toolbar; + private boolean mNullAccountName; + private String mAccountName; @Inject @Named("default") SharedPreferences mSharedPreferences; @Inject + RedditDataRoomDatabase mRedditDataRoomDatabase; + @Inject CustomThemeWrapper mCustomThemeWrapper; @Override @@ -68,14 +75,7 @@ public class SettingsActivity extends BaseActivity implements setSupportActionBar(toolbar); - if (savedInstanceState == null) { - getSupportFragmentManager() - .beginTransaction() - .replace(R.id.frame_layout_settings_activity, new MainPreferenceFragment()) - .commit(); - } else { - setTitle(savedInstanceState.getCharSequence(TITLE_STATE)); - } + getCurrentAccountAndBindView(savedInstanceState); getSupportFragmentManager().addOnBackStackChangedListener(() -> { if (getSupportFragmentManager().getBackStackEntryCount() == 0) { @@ -90,6 +90,25 @@ public class SettingsActivity extends BaseActivity implements }); } + private void getCurrentAccountAndBindView(Bundle savedInstanceState) { + new GetCurrentAccountAsyncTask(mRedditDataRoomDatabase.accountDao(), account -> { + if (account == null) { + mNullAccountName = true; + } else { + mAccountName = account.getUsername(); + } + + if (savedInstanceState == null) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.frame_layout_settings_activity, new MainPreferenceFragment()) + .commit(); + } else { + setTitle(savedInstanceState.getCharSequence(TITLE_STATE)); + } + }).execute(); + } + @Override public SharedPreferences getDefaultSharedPreferences() { return mSharedPreferences; @@ -135,6 +154,9 @@ public class SettingsActivity extends BaseActivity implements final Fragment fragment = getSupportFragmentManager().getFragmentFactory().instantiate( getClassLoader(), pref.getFragment()); + if (fragment instanceof CustomizeMainPageTabsFragment) { + args.putString(CustomizeMainPageTabsFragment.EXTRA_ACCOUNT_NAME, mAccountName); + } fragment.setArguments(args); fragment.setTargetFragment(caller, 0); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SubmitCrosspostActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SubmitCrosspostActivity.java new file mode 100644 index 00000000..4718755b --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/SubmitCrosspostActivity.java @@ -0,0 +1,605 @@ +package ml.docilealligator.infinityforreddit.Activity; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.request.RequestOptions; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.transition.Transition; +import com.davemorrissey.labs.subscaleview.ImageSource; +import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.snackbar.Snackbar; +import com.libRG.CustomTextView; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + +import javax.inject.Inject; +import javax.inject.Named; + +import butterknife.BindView; +import butterknife.ButterKnife; +import jp.wasabeef.glide.transformations.RoundedCornersTransformation; +import ml.docilealligator.infinityforreddit.AsyncTask.GetCurrentAccountAsyncTask; +import ml.docilealligator.infinityforreddit.AsyncTask.LoadSubredditIconAsyncTask; +import ml.docilealligator.infinityforreddit.BottomSheetFragment.FlairBottomSheetFragment; +import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; +import ml.docilealligator.infinityforreddit.Event.SubmitCrosspostEvent; +import ml.docilealligator.infinityforreddit.Event.SwitchAccountEvent; +import ml.docilealligator.infinityforreddit.Flair; +import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.Post.Post; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; +import ml.docilealligator.infinityforreddit.Service.SubmitPostService; +import ml.docilealligator.infinityforreddit.Utils.APIUtils; +import pl.droidsonroids.gif.GifImageView; +import retrofit2.Retrofit; + +public class SubmitCrosspostActivity extends BaseActivity implements FlairBottomSheetFragment.FlairSelectionCallback { + + public static final String EXTRA_POST = "EP"; + + private static final String SUBREDDIT_NAME_STATE = "SNS"; + private static final String SUBREDDIT_ICON_STATE = "SIS"; + private static final String SUBREDDIT_SELECTED_STATE = "SSS"; + private static final String SUBREDDIT_IS_USER_STATE = "SIUS"; + private static final String LOAD_SUBREDDIT_ICON_STATE = "LSIS"; + private static final String IS_POSTING_STATE = "IPS"; + private static final String FLAIR_STATE = "FS"; + private static final String IS_SPOILER_STATE = "ISS"; + private static final String IS_NSFW_STATE = "INS"; + private static final String NULL_ACCESS_TOKEN_STATE = "NATS"; + private static final String ACCESS_TOKEN_STATE = "ATS"; + + private static final int SUBREDDIT_SELECTION_REQUEST_CODE = 0; + + @BindView(R.id.coordinator_layout_submit_crosspost_activity) + CoordinatorLayout coordinatorLayout; + @BindView(R.id.appbar_layout_submit_crosspost_activity) + AppBarLayout appBarLayout; + @BindView(R.id.toolbar_submit_crosspost_activity) + Toolbar toolbar; + @BindView(R.id.subreddit_icon_gif_image_view_submit_crosspost_activity) + GifImageView iconGifImageView; + @BindView(R.id.subreddit_name_text_view_submit_crosspost_activity) + TextView subredditNameTextView; + @BindView(R.id.rules_button_submit_crosspost_activity) + Button rulesButton; + @BindView(R.id.divider_1_submit_crosspost_activity) + View divider1; + @BindView(R.id.flair_custom_text_view_submit_crosspost_activity) + CustomTextView flairTextView; + @BindView(R.id.spoiler_custom_text_view_submit_crosspost_activity) + CustomTextView spoilerTextView; + @BindView(R.id.nsfw_custom_text_view_submit_crosspost_activity) + CustomTextView nsfwTextView; + @BindView(R.id.divider_2_submit_crosspost_activity) + View divider2; + @BindView(R.id.post_title_edit_text_submit_crosspost_activity) + EditText titleEditText; + @BindView(R.id.divider_3_submit_crosspost_activity) + View divider3; + @BindView(R.id.post_content_text_view_submit_crosspost_activity) + TextView contentTextView; + @BindView(R.id.frame_layout_submit_crosspost_activity) + FrameLayout frameLayout; + @BindView(R.id.image_view_submit_crosspost_activity) + SubsamplingScaleImageView imageView; + @BindView(R.id.play_button_image_view_submit_crosspost_activity) + ImageView playButton; + @Inject + @Named("no_oauth") + Retrofit mRetrofit; + @Inject + @Named("oauth") + Retrofit mOauthRetrofit; + @Inject + RedditDataRoomDatabase mRedditDataRoomDatabase; + @Inject + @Named("default") + SharedPreferences mSharedPreferences; + @Inject + CustomThemeWrapper mCustomThemeWrapper; + private boolean mNullAccessToken = false; + private String mAccessToken; + private Post post; + private String iconUrl; + private String subredditName; + private boolean subredditSelected = false; + private boolean subredditIsUser; + private boolean loadSubredditIconSuccessful = true; + private boolean isPosting; + private int primaryTextColor; + private int flairBackgroundColor; + private int flairTextColor; + private int spoilerBackgroundColor; + private int spoilerTextColor; + private int nsfwBackgroundColor; + private int nsfwTextColor; + private Flair flair; + private boolean isSpoiler = false; + private boolean isNSFW = false; + private Resources resources; + private Menu mMenu; + private RequestManager mGlide; + private FlairBottomSheetFragment flairSelectionBottomSheetFragment; + private Snackbar mPostingSnackbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + ((Infinity) getApplication()).getAppComponent().inject(this); + + setImmersiveModeNotApplicable(); + + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_submit_crosspost); + + ButterKnife.bind(this); + + EventBus.getDefault().register(this); + + applyCustomTheme(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && isChangeStatusBarIconColor()) { + addOnOffsetChangedListener(appBarLayout); + } + + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + mGlide = Glide.with(this); + + mPostingSnackbar = Snackbar.make(coordinatorLayout, R.string.posting, Snackbar.LENGTH_INDEFINITE); + + resources = getResources(); + + post = getIntent().getParcelableExtra(EXTRA_POST); + + if (savedInstanceState != null) { + mNullAccessToken = savedInstanceState.getBoolean(NULL_ACCESS_TOKEN_STATE); + mAccessToken = savedInstanceState.getString(ACCESS_TOKEN_STATE); + + if (!mNullAccessToken && mAccessToken == null) { + getCurrentAccount(); + } + + subredditName = savedInstanceState.getString(SUBREDDIT_NAME_STATE); + iconUrl = savedInstanceState.getString(SUBREDDIT_ICON_STATE); + subredditSelected = savedInstanceState.getBoolean(SUBREDDIT_SELECTED_STATE); + subredditIsUser = savedInstanceState.getBoolean(SUBREDDIT_IS_USER_STATE); + loadSubredditIconSuccessful = savedInstanceState.getBoolean(LOAD_SUBREDDIT_ICON_STATE); + isPosting = savedInstanceState.getBoolean(IS_POSTING_STATE); + flair = savedInstanceState.getParcelable(FLAIR_STATE); + isSpoiler = savedInstanceState.getBoolean(IS_SPOILER_STATE); + isNSFW = savedInstanceState.getBoolean(IS_NSFW_STATE); + + if (subredditName != null) { + subredditNameTextView.setTextColor(primaryTextColor); + subredditNameTextView.setText(subredditName); + flairTextView.setVisibility(View.VISIBLE); + if (!loadSubredditIconSuccessful) { + loadSubredditIcon(); + } + } + displaySubredditIcon(); + + if (isPosting) { + mPostingSnackbar.show(); + } + + if (flair != null) { + flairTextView.setText(flair.getText()); + flairTextView.setBackgroundColor(flairBackgroundColor); + flairTextView.setBorderColor(flairBackgroundColor); + flairTextView.setTextColor(flairTextColor); + } + if (isSpoiler) { + spoilerTextView.setBackgroundColor(spoilerBackgroundColor); + spoilerTextView.setBorderColor(spoilerBackgroundColor); + spoilerTextView.setTextColor(spoilerTextColor); + } + if (isNSFW) { + nsfwTextView.setBackgroundColor(nsfwBackgroundColor); + nsfwTextView.setBorderColor(nsfwBackgroundColor); + nsfwTextView.setTextColor(nsfwTextColor); + } + } else { + getCurrentAccount(); + + isPosting = false; + + mGlide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .into(iconGifImageView); + + if (post.isSpoiler()) { + spoilerTextView.setBackgroundColor(spoilerBackgroundColor); + spoilerTextView.setBorderColor(spoilerBackgroundColor); + spoilerTextView.setTextColor(spoilerTextColor); + } + if (post.isNSFW()) { + nsfwTextView.setBackgroundColor(nsfwBackgroundColor); + nsfwTextView.setBorderColor(nsfwBackgroundColor); + nsfwTextView.setTextColor(nsfwTextColor); + } + + titleEditText.setText(post.getTitle()); + } + + if (post.getPostType() == Post.TEXT_TYPE) { + contentTextView.setVisibility(View.VISIBLE); + contentTextView.setText(post.getSelfTextPlain()); + } else if (post.getPostType() == Post.LINK_TYPE || post.getPostType() == Post.NO_PREVIEW_LINK_TYPE) { + contentTextView.setVisibility(View.VISIBLE); + contentTextView.setText(post.getUrl()); + } else if (post.getPostType() == Post.GIF_TYPE || post.getPostType() == Post.GALLERY_TYPE || post.getPostType() == Post.IMAGE_TYPE) { + frameLayout.setVisibility(View.VISIBLE); + mGlide.asBitmap().load(post.getPreviewUrl()).into(new CustomTarget<Bitmap>() { + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { + imageView.setImage(ImageSource.bitmap(resource)); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + } else if (post.getPostType() == Post.VIDEO_TYPE) { + frameLayout.setVisibility(View.VISIBLE); + mGlide.asBitmap().load(post.getPreviewUrl()).into(new CustomTarget<Bitmap>() { + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { + imageView.setImage(ImageSource.bitmap(resource)); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + playButton.setVisibility(View.VISIBLE); + } + + iconGifImageView.setOnClickListener(view -> { + Intent intent = new Intent(this, SubredditSelectionActivity.class); + startActivityForResult(intent, SUBREDDIT_SELECTION_REQUEST_CODE); + }); + + subredditNameTextView.setOnClickListener(view -> { + Intent intent = new Intent(this, SubredditSelectionActivity.class); + startActivityForResult(intent, SUBREDDIT_SELECTION_REQUEST_CODE); + }); + + rulesButton.setOnClickListener(view -> { + if (subredditName == null) { + Snackbar.make(coordinatorLayout, R.string.select_a_subreddit, Snackbar.LENGTH_SHORT).show(); + } else { + Intent intent = new Intent(this, RulesActivity.class); + if (subredditIsUser) { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, "u_" + subredditName); + } else { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, subredditName); + } + startActivity(intent); + } + }); + + flairTextView.setOnClickListener(view -> { + if (flair == null) { + flairSelectionBottomSheetFragment = new FlairBottomSheetFragment(); + Bundle bundle = new Bundle(); + bundle.putString(FlairBottomSheetFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + if (subredditIsUser) { + bundle.putString(FlairBottomSheetFragment.EXTRA_SUBREDDIT_NAME, "u_" + subredditName); + } else { + bundle.putString(FlairBottomSheetFragment.EXTRA_SUBREDDIT_NAME, subredditName); + } + flairSelectionBottomSheetFragment.setArguments(bundle); + flairSelectionBottomSheetFragment.show(getSupportFragmentManager(), flairSelectionBottomSheetFragment.getTag()); + } else { + flairTextView.setBackgroundColor(resources.getColor(android.R.color.transparent)); + flairTextView.setTextColor(primaryTextColor); + flairTextView.setText(getString(R.string.flair)); + flair = null; + } + }); + + spoilerTextView.setOnClickListener(view -> { + if (!isSpoiler) { + spoilerTextView.setBackgroundColor(spoilerBackgroundColor); + spoilerTextView.setBorderColor(spoilerBackgroundColor); + spoilerTextView.setTextColor(spoilerTextColor); + isSpoiler = true; + } else { + spoilerTextView.setBackgroundColor(resources.getColor(android.R.color.transparent)); + spoilerTextView.setTextColor(primaryTextColor); + isSpoiler = false; + } + }); + + nsfwTextView.setOnClickListener(view -> { + if (!isNSFW) { + nsfwTextView.setBackgroundColor(nsfwBackgroundColor); + nsfwTextView.setBorderColor(nsfwBackgroundColor); + nsfwTextView.setTextColor(nsfwTextColor); + isNSFW = true; + } else { + nsfwTextView.setBackgroundColor(resources.getColor(android.R.color.transparent)); + nsfwTextView.setTextColor(primaryTextColor); + isNSFW = false; + } + }); + } + + @Override + protected SharedPreferences getDefaultSharedPreferences() { + return mSharedPreferences; + } + + @Override + protected CustomThemeWrapper getCustomThemeWrapper() { + return mCustomThemeWrapper; + } + + @Override + protected void applyCustomTheme() { + coordinatorLayout.setBackgroundColor(mCustomThemeWrapper.getBackgroundColor()); + applyAppBarLayoutAndToolbarTheme(appBarLayout, toolbar); + int secondaryTextColor = mCustomThemeWrapper.getSecondaryTextColor(); + subredditNameTextView.setTextColor(secondaryTextColor); + rulesButton.setTextColor(mCustomThemeWrapper.getButtonTextColor()); + rulesButton.setBackgroundTintList(ColorStateList.valueOf(mCustomThemeWrapper.getColorPrimaryLightTheme())); + int dividerColor = mCustomThemeWrapper.getDividerColor(); + divider1.setBackgroundColor(dividerColor); + divider2.setBackgroundColor(dividerColor); + divider3.setBackgroundColor(dividerColor); + primaryTextColor = mCustomThemeWrapper.getPrimaryTextColor(); + flairBackgroundColor = mCustomThemeWrapper.getFlairBackgroundColor(); + flairTextColor = mCustomThemeWrapper.getFlairTextColor(); + spoilerBackgroundColor = mCustomThemeWrapper.getSpoilerBackgroundColor(); + spoilerTextColor = mCustomThemeWrapper.getSpoilerTextColor(); + nsfwBackgroundColor = mCustomThemeWrapper.getNsfwBackgroundColor(); + nsfwTextColor = mCustomThemeWrapper.getNsfwTextColor(); + flairTextView.setTextColor(primaryTextColor); + spoilerTextView.setTextColor(primaryTextColor); + nsfwTextView.setTextColor(primaryTextColor); + titleEditText.setTextColor(primaryTextColor); + titleEditText.setHintTextColor(secondaryTextColor); + contentTextView.setTextColor(primaryTextColor); + contentTextView.setHintTextColor(secondaryTextColor); + } + + private void getCurrentAccount() { + new GetCurrentAccountAsyncTask(mRedditDataRoomDatabase.accountDao(), account -> { + if (account == null) { + mNullAccessToken = true; + } else { + mAccessToken = account.getAccessToken(); + } + }).execute(); + } + + private void displaySubredditIcon() { + if (iconUrl != null && !iconUrl.equals("")) { + mGlide.load(iconUrl) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .error(mGlide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))) + .into(iconGifImageView); + } else { + mGlide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .into(iconGifImageView); + } + } + + private void loadSubredditIcon() { + new LoadSubredditIconAsyncTask(mRedditDataRoomDatabase, subredditName, mRetrofit, iconImageUrl -> { + iconUrl = iconImageUrl; + displaySubredditIcon(); + loadSubredditIconSuccessful = true; + }).execute(); + } + + private void promptAlertDialog(int titleResId, int messageResId) { + new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme) + .setTitle(titleResId) + .setMessage(messageResId) + .setPositiveButton(R.string.yes, (dialogInterface, i) + -> finish()) + .setNegativeButton(R.string.no, null) + .show(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.submit_crosspost_activity, menu); + applyMenuItemTheme(menu); + mMenu = menu; + if (isPosting) { + mMenu.findItem(R.id.action_send_submit_crosspost_activity).setEnabled(false); + mMenu.findItem(R.id.action_send_submit_crosspost_activity).getIcon().setAlpha(130); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + if (isPosting) { + promptAlertDialog(R.string.exit_when_submit, R.string.exit_when_submit_post_detail); + return true; + } else { + if (!titleEditText.getText().toString().equals("")) { + promptAlertDialog(R.string.discard, R.string.discard_detail); + return true; + } + } + finish(); + return true; + case R.id.action_send_submit_crosspost_activity: + if (!subredditSelected) { + Snackbar.make(coordinatorLayout, R.string.select_a_subreddit, Snackbar.LENGTH_SHORT).show(); + return true; + } + + if (titleEditText.getText() == null || titleEditText.getText().toString().equals("")) { + Snackbar.make(coordinatorLayout, R.string.title_required, Snackbar.LENGTH_SHORT).show(); + return true; + } + + isPosting = true; + + item.setEnabled(false); + item.getIcon().setAlpha(130); + + mPostingSnackbar.show(); + + String subredditName; + if (subredditIsUser) { + subredditName = "u_" + subredditNameTextView.getText().toString(); + } else { + subredditName = subredditNameTextView.getText().toString(); + } + + Intent intent = new Intent(this, SubmitPostService.class); + intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken); + intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName); + intent.putExtra(SubmitPostService.EXTRA_TITLE, titleEditText.getText().toString()); + if (post.isCrosspost()) { + intent.putExtra(SubmitPostService.EXTRA_CONTENT, "t3_" + post.getCrosspostParentId()); + } else { + intent.putExtra(SubmitPostService.EXTRA_CONTENT, post.getFullName()); + } + intent.putExtra(SubmitPostService.EXTRA_KIND, APIUtils.KIND_CROSSPOST); + intent.putExtra(SubmitPostService.EXTRA_FLAIR, flair); + intent.putExtra(SubmitPostService.EXTRA_IS_SPOILER, isSpoiler); + intent.putExtra(SubmitPostService.EXTRA_IS_NSFW, isNSFW); + intent.putExtra(SubmitPostService.EXTRA_POST_TYPE, SubmitPostService.EXTRA_POST_TYPE_CROSSPOST); + startService(intent); + + return true; + } + + return false; + } + + @Override + public void onBackPressed() { + if (isPosting) { + promptAlertDialog(R.string.exit_when_submit, R.string.exit_when_submit_post_detail); + } else { + if (!titleEditText.getText().toString().equals("")) { + promptAlertDialog(R.string.discard, R.string.discard_detail); + } else { + finish(); + } + } + } + + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(SUBREDDIT_NAME_STATE, subredditName); + outState.putString(SUBREDDIT_ICON_STATE, iconUrl); + outState.putBoolean(SUBREDDIT_SELECTED_STATE, subredditSelected); + outState.putBoolean(SUBREDDIT_IS_USER_STATE, subredditIsUser); + outState.putBoolean(LOAD_SUBREDDIT_ICON_STATE, loadSubredditIconSuccessful); + outState.putBoolean(IS_POSTING_STATE, isPosting); + outState.putParcelable(FLAIR_STATE, flair); + outState.putBoolean(IS_SPOILER_STATE, isSpoiler); + outState.putBoolean(IS_NSFW_STATE, isNSFW); + outState.putBoolean(NULL_ACCESS_TOKEN_STATE, mNullAccessToken); + outState.putString(ACCESS_TOKEN_STATE, mAccessToken); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == SUBREDDIT_SELECTION_REQUEST_CODE) { + if (resultCode == RESULT_OK) { + subredditName = data.getExtras().getString(SubredditSelectionActivity.EXTRA_RETURN_SUBREDDIT_NAME); + iconUrl = data.getExtras().getString(SubredditSelectionActivity.EXTRA_RETURN_SUBREDDIT_ICON_URL); + subredditSelected = true; + subredditIsUser = data.getExtras().getBoolean(SubredditSelectionActivity.EXTRA_RETURN_SUBREDDIT_IS_USER); + + subredditNameTextView.setTextColor(primaryTextColor); + subredditNameTextView.setText(subredditName); + displaySubredditIcon(); + + flairTextView.setVisibility(View.VISIBLE); + flairTextView.setBackgroundColor(resources.getColor(android.R.color.transparent)); + flairTextView.setTextColor(primaryTextColor); + flairTextView.setText(getString(R.string.flair)); + flair = null; + } + } + } + + @Override + protected void onDestroy() { + EventBus.getDefault().unregister(this); + super.onDestroy(); + } + + @Override + public void flairSelected(Flair flair) { + this.flair = flair; + flairTextView.setText(flair.getText()); + flairTextView.setBackgroundColor(flairBackgroundColor); + flairTextView.setBorderColor(flairBackgroundColor); + flairTextView.setTextColor(flairTextColor); + } + + @Subscribe + public void onAccountSwitchEvent(SwitchAccountEvent event) { + finish(); + } + + @Subscribe + public void onSubmitTextPostEvent(SubmitCrosspostEvent submitCrosspostEvent) { + isPosting = false; + mPostingSnackbar.dismiss(); + if (submitCrosspostEvent.postSuccess) { + Intent intent = new Intent(this, ViewPostDetailActivity.class); + intent.putExtra(ViewPostDetailActivity.EXTRA_POST_DATA, submitCrosspostEvent.post); + startActivity(intent); + finish(); + } else { + mMenu.findItem(R.id.action_send_post_text_activity).setEnabled(true); + mMenu.findItem(R.id.action_send_post_text_activity).getIcon().setAlpha(255); + if (submitCrosspostEvent.errorMessage == null || submitCrosspostEvent.errorMessage.equals("")) { + Snackbar.make(coordinatorLayout, R.string.post_failed, Snackbar.LENGTH_SHORT).show(); + } else { + Snackbar.make(coordinatorLayout, submitCrosspostEvent.errorMessage.substring(0, 1).toUpperCase() + + submitCrosspostEvent.errorMessage.substring(1), Snackbar.LENGTH_SHORT).show(); + } + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewImageOrGifActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewImageOrGifActivity.java index 5cea5c59..32a3ab0d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewImageOrGifActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewImageOrGifActivity.java @@ -52,8 +52,8 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; +import ml.docilealligator.infinityforreddit.AsyncTask.SaveBitmapImageToFileAsyncTask; import ml.docilealligator.infinityforreddit.AsyncTask.SaveGIFToFileAsyncTask; -import ml.docilealligator.infinityforreddit.AsyncTask.SaveImageToFileAsyncTask; import ml.docilealligator.infinityforreddit.BottomSheetFragment.SetAsWallpaperBottomSheetFragment; import ml.docilealligator.infinityforreddit.BuildConfig; import ml.docilealligator.infinityforreddit.Font.ContentFontFamily; @@ -63,9 +63,8 @@ import ml.docilealligator.infinityforreddit.Font.FontStyle; import ml.docilealligator.infinityforreddit.Font.TitleFontFamily; import ml.docilealligator.infinityforreddit.Font.TitleFontStyle; import ml.docilealligator.infinityforreddit.Infinity; -import ml.docilealligator.infinityforreddit.MediaDownloader; -import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Service.DownloadMediaService; import ml.docilealligator.infinityforreddit.SetAsWallpaperCallback; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.WallpaperSetter; @@ -86,7 +85,6 @@ public class ViewImageOrGifActivity extends AppCompatActivity implements SetAsWa @Inject @Named("default") SharedPreferences mSharedPreferences; - private MediaDownloader mediaDownloader; private boolean isActionBarHidden = false; private boolean isDownloading = false; private RequestManager glide; @@ -133,8 +131,6 @@ public class ViewImageOrGifActivity extends AppCompatActivity implements SetAsWa Slidr.attach(this, new SlidrConfig.Builder().position(SlidrPosition.VERTICAL).distanceThreshold(0.125f).build()); - mediaDownloader = new MediaDownloaderImpl(); - glide = Glide.with(this); Intent intent = getIntent(); @@ -224,7 +220,7 @@ public class ViewImageOrGifActivity extends AppCompatActivity implements SetAsWa public void onImageLoaded() { view.setDoubleTapZoomDpi(70); view.setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_FIXED); - view.setQuickScaleEnabled(false); + view.setQuickScaleEnabled(true); } @Override @@ -292,15 +288,14 @@ public class ViewImageOrGifActivity extends AppCompatActivity implements SetAsWa // Permission is not granted // No explanation needed; request the permission - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); } else { // Permission has already been granted - mediaDownloader.download(mImageUrl, mImageFileName, this); + download(); } } else { - mediaDownloader.download(mImageUrl, mImageFileName, this); + download(); } return true; @@ -336,6 +331,21 @@ public class ViewImageOrGifActivity extends AppCompatActivity implements SetAsWa return false; } + private void download() { + isDownloading = false; + + Intent intent = new Intent(this, DownloadMediaService.class); + intent.putExtra(DownloadMediaService.EXTRA_URL, mImageUrl); + intent.putExtra(DownloadMediaService.EXTRA_MEDIA_TYPE, isGif ? DownloadMediaService.EXTRA_MEDIA_TYPE_GIF : DownloadMediaService.EXTRA_MEDIA_TYPE_IMAGE); + intent.putExtra(DownloadMediaService.EXTRA_FILE_NAME, mImageFileName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(intent); + } else { + startService(intent); + } + Toast.makeText(this, R.string.download_started, Toast.LENGTH_SHORT).show(); + } + private void shareImage() { glide.asBitmap().load(mImageUrl).into(new CustomTarget<Bitmap>() { @@ -343,8 +353,8 @@ public class ViewImageOrGifActivity extends AppCompatActivity implements SetAsWa public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { if (getExternalCacheDir() != null) { Toast.makeText(ViewImageOrGifActivity.this, R.string.save_image_first, Toast.LENGTH_SHORT).show(); - new SaveImageToFileAsyncTask(resource, getExternalCacheDir().getPath(), mImageFileName, - new SaveImageToFileAsyncTask.SaveImageToFileAsyncTaskListener() { + new SaveBitmapImageToFileAsyncTask(resource, getExternalCacheDir().getPath(), mImageFileName, + new SaveBitmapImageToFileAsyncTask.SaveBitmapImageToFileAsyncTaskListener() { @Override public void saveSuccess(File imageFile) { Uri uri = FileProvider.getUriForFile(ViewImageOrGifActivity.this, @@ -421,10 +431,10 @@ public class ViewImageOrGifActivity extends AppCompatActivity implements SetAsWa if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + isDownloading = false; } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && isDownloading) { - mediaDownloader.download(mImageUrl, mImageFileName, this); + download(); } - isDownloading = false; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewMultiRedditDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewMultiRedditDetailActivity.java index 8e172c23..b2280232 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewMultiRedditDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewMultiRedditDetailActivity.java @@ -164,7 +164,6 @@ public class ViewMultiRedditDetailActivity extends BaseActivity implements SortT sortTypeBottomSheetFragment = new SortTypeBottomSheetFragment(); Bundle bottomSheetBundle = new Bundle(); bottomSheetBundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, true); - bottomSheetBundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_RANDOM_TYPE, true); sortTypeBottomSheetFragment.setArguments(bottomSheetBundle); sortTimeBottomSheetFragment = new SortTimeBottomSheetFragment(); @@ -193,6 +192,7 @@ public class ViewMultiRedditDetailActivity extends BaseActivity implements SortT bundle.putInt(PostFragment.EXTRA_POST_TYPE, PostDataSource.TYPE_MULTI_REDDIT); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); mFragment.setArguments(bundle); getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_view_multi_reddit_detail_activity, mFragment).commit(); } @@ -304,13 +304,6 @@ public class ViewMultiRedditDetailActivity extends BaseActivity implements SortT @Override public void sortTypeSelected(SortType sortType) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_MULTI_REDDIT_POST_BASE + multiPath, - sortType.getType().name()).apply(); - if (sortType.getTime() != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_MULTI_REDDIT_POST_BASE + multiPath, - sortType.getTime().name()).apply(); - } - ((PostFragment) mFragment).changeSortType(sortType); displaySortType(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java index 0fbc96b2..062d7f5b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java @@ -247,7 +247,7 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); params.bottomMargin = navBarHeight; fab.setLayoutParams(params); - mRecyclerView.setPadding(0, 0, 0, navBarHeight); + mRecyclerView.setPadding(0, 0, 0, navBarHeight + mRecyclerView.getPaddingBottom()); showToast = true; } } @@ -387,6 +387,22 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS } @Override + protected void onResume() { + super.onResume(); + if (mAdapter != null && mRecyclerView != null) { + mRecyclerView.onWindowVisibilityChanged(View.VISIBLE); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mAdapter != null && mRecyclerView != null) { + mRecyclerView.onWindowVisibilityChanged(View.GONE); + } + } + + @Override public SharedPreferences getDefaultSharedPreferences() { return mSharedPreferences; } @@ -542,8 +558,6 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS hideItem.setVisible(true); hideItem.setTitle(R.string.action_hide_post); } - - mMenu.findItem(R.id.action_report_view_post_detail_activity).setVisible(true); } else { saveItem.setVisible(false); hideItem.setVisible(false); @@ -1440,6 +1454,10 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS flairBottomSheetFragment.show(getSupportFragmentManager(), flairBottomSheetFragment.getTag()); return true; case R.id.action_report_view_post_detail_activity: + if (mAccessToken == null) { + Toast.makeText(this, R.string.login_first, Toast.LENGTH_SHORT).show(); + return true; + } Intent intent = new Intent(this, ReportActivity.class); intent.putExtra(ReportActivity.EXTRA_SUBREDDIT_NAME, mPost.getSubredditName()); intent.putExtra(ReportActivity.EXTRA_THING_FULLNAME, mPost.getFullName()); @@ -1448,6 +1466,11 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS case R.id.action_see_removed_view_post_detail_activity: showRemovedPost(); return true; + case R.id.action_crosspost_view_post_detail_activity: + Intent submitCrosspostIntent = new Intent(this, SubmitCrosspostActivity.class); + submitCrosspostIntent.putExtra(SubmitCrosspostActivity.EXTRA_POST, mPost); + startActivity(submitCrosspostIntent); + return true; case android.R.id.home: onBackPressed(); return true; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewSubredditDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewSubredditDetailActivity.java index 3c8625c7..2230f81f 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewSubredditDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewSubredditDetailActivity.java @@ -904,6 +904,7 @@ public class ViewSubredditDetailActivity extends BaseActivity implements SortTyp bundle.putInt(PostFragment.EXTRA_POST_TYPE, PostDataSource.TYPE_SUBREDDIT); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; } @@ -988,11 +989,6 @@ public class ViewSubredditDetailActivity extends BaseActivity implements SortTyp public void changeSortType(SortType sortType) { if (postFragment != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_SUBREDDIT_POST_BASE + subredditName, sortType.getType().name()).apply(); - if (sortType.getTime() != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_SUBREDDIT_POST_BASE + subredditName, sortType.getTime().name()).apply(); - } - postFragment.changeSortType(sortType); displaySortTypeInToolbar(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewUserDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewUserDetailActivity.java index 426f6504..e2099faa 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewUserDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewUserDetailActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.content.res.Resources; +import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; @@ -56,29 +57,30 @@ import ml.docilealligator.infinityforreddit.AppBarStateChangeListener; import ml.docilealligator.infinityforreddit.AsyncTask.CheckIsFollowingUserAsyncTask; import ml.docilealligator.infinityforreddit.AsyncTask.GetCurrentAccountAsyncTask; import ml.docilealligator.infinityforreddit.AsyncTask.SwitchAccountAsyncTask; +import ml.docilealligator.infinityforreddit.BottomSheetFragment.PostLayoutBottomSheetFragment; +import ml.docilealligator.infinityforreddit.BottomSheetFragment.SortTimeBottomSheetFragment; +import ml.docilealligator.infinityforreddit.BottomSheetFragment.UserThingSortTypeBottomSheetFragment; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.DeleteThing; import ml.docilealligator.infinityforreddit.Event.ChangeNSFWEvent; import ml.docilealligator.infinityforreddit.Event.SwitchAccountEvent; -import ml.docilealligator.infinityforreddit.User.FetchUserData; import ml.docilealligator.infinityforreddit.Fragment.CommentsListingFragment; import ml.docilealligator.infinityforreddit.Fragment.PostFragment; -import ml.docilealligator.infinityforreddit.BottomSheetFragment.PostLayoutBottomSheetFragment; -import ml.docilealligator.infinityforreddit.BottomSheetFragment.SortTimeBottomSheetFragment; -import ml.docilealligator.infinityforreddit.BottomSheetFragment.UserThingSortTypeBottomSheetFragment; import ml.docilealligator.infinityforreddit.FragmentCommunicator; import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.Message.ReadMessage; import ml.docilealligator.infinityforreddit.Post.PostDataSource; import ml.docilealligator.infinityforreddit.R; -import ml.docilealligator.infinityforreddit.Message.ReadMessage; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.SortTypeSelectionCallback; import ml.docilealligator.infinityforreddit.SubscribedUserDatabase.SubscribedUserDao; +import ml.docilealligator.infinityforreddit.User.BlockUser; +import ml.docilealligator.infinityforreddit.User.FetchUserData; import ml.docilealligator.infinityforreddit.User.UserDao; import ml.docilealligator.infinityforreddit.User.UserData; -import ml.docilealligator.infinityforreddit.User.UserViewModel; import ml.docilealligator.infinityforreddit.User.UserFollowing; +import ml.docilealligator.infinityforreddit.User.UserViewModel; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.Utils.Utils; import pl.droidsonroids.gif.GifImageView; @@ -653,10 +655,44 @@ public class ViewUserDetailActivity extends BaseActivity implements SortTypeSele } return true; case R.id.action_send_private_message_view_user_detail_activity: + if (mAccessToken == null) { + Toast.makeText(this, R.string.login_first, Toast.LENGTH_SHORT).show(); + return true; + } + Intent pmIntent = new Intent(this, SendPrivateMessageActivity.class); pmIntent.putExtra(SendPrivateMessageActivity.EXTRA_RECIPIENT_USERNAME, username); startActivity(pmIntent); return true; + case R.id.action_report_view_user_detail_activity: + Intent reportIntent = new Intent(this, LinkResolverActivity.class); + reportIntent.setData(Uri.parse("https://www.reddithelp.com/en/categories/rules-reporting/account-and-community-restrictions/what-should-i-do-if-i-see-something-i")); + startActivity(reportIntent); + return true; + case R.id.action_block_user_view_user_detail_activity: + if (mAccessToken == null) { + Toast.makeText(this, R.string.login_first, Toast.LENGTH_SHORT).show(); + return true; + } + + new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.block_user) + .setMessage(R.string.are_you_sure) + .setPositiveButton(R.string.yes, (dialogInterface, i) + -> BlockUser.blockUser(mOauthRetrofit, mAccessToken, username, new BlockUser.BlockUserListener() { + @Override + public void success() { + Toast.makeText(ViewUserDetailActivity.this, R.string.block_user_success, Toast.LENGTH_SHORT).show(); + } + + @Override + public void failed() { + Toast.makeText(ViewUserDetailActivity.this, R.string.block_user_failed, Toast.LENGTH_SHORT).show(); + } + })) + .setNegativeButton(R.string.no, null) + .show(); + return true; } return false; } @@ -783,6 +819,7 @@ public class ViewUserDetailActivity extends BaseActivity implements SortTypeSele bundle.putString(PostFragment.EXTRA_USER_WHERE, PostDataSource.USER_WHERE_SUBMITTED); bundle.putInt(PostFragment.EXTRA_FILTER, PostFragment.EXTRA_NO_FILTER); bundle.putString(PostFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(PostFragment.EXTRA_ACCOUNT_NAME, mAccountName); fragment.setArguments(bundle); return fragment; } @@ -871,11 +908,6 @@ public class ViewUserDetailActivity extends BaseActivity implements SortTypeSele public void changeSortType(SortType sortType) { if (viewPager.getCurrentItem() == 0) { if (postFragment != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_USER_POST_BASE + username, sortType.getType().name()).apply(); - if(sortType.getTime() != null) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_USER_POST_BASE + username, sortType.getTime().name()).apply(); - } - postFragment.changeSortType(sortType); } } else { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewVideoActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewVideoActivity.java index 82621a6c..0ff6ee0c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewVideoActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewVideoActivity.java @@ -59,9 +59,8 @@ import ml.docilealligator.infinityforreddit.Font.ContentFontFamily; import ml.docilealligator.infinityforreddit.Font.FontFamily; import ml.docilealligator.infinityforreddit.Font.TitleFontFamily; import ml.docilealligator.infinityforreddit.Infinity; -import ml.docilealligator.infinityforreddit.MediaDownloader; -import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Service.DownloadMediaService; import ml.docilealligator.infinityforreddit.Service.DownloadRedditVideoService; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import retrofit2.Retrofit; @@ -98,7 +97,6 @@ public class ViewVideoActivity extends AppCompatActivity { private Uri mVideoUri; private SimpleExoPlayer player; private DataSource.Factory dataSourceFactory; - private MediaDownloader mediaDownloader; private String videoDownloadUrl; private String videoFileName; @@ -173,8 +171,6 @@ public class ViewVideoActivity extends AppCompatActivity { overridePendingTransition(0, slide); }); - mediaDownloader = new MediaDownloaderImpl(); - Intent intent = getIntent(); mVideoUri = intent.getData(); postTitle = intent.getStringExtra(EXTRA_POST_TITLE); @@ -374,6 +370,10 @@ public class ViewVideoActivity extends AppCompatActivity { finish(); return true; case R.id.action_download_view_video_activity: + if (isDownloading) { + return false; + } + if (videoDownloadUrl == null) { Toast.makeText(this, R.string.fetching_video_info_please_wait, Toast.LENGTH_SHORT).show(); return true; @@ -434,7 +434,15 @@ public class ViewVideoActivity extends AppCompatActivity { isDownloading = false; if (videoType != VIDEO_TYPE_NORMAL) { - mediaDownloader.download(videoDownloadUrl, videoFileName, this); + Intent intent = new Intent(this, DownloadMediaService.class); + intent.putExtra(DownloadMediaService.EXTRA_URL, videoDownloadUrl); + intent.putExtra(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_VIDEO); + intent.putExtra(DownloadMediaService.EXTRA_FILE_NAME, videoFileName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(intent); + } else { + startService(intent); + } } else { Intent intent = new Intent(this, DownloadRedditVideoService.class); intent.putExtra(DownloadRedditVideoService.EXTRA_VIDEO_URL, videoDownloadUrl); @@ -446,8 +454,8 @@ public class ViewVideoActivity extends AppCompatActivity { } else { startService(intent); } - Toast.makeText(this, R.string.download_started, Toast.LENGTH_SHORT).show(); } + Toast.makeText(this, R.string.download_started, Toast.LENGTH_SHORT).show(); } @Override diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java index fb69a601..3ba327aa 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java @@ -5,6 +5,7 @@ import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; @@ -12,7 +13,11 @@ import android.net.Uri; import android.os.Bundle; import android.text.Html; import android.text.Spannable; +import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.TextPaint; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; import android.text.style.SuperscriptSpan; import android.text.util.Linkify; import android.view.LayoutInflater; @@ -56,6 +61,8 @@ import org.commonmark.ext.gfm.tables.TableBlock; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import butterknife.BindView; import butterknife.ButterKnife; @@ -77,7 +84,6 @@ import io.noties.markwon.recycler.MarkwonAdapter; import io.noties.markwon.recycler.table.TableEntry; import io.noties.markwon.recycler.table.TableEntryPlugin; import io.noties.markwon.simple.ext.SimpleExtPlugin; -import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import jp.wasabeef.glide.transformations.BlurTransformation; import jp.wasabeef.glide.transformations.RoundedCornersTransformation; import ml.docilealligator.infinityforreddit.Activity.CommentActivity; @@ -236,10 +242,63 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy mRedditDataRoomDatabase = redditDataRoomDatabase; mGlide = glide; mSecondaryTextColor = customThemeWrapper.getSecondaryTextColor(); + mCommentTextColor = customThemeWrapper.getCommentColor(); int markdownColor = customThemeWrapper.getPostContentColor(); int linkColor = customThemeWrapper.getLinkColor(); mPostDetailMarkwon = Markwon.builder(mActivity) .usePlugin(new AbstractMarkwonPlugin() { + @NonNull + @Override + public String processMarkdown(@NonNull String markdown) { + StringBuilder markdownStringBuilder = new StringBuilder(markdown); + Pattern spoilerPattern = Pattern.compile(">![\\S\\s]*?!<"); + Matcher matcher = spoilerPattern.matcher(markdownStringBuilder); + while (matcher.find()) { + markdownStringBuilder.replace(matcher.start(), matcher.start() + 1, ">"); + } + return super.processMarkdown(markdownStringBuilder.toString()); + } + + @Override + public void afterSetText(@NonNull TextView textView) { + textView.setHighlightColor(Color.TRANSPARENT); + SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText().toString()); + Pattern spoilerPattern = Pattern.compile(">![\\S\\s]*?!<"); + Matcher matcher = spoilerPattern.matcher(markdownStringBuilder); + int start = 0; + boolean find = false; + while (matcher.find(start)) { + find = true; + markdownStringBuilder.delete(matcher.end() - 2, matcher.end()); + markdownStringBuilder.delete(matcher.start(), matcher.start() + 2); + ClickableSpan clickableSpan = new ClickableSpan() { + private boolean isShowing = false; + @Override + public void updateDrawState(@NonNull TextPaint ds) { + if (isShowing) { + super.updateDrawState(ds); + ds.setColor(markdownColor); + } else { + ds.bgColor = markdownColor; + ds.setColor(markdownColor); + } + ds.setUnderlineText(false); + } + + @Override + public void onClick(@NonNull View view) { + isShowing = !isShowing; + view.invalidate(); + } + }; + markdownStringBuilder.setSpan(clickableSpan, matcher.start(), matcher.end() - 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + start = matcher.end() - 4; + } + if (find) { + textView.setText(markdownStringBuilder); + } + } + @Override public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { textView.setTextColor(markdownColor); @@ -265,7 +324,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy } intent.putExtra(LinkResolverActivity.EXTRA_IS_NSFW, mPost.isNSFW()); mActivity.startActivity(intent); - }).urlProcessor(new UrlProcessorRelativeToAbsolute("https://www.reddit.com")); + }); } @Override @@ -276,15 +335,66 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy .usePlugin(StrikethroughPlugin.create()) .usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS)) .usePlugin(SimpleExtPlugin.create(plugin -> - plugin.addExtension(1, '^', (configuration, props) -> { - return new SuperscriptSpan(); - }) + plugin.addExtension(1, '^', (configuration, props) -> { + return new SuperscriptSpan(); + }) ) ) .usePlugin(TableEntryPlugin.create(mActivity)) .build(); mCommentMarkwon = Markwon.builder(mActivity) .usePlugin(new AbstractMarkwonPlugin() { + @NonNull + @Override + public String processMarkdown(@NonNull String markdown) { + StringBuilder markdownStringBuilder = new StringBuilder(markdown); + Pattern spoilerPattern = Pattern.compile(">![\\S\\s]*?!<"); + Matcher matcher = spoilerPattern.matcher(markdownStringBuilder); + while (matcher.find()) { + markdownStringBuilder.replace(matcher.start(), matcher.start() + 1, ">"); + } + return super.processMarkdown(markdownStringBuilder.toString()); + } + + @Override + public void afterSetText(@NonNull TextView textView) { + SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText().toString()); + Pattern spoilerPattern = Pattern.compile(">![\\S\\s]*?!<"); + Matcher matcher = spoilerPattern.matcher(markdownStringBuilder); + int start = 0; + boolean find = false; + while (matcher.find(start)) { + find = true; + markdownStringBuilder.delete(matcher.end() - 2, matcher.end()); + markdownStringBuilder.delete(matcher.start(), matcher.start() + 2); + ClickableSpan clickableSpan = new ClickableSpan() { + private boolean isShowing = false; + @Override + public void updateDrawState(@NonNull TextPaint ds) { + if (isShowing) { + super.updateDrawState(ds); + ds.setColor(mCommentTextColor); + } else { + ds.bgColor = mCommentTextColor; + ds.setColor(mCommentTextColor); + } + ds.setUnderlineText(false); + } + + @Override + public void onClick(@NonNull View view) { + isShowing = !isShowing; + view.invalidate(); + } + }; + markdownStringBuilder.setSpan(clickableSpan, matcher.start(), matcher.end() - 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + start = matcher.end() - 4; + } + if (find) { + textView.setText(markdownStringBuilder); + } + } + @Override public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { builder.linkResolver((view, link) -> { @@ -297,7 +407,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy } intent.putExtra(LinkResolverActivity.EXTRA_IS_NSFW, mPost.isNSFW()); mActivity.startActivity(intent); - }).urlProcessor(new UrlProcessorRelativeToAbsolute("https://www.reddit.com")); + }); } @Override @@ -371,7 +481,6 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy mCardViewColor = customThemeWrapper.getCardViewBackgroundColor(); mPostTitleColor = customThemeWrapper.getPostTitleColor(); mPrimaryTextColor = customThemeWrapper.getPrimaryTextColor(); - mCommentTextColor = customThemeWrapper.getCommentColor(); mDividerColor = customThemeWrapper.getDividerColor(); mCommentBackgroundColor = customThemeWrapper.getCommentBackgroundColor(); mPostTypeBackgroundColor = customThemeWrapper.getPostTypeBackgroundColor(); @@ -3253,6 +3362,8 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy } }); + commentMarkdownView.setMovementMethod(LinkMovementMethod.getInstance()); + if (mSwapTapAndLong) { if (mCommentToolbarHideOnClick) { View.OnLongClickListener hideToolbarOnLongClickListener = view -> hideToolbar(); @@ -3260,20 +3371,29 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy commentMarkdownView.setOnLongClickListener(hideToolbarOnLongClickListener); commentTimeTextView.setOnLongClickListener(hideToolbarOnLongClickListener); } - View.OnClickListener expandCommentsOnClickListener = view -> expandComments(); - commentMarkdownView.setOnClickListener(expandCommentsOnClickListener); - itemView.setOnClickListener(expandCommentsOnClickListener); + commentMarkdownView.setOnClickListener(view -> { + if (commentMarkdownView.getSelectionStart() == -1 && commentMarkdownView.getSelectionEnd() == -1) { + expandComments(); + } + }); + itemView.setOnClickListener(view -> expandComments()); } else { if (mCommentToolbarHideOnClick) { + commentMarkdownView.setOnClickListener(view -> { + if (commentMarkdownView.getSelectionStart() == -1 && commentMarkdownView.getSelectionEnd() == -1) { + hideToolbar(); + } + }); View.OnClickListener hideToolbarOnClickListener = view -> hideToolbar(); linearLayout.setOnClickListener(hideToolbarOnClickListener); - commentMarkdownView.setOnClickListener(hideToolbarOnClickListener); commentTimeTextView.setOnClickListener(hideToolbarOnClickListener); } View.OnLongClickListener expandsCommentsOnLongClickListener = view -> expandComments(); commentMarkdownView.setOnLongClickListener(expandsCommentsOnLongClickListener); itemView.setOnLongClickListener(expandsCommentsOnLongClickListener); } + commentMarkdownView.setMovementMethod(LinkMovementMethod.getInstance()); + commentMarkdownView.setHighlightColor(Color.TRANSPARENT); } private boolean expandComments() { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java index 349fb1b7..f5c59ca4 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java @@ -4,8 +4,14 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.ColorStateList; +import android.graphics.Color; import android.net.Uri; import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; import android.text.style.SuperscriptSpan; import android.text.util.Linkify; import android.view.LayoutInflater; @@ -27,6 +33,8 @@ import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import butterknife.BindView; import butterknife.ButterKnife; @@ -102,8 +110,63 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment super(DIFF_CALLBACK); mContext = context; mOauthRetrofit = oauthRetrofit; + mCommentColor = customThemeWrapper.getCommentColor(); mMarkwon = Markwon.builder(mContext) .usePlugin(new AbstractMarkwonPlugin() { + @NonNull + @Override + public String processMarkdown(@NonNull String markdown) { + StringBuilder markdownStringBuilder = new StringBuilder(markdown); + Pattern spoilerPattern = Pattern.compile(">![\\S\\s]*?!<"); + Matcher matcher = spoilerPattern.matcher(markdownStringBuilder); + while (matcher.find()) { + markdownStringBuilder.replace(matcher.start(), matcher.start() + 1, ">"); + } + return super.processMarkdown(markdownStringBuilder.toString()); + } + + @Override + public void afterSetText(@NonNull TextView textView) { + textView.setHighlightColor(Color.TRANSPARENT); + SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText().toString()); + Pattern spoilerPattern = Pattern.compile(">![\\S\\s]*?!<"); + Matcher matcher = spoilerPattern.matcher(markdownStringBuilder); + int start = 0; + boolean find = false; + while (matcher.find(start)) { + find = true; + markdownStringBuilder.delete(matcher.end() - 2, matcher.end()); + markdownStringBuilder.delete(matcher.start(), matcher.start() + 2); + int matcherStart = matcher.start(); + int matcherEnd = matcher.end(); + ClickableSpan clickableSpan = new ClickableSpan() { + private boolean isShowing = false; + @Override + public void updateDrawState(@NonNull TextPaint ds) { + if (isShowing) { + super.updateDrawState(ds); + ds.setColor(mCommentColor); + } else { + ds.bgColor = mCommentColor; + ds.setColor(mCommentColor); + } + ds.setUnderlineText(false); + } + + @Override + public void onClick(@NonNull View view) { + isShowing = !isShowing; + view.invalidate(); + } + }; + markdownStringBuilder.setSpan(clickableSpan, matcherStart, matcherEnd - 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + start = matcherEnd - 4; + } + if (find) { + textView.setText(markdownStringBuilder); + } + } + @Override public void configureTheme(@NonNull MarkwonTheme.Builder builder) { builder.linkColor(customThemeWrapper.getLinkColor()); @@ -250,8 +313,11 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment ((CommentViewHolder) holder).verticalBlock.setVisibility(View.GONE); - ((CommentViewHolder) holder).commentMarkdownView.setOnClickListener(view -> - ((CommentViewHolder) holder).linearLayout.callOnClick()); + ((CommentViewHolder) holder).commentMarkdownView.setOnClickListener(view -> { + if (((CommentViewHolder) holder).commentMarkdownView.getSelectionStart() == -1 && ((CommentViewHolder) holder).commentMarkdownView.getSelectionEnd() == -1) { + ((CommentViewHolder) holder).linearLayout.callOnClick(); + } + }); ((CommentViewHolder) holder).upvoteButton.setOnClickListener(view -> { if (mAccessToken == null) { @@ -542,6 +608,8 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment saveButton.setColorFilter(mCommentIconAndInfoColor, android.graphics.PorterDuff.Mode.SRC_IN); replyButton.setColorFilter(mCommentIconAndInfoColor, android.graphics.PorterDuff.Mode.SRC_IN); commentDivider.setBackgroundColor(mDividerColor); + + commentMarkdownView.setMovementMethod(LinkMovementMethod.getInstance()); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java index b558db87..7c7d8f53 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java @@ -30,6 +30,7 @@ import androidx.constraintlayout.widget.ConstraintSet; import androidx.core.graphics.drawable.DrawableCompat; import androidx.paging.PagedListAdapter; import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; @@ -607,11 +608,12 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView ((PostGalleryTypeViewHolder) holder).noPreviewLinkImageView.setVisibility(View.VISIBLE); } } else if (holder instanceof PostTextTypeViewHolder) { - if (post.getSelfTextPlainTrimmed() != null && !post.getSelfTextPlainTrimmed().equals("")) { + if (!post.isSpoiler() && post.getSelfTextPlainTrimmed() != null && !post.getSelfTextPlainTrimmed().equals("")) { ((PostTextTypeViewHolder) holder).contentTextView.setVisibility(View.VISIBLE); ((PostTextTypeViewHolder) holder).contentTextView.setText(post.getSelfTextPlainTrimmed()); } } + mCallback.currentlyBindItem(holder.getAdapterPosition()); } } else if (holder instanceof PostCompactBaseViewHolder) { Post post = getItem(position); @@ -864,6 +866,8 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView } else { ((PostCompactBaseViewHolder) holder).saveButton.setImageResource(R.drawable.ic_bookmark_border_grey_24dp); } + + mCallback.currentlyBindItem(holder.getAdapterPosition()); } } } @@ -1052,6 +1056,15 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView return super.getItemCount(); } + @Nullable + public Post getItemByPosition(int position) { + if (position >= 0 && super.getItemCount() > position) { + return super.getItem(position); + } + + return null; + } + public void setVoteButtonsPosition(boolean voteButtonsOnTheRight) { mVoteButtonsOnTheRight = voteButtonsOnTheRight; } @@ -1166,6 +1179,7 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView ((PostGalleryTypeViewHolder) holder).errorRelativeLayout.setVisibility(View.GONE); ((PostGalleryTypeViewHolder) holder).noPreviewLinkImageView.setVisibility(View.GONE); } else if (holder instanceof PostTextTypeViewHolder) { + ((PostTextTypeViewHolder) holder).contentTextView.setText(""); ((PostTextTypeViewHolder) holder).contentTextView.setVisibility(View.GONE); } @@ -1227,10 +1241,25 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView return null; } + public void onItemSwipe(RecyclerView.ViewHolder viewHolder, int direction) { + if (viewHolder instanceof PostBaseViewHolder) { + Post post = getItem(viewHolder.getAdapterPosition()); + if (post != null) { + if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { + ((PostBaseViewHolder) viewHolder).upvoteButton.performClick(); + } else { + ((PostBaseViewHolder) viewHolder).downvoteButton.performClick(); + } + } + } + } + public interface Callback { void retryLoadingMore(); void typeChipClicked(int filter); + + void currentlyBindItem(int position); } class PostBaseViewHolder extends RecyclerView.ViewHolder { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java index 3542c686..34695608 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java @@ -13,6 +13,7 @@ import ml.docilealligator.infinityforreddit.Activity.EditCommentActivity; import ml.docilealligator.infinityforreddit.Activity.EditMultiRedditActivity; import ml.docilealligator.infinityforreddit.Activity.EditPostActivity; import ml.docilealligator.infinityforreddit.Activity.FilteredThingActivity; +import ml.docilealligator.infinityforreddit.Activity.InboxActivity; import ml.docilealligator.infinityforreddit.Activity.LinkResolverActivity; import ml.docilealligator.infinityforreddit.Activity.LoginActivity; import ml.docilealligator.infinityforreddit.Activity.MainActivity; @@ -28,13 +29,13 @@ import ml.docilealligator.infinityforreddit.Activity.SearchSubredditsResultActiv import ml.docilealligator.infinityforreddit.Activity.SelectedSubredditsActivity; import ml.docilealligator.infinityforreddit.Activity.SendPrivateMessageActivity; import ml.docilealligator.infinityforreddit.Activity.SettingsActivity; +import ml.docilealligator.infinityforreddit.Activity.SubmitCrosspostActivity; import ml.docilealligator.infinityforreddit.Activity.SubredditMultiselectionActivity; import ml.docilealligator.infinityforreddit.Activity.SubredditSelectionActivity; import ml.docilealligator.infinityforreddit.Activity.SubscribedThingListingActivity; import ml.docilealligator.infinityforreddit.Activity.ThemePreviewActivity; import ml.docilealligator.infinityforreddit.Activity.ViewImageOrGifActivity; import ml.docilealligator.infinityforreddit.Activity.ViewImgurMediaActivity; -import ml.docilealligator.infinityforreddit.Activity.InboxActivity; import ml.docilealligator.infinityforreddit.Activity.ViewMultiRedditDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewPostDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewPrivateMessagesActivity; @@ -42,8 +43,8 @@ import ml.docilealligator.infinityforreddit.Activity.ViewRedditGalleryActivity; import ml.docilealligator.infinityforreddit.Activity.ViewSubredditDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewUserDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewVideoActivity; -import ml.docilealligator.infinityforreddit.Fragment.CommentsListingFragment; import ml.docilealligator.infinityforreddit.BottomSheetFragment.FlairBottomSheetFragment; +import ml.docilealligator.infinityforreddit.Fragment.CommentsListingFragment; import ml.docilealligator.infinityforreddit.Fragment.FollowedUsersListingFragment; import ml.docilealligator.infinityforreddit.Fragment.InboxFragment; import ml.docilealligator.infinityforreddit.Fragment.MultiRedditListingFragment; @@ -54,10 +55,12 @@ import ml.docilealligator.infinityforreddit.Fragment.SubscribedSubredditsListing import ml.docilealligator.infinityforreddit.Fragment.UserListingFragment; import ml.docilealligator.infinityforreddit.Fragment.ViewImgurVideoFragment; import ml.docilealligator.infinityforreddit.Fragment.ViewRedditGalleryVideoFragment; +import ml.docilealligator.infinityforreddit.Service.DownloadMediaService; import ml.docilealligator.infinityforreddit.Service.DownloadRedditVideoService; import ml.docilealligator.infinityforreddit.Service.SubmitPostService; import ml.docilealligator.infinityforreddit.Settings.AdvancedPreferenceFragment; import ml.docilealligator.infinityforreddit.Settings.CustomizeMainPageTabsFragment; +import ml.docilealligator.infinityforreddit.Settings.DownloadLocationPreferenceFragment; import ml.docilealligator.infinityforreddit.Settings.GesturesAndButtonsPreferenceFragment; import ml.docilealligator.infinityforreddit.Settings.MainPreferenceFragment; import ml.docilealligator.infinityforreddit.Settings.NotificationPreferenceFragment; @@ -167,8 +170,6 @@ public interface AppComponent { void inject(ReportActivity reportActivity); - void inject(CustomizeMainPageTabsFragment customizeMainPageTabsFragment); - void inject(ViewImgurMediaActivity viewImgurMediaActivity); void inject(ViewImgurVideoFragment viewImgurVideoFragment); @@ -188,4 +189,12 @@ public interface AppComponent { void inject(ViewRedditGalleryActivity viewRedditGalleryActivity); void inject(ViewRedditGalleryVideoFragment viewRedditGalleryVideoFragment); + + void inject(CustomizeMainPageTabsFragment customizeMainPageTabsFragment); + + void inject(DownloadMediaService downloadMediaService); + + void inject(DownloadLocationPreferenceFragment downloadLocationPreferenceFragment); + + void inject(SubmitCrosspostActivity submitCrosspostActivity); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java index d70a167d..a1dd3517 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java @@ -23,8 +23,8 @@ import im.ene.toro.exoplayer.ExoCreator; import im.ene.toro.exoplayer.MediaSourceBuilder; import im.ene.toro.exoplayer.ToroExo; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; -import ml.docilealligator.infinityforreddit.Utils.CustomThemeSharedPreferencesUtils; import ml.docilealligator.infinityforreddit.Utils.APIUtils; +import ml.docilealligator.infinityforreddit.Utils.CustomThemeSharedPreferencesUtils; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import okhttp3.ConnectionPool; import okhttp3.OkHttpClient; @@ -91,7 +91,7 @@ class AppModule { } @Provides - @Named("download_reddit_video") + @Named("download_media") @Singleton Retrofit provideDownloadRedditVideoRetrofit() { return new Retrofit.Builder() @@ -200,6 +200,18 @@ class AppModule { } @Provides + @Named("post_feed_scrolled_position_cache") + SharedPreferences providePostFeedScrolledPositionSharedPreferences() { + return mApplication.getSharedPreferences(SharedPreferencesUtils.FRONT_PAGE_SCROLLED_POSITION_SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE); + } + + @Provides + @Named("main_activity_tabs") + SharedPreferences provideMainActivityTabsSharedPreferences() { + return mApplication.getSharedPreferences(SharedPreferencesUtils.MAIN_PAGE_TABS_SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE); + } + + @Provides @Singleton CustomThemeWrapper provideCustomThemeWrapper(@Named("light_theme") SharedPreferences lightThemeSharedPreferences, @Named("dark_theme") SharedPreferences darkThemeSharedPreferences, diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/DeleteAllSortTypesAsyncTask.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/DeleteAllSortTypesAsyncTask.java index 153e0899..2e76b6c3 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/DeleteAllSortTypesAsyncTask.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/DeleteAllSortTypesAsyncTask.java @@ -31,16 +31,16 @@ public class DeleteAllSortTypesAsyncTask extends AsyncTask<Void, Void, Void> { for(Map.Entry<String,?> entry : keys.entrySet()){ String key = entry.getKey(); - if (key.startsWith(SharedPreferencesUtils.SORT_TYPE_BEST_POST) || key.startsWith(SharedPreferencesUtils.SORT_TIME_BEST_POST) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_ALL_POST) || key.startsWith(SharedPreferencesUtils.SORT_TIME_ALL_POST) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_POPULAR_POST) || key.startsWith(SharedPreferencesUtils.SORT_TIME_POPULAR_POST) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_SEARCH_POST) || key.startsWith(SharedPreferencesUtils.SORT_TIME_SEARCH_POST) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_SUBREDDIT_POST_BASE) || key.startsWith(SharedPreferencesUtils.SORT_TIME_SUBREDDIT_POST_BASE) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_MULTI_REDDIT_POST_BASE) || key.startsWith(SharedPreferencesUtils.SORT_TIME_MULTI_REDDIT_POST_BASE) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_USER_POST_BASE) || key.startsWith(SharedPreferencesUtils.SORT_TIME_USER_POST_BASE) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_USER_COMMENT) || key.startsWith(SharedPreferencesUtils.SORT_TIME_USER_COMMENT) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_SEARCH_SUBREDDIT) || key.startsWith(SharedPreferencesUtils.SORT_TYPE_SEARCH_USER) - || key.startsWith(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT)) { + if (key.contains(SharedPreferencesUtils.SORT_TYPE_BEST_POST) || key.contains(SharedPreferencesUtils.SORT_TIME_BEST_POST) + || key.contains(SharedPreferencesUtils.SORT_TYPE_ALL_POST_LEGACY) || key.contains(SharedPreferencesUtils.SORT_TIME_ALL_POST_LEGACY) + || key.contains(SharedPreferencesUtils.SORT_TYPE_POPULAR_POST_LEGACY) || key.contains(SharedPreferencesUtils.SORT_TIME_POPULAR_POST_LEGACY) + || key.contains(SharedPreferencesUtils.SORT_TYPE_SEARCH_POST) || key.contains(SharedPreferencesUtils.SORT_TIME_SEARCH_POST) + || key.contains(SharedPreferencesUtils.SORT_TYPE_SUBREDDIT_POST_BASE) || key.contains(SharedPreferencesUtils.SORT_TIME_SUBREDDIT_POST_BASE) + || key.contains(SharedPreferencesUtils.SORT_TYPE_MULTI_REDDIT_POST_BASE) || key.contains(SharedPreferencesUtils.SORT_TIME_MULTI_REDDIT_POST_BASE) + || key.contains(SharedPreferencesUtils.SORT_TYPE_USER_POST_BASE) || key.contains(SharedPreferencesUtils.SORT_TIME_USER_POST_BASE) + || key.contains(SharedPreferencesUtils.SORT_TYPE_USER_COMMENT) || key.contains(SharedPreferencesUtils.SORT_TIME_USER_COMMENT) + || key.contains(SharedPreferencesUtils.SORT_TYPE_SEARCH_SUBREDDIT) || key.contains(SharedPreferencesUtils.SORT_TYPE_SEARCH_USER) + || key.contains(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT)) { editor.remove(key); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/SaveImageToFileAsyncTask.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/SaveBitmapImageToFileAsyncTask.java index 65c1c199..f70a87be 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/SaveImageToFileAsyncTask.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/SaveBitmapImageToFileAsyncTask.java @@ -8,23 +8,23 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -public class SaveImageToFileAsyncTask extends AsyncTask<Void, Void, Void> { +public class SaveBitmapImageToFileAsyncTask extends AsyncTask<Void, Void, Void> { private Bitmap resource; private String cacheDirPath; private String fileName; - private SaveImageToFileAsyncTaskListener saveImageToFileAsyncTaskListener; + private SaveBitmapImageToFileAsyncTaskListener saveBitmapImageToFileAsyncTaskListener; private boolean saveSuccess = true; private File imageFile; - public SaveImageToFileAsyncTask(Bitmap resource, String cacheDirPath, String fileName, - SaveImageToFileAsyncTaskListener saveImageToFileAsyncTaskListener) { + public SaveBitmapImageToFileAsyncTask(Bitmap resource, String cacheDirPath, String fileName, + SaveBitmapImageToFileAsyncTaskListener saveBitmapImageToFileAsyncTaskListener) { this.resource = resource; this.cacheDirPath = cacheDirPath; this.fileName = fileName; - this.saveImageToFileAsyncTaskListener = saveImageToFileAsyncTaskListener; + this.saveBitmapImageToFileAsyncTaskListener = saveBitmapImageToFileAsyncTaskListener; } - public interface SaveImageToFileAsyncTaskListener { + public interface SaveBitmapImageToFileAsyncTaskListener { void saveSuccess(File imageFile); void saveFailed(); } @@ -47,9 +47,9 @@ public class SaveImageToFileAsyncTask extends AsyncTask<Void, Void, Void> { protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); if (saveSuccess) { - saveImageToFileAsyncTaskListener.saveSuccess(imageFile); + saveBitmapImageToFileAsyncTaskListener.saveSuccess(imageFile); } else { - saveImageToFileAsyncTaskListener.saveFailed(); + saveBitmapImageToFileAsyncTaskListener.saveFailed(); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/BottomSheetFragment/SortTypeBottomSheetFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/BottomSheetFragment/SortTypeBottomSheetFragment.java index ee5ba39f..d86bb207 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/BottomSheetFragment/SortTypeBottomSheetFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/BottomSheetFragment/SortTypeBottomSheetFragment.java @@ -29,15 +29,12 @@ import ml.docilealligator.infinityforreddit.SortTypeSelectionCallback; public class SortTypeBottomSheetFragment extends RoundedBottomSheetDialogFragment { public static final String EXTRA_NO_BEST_TYPE = "ENBT"; - public static final String EXTRA_NO_RANDOM_TYPE = "ENRT"; @BindView(R.id.best_type_text_view_sort_type_bottom_sheet_fragment) TextView bestTypeTextView; @BindView(R.id.hot_type_text_view_sort_type_bottom_sheet_fragment) TextView hotTypeTextView; @BindView(R.id.new_type_text_view_sort_type_bottom_sheet_fragment) TextView newTypeTextView; - @BindView(R.id.random_type_text_view_sort_type_bottom_sheet_fragment) - TextView randomTypeTextView; @BindView(R.id.rising_type_text_view_sort_type_bottom_sheet_fragment) TextView risingTypeTextView; @BindView(R.id.top_type_text_view_sort_type_bottom_sheet_fragment) @@ -79,15 +76,6 @@ public class SortTypeBottomSheetFragment extends RoundedBottomSheetDialogFragmen dismiss(); }); - if (getArguments() == null || (getArguments().containsKey(EXTRA_NO_RANDOM_TYPE) && getArguments().getBoolean(EXTRA_NO_RANDOM_TYPE))) { - randomTypeTextView.setVisibility(View.GONE); - } else { - randomTypeTextView.setOnClickListener(view -> { - ((SortTypeSelectionCallback) activity).sortTypeSelected(new SortType(SortType.Type.RANDOM)); - dismiss(); - }); - } - risingTypeTextView.setOnClickListener(view -> { ((SortTypeSelectionCallback) activity).sortTypeSelected(new SortType(SortType.Type.RISING)); dismiss(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CustomTheme/CustomThemeWrapper.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CustomTheme/CustomThemeWrapper.java index 3a30ba62..7dd17c41 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CustomTheme/CustomThemeWrapper.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CustomTheme/CustomThemeWrapper.java @@ -409,7 +409,7 @@ public class CustomThemeWrapper { public int getAwardedCommentBackgroundColor() { return getThemeSharedPreferences().getInt(CustomThemeSharedPreferencesUtils.AWARDED_COMMENT_BACKGROUND_COLOR, - getDefaultColor("#FFF162", "#FF6400", "#FF6400")); + getDefaultColor("#FFFFFF", "#242424", "#000000")); } public int getNavBarColor() { @@ -550,7 +550,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#8EDFBA"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FFF162"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#FFFFFF"); customTheme.navBarColor = Color.parseColor("#FFFFFF"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = true; @@ -635,7 +635,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#21C561"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FF6400"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#242424"); customTheme.navBarColor = Color.parseColor("#121212"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = false; @@ -720,7 +720,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#21C561"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FF6400"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#000000"); customTheme.navBarColor = Color.parseColor("#000000"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = false; @@ -805,7 +805,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#8EDFBA"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FFF162"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#FFFFFF"); customTheme.navBarColor = Color.parseColor("#FFFFFF"); customTheme.isLightStatusBar = true; customTheme.isLightNavBar = true; @@ -890,7 +890,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#21C561"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FF6400"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#242424"); customTheme.navBarColor = Color.parseColor("#121212"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = false; @@ -975,7 +975,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#21C561"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FF6400"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#000000"); customTheme.navBarColor = Color.parseColor("#000000"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = false; @@ -1060,7 +1060,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#8EDFBA"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FFF162"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#FFFFFF"); customTheme.navBarColor = Color.parseColor("#FFFFFF"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = true; @@ -1145,7 +1145,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#21C561"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FF6400"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#242424"); customTheme.navBarColor = Color.parseColor("#121212"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = false; @@ -1230,7 +1230,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#21C561"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FF6400"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#000000"); customTheme.navBarColor = Color.parseColor("#000000"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = false; @@ -1315,7 +1315,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#21C561"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FF6400"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#393A59"); customTheme.navBarColor = Color.parseColor("#393A59"); customTheme.isLightStatusBar = false; customTheme.isLightNavBar = false; @@ -1400,7 +1400,7 @@ public class CustomThemeWrapper { customTheme.sentMessageBackgroundColor = Color.parseColor("#31BF7D"); customTheme.sendMessageIconColor = Color.parseColor("#4185F4"); customTheme.fullyCollapsedCommentBackgroundColor = Color.parseColor("#8EDFBA"); - customTheme.awardedCommentBackgroundColor = Color.parseColor("#FFF162"); + customTheme.awardedCommentBackgroundColor = Color.parseColor("#C0F0F4"); customTheme.navBarColor = Color.parseColor("#D48AE0"); customTheme.isLightStatusBar = true; customTheme.isLightNavBar = true; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Event/ChangeSavePostFeedScrolledPositionEvent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Event/ChangeSavePostFeedScrolledPositionEvent.java new file mode 100644 index 00000000..5dd363eb --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Event/ChangeSavePostFeedScrolledPositionEvent.java @@ -0,0 +1,9 @@ +package ml.docilealligator.infinityforreddit.Event; + +public class ChangeSavePostFeedScrolledPositionEvent { + public boolean savePostFeedScrolledPosition; + + public ChangeSavePostFeedScrolledPositionEvent(boolean savePostFeedScrolledPosition) { + this.savePostFeedScrolledPosition = savePostFeedScrolledPosition; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Event/DownloadMediaEvent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Event/DownloadMediaEvent.java new file mode 100644 index 00000000..174b49ea --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Event/DownloadMediaEvent.java @@ -0,0 +1,9 @@ +package ml.docilealligator.infinityforreddit.Event; + +public class DownloadMediaEvent { + public boolean isSuccessful; + + public DownloadMediaEvent(boolean isSuccessful) { + this.isSuccessful = isSuccessful; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Event/SubmitCrosspostEvent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Event/SubmitCrosspostEvent.java new file mode 100644 index 00000000..55b4a5bd --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Event/SubmitCrosspostEvent.java @@ -0,0 +1,15 @@ +package ml.docilealligator.infinityforreddit.Event; + +import ml.docilealligator.infinityforreddit.Post.Post; + +public class SubmitCrosspostEvent { + public boolean postSuccess; + public Post post; + public String errorMessage; + + public SubmitCrosspostEvent(boolean postSuccess, Post post, String errorMessage) { + this.postSuccess = postSuccess; + this.post = post; + this.errorMessage = errorMessage; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java index 67a5e8bd..7edfa0c4 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java @@ -6,11 +6,16 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Canvas; import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.CountDownTimer; import android.os.Handler; +import android.os.VibrationEffect; +import android.os.Vibrator; import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -27,9 +32,11 @@ import androidx.annotation.DimenRes; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.paging.PagedList; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; @@ -66,6 +73,7 @@ import ml.docilealligator.infinityforreddit.Event.ChangeMuteAutoplayingVideosEve import ml.docilealligator.infinityforreddit.Event.ChangeMuteNSFWVideoEvent; import ml.docilealligator.infinityforreddit.Event.ChangeNSFWBlurEvent; import ml.docilealligator.infinityforreddit.Event.ChangePostLayoutEvent; +import ml.docilealligator.infinityforreddit.Event.ChangeSavePostFeedScrolledPositionEvent; import ml.docilealligator.infinityforreddit.Event.ChangeShowAbsoluteNumberOfVotesEvent; import ml.docilealligator.infinityforreddit.Event.ChangeShowElapsedTimeEvent; import ml.docilealligator.infinityforreddit.Event.ChangeSpoilerBlurEvent; @@ -107,6 +115,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { public static final String EXTRA_FILTER = "EF"; public static final int EXTRA_NO_FILTER = -2; public static final String EXTRA_ACCESS_TOKEN = "EAT"; + public static final String EXTRA_ACCOUNT_NAME = "EAN"; private static final String IS_IN_LAZY_MODE_STATE = "IILMS"; private static final String RECYCLER_VIEW_POSITION_STATE = "RVPS"; @@ -143,6 +152,9 @@ public class PostFragment extends Fragment implements FragmentCommunicator { CustomThemeWrapper customThemeWrapper; @Inject ExoCreator exoCreator; + @Inject + @Named("post_feed_scrolled_position_cache") + SharedPreferences postFeedScrolledPositionSharedPreferences; private RequestManager mGlide; private AppCompatActivity activity; private LinearLayoutManager mLinearLayoutManager; @@ -151,6 +163,8 @@ public class PostFragment extends Fragment implements FragmentCommunicator { private boolean isInLazyMode = false; private boolean isLazyModePaused = false; private boolean hasPost = false; + private boolean isShown = false; + private boolean savePostFeedScrolledPosition; private PostRecyclerViewAdapter mAdapter; private RecyclerView.SmoothScroller smoothScroller; private Window window; @@ -158,8 +172,19 @@ public class PostFragment extends Fragment implements FragmentCommunicator { private LazyModeRunnable lazyModeRunnable; private CountDownTimer resumeLazyModeCountDownTimer; private float lazyModeInterval; + private String accountName; + private String subredditName; + private String username; + private String multiRedditPath; + private int maxPosition = -1; private int postLayout; private SortType sortType; + private ColorDrawable backgroundLeft; + private ColorDrawable backgroundRight; + private Drawable drawableLeft; + private Drawable drawableRight; + private float swipeActionThreshold = 0.3f; + private ItemTouchHelper touchHelper; public PostFragment() { // Required empty public constructor @@ -168,6 +193,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { @Override public void onResume() { super.onResume(); + isShown = true; if (mPostRecyclerView.getAdapter() != null) { ((PostRecyclerViewAdapter) mPostRecyclerView.getAdapter()).setCanStartActivity(true); } @@ -247,7 +273,14 @@ public class PostFragment extends Fragment implements FragmentCommunicator { activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); int windowWidth = displayMetrics.widthPixels; - if (resources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT && !resources.getBoolean(R.bool.isTablet)) { + int nColumns; + if (resources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + nColumns = Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.NUMBER_OF_COLUMNS_IN_POST_FEED_PORTRAIT, "1")); + } else { + nColumns = Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.NUMBER_OF_COLUMNS_IN_POST_FEED_LANDSCAPE, "1")); + } + + if (nColumns == 1) { mLinearLayoutManager = new LinearLayoutManager(activity); mPostRecyclerView.setLayoutManager(mLinearLayoutManager); } else { @@ -353,12 +386,14 @@ public class PostFragment extends Fragment implements FragmentCommunicator { int filter = getArguments().getInt(EXTRA_FILTER); String accessToken = getArguments().getString(EXTRA_ACCESS_TOKEN); + accountName = getArguments().getString(EXTRA_ACCOUNT_NAME); boolean nsfw = mSharedPreferences.getBoolean(SharedPreferencesUtils.NSFW_KEY, false); int defaultPostLayout = Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.DEFAULT_POST_LAYOUT_KEY, "0")); + savePostFeedScrolledPosition = mSharedPreferences.getBoolean(SharedPreferencesUtils.SAVE_FRONT_PAGE_SCROLLED_POSITION, false); Locale locale = getResources().getConfiguration().locale; if (postType == PostDataSource.TYPE_SEARCH) { - String subredditName = getArguments().getString(EXTRA_NAME); + subredditName = getArguments().getString(EXTRA_NAME); String query = getArguments().getString(EXTRA_QUERY); String sort = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_SEARCH_POST, SortType.Type.RELEVANCE.name()); @@ -369,56 +404,49 @@ public class PostFragment extends Fragment implements FragmentCommunicator { mAdapter = new PostRecyclerViewAdapter(activity, mOauthRetrofit, mRetrofit, mRedditDataRoomDatabase, customThemeWrapper, locale, windowWidth, accessToken, postType, postLayout, true, mSharedPreferences, exoCreator, new PostRecyclerViewAdapter.Callback() { - @Override - public void retryLoadingMore() { - mPostViewModel.retryLoadingMore(); - } + @Override + public void retryLoadingMore() { + mPostViewModel.retryLoadingMore(); + } - @Override - public void typeChipClicked(int filter) { - Intent intent = new Intent(activity, FilteredThingActivity.class); - intent.putExtra(FilteredThingActivity.EXTRA_NAME, subredditName); - intent.putExtra(FilteredThingActivity.EXTRA_QUERY, query); - intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); - intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); - startActivity(intent); - } - }); + @Override + public void typeChipClicked(int filter) { + Intent intent = new Intent(activity, FilteredThingActivity.class); + intent.putExtra(FilteredThingActivity.EXTRA_NAME, subredditName); + intent.putExtra(FilteredThingActivity.EXTRA_QUERY, query); + intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); + intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); + startActivity(intent); + } - if (accessToken == null) { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mRetrofit, null, - getResources().getConfiguration().locale, subredditName, query, postType, - sortType, filter, nsfw)).get(PostViewModel.class); - } else { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mOauthRetrofit, accessToken, - getResources().getConfiguration().locale, subredditName, query, postType, - sortType, filter, nsfw)).get(PostViewModel.class); - } + @Override + public void currentlyBindItem(int position) { + if (maxPosition < position) { + maxPosition = position; + } + } + }); + + mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(accessToken == null ? mRetrofit : mOauthRetrofit, accessToken, + accountName, getResources().getConfiguration().locale, mSharedPreferences, + postFeedScrolledPositionSharedPreferences, subredditName, query, postType, sortType, filter, nsfw)).get(PostViewModel.class); } else if (postType == PostDataSource.TYPE_SUBREDDIT) { - String subredditName = getArguments().getString(EXTRA_NAME); + subredditName = getArguments().getString(EXTRA_NAME); String sort; String sortTime = null; + sort = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_SUBREDDIT_POST_BASE + subredditName, SortType.Type.HOT.name()); + if(sort.equals(SortType.Type.CONTROVERSIAL.name()) || sort.equals(SortType.Type.TOP.name())) { + sortTime = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TIME_SUBREDDIT_POST_BASE + subredditName, SortType.Time.ALL.name()); + } boolean displaySubredditName = subredditName != null && (subredditName.equals("popular") || subredditName.equals("all")); if(displaySubredditName) { if(subredditName.equals("popular")) { - sort = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_POPULAR_POST, SortType.Type.HOT.name()); - if(sort.equals(SortType.Type.CONTROVERSIAL.name()) || sort.equals(SortType.Type.TOP.name())) { - sortTime = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TIME_POPULAR_POST, SortType.Time.ALL.name()); - } postLayout = mPostLayoutSharedPreferences.getInt(SharedPreferencesUtils.POST_LAYOUT_POPULAR_POST, defaultPostLayout); } else { - sort = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_ALL_POST, SortType.Type.HOT.name()); - if(sort.equals(SortType.Type.CONTROVERSIAL.name()) || sort.equals(SortType.Type.TOP.name())) { - sortTime = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TIME_ALL_POST, SortType.Time.ALL.name()); - } postLayout = mPostLayoutSharedPreferences.getInt(SharedPreferencesUtils.POST_LAYOUT_ALL_POST, defaultPostLayout); } } else { - sort = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_SUBREDDIT_POST_BASE + subredditName, SortType.Type.HOT.name()); - if(sort.equals(SortType.Type.CONTROVERSIAL.name()) || sort.equals(SortType.Type.TOP.name())) { - sortTime = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TIME_SUBREDDIT_POST_BASE + subredditName, SortType.Time.ALL.name()); - } postLayout = mPostLayoutSharedPreferences.getInt(SharedPreferencesUtils.POST_LAYOUT_SUBREDDIT_POST_BASE + subredditName, defaultPostLayout); } @@ -431,32 +459,33 @@ public class PostFragment extends Fragment implements FragmentCommunicator { mAdapter = new PostRecyclerViewAdapter(activity, mOauthRetrofit, mRetrofit, mRedditDataRoomDatabase, customThemeWrapper, locale, windowWidth, accessToken, postType, postLayout, displaySubredditName, mSharedPreferences, exoCreator, new PostRecyclerViewAdapter.Callback() { - @Override - public void retryLoadingMore() { - mPostViewModel.retryLoadingMore(); - } + @Override + public void retryLoadingMore() { + mPostViewModel.retryLoadingMore(); + } - @Override - public void typeChipClicked(int filter) { - Intent intent = new Intent(activity, FilteredThingActivity.class); - intent.putExtra(FilteredThingActivity.EXTRA_NAME, subredditName); - intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); - intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); - startActivity(intent); - } - }); + @Override + public void typeChipClicked(int filter) { + Intent intent = new Intent(activity, FilteredThingActivity.class); + intent.putExtra(FilteredThingActivity.EXTRA_NAME, subredditName); + intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); + intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); + startActivity(intent); + } - if (accessToken == null) { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mRetrofit, accessToken, - getResources().getConfiguration().locale, subredditName, postType, sortType, - filter, nsfw)).get(PostViewModel.class); - } else { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mOauthRetrofit, accessToken, - getResources().getConfiguration().locale, subredditName, postType, sortType, - filter, nsfw)).get(PostViewModel.class); - } + @Override + public void currentlyBindItem(int position) { + if (maxPosition < position) { + maxPosition = position; + } + } + }); + + mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(accessToken == null ? mRetrofit : mOauthRetrofit, accessToken, + accountName, getResources().getConfiguration().locale, mSharedPreferences, + postFeedScrolledPositionSharedPreferences, subredditName, postType, sortType, filter, nsfw)).get(PostViewModel.class); } else if(postType == PostDataSource.TYPE_MULTI_REDDIT) { - String multiRedditPath = getArguments().getString(EXTRA_NAME); + multiRedditPath = getArguments().getString(EXTRA_NAME); String sort; String sortTime = null; @@ -491,19 +520,20 @@ public class PostFragment extends Fragment implements FragmentCommunicator { intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); startActivity(intent); } + + @Override + public void currentlyBindItem(int position) { + if (maxPosition < position) { + maxPosition = position; + } + } }); - if (accessToken == null) { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mRetrofit, null, - getResources().getConfiguration().locale, multiRedditPath, postType, sortType, - filter, nsfw)).get(PostViewModel.class); - } else { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mOauthRetrofit, accessToken, - getResources().getConfiguration().locale, multiRedditPath, postType, sortType, - filter, nsfw)).get(PostViewModel.class); - } + mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(accessToken == null ? mRetrofit : mOauthRetrofit, accessToken, + accountName, getResources().getConfiguration().locale, mSharedPreferences, + postFeedScrolledPositionSharedPreferences, multiRedditPath, postType, sortType, filter, nsfw)).get(PostViewModel.class); } else if (postType == PostDataSource.TYPE_USER) { - String username = getArguments().getString(EXTRA_USER_NAME); + username = getArguments().getString(EXTRA_USER_NAME); String where = getArguments().getString(EXTRA_USER_WHERE); if (where != null && where.equals(PostDataSource.USER_WHERE_SUBMITTED)) { CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) mFetchPostInfoLinearLayout.getLayoutParams(); @@ -523,31 +553,32 @@ public class PostFragment extends Fragment implements FragmentCommunicator { mAdapter = new PostRecyclerViewAdapter(activity, mOauthRetrofit, mRetrofit, mRedditDataRoomDatabase, customThemeWrapper, locale, windowWidth, accessToken, postType, postLayout, true, mSharedPreferences, exoCreator, new PostRecyclerViewAdapter.Callback() { - @Override - public void retryLoadingMore() { - mPostViewModel.retryLoadingMore(); - } + @Override + public void retryLoadingMore() { + mPostViewModel.retryLoadingMore(); + } - @Override - public void typeChipClicked(int filter) { - Intent intent = new Intent(activity, FilteredThingActivity.class); - intent.putExtra(FilteredThingActivity.EXTRA_NAME, username); - intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); - intent.putExtra(FilteredThingActivity.EXTRA_USER_WHERE, where); - intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); - startActivity(intent); - } - }); + @Override + public void typeChipClicked(int filter) { + Intent intent = new Intent(activity, FilteredThingActivity.class); + intent.putExtra(FilteredThingActivity.EXTRA_NAME, username); + intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); + intent.putExtra(FilteredThingActivity.EXTRA_USER_WHERE, where); + intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); + startActivity(intent); + } - if (accessToken == null) { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mRetrofit, accessToken, - getResources().getConfiguration().locale, username, postType, sortType, where, - filter, nsfw)).get(PostViewModel.class); - } else { - mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mOauthRetrofit, accessToken, - getResources().getConfiguration().locale, username, postType, sortType, where, - filter, nsfw)).get(PostViewModel.class); - } + @Override + public void currentlyBindItem(int position) { + if (maxPosition < position) { + maxPosition = position; + } + } + }); + + mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(accessToken == null ? mRetrofit : mOauthRetrofit, accessToken, + accountName, getResources().getConfiguration().locale, mSharedPreferences, + postFeedScrolledPositionSharedPreferences, username, postType, sortType, where, filter, nsfw)).get(PostViewModel.class); } else { String sort = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_BEST_POST, SortType.Type.BEST.name()); if(sort.equals(SortType.Type.CONTROVERSIAL.name()) || sort.equals(SortType.Type.TOP.name())) { @@ -561,29 +592,139 @@ public class PostFragment extends Fragment implements FragmentCommunicator { mAdapter = new PostRecyclerViewAdapter(activity, mOauthRetrofit, mRetrofit, mRedditDataRoomDatabase, customThemeWrapper, locale, windowWidth, accessToken, postType, postLayout, true, mSharedPreferences, exoCreator, new PostRecyclerViewAdapter.Callback() { - @Override - public void retryLoadingMore() { - mPostViewModel.retryLoadingMore(); - } + @Override + public void retryLoadingMore() { + mPostViewModel.retryLoadingMore(); + } - @Override - public void typeChipClicked(int filter) { - Intent intent = new Intent(activity, FilteredThingActivity.class); - intent.putExtra(FilteredThingActivity.EXTRA_NAME, activity.getString(R.string.best)); - intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); - intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); - startActivity(intent); - } - }); + @Override + public void typeChipClicked(int filter) { + Intent intent = new Intent(activity, FilteredThingActivity.class); + intent.putExtra(FilteredThingActivity.EXTRA_NAME, activity.getString(R.string.best)); + intent.putExtra(FilteredThingActivity.EXTRA_POST_TYPE, postType); + intent.putExtra(FilteredThingActivity.EXTRA_FILTER, filter); + startActivity(intent); + } + + @Override + public void currentlyBindItem(int position) { + if (maxPosition < position) { + maxPosition = position; + } + } + }); mPostViewModel = new ViewModelProvider(this, new PostViewModel.Factory(mOauthRetrofit, accessToken, - getResources().getConfiguration().locale, postType, sortType, filter, nsfw)).get(PostViewModel.class); + accountName, getResources().getConfiguration().locale, mSharedPreferences, postFeedScrolledPositionSharedPreferences, + postType, sortType, filter, nsfw)).get(PostViewModel.class); } if (activity instanceof ActivityToolbarInterface) { ((ActivityToolbarInterface) activity).displaySortType(); } + Vibrator v = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); + // Vibrate for 500 milliseconds + backgroundLeft = new ColorDrawable(customThemeWrapper.getDownvoted()); + backgroundRight = new ColorDrawable(customThemeWrapper.getUpvoted()); + drawableLeft = ResourcesCompat.getDrawable(activity.getResources(), R.drawable.ic_arrow_downward_black_24dp, null); + drawableRight = ResourcesCompat.getDrawable(activity.getResources(), R.drawable.ic_arrow_upward_black_24dp, null); + int screenBottom = window.getDecorView().getHeight(); + touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { + boolean exceedThreshold = false; + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; + return makeMovementFlags(0, swipeFlags); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return true; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + if (touchHelper != null) { + touchHelper.attachToRecyclerView(null); + touchHelper.attachToRecyclerView(mPostRecyclerView); + if (mAdapter != null) { + mAdapter.onItemSwipe(viewHolder, direction); + } + } + } + + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + + View itemView = viewHolder.itemView; + int horizontalOffset = (int) Utils.convertDpToPixel(16, activity); + if (dX > 0) { + if (dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (v != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + v.vibrate(VibrationEffect.createOneShot(10, 175)); + } else { + //deprecated in API 26 + v.vibrate(10); + } + } + } + backgroundLeft.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundLeft.setBounds(0, 0, 0, 0); + } + + drawableLeft.setBounds(itemView.getLeft() + ((int) dX) - horizontalOffset - drawableLeft.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() - drawableLeft.getIntrinsicHeight()) / 2, + itemView.getLeft() + ((int) dX) - horizontalOffset, + (itemView.getBottom() + itemView.getTop() + drawableLeft.getIntrinsicHeight()) / 2); + backgroundLeft.draw(c); + drawableLeft.draw(c); + } else if (dX < 0) { + if (-dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (v != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + v.vibrate(VibrationEffect.createOneShot(10, 175)); + } else { + //deprecated in API 26 + v.vibrate(10); + } + } + } + backgroundRight.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundRight.setBounds(0, 0, 0, 0); + } + drawableRight.setBounds(itemView.getRight() + ((int) dX) + horizontalOffset, + (itemView.getBottom() + itemView.getTop() - drawableRight.getIntrinsicHeight()) / 2, + itemView.getRight() + ((int) dX) + horizontalOffset + drawableRight.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() + drawableRight.getIntrinsicHeight()) / 2); + backgroundRight.draw(c); + drawableRight.draw(c); + } + } + + @Override + public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { + return swipeActionThreshold; + } + }); + + touchHelper.attachToRecyclerView(mPostRecyclerView); mPostRecyclerView.setAdapter(mAdapter); mPostRecyclerView.setCacheManager(mAdapter); mPostRecyclerView.setPlayerInitializer(order -> { @@ -627,6 +768,40 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } public void changeSortType(SortType sortType) { + switch (postType) { + case PostDataSource.TYPE_FRONT_PAGE: + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_BEST_POST, sortType.getType().name()).apply(); + if (sortType.getTime() != null) { + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_BEST_POST, sortType.getTime().name()).apply(); + } + break; + case PostDataSource.TYPE_SUBREDDIT: + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_SUBREDDIT_POST_BASE + subredditName, sortType.getType().name()).apply(); + if (sortType.getTime() != null) { + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_SUBREDDIT_POST_BASE + subredditName, sortType.getTime().name()).apply(); + } + break; + case PostDataSource.TYPE_USER: + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_USER_POST_BASE + username, sortType.getType().name()).apply(); + if(sortType.getTime() != null) { + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_USER_POST_BASE + username, sortType.getTime().name()).apply(); + } + break; + case PostDataSource.TYPE_SEARCH: + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_SEARCH_POST, sortType.getType().name()).apply(); + if(sortType.getTime() != null) { + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_SEARCH_POST, sortType.getTime().name()).apply(); + } + break; + case PostDataSource.TYPE_MULTI_REDDIT: + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_MULTI_REDDIT_POST_BASE + multiRedditPath, + sortType.getType().name()).apply(); + if (sortType.getTime() != null) { + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TIME_MULTI_REDDIT_POST_BASE + multiRedditPath, + sortType.getTime().name()).apply(); + } + break; + } if (mFetchPostInfoLinearLayout.getVisibility() != View.GONE) { mFetchPostInfoLinearLayout.setVisibility(View.GONE); mGlide.clear(mFetchPostInfoImageView); @@ -660,6 +835,24 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } @Override + public void onStop() { + super.onStop(); + saveCache(); + } + + private void saveCache() { + if (savePostFeedScrolledPosition && postType == PostDataSource.TYPE_FRONT_PAGE && sortType != null && sortType.getType() == SortType.Type.BEST && mAdapter != null) { + Post currentPost = mAdapter.getItemByPosition(maxPosition); + if (currentPost != null) { + String accountNameForCache = accountName == null ? SharedPreferencesUtils.FRONT_PAGE_SCROLLED_POSITION_ANONYMOUS : accountName; + String key = accountNameForCache + SharedPreferencesUtils.FRONT_PAGE_SCROLLED_POSITION_FRONT_PAGE_BASE; + String value = currentPost.getFullName(); + postFeedScrolledPositionSharedPreferences.edit().putString(key, value).apply(); + } + } + } + + @Override public void refresh() { mAdapter.removeFooter(); mFetchPostInfoLinearLayout.setVisibility(View.GONE); @@ -667,6 +860,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { if (isInLazyMode) { stopLazyMode(); } + saveCache(); mPostViewModel.refresh(); } @@ -959,6 +1153,11 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } } + @Subscribe + public void onChangeSavePostFeedScrolledPositionEvent(ChangeSavePostFeedScrolledPositionEvent changeSavePostFeedScrolledPositionEvent) { + savePostFeedScrolledPosition = changeSavePostFeedScrolledPositionEvent.savePostFeedScrolledPosition; + } + private void refreshAdapter() { int previousPosition = -1; if (mLinearLayoutManager != null) { @@ -997,6 +1196,10 @@ public class PostFragment extends Fragment implements FragmentCommunicator { return sortType; } + public int getPostType() { + return postType; + } + @Override public void onPause() { super.onPause(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SidebarFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SidebarFragment.java index c7431b20..bc45fa84 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SidebarFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SidebarFragment.java @@ -38,15 +38,14 @@ import io.noties.markwon.recycler.MarkwonAdapter; import io.noties.markwon.recycler.table.TableEntry; import io.noties.markwon.recycler.table.TableEntryPlugin; import io.noties.markwon.simple.ext.SimpleExtPlugin; -import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import ml.docilealligator.infinityforreddit.Activity.LinkResolverActivity; import ml.docilealligator.infinityforreddit.Activity.ViewSubredditDetailActivity; import ml.docilealligator.infinityforreddit.AsyncTask.InsertSubredditDataAsyncTask; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; -import ml.docilealligator.infinityforreddit.Subreddit.FetchSubredditData; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; +import ml.docilealligator.infinityforreddit.Subreddit.FetchSubredditData; import ml.docilealligator.infinityforreddit.Subreddit.SubredditData; import ml.docilealligator.infinityforreddit.Subreddit.SubredditViewModel; import retrofit2.Retrofit; @@ -118,8 +117,7 @@ public class SidebarFragment extends Fragment { intent.setData(uri); } startActivity(intent); - }).urlProcessor(new UrlProcessorRelativeToAbsolute("https://www.reddit.com")); - + }); } }) .usePlugin(StrikethroughPlugin.create()) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java index d25408aa..29101dd6 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java @@ -21,7 +21,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.fragment.app.Fragment; @@ -42,13 +41,12 @@ import java.io.File; import butterknife.BindView; import butterknife.ButterKnife; import ml.docilealligator.infinityforreddit.Activity.ViewImgurMediaActivity; -import ml.docilealligator.infinityforreddit.AsyncTask.SaveImageToFileAsyncTask; +import ml.docilealligator.infinityforreddit.AsyncTask.SaveBitmapImageToFileAsyncTask; import ml.docilealligator.infinityforreddit.BottomSheetFragment.SetAsWallpaperBottomSheetFragment; import ml.docilealligator.infinityforreddit.BuildConfig; import ml.docilealligator.infinityforreddit.ImgurMedia; -import ml.docilealligator.infinityforreddit.MediaDownloader; -import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Service.DownloadMediaService; import ml.docilealligator.infinityforreddit.SetAsWallpaperCallback; public class ViewImgurImageFragment extends Fragment { @@ -65,7 +63,6 @@ public class ViewImgurImageFragment extends Fragment { private ViewImgurMediaActivity activity; private RequestManager glide; - private MediaDownloader mediaDownloader; private ImgurMedia imgurMedia; private boolean isDownloading = false; private boolean isActionBarHidden = false; @@ -85,7 +82,6 @@ public class ViewImgurImageFragment extends Fragment { imgurMedia = getArguments().getParcelable(EXTRA_IMGUR_IMAGES); glide = Glide.with(activity); - mediaDownloader = new MediaDownloaderImpl(); loadImage(); imageView.setOnClickListener(view -> { @@ -166,15 +162,14 @@ public class ViewImgurImageFragment extends Fragment { // Permission is not granted // No explanation needed; request the permission - ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); } else { // Permission has already been granted - mediaDownloader.download(imgurMedia.getLink(), imgurMedia.getFileName(), getContext()); + download(); } } else { - mediaDownloader.download(imgurMedia.getLink(), imgurMedia.getFileName(), getContext()); + download(); } return true; @@ -185,9 +180,9 @@ public class ViewImgurImageFragment extends Fragment { public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { if (activity.getExternalCacheDir() != null) { Toast.makeText(activity, R.string.save_image_first, Toast.LENGTH_SHORT).show(); - new SaveImageToFileAsyncTask(resource, activity.getExternalCacheDir().getPath(), + new SaveBitmapImageToFileAsyncTask(resource, activity.getExternalCacheDir().getPath(), imgurMedia.getFileName(), - new SaveImageToFileAsyncTask.SaveImageToFileAsyncTaskListener() { + new SaveBitmapImageToFileAsyncTask.SaveBitmapImageToFileAsyncTaskListener() { @Override public void saveSuccess(File imageFile) { Uri uri = FileProvider.getUriForFile(activity, @@ -234,15 +229,30 @@ public class ViewImgurImageFragment extends Fragment { return false; } + private void download() { + isDownloading = false; + + Intent intent = new Intent(activity, DownloadMediaService.class); + intent.putExtra(DownloadMediaService.EXTRA_URL, imgurMedia.getLink()); + intent.putExtra(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_IMAGE); + intent.putExtra(DownloadMediaService.EXTRA_FILE_NAME, imgurMedia.getFileName()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + activity.startForegroundService(intent); + } else { + activity.startService(intent); + } + Toast.makeText(activity, R.string.download_started, Toast.LENGTH_SHORT).show(); + } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Toast.makeText(activity, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + isDownloading = false; } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && isDownloading) { - mediaDownloader.download(imgurMedia.getLink(), imgurMedia.getFileName(), getContext()); + download(); } - isDownloading = false; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java index 30a00c21..154901bb 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java @@ -3,6 +3,7 @@ package ml.docilealligator.infinityforreddit.Fragment; import android.Manifest; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -21,7 +22,6 @@ import android.widget.LinearLayout; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; @@ -47,9 +47,8 @@ import butterknife.BindView; import butterknife.ButterKnife; import ml.docilealligator.infinityforreddit.ImgurMedia; import ml.docilealligator.infinityforreddit.Infinity; -import ml.docilealligator.infinityforreddit.MediaDownloader; -import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Service.DownloadMediaService; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; public class ViewImgurVideoFragment extends Fragment { @@ -66,7 +65,6 @@ public class ViewImgurVideoFragment extends Fragment { private ImgurMedia imgurMedia; private SimpleExoPlayer player; private DataSource.Factory dataSourceFactory; - private MediaDownloader mediaDownloader; private boolean wasPlaying = false; private boolean isMute = false; private boolean isDownloading = false; @@ -129,8 +127,6 @@ public class ViewImgurVideoFragment extends Fragment { } }); - mediaDownloader = new MediaDownloaderImpl(); - TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(); TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector); @@ -160,8 +156,7 @@ public class ViewImgurVideoFragment extends Fragment { // Permission is not granted // No explanation needed; request the permission - ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); } else { // Permission has already been granted @@ -180,17 +175,26 @@ public class ViewImgurVideoFragment extends Fragment { if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Toast.makeText(activity, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + isDownloading = false; } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && isDownloading) { download(); } - isDownloading = false; } } private void download() { isDownloading = false; - mediaDownloader.download(imgurMedia.getLink(), imgurMedia.getFileName(), getContext()); + Intent intent = new Intent(activity, DownloadMediaService.class); + intent.putExtra(DownloadMediaService.EXTRA_URL, imgurMedia.getLink()); + intent.putExtra(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_VIDEO); + intent.putExtra(DownloadMediaService.EXTRA_FILE_NAME, imgurMedia.getFileName()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + activity.startForegroundService(intent); + } else { + activity.startService(intent); + } + Toast.makeText(activity, R.string.download_started, Toast.LENGTH_SHORT).show(); } private void preparePlayer(Bundle savedInstanceState) { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryImageOrGifFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryImageOrGifFragment.java index 0b466749..a34e8628 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryImageOrGifFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryImageOrGifFragment.java @@ -21,7 +21,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.fragment.app.Fragment; @@ -47,14 +46,13 @@ import java.io.File; import butterknife.BindView; import butterknife.ButterKnife; import ml.docilealligator.infinityforreddit.Activity.ViewRedditGalleryActivity; +import ml.docilealligator.infinityforreddit.AsyncTask.SaveBitmapImageToFileAsyncTask; import ml.docilealligator.infinityforreddit.AsyncTask.SaveGIFToFileAsyncTask; -import ml.docilealligator.infinityforreddit.AsyncTask.SaveImageToFileAsyncTask; import ml.docilealligator.infinityforreddit.BottomSheetFragment.SetAsWallpaperBottomSheetFragment; import ml.docilealligator.infinityforreddit.BuildConfig; -import ml.docilealligator.infinityforreddit.MediaDownloader; -import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; import ml.docilealligator.infinityforreddit.Post.Post; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Service.DownloadMediaService; import ml.docilealligator.infinityforreddit.SetAsWallpaperCallback; public class ViewRedditGalleryImageOrGifFragment extends Fragment { @@ -71,7 +69,6 @@ public class ViewRedditGalleryImageOrGifFragment extends Fragment { private ViewRedditGalleryActivity activity; private RequestManager glide; - private MediaDownloader mediaDownloader; private Post.Gallery media; private boolean isDownloading = false; private boolean isActionBarHidden = false; @@ -93,7 +90,6 @@ public class ViewRedditGalleryImageOrGifFragment extends Fragment { media = getArguments().getParcelable(EXTRA_REDDIT_GALLERY_MEDIA); glide = Glide.with(activity); - mediaDownloader = new MediaDownloaderImpl(); imageView.setImageViewFactory(new GlideImageViewFactory()); @@ -142,7 +138,7 @@ public class ViewRedditGalleryImageOrGifFragment extends Fragment { public void onImageLoaded() { view.setDoubleTapZoomDpi(70); view.setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_FIXED); - view.setQuickScaleEnabled(false); + view.setQuickScaleEnabled(true); } @Override @@ -232,15 +228,14 @@ public class ViewRedditGalleryImageOrGifFragment extends Fragment { // Permission is not granted // No explanation needed; request the permission - ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); } else { // Permission has already been granted - mediaDownloader.download(media.url, media.fileName, getContext()); + download(); } } else { - mediaDownloader.download(media.url, media.fileName, getContext()); + download(); } return true; @@ -267,15 +262,30 @@ public class ViewRedditGalleryImageOrGifFragment extends Fragment { return false; } + private void download() { + isDownloading = false; + + Intent intent = new Intent(activity, DownloadMediaService.class); + intent.putExtra(DownloadMediaService.EXTRA_URL, media.url); + intent.putExtra(DownloadMediaService.EXTRA_MEDIA_TYPE, media.mediaType == Post.Gallery.TYPE_GIF ? DownloadMediaService.EXTRA_MEDIA_TYPE_GIF: DownloadMediaService.EXTRA_MEDIA_TYPE_IMAGE); + intent.putExtra(DownloadMediaService.EXTRA_FILE_NAME, media.fileName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + activity.startForegroundService(intent); + } else { + activity.startService(intent); + } + Toast.makeText(activity, R.string.download_started, Toast.LENGTH_SHORT).show(); + } + private void shareImage() { glide.asBitmap().load(media.url).into(new CustomTarget<Bitmap>() { @Override public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { if (activity.getExternalCacheDir() != null) { Toast.makeText(activity, R.string.save_image_first, Toast.LENGTH_SHORT).show(); - new SaveImageToFileAsyncTask(resource, activity.getExternalCacheDir().getPath(), + new SaveBitmapImageToFileAsyncTask(resource, activity.getExternalCacheDir().getPath(), media.fileName, - new SaveImageToFileAsyncTask.SaveImageToFileAsyncTaskListener() { + new SaveBitmapImageToFileAsyncTask.SaveBitmapImageToFileAsyncTaskListener() { @Override public void saveSuccess(File imageFile) { Uri uri = FileProvider.getUriForFile(activity, @@ -352,10 +362,10 @@ public class ViewRedditGalleryImageOrGifFragment extends Fragment { if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Toast.makeText(activity, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + isDownloading = false; } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && isDownloading) { - mediaDownloader.download(media.url, media.fileName, getContext()); + download(); } - isDownloading = false; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryVideoFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryVideoFragment.java index 2a0ec80f..3357b44e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryVideoFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryVideoFragment.java @@ -3,6 +3,7 @@ package ml.docilealligator.infinityforreddit.Fragment; import android.Manifest; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -21,7 +22,6 @@ import android.widget.LinearLayout; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; @@ -46,10 +46,9 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; import ml.docilealligator.infinityforreddit.Infinity; -import ml.docilealligator.infinityforreddit.MediaDownloader; -import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; import ml.docilealligator.infinityforreddit.Post.Post; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Service.DownloadMediaService; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; public class ViewRedditGalleryVideoFragment extends Fragment { @@ -66,7 +65,6 @@ public class ViewRedditGalleryVideoFragment extends Fragment { private Post.Gallery galleryVideo; private SimpleExoPlayer player; private DataSource.Factory dataSourceFactory; - private MediaDownloader mediaDownloader; private boolean wasPlaying = false; private boolean isMute = false; private boolean isDownloading = false; @@ -129,8 +127,6 @@ public class ViewRedditGalleryVideoFragment extends Fragment { } }); - mediaDownloader = new MediaDownloaderImpl(); - TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(); TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector); @@ -160,8 +156,7 @@ public class ViewRedditGalleryVideoFragment extends Fragment { // Permission is not granted // No explanation needed; request the permission - ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); } else { // Permission has already been granted @@ -180,17 +175,26 @@ public class ViewRedditGalleryVideoFragment extends Fragment { if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Toast.makeText(activity, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + isDownloading = false; } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && isDownloading) { download(); } - isDownloading = false; } } private void download() { isDownloading = false; - mediaDownloader.download(galleryVideo.url, galleryVideo.fileName, getContext()); + Intent intent = new Intent(activity, DownloadMediaService.class); + intent.putExtra(DownloadMediaService.EXTRA_URL, galleryVideo.url); + intent.putExtra(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_VIDEO); + intent.putExtra(DownloadMediaService.EXTRA_FILE_NAME, galleryVideo.fileName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + activity.startForegroundService(intent); + } else { + activity.startService(intent); + } + Toast.makeText(activity, R.string.download_started, Toast.LENGTH_SHORT).show(); } private void preparePlayer(Bundle savedInstanceState) { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MediaDownloader.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MediaDownloader.java deleted file mode 100644 index 9967a6a4..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/MediaDownloader.java +++ /dev/null @@ -1,7 +0,0 @@ -package ml.docilealligator.infinityforreddit; - -import android.content.Context; - -public interface MediaDownloader { - void download(String url, String fileName, Context ctx); -} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MediaDownloaderImpl.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MediaDownloaderImpl.java deleted file mode 100644 index 638bdf93..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/MediaDownloaderImpl.java +++ /dev/null @@ -1,58 +0,0 @@ -package ml.docilealligator.infinityforreddit; - -import android.app.DownloadManager; -import android.content.Context; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.widget.Toast; - -import java.io.File; - -public class MediaDownloaderImpl implements MediaDownloader { - - @Override - public void download(String url, String fileName, Context ctx) { - DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); - request.setTitle(fileName); - - request.allowScanningByMediaScanner(); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - - //Android Q support - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, fileName); - } else { - String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString(); - File directory = new File(path + "/Infinity/"); - boolean saveToInfinityFolder = true; - if (!directory.exists()) { - if (!directory.mkdir()) { - saveToInfinityFolder = false; - } - } else { - if (directory.isFile()) { - if (!(directory.delete() && directory.mkdir())) { - saveToInfinityFolder = false; - } - } - } - - if (saveToInfinityFolder) { - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES + "/Infinity/", fileName); - } else { - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, fileName); - } - } - - DownloadManager manager = (DownloadManager) ctx.getSystemService(Context.DOWNLOAD_SERVICE); - - if (manager == null) { - Toast.makeText(ctx, R.string.download_failed, Toast.LENGTH_SHORT).show(); - return; - } - - manager.enqueue(request); - Toast.makeText(ctx, R.string.download_started, Toast.LENGTH_SHORT).show(); - } -} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MultiReddit/MultiRedditJSONModel.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MultiReddit/MultiRedditJSONModel.java index df921d35..665a9092 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/MultiReddit/MultiRedditJSONModel.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/MultiReddit/MultiRedditJSONModel.java @@ -35,14 +35,4 @@ public class MultiRedditJSONModel { Gson gson = new Gson(); return gson.toJson(this); } - - class SubredditInMultiReddit { - String name; - - SubredditInMultiReddit() {} - - SubredditInMultiReddit(String subredditName) { - name = subredditName; - } - } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MultiReddit/SubredditInMultiReddit.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MultiReddit/SubredditInMultiReddit.java new file mode 100644 index 00000000..34a1e638 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/MultiReddit/SubredditInMultiReddit.java @@ -0,0 +1,11 @@ +package ml.docilealligator.infinityforreddit.MultiReddit; + +public class SubredditInMultiReddit { + String name; + + SubredditInMultiReddit() {} + + SubredditInMultiReddit(String subredditName) { + name = subredditName; + } +}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/NotificationUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/NotificationUtils.java index 155e4b02..c0935772 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/NotificationUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/NotificationUtils.java @@ -13,8 +13,17 @@ public class NotificationUtils { static final String CHANNEL_NEW_MESSAGES = "New Messages"; public static final String CHANNEL_ID_DOWNLOAD_REDDIT_VIDEO = "download_reddit_video"; public static final String CHANNEL_DOWNLOAD_REDDIT_VIDEO = "Download Reddit Video"; + public static final String CHANNEL_ID_DOWNLOAD_VIDEO = "download_video"; + public static final String CHANNEL_DOWNLOAD_VIDEO = "Download Video"; + public static final String CHANNEL_ID_DOWNLOAD_IMAGE = "download_image"; + public static final String CHANNEL_DOWNLOAD_IMAGE = "Download Image"; + public static final String CHANNEL_ID_DOWNLOAD_GIF = "download_gif"; + public static final String CHANNEL_DOWNLOAD_GIF = "Download Gif"; public static final int SUBMIT_POST_SERVICE_NOTIFICATION_ID = 10000; public static final int DOWNLOAD_REDDIT_VIDEO_NOTIFICATION_ID = 20000; + public static final int DOWNLOAD_VIDEO_NOTIFICATION_ID = 30000; + public static final int DOWNLOAD_IMAGE_NOTIFICATION_ID = 40000; + public static final int DOWNLOAD_GIF_NOTIFICATION_ID = 50000; private static final int SUMMARY_BASE_ID_UNREAD_MESSAGE = 0; private static final int NOTIFICATION_BASE_ID_UNREAD_MESSAGE = 1; 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 56aff32d..d444a0b6 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/PostDataSource.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/PostDataSource.java @@ -1,5 +1,7 @@ package ml.docilealligator.infinityforreddit.Post; +import android.content.SharedPreferences; + import androidx.annotation.NonNull; import androidx.lifecycle.MutableLiveData; import androidx.paging.PageKeyedDataSource; @@ -9,10 +11,11 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; -import ml.docilealligator.infinityforreddit.NetworkState; import ml.docilealligator.infinityforreddit.API.RedditAPI; +import ml.docilealligator.infinityforreddit.NetworkState; import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.Utils.APIUtils; +import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Retrofit; @@ -34,7 +37,10 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { private Retrofit retrofit; private String accessToken; + private String accountName; private Locale locale; + private SharedPreferences sharedPreferences; + private SharedPreferences postFeedScrolledPositionSharedPreferences; private String subredditOrUserName; private String query; private int postType; @@ -52,11 +58,15 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { private LoadParams<String> params; private LoadCallback<String, Post> callback; - PostDataSource(Retrofit retrofit, String accessToken, Locale locale, int postType, SortType sortType, - int filter, boolean nsfw) { + PostDataSource(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, int postType, + SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; paginationNetworkStateLiveData = new MutableLiveData<>(); initialLoadStateLiveData = new MutableLiveData<>(); hasPostLiveData = new MutableLiveData<>(); @@ -67,11 +77,15 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { postLinkedHashSet = new LinkedHashSet<>(); } - PostDataSource(Retrofit retrofit, String accessToken, Locale locale, String path, int postType, + PostDataSource(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, String path, int postType, SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; if (postType == TYPE_SUBREDDIT) { this.subredditOrUserName = path; } else { @@ -103,11 +117,15 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { postLinkedHashSet = new LinkedHashSet<>(); } - PostDataSource(Retrofit retrofit, String accessToken, Locale locale, String subredditOrUserName, int postType, - SortType sortType, String where, int filter, boolean nsfw) { + PostDataSource(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, String subredditOrUserName, + int postType, SortType sortType, String where, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditOrUserName = subredditOrUserName; paginationNetworkStateLiveData = new MutableLiveData<>(); initialLoadStateLiveData = new MutableLiveData<>(); @@ -120,11 +138,15 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { postLinkedHashSet = new LinkedHashSet<>(); } - PostDataSource(Retrofit retrofit, String accessToken, Locale locale, String subredditOrUserName, String query, - int postType, SortType sortType, int filter, boolean nsfw) { + PostDataSource(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, String subredditOrUserName, + String query, int postType, SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditOrUserName = subredditOrUserName; this.query = query; paginationNetworkStateLiveData = new MutableLiveData<>(); @@ -152,10 +174,15 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { @Override public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull final LoadInitialCallback<String, Post> callback) { initialLoadStateLiveData.postValue(NetworkState.LOADING); - switch (postType) { case TYPE_FRONT_PAGE: - loadBestPostsInitial(callback, null); + boolean savePostFeedScrolledPosition = sortType != null && sortType.getType() == SortType.Type.BEST && sharedPreferences.getBoolean(SharedPreferencesUtils.SAVE_FRONT_PAGE_SCROLLED_POSITION, false); + String accountNameForCache = accountName == null ? SharedPreferencesUtils.FRONT_PAGE_SCROLLED_POSITION_ANONYMOUS : accountName; + if (savePostFeedScrolledPosition) { + loadBestPostsInitial(callback, postFeedScrolledPositionSharedPreferences.getString(accountNameForCache + SharedPreferencesUtils.FRONT_PAGE_SCROLLED_POSITION_FRONT_PAGE_BASE, null)); + } else { + loadBestPostsInitial(callback, null); + } break; case TYPE_SUBREDDIT: loadSubredditPostsInitial(callback, null); @@ -220,56 +247,38 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { @Override public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { if (response.isSuccessful()) { - if (sortType.getType().value.equals(SortType.Type.RANDOM.value)) { - ParsePost.parsePost(response.body(), locale, new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(Post post) { - ArrayList<Post> singlePostList = new ArrayList<>(); - singlePostList.add(post); - callback.onResult(singlePostList, null, null); - hasPostLiveData.postValue(true); - initialLoadStateLiveData.postValue(NetworkState.LOADED); - } - - @Override - public void onParsePostFail() { - initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data")); - } - }); - } else { - ParsePost.parsePosts(response.body(), locale, -1, filter, nsfw, - new ParsePost.ParsePostsListingListener() { - @Override - public void onParsePostsListingSuccess(LinkedHashSet<Post> newPosts, String lastItem) { - String nextPageKey; - if (lastItem == null || lastItem.equals("") || lastItem.equals("null")) { - nextPageKey = null; - } else { - nextPageKey = lastItem; - } - - if (newPosts.size() != 0) { - postLinkedHashSet.addAll(newPosts); - callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); - hasPostLiveData.postValue(true); - } else if (nextPageKey != null) { - loadBestPostsInitial(callback, nextPageKey); - return; - } else { - postLinkedHashSet.addAll(newPosts); - callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); - hasPostLiveData.postValue(false); - } - - initialLoadStateLiveData.postValue(NetworkState.LOADED); + ParsePost.parsePosts(response.body(), locale, -1, filter, nsfw, + new ParsePost.ParsePostsListingListener() { + @Override + public void onParsePostsListingSuccess(LinkedHashSet<Post> newPosts, String lastItem) { + String nextPageKey; + if (lastItem == null || lastItem.equals("") || lastItem.equals("null")) { + nextPageKey = null; + } else { + nextPageKey = lastItem; } - @Override - public void onParsePostsListingFail() { - initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing posts")); + if (newPosts.size() != 0) { + postLinkedHashSet.addAll(newPosts); + callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); + hasPostLiveData.postValue(true); + } else if (nextPageKey != null) { + loadBestPostsInitial(callback, nextPageKey); + return; + } else { + postLinkedHashSet.addAll(newPosts); + callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); + hasPostLiveData.postValue(false); } - }); - } + + initialLoadStateLiveData.postValue(NetworkState.LOADED); + } + + @Override + public void onParsePostsListingFail() { + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing posts")); + } + }); } else { initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "code: " + response.code() + " message: " + response.message())); @@ -361,56 +370,38 @@ public class PostDataSource extends PageKeyedDataSource<String, Post> { @Override public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { if (response.isSuccessful()) { - if (sortType.getType().value.equals(SortType.Type.RANDOM.value)) { - ParsePost.parsePost(response.body(), locale, new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(Post post) { - ArrayList<Post> singlePostList = new ArrayList<>(); - singlePostList.add(post); - callback.onResult(singlePostList, null, null); - hasPostLiveData.postValue(true); - initialLoadStateLiveData.postValue(NetworkState.LOADED); - } - - @Override - public void onParsePostFail() { - initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data")); - } - }); - } else { - ParsePost.parsePosts(response.body(), locale, -1, filter, nsfw, - new ParsePost.ParsePostsListingListener() { - @Override - public void onParsePostsListingSuccess(LinkedHashSet<Post> newPosts, String lastItem) { - String nextPageKey; - if (lastItem == null || lastItem.equals("") || lastItem.equals("null")) { - nextPageKey = null; - } else { - nextPageKey = lastItem; - } - - if (newPosts.size() != 0) { - postLinkedHashSet.addAll(newPosts); - callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); - hasPostLiveData.postValue(true); - } else if (nextPageKey != null) { - loadSubredditPostsInitial(callback, nextPageKey); - return; - } else { - postLinkedHashSet.addAll(newPosts); - callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); - hasPostLiveData.postValue(false); - } - - initialLoadStateLiveData.postValue(NetworkState.LOADED); + ParsePost.parsePosts(response.body(), locale, -1, filter, nsfw, + new ParsePost.ParsePostsListingListener() { + @Override + public void onParsePostsListingSuccess(LinkedHashSet<Post> newPosts, String lastItem) { + String nextPageKey; + if (lastItem == null || lastItem.equals("") || lastItem.equals("null")) { + nextPageKey = null; + } else { + nextPageKey = lastItem; } - @Override - public void onParsePostsListingFail() { - initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing posts")); + if (newPosts.size() != 0) { + postLinkedHashSet.addAll(newPosts); + callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); + hasPostLiveData.postValue(true); + } else if (nextPageKey != null) { + loadSubredditPostsInitial(callback, nextPageKey); + return; + } else { + postLinkedHashSet.addAll(newPosts); + callback.onResult(new ArrayList<>(newPosts), null, nextPageKey); + hasPostLiveData.postValue(false); } - }); - } + + initialLoadStateLiveData.postValue(NetworkState.LOADED); + } + + @Override + public void onParsePostsListingFail() { + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing posts")); + } + }); } else { initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "code: " + response + " message: " + response.message())); 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 eb953d7d..39c4d6b1 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/PostDataSourceFactory.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/PostDataSourceFactory.java @@ -1,5 +1,7 @@ package ml.docilealligator.infinityforreddit.Post; +import android.content.SharedPreferences; + import androidx.annotation.NonNull; import androidx.lifecycle.MutableLiveData; import androidx.paging.DataSource; @@ -12,7 +14,10 @@ import retrofit2.Retrofit; class PostDataSourceFactory extends DataSource.Factory { private Retrofit retrofit; private String accessToken; + private String accountName; private Locale locale; + private SharedPreferences sharedPreferences; + private SharedPreferences postFeedScrolledPositionSharedPreferences; private String subredditName; private String query; private int postType; @@ -24,11 +29,15 @@ class PostDataSourceFactory extends DataSource.Factory { private PostDataSource postDataSource; private MutableLiveData<PostDataSource> postDataSourceLiveData; - PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, int postType, SortType sortType, - int filter, boolean nsfw) { + PostDataSourceFactory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, + int postType, SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; postDataSourceLiveData = new MutableLiveData<>(); this.postType = postType; this.sortType = sortType; @@ -36,11 +45,15 @@ class PostDataSourceFactory extends DataSource.Factory { this.nsfw = nsfw; } - PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, String subredditName, - int postType, SortType sortType, int filter, boolean nsfw) { + PostDataSourceFactory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, + String subredditName, int postType, SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditName = subredditName; postDataSourceLiveData = new MutableLiveData<>(); this.postType = postType; @@ -49,11 +62,16 @@ class PostDataSourceFactory extends DataSource.Factory { this.nsfw = nsfw; } - PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, String subredditName, - int postType, SortType sortType, String where, int filter, boolean nsfw) { + PostDataSourceFactory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, + String subredditName, int postType, SortType sortType, String where, int filter, + boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditName = subredditName; postDataSourceLiveData = new MutableLiveData<>(); this.postType = postType; @@ -63,11 +81,16 @@ class PostDataSourceFactory extends DataSource.Factory { this.nsfw = nsfw; } - PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, String subredditName, - String query, int postType, SortType sortType, int filter, boolean nsfw) { + PostDataSourceFactory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, + String subredditName, String query, int postType, SortType sortType, int filter, + boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditName = subredditName; this.query = query; postDataSourceLiveData = new MutableLiveData<>(); @@ -81,17 +104,17 @@ class PostDataSourceFactory extends DataSource.Factory { @Override public DataSource<String, Post> create() { if (postType == PostDataSource.TYPE_FRONT_PAGE) { - postDataSource = new PostDataSource(retrofit, accessToken, locale, postType, sortType, - filter, nsfw); + postDataSource = new PostDataSource(retrofit, accessToken, accountName, locale, + sharedPreferences, postFeedScrolledPositionSharedPreferences, postType, sortType, filter, nsfw); } else if (postType == PostDataSource.TYPE_SEARCH) { - postDataSource = new PostDataSource(retrofit, accessToken, locale, subredditName, query, - postType, sortType, filter, nsfw); + postDataSource = new PostDataSource(retrofit, accessToken, accountName, locale, + sharedPreferences, postFeedScrolledPositionSharedPreferences, subredditName, query, postType, sortType, filter, nsfw); } else if (postType == PostDataSource.TYPE_SUBREDDIT || postType == PostDataSource.TYPE_MULTI_REDDIT) { - postDataSource = new PostDataSource(retrofit, accessToken, locale, subredditName, postType, - sortType, filter, nsfw); + postDataSource = new PostDataSource(retrofit, accessToken, accountName, locale, + sharedPreferences, postFeedScrolledPositionSharedPreferences, subredditName, postType, sortType, filter, nsfw); } else { - postDataSource = new PostDataSource(retrofit, accessToken, locale, subredditName, postType, - sortType, userWhere, filter, nsfw); + postDataSource = new PostDataSource(retrofit, accessToken, accountName, locale, + sharedPreferences, postFeedScrolledPositionSharedPreferences, subredditName, postType, sortType, userWhere, filter, nsfw); } postDataSourceLiveData.postValue(postDataSource); 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 6c7464d3..c141aa8a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/PostViewModel.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/PostViewModel.java @@ -1,5 +1,7 @@ package ml.docilealligator.infinityforreddit.Post; +import android.content.SharedPreferences; + import androidx.annotation.NonNull; import androidx.core.util.Pair; import androidx.lifecycle.LiveData; @@ -27,10 +29,11 @@ public class PostViewModel extends ViewModel { private MutableLiveData<SortType> sortTypeLiveData; private NSFWAndSortTypeLiveData nsfwAndSortTypeLiveData; - public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, int postType, SortType sortType, - int filter, boolean nsfw) { - postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, postType, - sortType, filter, nsfw); + public PostViewModel(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences cache, int postType, + SortType sortType, int filter, boolean nsfw) { + postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, accountName, locale, + sharedPreferences, cache, postType, sortType, filter, nsfw); initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), PostDataSource::getInitialLoadStateLiveData); @@ -58,10 +61,11 @@ public class PostViewModel extends ViewModel { }); } - public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, String subredditName, int postType, - SortType sortType, int filter, boolean nsfw) { - postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, subredditName, - postType, sortType, filter, nsfw); + public PostViewModel(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences cache, String subredditName, + int postType, SortType sortType, int filter, boolean nsfw) { + postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, accountName, locale, + sharedPreferences, cache, subredditName, postType, sortType, filter, nsfw); initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), PostDataSource::getInitialLoadStateLiveData); @@ -89,10 +93,12 @@ public class PostViewModel extends ViewModel { }); } - public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, String subredditName, int postType, - SortType sortType, String where, int filter, boolean nsfw) { - postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, subredditName, - postType, sortType, where, filter, nsfw); + public PostViewModel(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences cache, String subredditName, + int postType, SortType sortType, String where, int filter, + boolean nsfw) { + postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, accountName, locale, + sharedPreferences, cache, subredditName, postType, sortType, where, filter, nsfw); initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), PostDataSource::getInitialLoadStateLiveData); @@ -120,10 +126,12 @@ public class PostViewModel extends ViewModel { }); } - public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, String subredditName, String query, - int postType, SortType sortType, int filter, boolean nsfw) { - postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, subredditName, - query, postType, sortType, filter, nsfw); + public PostViewModel(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences cache, String subredditName, + String query, int postType, SortType sortType, int filter, + boolean nsfw) { + postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, accountName, locale, + sharedPreferences, cache, subredditName, query, postType, sortType, filter, nsfw); initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), PostDataSource::getInitialLoadStateLiveData); @@ -186,7 +194,10 @@ public class PostViewModel extends ViewModel { public static class Factory extends ViewModelProvider.NewInstanceFactory { private Retrofit retrofit; private String accessToken; + private String accountName; private Locale locale; + private SharedPreferences sharedPreferences; + private SharedPreferences postFeedScrolledPositionSharedPreferences; private String subredditName; private String query; private int postType; @@ -195,22 +206,30 @@ public class PostViewModel extends ViewModel { private int filter; private boolean nsfw; - public Factory(Retrofit retrofit, String accessToken, Locale locale, int postType, SortType sortType, - int filter, boolean nsfw) { + public Factory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, + int postType, SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.postType = postType; this.sortType = sortType; this.filter = filter; this.nsfw = nsfw; } - public Factory(Retrofit retrofit, String accessToken, Locale locale, String subredditName, int postType, - SortType sortType, int filter, boolean nsfw) { + public Factory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, String subredditName, + int postType, SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditName = subredditName; this.postType = postType; this.sortType = sortType; @@ -219,11 +238,16 @@ public class PostViewModel extends ViewModel { } //User posts - public Factory(Retrofit retrofit, String accessToken, Locale locale, String subredditName, int postType, - SortType sortType, String where, int filter, boolean nsfw) { + public Factory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, String subredditName, + int postType, SortType sortType, String where, int filter, + boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditName = subredditName; this.postType = postType; this.sortType = sortType; @@ -232,11 +256,15 @@ public class PostViewModel extends ViewModel { this.nsfw = nsfw; } - public Factory(Retrofit retrofit, String accessToken, Locale locale, String subredditName, String query, - int postType, SortType sortType, int filter, boolean nsfw) { + public Factory(Retrofit retrofit, String accessToken, String accountName, Locale locale, + SharedPreferences sharedPreferences, SharedPreferences postFeedScrolledPositionSharedPreferences, String subredditName, + String query, int postType, SortType sortType, int filter, boolean nsfw) { this.retrofit = retrofit; this.accessToken = accessToken; + this.accountName = accountName; this.locale = locale; + this.sharedPreferences = sharedPreferences; + this.postFeedScrolledPositionSharedPreferences = postFeedScrolledPositionSharedPreferences; this.subredditName = subredditName; this.query = query; this.postType = postType; @@ -249,17 +277,17 @@ public class PostViewModel extends ViewModel { @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { if (postType == PostDataSource.TYPE_FRONT_PAGE) { - return (T) new PostViewModel(retrofit, accessToken, locale, postType, sortType, filter, - nsfw); + return (T) new PostViewModel(retrofit, accessToken, accountName, locale, sharedPreferences, + postFeedScrolledPositionSharedPreferences, postType, sortType, filter, nsfw); } else if (postType == PostDataSource.TYPE_SEARCH) { - return (T) new PostViewModel(retrofit, accessToken, locale, subredditName, query, - postType, sortType, filter, nsfw); + return (T) new PostViewModel(retrofit, accessToken, accountName, locale, sharedPreferences, + postFeedScrolledPositionSharedPreferences, subredditName, query, postType, sortType, filter, nsfw); } else if (postType == PostDataSource.TYPE_SUBREDDIT || postType == PostDataSource.TYPE_MULTI_REDDIT) { - return (T) new PostViewModel(retrofit, accessToken, locale, subredditName, postType, - sortType, filter, nsfw); + return (T) new PostViewModel(retrofit, accessToken, accountName, locale, sharedPreferences, + postFeedScrolledPositionSharedPreferences, subredditName, postType, sortType, filter, nsfw); } else { - return (T) new PostViewModel(retrofit, accessToken, locale, subredditName, postType, - sortType, userWhere, filter, nsfw); + return (T) new PostViewModel(retrofit, accessToken, accountName, locale, sharedPreferences, + postFeedScrolledPositionSharedPreferences, subredditName, postType, sortType, userWhere, filter, nsfw); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/SubmitPost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/SubmitPost.java index 01a0cb3d..c1c908f2 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/SubmitPost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/SubmitPost.java @@ -157,6 +157,14 @@ public class SubmitPost { }); } + public static void submitCrosspost(Retrofit oauthRetrofit, String accessToken, + Locale locale, String subredditName, String title, String crosspostFullname, + Flair flair, boolean isSpoiler, boolean isNSFW, String kind, + SubmitPostListener submitPostListener) { + submitPost(oauthRetrofit, accessToken, locale, subredditName, title, crosspostFullname, + flair, isSpoiler, isNSFW, kind, null, submitPostListener); + } + private static void submitPost(Retrofit oauthRetrofit, String accessToken, Locale locale, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW, String kind, @@ -185,6 +193,9 @@ public class SubmitPost { params.put(APIUtils.URL_KEY, content); params.put(APIUtils.VIDEO_POSTER_URL_KEY, posterUrl); break; + case APIUtils.KIND_CROSSPOST: + params.put(APIUtils.CROSSPOST_FULLNAME_KEY, content); + break; } if (flair != null) { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Service/DownloadMediaService.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Service/DownloadMediaService.java new file mode 100644 index 00000000..fd552784 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Service/DownloadMediaService.java @@ -0,0 +1,414 @@ +package ml.docilealligator.infinityforreddit.Service; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.media.MediaScannerConnection; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Environment; +import android.os.IBinder; +import android.provider.MediaStore; + +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.documentfile.provider.DocumentFile; + +import org.greenrobot.eventbus.EventBus; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.inject.Inject; +import javax.inject.Named; + +import ml.docilealligator.infinityforreddit.API.DownloadFile; +import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; +import ml.docilealligator.infinityforreddit.Event.DownloadMediaEvent; +import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.NotificationUtils; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; +import okhttp3.ResponseBody; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +import static android.os.Environment.getExternalStoragePublicDirectory; + +public class DownloadMediaService extends Service { + public static final String EXTRA_URL = "EU"; + public static final String EXTRA_FILE_NAME = "EFN"; + public static final String EXTRA_MEDIA_TYPE = "EIG"; + public static final int EXTRA_MEDIA_TYPE_IMAGE = 0; + public static final int EXTRA_MEDIA_TYPE_GIF = 1; + public static final int EXTRA_MEDIA_TYPE_VIDEO = 2; + + private static final int NO_ERROR = -1; + private static final int ERROR_CANNOT_GET_DESTINATION_DIRECTORY = 0; + private static final int ERROR_FILE_CANNOT_DOWNLOAD = 1; + private static final int ERROR_FILE_CANNOT_SAVE = 2; + @Inject + @Named("download_media") + Retrofit retrofit; + @Inject + @Named("default") + SharedPreferences mSharedPreferences; + @Inject + CustomThemeWrapper mCustomThemeWrapper; + private int mediaType; + + public DownloadMediaService() { + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private String getNotificationChannelId() { + switch (mediaType) { + case EXTRA_MEDIA_TYPE_GIF: + return NotificationUtils.CHANNEL_ID_DOWNLOAD_GIF; + case EXTRA_MEDIA_TYPE_VIDEO: + return NotificationUtils.CHANNEL_ID_DOWNLOAD_VIDEO; + default: + return NotificationUtils.CHANNEL_ID_DOWNLOAD_IMAGE; + } + } + + private String getNotificationChannel() { + switch (mediaType) { + case EXTRA_MEDIA_TYPE_GIF: + return NotificationUtils.CHANNEL_DOWNLOAD_GIF; + case EXTRA_MEDIA_TYPE_VIDEO: + return NotificationUtils.CHANNEL_DOWNLOAD_VIDEO; + default: + return NotificationUtils.CHANNEL_DOWNLOAD_IMAGE; + } + } + + private int getNotificationId() { + switch (mediaType) { + case EXTRA_MEDIA_TYPE_GIF: + return NotificationUtils.DOWNLOAD_GIF_NOTIFICATION_ID; + case EXTRA_MEDIA_TYPE_VIDEO: + return NotificationUtils.DOWNLOAD_VIDEO_NOTIFICATION_ID; + default: + return NotificationUtils.DOWNLOAD_IMAGE_NOTIFICATION_ID; + } + } + + private String getDownloadLocation() { + switch (mediaType) { + case EXTRA_MEDIA_TYPE_GIF: + return mSharedPreferences.getString(SharedPreferencesUtils.GIF_DOWNLOAD_LOCATION, ""); + case EXTRA_MEDIA_TYPE_VIDEO: + return mSharedPreferences.getString(SharedPreferencesUtils.VIDEO_DOWNLOAD_LOCATION, ""); + default: + return mSharedPreferences.getString(SharedPreferencesUtils.IMAGE_DOWNLOAD_LOCATION, ""); + } + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + ((Infinity) getApplication()).getAppComponent().inject(this); + + String fileUrl = intent.getStringExtra(EXTRA_URL); + String fileName; + fileName = intent.getStringExtra(EXTRA_FILE_NAME); + mediaType = intent.getIntExtra(EXTRA_MEDIA_TYPE, EXTRA_MEDIA_TYPE_IMAGE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel serviceChannel; + serviceChannel = new NotificationChannel( + getNotificationChannelId(), + getNotificationChannel(), + NotificationManager.IMPORTANCE_LOW + ); + + NotificationManagerCompat manager = NotificationManagerCompat.from(this); + manager.createNotificationChannel(serviceChannel); + } + + switch (mediaType) { + case EXTRA_MEDIA_TYPE_GIF: + startForeground( + NotificationUtils.DOWNLOAD_GIF_NOTIFICATION_ID, + createNotification(R.string.downloading_gif, fileName, null) + ); + break; + case EXTRA_MEDIA_TYPE_VIDEO: + startForeground( + NotificationUtils.DOWNLOAD_VIDEO_NOTIFICATION_ID, + createNotification(R.string.downloading_video, fileName, null) + ); + break; + default: + startForeground( + NotificationUtils.DOWNLOAD_IMAGE_NOTIFICATION_ID, + createNotification(R.string.downloading_image, fileName, null) + ); + } + + retrofit.create(DownloadFile.class).downloadFile(fileUrl).enqueue(new Callback<ResponseBody>() { + @Override + public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) { + if (response.isSuccessful() && response.body() != null) { + String destinationFileDirectory = getDownloadLocation(); + String destinationFileUriString; + boolean isDefaultDestination; + if (destinationFileDirectory.equals("")) { + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + File directory = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + if (directory != null) { + String directoryPath = directory.getAbsolutePath() + "/Infinity/"; + File infinityDir = new File(directoryPath); + if (!infinityDir.exists() && !infinityDir.mkdir()) { + downloadFinished(null, fileName, ERROR_CANNOT_GET_DESTINATION_DIRECTORY); + return; + } + destinationFileUriString = directoryPath + fileName; + } else { + downloadFinished(null, fileName, ERROR_CANNOT_GET_DESTINATION_DIRECTORY); + return; + } + } else { + destinationFileUriString = Environment.DIRECTORY_PICTURES + "/Infinity/"; + } + isDefaultDestination = true; + } else { + isDefaultDestination = false; + DocumentFile picFile = DocumentFile.fromTreeUri(DownloadMediaService.this, Uri.parse(destinationFileDirectory)).createFile("image/*", fileName); + if (picFile == null) { + downloadFinished(null, fileName, ERROR_CANNOT_GET_DESTINATION_DIRECTORY); + return; + } + destinationFileUriString = picFile.getUri().toString(); + } + + new SaveImageOrGifAndCopyToExternalStorageAsyncTask(response.body(), mediaType, + isDefaultDestination, fileName, destinationFileUriString, getContentResolver(), + new SaveImageOrGifAndCopyToExternalStorageAsyncTask.SaveImageOrGifAndCopyToExternalStorageAsyncTaskListener() { + @Override + public void finished(Uri destinationFileUri, int errorCode) { + downloadFinished(destinationFileUri, fileName, errorCode); + } + + @Override + public void updateProgressNotification(int stringResId) { + updateNotification(stringResId, fileName, null); + } + }).execute(); + } + } + + @Override + public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) { + downloadFinished(null, fileName, ERROR_FILE_CANNOT_DOWNLOAD); + } + }); + return super.onStartCommand(intent, flags, startId); + } + + private Notification createNotification(int stringResId, String fileName, PendingIntent pendingIntent) { + NotificationCompat.Builder builder; + builder = new NotificationCompat.Builder(this, getNotificationChannelId()); + builder.setContentTitle(fileName).setContentText(getString(stringResId)); + if (pendingIntent != null) { + builder.setContentIntent(pendingIntent); + } + return builder.setSmallIcon(R.drawable.ic_notification) + .setColor(mCustomThemeWrapper.getColorPrimaryLightTheme()) + .build(); + } + + private void updateNotification(int stringResId, String fileName, PendingIntent pendingIntent) { + NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + if (notificationManager != null) { + notificationManager.notify(getNotificationId(), createNotification(stringResId, fileName, pendingIntent)); + } + } + + private void downloadFinished(Uri destinationFileUri, String fileName, int errorCode) { + if (errorCode != NO_ERROR) { + switch (errorCode) { + case ERROR_CANNOT_GET_DESTINATION_DIRECTORY: + updateNotification(R.string.downloading_image_or_gif_failed_cannot_get_destination_directory, fileName, null); + break; + case ERROR_FILE_CANNOT_DOWNLOAD: + updateNotification(R.string.downloading_media_failed_cannot_download_media, fileName, null); + break; + case ERROR_FILE_CANNOT_SAVE: + updateNotification(R.string.downloading_media_failed_cannot_save_to_destination_directory, fileName, null); + break; + } + EventBus.getDefault().post(new DownloadMediaEvent(false)); + } else { + MediaScannerConnection.scanFile( + this, new String[]{destinationFileUri.toString()}, null, + (path, uri) -> { + Intent intent = new Intent(); + intent.setAction(android.content.Intent.ACTION_VIEW); + intent.setDataAndType(destinationFileUri, "image/*"); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + updateNotification(R.string.downloading_media_finished, fileName, pendingIntent); + EventBus.getDefault().post(new DownloadMediaEvent(true)); + } + ); + } + stopForeground(false); + } + + private static class SaveImageOrGifAndCopyToExternalStorageAsyncTask extends AsyncTask<Void, Integer, Void> { + + private ResponseBody response; + private int mediaType; + private boolean isDefaultDestination; + private String destinationFileName; + @NonNull + private String destinationFileUriString; + private ContentResolver contentResolver; + private SaveImageOrGifAndCopyToExternalStorageAsyncTaskListener saveImageOrGifAndCopyToExternalStorageAsyncTaskListener; + private int errorCode = NO_ERROR; + + interface SaveImageOrGifAndCopyToExternalStorageAsyncTaskListener { + void finished(Uri destinationFileUri, int errorCode); + void updateProgressNotification(int stringResId); + } + + public SaveImageOrGifAndCopyToExternalStorageAsyncTask(ResponseBody response, int mediaType, + boolean isDefaultDestination, + String destinationFileName, + @NonNull String destinationFileUriString, + ContentResolver contentResolver, + SaveImageOrGifAndCopyToExternalStorageAsyncTaskListener saveImageOrGifAndCopyToExternalStorageAsyncTaskListener) { + this.response = response; + this.mediaType = mediaType; + this.isDefaultDestination = isDefaultDestination; + this.destinationFileName = destinationFileName; + this.destinationFileUriString = destinationFileUriString; + this.contentResolver = contentResolver; + this.saveImageOrGifAndCopyToExternalStorageAsyncTaskListener = saveImageOrGifAndCopyToExternalStorageAsyncTaskListener; + } + + @Override + protected void onProgressUpdate(Integer... values) { + super.onProgressUpdate(values); + saveImageOrGifAndCopyToExternalStorageAsyncTaskListener.updateProgressNotification(values[0]); + } + + @Override + protected Void doInBackground(Void... voids) { + switch (mediaType) { + case EXTRA_MEDIA_TYPE_IMAGE: + publishProgress(R.string.downloading_image_save_image); + break; + case EXTRA_MEDIA_TYPE_GIF: + publishProgress(R.string.downloading_gif_save_gif); + break; + case EXTRA_MEDIA_TYPE_VIDEO: + publishProgress(R.string.downloading_video_save_video); + } + + try { + writeResponseBodyToDisk(response); + } catch (IOException e) { + errorCode = ERROR_FILE_CANNOT_SAVE; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + saveImageOrGifAndCopyToExternalStorageAsyncTaskListener.finished(Uri.parse(destinationFileUriString), errorCode); + } + + private void writeResponseBodyToDisk(ResponseBody body) throws IOException { + if (isDefaultDestination) { + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + InputStream inputStream = body.byteStream(); + OutputStream outputStream = new FileOutputStream(destinationFileUriString); + byte[] fileReader = new byte[4096]; + + long fileSize = body.contentLength(); + long fileSizeDownloaded = 0; + + while (true) { + int read = inputStream.read(fileReader); + + if (read == -1) { + break; + } + + outputStream.write(fileReader, 0, read); + + fileSizeDownloaded += read; + } + + outputStream.flush(); + } else { + String relativeLocation = Environment.DIRECTORY_PICTURES + "/Infinity/"; + + ContentValues contentValues = new ContentValues(); + contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, destinationFileName); + contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/*"); + contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation); + contentValues.put(MediaStore.Images.Media.IS_PENDING, 1); + + final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + Uri uri = contentResolver.insert(contentUri, contentValues); + + if (uri == null) { + throw new IOException("Failed to create new MediaStore record."); + } + + OutputStream stream = contentResolver.openOutputStream(uri); + + if (stream == null) { + throw new IOException("Failed to get output stream."); + } + + InputStream in = body.byteStream(); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + stream.write(buf, 0, len); + } + contentValues.clear(); + contentValues.put(MediaStore.Images.Media.IS_PENDING, 0); + contentResolver.update(uri, contentValues, null, null); + destinationFileUriString = uri.toString(); + } + } else { + try (OutputStream stream = contentResolver.openOutputStream(Uri.parse(destinationFileUriString))) { + if (stream == null) { + throw new IOException("Failed to get output stream."); + } + + InputStream in = body.byteStream(); + + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + stream.write(buf, 0, len); + } + } + } + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Service/DownloadRedditVideoService.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Service/DownloadRedditVideoService.java index 562ff432..2e08b0f6 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Service/DownloadRedditVideoService.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Service/DownloadRedditVideoService.java @@ -9,6 +9,7 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.media.MediaCodec; import android.media.MediaExtractor; import android.media.MediaFormat; @@ -22,9 +23,9 @@ import android.os.IBinder; import android.provider.MediaStore; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; +import androidx.documentfile.provider.DocumentFile; import org.greenrobot.eventbus.EventBus; @@ -39,12 +40,13 @@ import java.nio.ByteBuffer; import javax.inject.Inject; import javax.inject.Named; -import ml.docilealligator.infinityforreddit.API.DownloadRedditVideo; +import ml.docilealligator.infinityforreddit.API.DownloadFile; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.Event.DownloadRedditVideoEvent; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.NotificationUtils; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Callback; @@ -66,12 +68,16 @@ public class DownloadRedditVideoService extends Service { private static final int ERROR_AUDIO_FILE_CANNOT_SAVE = 3; private static final int ERROR_MUX_FAILED = 4; private static final int ERROR_MUXED_VIDEO_FILE_CANNOT_SAVE = 5; + private static final int ERROR_CANNOT_GET_DESTINATION_DIRECTORY = 6; @Inject - @Named("download_reddit_video") + @Named("download_media") Retrofit retrofit; @Inject - CustomThemeWrapper mCustomThemeWrapper; + @Named("default") + SharedPreferences sharedPreferences; + @Inject + CustomThemeWrapper customThemeWrapper; String resultFile; public DownloadRedditVideoService() { @@ -87,10 +93,12 @@ public class DownloadRedditVideoService extends Service { ((Infinity) getApplication()).getAppComponent().inject(this); String videoUrl = intent.getStringExtra(EXTRA_VIDEO_URL); - String audioUrl = videoUrl.substring(0, videoUrl.lastIndexOf('/')) + "/audio"; + String audioUrl = videoUrl.substring(0, videoUrl.lastIndexOf('/')) + "/DASH_audio.mp4"; + String fileName = intent.getStringExtra(EXTRA_SUBREDDIT) + "-" + intent.getStringExtra(EXTRA_POST_ID); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationChannel serviceChannel = new NotificationChannel( + NotificationChannel serviceChannel; + serviceChannel = new NotificationChannel( NotificationUtils.CHANNEL_ID_DOWNLOAD_REDDIT_VIDEO, NotificationUtils.CHANNEL_DOWNLOAD_REDDIT_VIDEO, NotificationManager.IMPORTANCE_LOW @@ -100,25 +108,55 @@ public class DownloadRedditVideoService extends Service { manager.createNotificationChannel(serviceChannel); } - String fileName = intent.getStringExtra(EXTRA_SUBREDDIT) + "-" + intent.getStringExtra(EXTRA_POST_ID); - startForeground( NotificationUtils.DOWNLOAD_REDDIT_VIDEO_NOTIFICATION_ID, createNotification(R.string.downloading_reddit_video, fileName + ".mp4", null) ); - DownloadRedditVideo downloadRedditVideo = retrofit.create(DownloadRedditVideo.class); + DownloadFile downloadFile = retrofit.create(DownloadFile.class); File directory = getExternalCacheDir(); String destinationFileName = fileName + ".mp4"; if (directory != null) { String directoryPath = directory.getAbsolutePath() + "/"; - downloadRedditVideo.downloadFile(videoUrl).enqueue(new Callback<ResponseBody>() { + downloadFile.downloadFile(videoUrl).enqueue(new Callback<ResponseBody>() { @Override public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> videoResponse) { if (videoResponse.isSuccessful() && videoResponse.body() != null) { + String destinationFileDirectory = sharedPreferences.getString(SharedPreferencesUtils.VIDEO_DOWNLOAD_LOCATION, ""); + String destinationFileUriString; + boolean isDefaultDestination; + if (destinationFileDirectory.equals("")) { + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + File directory = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + if (directory != null) { + String directoryPath = directory.getAbsolutePath() + "/Infinity/"; + File infinityDir = new File(directoryPath); + if (!infinityDir.exists() && !infinityDir.mkdir()) { + downloadFinished(null, destinationFileName, ERROR_CANNOT_GET_DESTINATION_DIRECTORY); + return; + } + destinationFileUriString = directoryPath + destinationFileName; + } else { + downloadFinished(null, destinationFileName, ERROR_CANNOT_GET_DESTINATION_DIRECTORY); + return; + } + } else { + destinationFileUriString = Environment.DIRECTORY_PICTURES + "/Infinity/"; + } + isDefaultDestination = true; + } else { + isDefaultDestination = false; + DocumentFile picFile = DocumentFile.fromTreeUri(DownloadRedditVideoService.this, Uri.parse(destinationFileDirectory)).createFile("video/*", destinationFileName); + if (picFile == null) { + downloadFinished(null, destinationFileName, ERROR_CANNOT_GET_DESTINATION_DIRECTORY); + return; + } + destinationFileUriString = picFile.getUri().toString(); + } + updateNotification(R.string.downloading_reddit_video_audio_track, destinationFileName, null); - downloadRedditVideo.downloadFile(audioUrl).enqueue(new Callback<ResponseBody>() { + downloadFile.downloadFile(audioUrl).enqueue(new Callback<ResponseBody>() { @Override public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> audioResponse) { if (audioResponse.isSuccessful() && audioResponse.body() != null) { @@ -127,7 +165,8 @@ public class DownloadRedditVideoService extends Service { String outputFilePath = directoryPath + fileName + ".mp4"; new SaveTempMuxAndCopyAsyncTask(videoResponse.body(), audioResponse.body(), videoFilePath, audioFilePath, outputFilePath, - destinationFileName, getContentResolver(), + destinationFileName, destinationFileUriString, isDefaultDestination, + getContentResolver(), new SaveTempMuxAndCopyAsyncTask.SaveTempMuxAndCopyAsyncTaskListener() { @Override public void finished(Uri destinationFileUri, int errorCode) { @@ -144,10 +183,10 @@ public class DownloadRedditVideoService extends Service { }).execute(); } else { String videoFilePath = directoryPath + fileName + "-cache.mp4"; - String destinationFileName = fileName + ".mp4"; new SaveTempMuxAndCopyAsyncTask(videoResponse.body(), null, videoFilePath, null, null, - destinationFileName, getContentResolver(), + destinationFileName, destinationFileUriString, isDefaultDestination, + getContentResolver(), new SaveTempMuxAndCopyAsyncTask.SaveTempMuxAndCopyAsyncTaskListener() { @Override public void finished(Uri destinationFileUri, int errorCode) { @@ -166,10 +205,10 @@ public class DownloadRedditVideoService extends Service { @Override public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) { String videoFilePath = directoryPath + fileName + "-cache.mp4"; - String destinationFileName = fileName + ".mp4"; new SaveTempMuxAndCopyAsyncTask(videoResponse.body(), null, videoFilePath, null, null, - destinationFileName, getContentResolver(), + destinationFileName, destinationFileUriString, isDefaultDestination, + getContentResolver(), new SaveTempMuxAndCopyAsyncTask.SaveTempMuxAndCopyAsyncTaskListener() { @Override public void finished(Uri destinationFileUri, int errorCode) { @@ -222,6 +261,9 @@ public class DownloadRedditVideoService extends Service { case ERROR_MUXED_VIDEO_FILE_CANNOT_SAVE: updateNotification(R.string.downloading_reddit_video_failed_cannot_save_mux_video, fileName, null); break; + case ERROR_CANNOT_GET_DESTINATION_DIRECTORY: + updateNotification(R.string.downloading_media_failed_cannot_save_to_destination_directory, fileName, null); + break; } EventBus.getDefault().post(new DownloadRedditVideoEvent(false)); } else { @@ -247,7 +289,7 @@ public class DownloadRedditVideoService extends Service { builder.setContentIntent(pendingIntent); } return builder.setSmallIcon(R.drawable.ic_notification) - .setColor(mCustomThemeWrapper.getColorPrimaryLightTheme()) + .setColor(customThemeWrapper.getColorPrimaryLightTheme()) .build(); } @@ -267,14 +309,17 @@ public class DownloadRedditVideoService extends Service { private String audioFilePath; private String outputFilePath; private String destinationFileName; + @NonNull + private String destinationFileUriString; + private boolean isDefaultDestination; private ContentResolver contentResolver; private SaveTempMuxAndCopyAsyncTaskListener saveTempMuxAndCopyAsyncTaskListener; - private Uri destinationFileUri; private int errorCode = NO_ERROR; public SaveTempMuxAndCopyAsyncTask(ResponseBody videoResponse, ResponseBody audioResponse, String videoFilePath, String audioFilePath, String outputFilePath, - String destinationFileName, ContentResolver contentResolver, + String destinationFileName, @NonNull String destinationFileUriString, + boolean isDefaultDestination, ContentResolver contentResolver, SaveTempMuxAndCopyAsyncTaskListener saveTempMuxAndCopyAsyncTaskListener) { this.videoResponse = videoResponse; this.audioResponse = audioResponse; @@ -282,6 +327,8 @@ public class DownloadRedditVideoService extends Service { this.audioFilePath = audioFilePath; this.outputFilePath = outputFilePath; this.destinationFileName = destinationFileName; + this.destinationFileUriString = destinationFileUriString; + this.isDefaultDestination = isDefaultDestination; this.contentResolver = contentResolver; this.saveTempMuxAndCopyAsyncTaskListener = saveTempMuxAndCopyAsyncTaskListener; } @@ -315,10 +362,20 @@ public class DownloadRedditVideoService extends Service { } publishProgress(R.string.downloading_reddit_video_save_file_to_public_dir); - copyToDestination(outputFilePath); + try { + copyToDestination(outputFilePath); + } catch (IOException e) { + e.printStackTrace(); + errorCode = ERROR_MUXED_VIDEO_FILE_CANNOT_SAVE; + } } else { publishProgress(R.string.downloading_reddit_video_save_file_to_public_dir); - copyToDestination(videoFilePath); + try { + copyToDestination(videoFilePath); + } catch (IOException e) { + e.printStackTrace(); + errorCode = ERROR_MUXED_VIDEO_FILE_CANNOT_SAVE; + } } return null; } @@ -326,7 +383,7 @@ public class DownloadRedditVideoService extends Service { @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); - saveTempMuxAndCopyAsyncTaskListener.finished(destinationFileUri, errorCode); + saveTempMuxAndCopyAsyncTaskListener.finished(Uri.parse(destinationFileUriString), errorCode); } private String writeResponseBodyToDisk(ResponseBody body, String filePath) { @@ -450,99 +507,80 @@ public class DownloadRedditVideoService extends Service { return true; } - private void copyToDestination(String srcPath) { - if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - if (!copy(new File(srcPath), destinationFileName)) { - errorCode = ERROR_MUXED_VIDEO_FILE_CANNOT_SAVE; - } - } else { - try { - copyFileQ(new File(srcPath), destinationFileName); - } catch (IOException e) { - e.printStackTrace(); - errorCode = ERROR_MUXED_VIDEO_FILE_CANNOT_SAVE; - } - } - } + private void copyToDestination(String srcPath) throws IOException { + if (isDefaultDestination) { + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + InputStream in = new FileInputStream(srcPath); + OutputStream out = new FileOutputStream(destinationFileUriString); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } - @RequiresApi(api = Build.VERSION_CODES.Q) - private void copyFileQ(File src, String outputFileName) throws IOException { - String relativeLocation = Environment.DIRECTORY_MOVIES + "/Infinity/"; + new File(srcPath).delete(); + } else { + ContentValues contentValues = new ContentValues(); + contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, destinationFileName); + contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/*"); + contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, destinationFileUriString); + contentValues.put(MediaStore.Video.Media.IS_PENDING, 1); - ContentValues contentValues = new ContentValues(); - contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, outputFileName); - contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation); - contentValues.put(MediaStore.Video.Media.IS_PENDING, 1); + OutputStream stream = null; + Uri uri = null; - OutputStream stream = null; - Uri uri = null; + try { + final Uri contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + uri = contentResolver.insert(contentUri, contentValues); - try { - final Uri contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - uri = contentResolver.insert(contentUri, contentValues); + if (uri == null) { + throw new IOException("Failed to create new MediaStore record."); + } - if (uri == null) { - throw new IOException("Failed to create new MediaStore record."); - } + stream = contentResolver.openOutputStream(uri); + + if (stream == null) { + throw new IOException("Failed to get output stream."); + } - stream = contentResolver.openOutputStream(uri); + InputStream in = new FileInputStream(srcPath); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + stream.write(buf, 0, len); + } + + contentValues.clear(); + contentValues.put(MediaStore.Video.Media.IS_PENDING, 0); + contentResolver.update(uri, contentValues, null, null); + destinationFileUriString = uri.toString(); + } catch (IOException e) { + if (uri != null) { + // Don't leave an orphan entry in the MediaStore + contentResolver.delete(uri, null, null); + } + + throw e; + } finally { + if (stream != null) { + stream.close(); + } + } + } + } else { + OutputStream stream = contentResolver.openOutputStream(Uri.parse(destinationFileUriString)); if (stream == null) { throw new IOException("Failed to get output stream."); } - InputStream in = new FileInputStream(src); + InputStream in = new FileInputStream(srcPath); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { stream.write(buf, 0, len); } - - contentValues.clear(); - contentValues.put(MediaStore.Images.Media.IS_PENDING, 0); - contentResolver.update(uri, contentValues, null, null); - destinationFileUri = uri; - } catch (IOException e) { - if (uri != null) { - // Don't leave an orphan entry in the MediaStore - contentResolver.delete(uri, null, null); - } - - throw e; - } finally { - if (stream != null) { - stream.close(); - } - } - } - - private boolean copy(File src, String outputFileName) { - File directory = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); - if (directory != null) { - String directoryPath = directory.getAbsolutePath() + "/Infinity/"; - String destinationFilePath = directoryPath + outputFileName; - destinationFileUri = Uri.parse(destinationFilePath); - - try (InputStream in = new FileInputStream(src)) { - try (OutputStream out = new FileOutputStream(destinationFilePath)) { - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - - src.delete(); - return true; - } - } catch (IOException e) { - e.printStackTrace(); - src.delete(); - return false; - } - } else { - src.delete(); - return false; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Service/SubmitPostService.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Service/SubmitPostService.java index 5457ef84..c65196d8 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Service/SubmitPostService.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Service/SubmitPostService.java @@ -34,6 +34,7 @@ import javax.inject.Inject; import javax.inject.Named; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; +import ml.docilealligator.infinityforreddit.Event.SubmitCrosspostEvent; import ml.docilealligator.infinityforreddit.Event.SubmitImagePostEvent; import ml.docilealligator.infinityforreddit.Event.SubmitTextOrLinkPostEvent; import ml.docilealligator.infinityforreddit.Event.SubmitVideoOrGifPostEvent; @@ -43,6 +44,7 @@ import ml.docilealligator.infinityforreddit.NotificationUtils; import ml.docilealligator.infinityforreddit.Post.Post; import ml.docilealligator.infinityforreddit.Post.SubmitPost; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Utils.APIUtils; import retrofit2.Retrofit; public class SubmitPostService extends Service { @@ -58,6 +60,7 @@ public class SubmitPostService extends Service { public static final int EXTRA_POST_TEXT_OR_LINK = 0; public static final int EXTRA_POST_TYPE_IMAGE = 1; public static final int EXTRA_POST_TYPE_VIDEO = 2; + public static final int EXTRA_POST_TYPE_CROSSPOST = 3; @Inject @Named("oauth") Retrofit mOauthRetrofit; @@ -115,6 +118,10 @@ public class SubmitPostService extends Service { kind = intent.getStringExtra(EXTRA_KIND); startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting)); submitTextOrLinkPost(); + } else if (postType == EXTRA_POST_TYPE_CROSSPOST) { + content = intent.getStringExtra(EXTRA_CONTENT); + startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting)); + submitCrosspost(); } else if (postType == EXTRA_POST_TYPE_IMAGE) { mediaUri = intent.getData(); startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting_image)); @@ -156,6 +163,25 @@ public class SubmitPostService extends Service { }); } + private void submitCrosspost() { + SubmitPost.submitCrosspost(mOauthRetrofit, mAccessToken, getResources().getConfiguration().locale, + subredditName, title, content, flair, isSpoiler, isNSFW, APIUtils.KIND_CROSSPOST, new SubmitPost.SubmitPostListener() { + @Override + public void submitSuccessful(Post post) { + EventBus.getDefault().post(new SubmitCrosspostEvent(true, post, null)); + + stopService(); + } + + @Override + public void submitFailed(@Nullable String errorMessage) { + EventBus.getDefault().post(new SubmitCrosspostEvent(false, null, errorMessage)); + + stopService(); + } + }); + } + private void submitImagePost() { Glide.with(this) .asBitmap() diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/AdvancedPreferenceFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/AdvancedPreferenceFragment.java index de92c7fe..b9ce33fd 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/AdvancedPreferenceFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/AdvancedPreferenceFragment.java @@ -53,6 +53,9 @@ public class AdvancedPreferenceFragment extends PreferenceFragmentCompat { @Named("dark_theme") SharedPreferences darkThemeSharedPreferences; @Inject + @Named("post_feed_scrolled_position_cache") + SharedPreferences postFeedScrolledPositionSharedPreferences; + @Inject @Named("amoled_theme") SharedPreferences amoledThemeSharedPreferences; private Activity activity; @@ -68,6 +71,8 @@ public class AdvancedPreferenceFragment extends PreferenceFragmentCompat { Preference deleteSortTypePreference = findPreference(SharedPreferencesUtils.DELETE_ALL_SORT_TYPE_DATA_IN_DATABASE); Preference deletePostLaoutPreference = findPreference(SharedPreferencesUtils.DELETE_ALL_POST_LAYOUT_DATA_IN_DATABASE); Preference deleteAllThemesPreference = findPreference(SharedPreferencesUtils.DELETE_ALL_THEMES_IN_DATABASE); + Preference deletePostFeedScrolledPositionsPreference = findPreference(SharedPreferencesUtils.DELETE_FRONT_PAGE_SCROLLED_POSITIONS_IN_DATABASE); + Preference deleteAllLegacySettingsPreference = findPreference(SharedPreferencesUtils.DELETE_ALL_LEGACY_SETTINGS); Preference resetAllSettingsPreference = findPreference(SharedPreferencesUtils.RESET_ALL_SETTINGS); if (deleteSubredditsPreference != null) { @@ -142,6 +147,54 @@ public class AdvancedPreferenceFragment extends PreferenceFragmentCompat { }); } + if (deletePostFeedScrolledPositionsPreference != null) { + deletePostFeedScrolledPositionsPreference.setOnPreferenceClickListener(preference -> { + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.are_you_sure) + .setPositiveButton(R.string.yes, (dialogInterface, i) + -> { + postFeedScrolledPositionSharedPreferences.edit().clear().apply(); + Toast.makeText(activity, R.string.delete_all_front_page_scrolled_positions_success, Toast.LENGTH_SHORT).show(); + }) + .setNegativeButton(R.string.no, null) + .show(); + return true; + }); + } + + if (deleteAllLegacySettingsPreference != null) { + deleteAllLegacySettingsPreference.setOnPreferenceClickListener(preference -> { + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.are_you_sure) + .setPositiveButton(R.string.yes, (dialogInterface, i) + -> { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_1_TITLE_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_2_TITLE_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_3_TITLE_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_1_POST_TYPE_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_2_POST_TYPE_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_3_POST_TYPE_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_1_NAME_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_2_NAME_LEGACY); + editor.remove(SharedPreferencesUtils.MAIN_PAGE_TAB_3_NAME_LEGACY); + + SharedPreferences.Editor sortTypeEditor = mSortTypeSharedPreferences.edit(); + sortTypeEditor.remove(SharedPreferencesUtils.SORT_TYPE_ALL_POST_LEGACY); + sortTypeEditor.remove(SharedPreferencesUtils.SORT_TIME_ALL_POST_LEGACY); + sortTypeEditor.remove(SharedPreferencesUtils.SORT_TYPE_POPULAR_POST_LEGACY); + sortTypeEditor.remove(SharedPreferencesUtils.SORT_TIME_POPULAR_POST_LEGACY); + + editor.apply(); + sortTypeEditor.apply(); + Toast.makeText(activity, R.string.delete_all_legacy_settings_success, Toast.LENGTH_SHORT).show(); + }) + .setNegativeButton(R.string.no, null) + .show(); + return true; + }); + } + if (resetAllSettingsPreference != null) { resetAllSettingsPreference.setOnPreferenceClickListener(preference -> { new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CrashReportsFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CrashReportsFragment.java deleted file mode 100644 index 04bdc0e9..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CrashReportsFragment.java +++ /dev/null @@ -1,54 +0,0 @@ -package ml.docilealligator.infinityforreddit.Settings; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.crazylegend.crashyreporter.CrashyReporter; - -import butterknife.BindView; -import butterknife.ButterKnife; -import ml.docilealligator.infinityforreddit.R; - -public class CrashReportsFragment extends Fragment { - - @BindView(R.id.recycler_view_crash_reports_fragment) - RecyclerView recyclerView; - private Activity activity; - private CrashReportsRecyclerViewAdapter adapter; - private LinearLayoutManager linearLayoutManager; - - public CrashReportsFragment() { - // Required empty public constructor - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - // Inflate the layout for this fragment - View rootView = inflater.inflate(R.layout.fragment_crash_reports, container, false); - - ButterKnife.bind(this, rootView); - - adapter = new CrashReportsRecyclerViewAdapter(CrashyReporter.INSTANCE.getLogsAsStrings()); - linearLayoutManager = new LinearLayoutManager(activity); - recyclerView.setLayoutManager(linearLayoutManager); - recyclerView.setAdapter(adapter); - - return rootView; - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.activity = (Activity) context; - } -}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CrashReportsRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CrashReportsRecyclerViewAdapter.java deleted file mode 100644 index 82c43795..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CrashReportsRecyclerViewAdapter.java +++ /dev/null @@ -1,46 +0,0 @@ -package ml.docilealligator.infinityforreddit.Settings; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import java.util.List; - -import ml.docilealligator.infinityforreddit.R; - -class CrashReportsRecyclerViewAdapter extends RecyclerView.Adapter<CrashReportsRecyclerViewAdapter.CrashReportViewHolder> { - private List<String> crashReports; - - public CrashReportsRecyclerViewAdapter(List<String> crashReports) { - this.crashReports = crashReports; - } - - @NonNull - @Override - public CrashReportViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new CrashReportViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_crash_report, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull CrashReportViewHolder holder, int position) { - holder.crashReportTextView.setText(crashReports.get(holder.getAdapterPosition())); - } - - @Override - public int getItemCount() { - return crashReports == null ? 0 : crashReports.size(); - } - - class CrashReportViewHolder extends RecyclerView.ViewHolder { - TextView crashReportTextView; - - public CrashReportViewHolder(@NonNull View itemView) { - super(itemView); - crashReportTextView = (TextView) itemView; - } - } -}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CustomizeMainPageTabsFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CustomizeMainPageTabsFragment.java index 33ad2ea9..68d324b8 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CustomizeMainPageTabsFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/CustomizeMainPageTabsFragment.java @@ -1,167 +1,501 @@ package ml.docilealligator.infinityforreddit.Settings; +import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.preference.EditTextPreference; -import androidx.preference.ListPreference; -import androidx.preference.PreferenceFragmentCompat; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import javax.inject.Inject; import javax.inject.Named; -import ml.docilealligator.infinityforreddit.Activity.SettingsActivity; -import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; +import butterknife.BindView; +import butterknife.ButterKnife; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; -/** - * A simple {@link Fragment} subclass. - */ -public class CustomizeMainPageTabsFragment extends PreferenceFragmentCompat { +public class CustomizeMainPageTabsFragment extends Fragment { + public static final String EXTRA_ACCOUNT_NAME = "EAN"; + + @BindView(R.id.info_text_view_customize_main_page_tabs_fragment) + TextView infoTextView; + @BindView(R.id.divider_1_customize_main_page_tabs_fragment) + View divider1; + @BindView(R.id.tab_1_group_summary_customize_main_page_tabs_fragment) + TextView tab1GroupSummaryTextView; + @BindView(R.id.tab_1_title_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab1TitleLinearLayout; + @BindView(R.id.tab_1_title_summary_text_view_customize_main_page_tabs_fragment) + TextView tab1TitleSummaryTextView; + @BindView(R.id.tab_1_type_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab1TypeLinearLayout; + @BindView(R.id.tab_1_type_summary_text_view_customize_main_page_tabs_fragment) + TextView tab1TypeSummaryTextView; + @BindView(R.id.tab_1_name_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab1NameLinearLayout; + @BindView(R.id.tab_1_name_title_text_view_customize_main_page_tabs_fragment) + TextView tab1NameTitleTextView; + @BindView(R.id.tab_1_name_summary_text_view_customize_main_page_tabs_fragment) + TextView tab1NameSummaryTextView; + @BindView(R.id.divider_2_customize_main_page_tabs_fragment) + View divider2; + @BindView(R.id.tab_2_group_summary_customize_main_page_tabs_fragment) + TextView tab2GroupSummaryTextView; + @BindView(R.id.tab_2_title_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab2TitleLinearLayout; + @BindView(R.id.tab_2_title_summary_text_view_customize_main_page_tabs_fragment) + TextView tab2TitleSummaryTextView; + @BindView(R.id.tab_2_type_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab2TypeLinearLayout; + @BindView(R.id.tab_2_type_summary_text_view_customize_main_page_tabs_fragment) + TextView tab2TypeSummaryTextView; + @BindView(R.id.tab_2_name_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab2NameLinearLayout; + @BindView(R.id.tab_2_name_title_text_view_customize_main_page_tabs_fragment) + TextView tab2NameTitleTextView; + @BindView(R.id.tab_2_name_summary_text_view_customize_main_page_tabs_fragment) + TextView tab2NameSummaryTextView; + @BindView(R.id.divider_3_customize_main_page_tabs_fragment) + View divider3; + @BindView(R.id.tab_3_group_summary_customize_main_page_tabs_fragment) + TextView tab3GroupSummaryTextView; + @BindView(R.id.tab_3_title_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab3TitleLinearLayout; + @BindView(R.id.tab_3_title_summary_text_view_customize_main_page_tabs_fragment) + TextView tab3TitleSummaryTextView; + @BindView(R.id.tab_3_type_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab3TypeLinearLayout; + @BindView(R.id.tab_3_type_summary_text_view_customize_main_page_tabs_fragment) + TextView tab3TypeSummaryTextView; + @BindView(R.id.tab_3_name_linear_layout_customize_main_page_tabs_fragment) + LinearLayout tab3NameLinearLayout; + @BindView(R.id.tab_3_name_title_text_view_customize_main_page_tabs_fragment) + TextView tab3NameTitleTextView; + @BindView(R.id.tab_3_name_summary_text_view_customize_main_page_tabs_fragment) + TextView tab3NameSummaryTextView; @Inject - @Named("default") - SharedPreferences mSharedPreferences; - @Inject - CustomThemeWrapper customThemeWrapper; - private SettingsActivity activity; + @Named("main_activity_tabs") + SharedPreferences sharedPreferences; + private Activity activity; + private String tab1CurrentTitle; + private int tab1CurrentPostType; + private String tab1CurrentName; + private String tab2CurrentTitle; + private int tab2CurrentPostType; + private String tab2CurrentName; + private String tab3CurrentTitle; + private int tab3CurrentPostType; + private String tab3CurrentName; + + public CustomizeMainPageTabsFragment() { + // Required empty public constructor + } @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - setPreferencesFromResource(R.xml.customize_main_page_tabs_preferences, rootKey); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View rootView = inflater.inflate(R.layout.fragment_customize_main_page_tabs, container, false); ((Infinity) activity.getApplication()).getAppComponent().inject(this); - EditTextPreference tab1TitlePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_1_TITLE); - EditTextPreference tab2TitlePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_2_TITLE); - EditTextPreference tab3TitlePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_3_TITLE); - ListPreference tab1PostTypePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_1_POST_TYPE); - ListPreference tab2PostTypePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_2_POST_TYPE); - ListPreference tab3PostTypePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_3_POST_TYPE); - EditTextPreference tab1NamePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_1_NAME); - EditTextPreference tab2NamePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_2_NAME); - EditTextPreference tab3NamePreference = findPreference(SharedPreferencesUtils.MAIN_PAGE_TAB_3_NAME); - - if (tab1TitlePreference != null && tab1PostTypePreference != null && tab1NamePreference != null) { - String postType = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_1_POST_TYPE, - SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME); - if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT.equals(postType)) { - tab1NamePreference.setVisible(true); - tab1NamePreference.setTitle(R.string.settings_tab_subreddit_name); - } else if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT.equals(postType)) { - tab1NamePreference.setVisible(true); - tab1NamePreference.setTitle(R.string.settings_tab_multi_reddit_name); - } else if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER.equals(postType)) { - tab1NamePreference.setVisible(true); - tab1NamePreference.setTitle(R.string.settings_tab_username); - } + ButterKnife.bind(this, rootView); - tab1PostTypePreference.setOnPreferenceChangeListener((preference, newValue) -> { - switch ((String) newValue) { - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME: - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_POPULAR: - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL: - tab1NamePreference.setVisible(false); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: - tab1NamePreference.setVisible(true); - tab1NamePreference.setTitle(R.string.settings_tab_subreddit_name); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: - tab1NamePreference.setVisible(true); - tab1NamePreference.setTitle(R.string.settings_tab_multi_reddit_name); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: - tab1NamePreference.setVisible(true); - tab1NamePreference.setTitle(R.string.settings_tab_username); - } - return true; - }); + String accountName = getArguments().getString(EXTRA_ACCOUNT_NAME); + + if (accountName == null) { + infoTextView.setText(R.string.settings_customize_tabs_in_main_page_summary); + divider1.setVisibility(View.GONE); + tab1GroupSummaryTextView.setVisibility(View.GONE); + tab1TitleLinearLayout.setVisibility(View.GONE); + tab1TypeLinearLayout.setVisibility(View.GONE); + divider2.setVisibility(View.GONE); + tab2GroupSummaryTextView.setVisibility(View.GONE); + tab2TitleLinearLayout.setVisibility(View.GONE); + tab2TypeLinearLayout.setVisibility(View.GONE); + divider3.setVisibility(View.GONE); + tab3GroupSummaryTextView.setVisibility(View.GONE); + tab3TitleLinearLayout.setVisibility(View.GONE); + tab3TypeLinearLayout.setVisibility(View.GONE); + + return rootView; } - if (tab2TitlePreference != null && tab2PostTypePreference != null && tab2NamePreference != null) { - String postType = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_2_POST_TYPE, - SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_POPULAR); - if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT.equals(postType)) { - tab2NamePreference.setVisible(true); - tab2NamePreference.setTitle(R.string.settings_tab_subreddit_name); - } else if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT.equals(postType)) { - tab2NamePreference.setVisible(true); - tab2NamePreference.setTitle(R.string.settings_tab_multi_reddit_name); - } else if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER.equals(postType)) { - tab2NamePreference.setVisible(true); - tab2NamePreference.setTitle(R.string.settings_tab_username); + String[] typeValues = activity.getResources().getStringArray(R.array.settings_tab_post_type); + + tab1CurrentTitle = sharedPreferences.getString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_TITLE, getString(R.string.home)); + tab1CurrentPostType = sharedPreferences.getInt((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME); + tab1CurrentName = sharedPreferences.getString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_NAME, ""); + tab1TypeSummaryTextView.setText(typeValues[tab1CurrentPostType]); + tab1TitleSummaryTextView.setText(tab1CurrentTitle); + tab1NameSummaryTextView.setText(tab1CurrentName); + applyTab1NameView(tab1NameLinearLayout, tab1NameTitleTextView, tab1CurrentPostType); + + View dialogView = activity.getLayoutInflater().inflate(R.layout.dialog_edit_text, null); + EditText editText = dialogView.findViewById(R.id.edit_text_edit_text_dialog); + + tab1TitleLinearLayout.setOnClickListener(view -> { + editText.setHint(R.string.settings_tab_title); + editText.setText(tab1CurrentTitle); + editText.requestFocus(); + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } + if (dialogView.getParent() != null) { + ((ViewGroup) dialogView.getParent()).removeView(dialogView); + } + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.settings_tab_title) + .setView(dialogView) + .setPositiveButton(R.string.ok, (dialogInterface, i) + -> { + tab1CurrentTitle = editText.getText().toString(); + sharedPreferences.edit().putString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_TITLE, tab1CurrentTitle).apply(); + tab1TitleSummaryTextView.setText(tab1CurrentTitle); + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .show(); + }); - tab2PostTypePreference.setOnPreferenceChangeListener((preference, newValue) -> { - switch ((String) newValue) { - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME: - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_POPULAR: - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL: - tab2NamePreference.setVisible(false); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: - tab2NamePreference.setVisible(true); - tab2NamePreference.setTitle(R.string.settings_tab_subreddit_name); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: - tab2NamePreference.setVisible(true); - tab2NamePreference.setTitle(R.string.settings_tab_multi_reddit_name); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: - tab2NamePreference.setVisible(true); - tab2NamePreference.setTitle(R.string.settings_tab_username); - } - return true; - }); - } + tab1TypeLinearLayout.setOnClickListener(view -> { + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.settings_tab_title) + .setSingleChoiceItems(typeValues, tab1CurrentPostType, (dialogInterface, i) -> { + tab1CurrentPostType = i; + sharedPreferences.edit().putInt((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_POST_TYPE, i).apply(); + tab1TypeSummaryTextView.setText(typeValues[i]); + applyTab1NameView(tab1NameLinearLayout, tab1NameTitleTextView, i); + dialogInterface.dismiss(); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + }); + + tab1NameLinearLayout.setOnClickListener(view -> { + int titleId; + switch (tab1CurrentPostType) { + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: + titleId = R.string.settings_tab_subreddit_name; + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: + titleId = R.string.settings_tab_multi_reddit_name; + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: + titleId = R.string.settings_tab_username; + break; + default: + return; + } + editText.setText(tab1CurrentName); + editText.setHint(titleId); + editText.requestFocus(); + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + if (dialogView.getParent() != null) { + ((ViewGroup) dialogView.getParent()).removeView(dialogView); + } + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(titleId) + .setView(dialogView) + .setPositiveButton(R.string.ok, (dialogInterface, i) + -> { + tab1CurrentName = editText.getText().toString(); + sharedPreferences.edit().putString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_1_NAME, tab1CurrentName).apply(); + tab1NameSummaryTextView.setText(tab1CurrentName); + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .show(); + }); + + tab2CurrentTitle = sharedPreferences.getString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_TITLE, getString(R.string.popular)); + tab2CurrentPostType = sharedPreferences.getInt((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_POPULAR); + tab2CurrentName = sharedPreferences.getString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_NAME, ""); + tab2TypeSummaryTextView.setText(typeValues[tab2CurrentPostType]); + tab2TitleSummaryTextView.setText(tab2CurrentTitle); + tab2NameSummaryTextView.setText(tab2CurrentName); + applyTab2NameView(tab2NameLinearLayout, tab2NameTitleTextView, tab2CurrentPostType); - if (tab3TitlePreference != null && tab3PostTypePreference != null && tab3NamePreference != null) { - String postType = mSharedPreferences.getString(SharedPreferencesUtils.MAIN_PAGE_TAB_3_POST_TYPE, - SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL); - if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT.equals(postType)) { - tab3NamePreference.setVisible(true); - tab3NamePreference.setTitle(R.string.settings_tab_subreddit_name); - } else if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT.equals(postType)) { - tab3NamePreference.setVisible(true); - tab3NamePreference.setTitle(R.string.settings_tab_multi_reddit_name); - } else if (SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER.equals(postType)) { - tab3NamePreference.setVisible(true); - tab3NamePreference.setTitle(R.string.settings_tab_username); + tab2TitleLinearLayout.setOnClickListener(view -> { + editText.setHint(R.string.settings_tab_title); + editText.setText(tab2CurrentTitle); + editText.requestFocus(); + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + if (dialogView.getParent() != null) { + ((ViewGroup) dialogView.getParent()).removeView(dialogView); } + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.settings_tab_title) + .setView(dialogView) + .setPositiveButton(R.string.ok, (dialogInterface, i) + -> { + tab2CurrentTitle = editText.getText().toString(); + sharedPreferences.edit().putString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_TITLE, tab2CurrentTitle).apply(); + tab2TitleSummaryTextView.setText(tab2CurrentTitle); + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .show(); + }); + + tab2TypeLinearLayout.setOnClickListener(view -> { + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.settings_tab_title) + .setSingleChoiceItems(typeValues, tab2CurrentPostType, (dialogInterface, i) -> { + tab2CurrentPostType = i; + sharedPreferences.edit().putInt((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_POST_TYPE, i).apply(); + tab2TypeSummaryTextView.setText(typeValues[i]); + applyTab2NameView(tab2NameLinearLayout, tab2NameTitleTextView, i); + dialogInterface.dismiss(); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + }); + + tab2NameLinearLayout.setOnClickListener(view -> { + int titleId; + switch (tab2CurrentPostType) { + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: + titleId = R.string.settings_tab_subreddit_name; + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: + titleId = R.string.settings_tab_multi_reddit_name; + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: + titleId = R.string.settings_tab_username; + break; + default: + return; + } + editText.setText(tab2CurrentName); + editText.setHint(titleId); + editText.requestFocus(); + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + if (dialogView.getParent() != null) { + ((ViewGroup) dialogView.getParent()).removeView(dialogView); + } + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(titleId) + .setView(dialogView) + .setPositiveButton(R.string.ok, (dialogInterface, i) + -> { + tab2CurrentName = editText.getText().toString(); + sharedPreferences.edit().putString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_2_NAME, tab2CurrentName).apply(); + tab2NameSummaryTextView.setText(tab2CurrentName); + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .show(); + }); + + tab3CurrentTitle = sharedPreferences.getString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_TITLE, getString(R.string.all)); + tab3CurrentPostType = sharedPreferences.getInt((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_POST_TYPE, SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL); + tab3CurrentName = sharedPreferences.getString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_NAME, ""); + tab3TypeSummaryTextView.setText(typeValues[tab3CurrentPostType]); + tab3TitleSummaryTextView.setText(tab3CurrentTitle); + tab3NameSummaryTextView.setText(tab3CurrentName); + applyTab3NameView(tab3NameLinearLayout, tab3NameTitleTextView, tab3CurrentPostType); + + tab3TitleLinearLayout.setOnClickListener(view -> { + editText.setHint(R.string.settings_tab_title); + editText.setText(tab3CurrentTitle); + editText.requestFocus(); + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + if (dialogView.getParent() != null) { + ((ViewGroup) dialogView.getParent()).removeView(dialogView); + } + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.settings_tab_title) + .setView(dialogView) + .setPositiveButton(R.string.ok, (dialogInterface, i) + -> { + tab3CurrentTitle = editText.getText().toString(); + sharedPreferences.edit().putString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_TITLE, tab3CurrentTitle).apply(); + tab3TitleSummaryTextView.setText(tab3CurrentTitle); + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .show(); + }); + + tab3TypeLinearLayout.setOnClickListener(view -> { + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.settings_tab_title) + .setSingleChoiceItems(typeValues, tab3CurrentPostType, (dialogInterface, i) -> { + tab3CurrentPostType = i; + sharedPreferences.edit().putInt((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_POST_TYPE, i).apply(); + tab3TypeSummaryTextView.setText(typeValues[i]); + applyTab3NameView(tab3NameLinearLayout, tab3NameTitleTextView, i); + dialogInterface.dismiss(); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + }); + + tab3NameLinearLayout.setOnClickListener(view -> { + int titleId; + switch (tab3CurrentPostType) { + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: + titleId = R.string.settings_tab_subreddit_name; + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: + titleId = R.string.settings_tab_multi_reddit_name; + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: + titleId = R.string.settings_tab_username; + break; + default: + return; + } + editText.setText(tab3CurrentName); + editText.setHint(titleId); + editText.requestFocus(); + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + if (dialogView.getParent() != null) { + ((ViewGroup) dialogView.getParent()).removeView(dialogView); + } + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(titleId) + .setView(dialogView) + .setPositiveButton(R.string.ok, (dialogInterface, i) + -> { + tab3CurrentName = editText.getText().toString(); + sharedPreferences.edit().putString((accountName == null ? "" : accountName) + SharedPreferencesUtils.MAIN_PAGE_TAB_3_NAME, tab3CurrentName).apply(); + tab3NameSummaryTextView.setText(tab3CurrentName); + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + if (imm != null) { + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + }) + .show(); + }); + + return rootView; + } + + private void applyTab1NameView(LinearLayout linearLayout, TextView titleTextView, int postType) { + switch (postType) { + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_subreddit_name); + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_multi_reddit_name); + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_username); + break; + default: + linearLayout.setVisibility(View.GONE); + } + } + + private void applyTab2NameView(LinearLayout linearLayout, TextView titleTextView, int postType) { + switch (postType) { + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_subreddit_name); + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_multi_reddit_name); + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_username); + break; + default: + linearLayout.setVisibility(View.GONE); + } + } - tab3PostTypePreference.setOnPreferenceChangeListener((preference, newValue) -> { - switch ((String) newValue) { - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_HOME: - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_POPULAR: - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_ALL: - tab3NamePreference.setVisible(false); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: - tab3NamePreference.setVisible(true); - tab3NamePreference.setTitle(R.string.settings_tab_subreddit_name); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: - tab3NamePreference.setVisible(true); - tab3NamePreference.setTitle(R.string.settings_tab_multi_reddit_name); - break; - case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: - tab3NamePreference.setVisible(true); - tab3NamePreference.setTitle(R.string.settings_tab_username); - } - return true; - }); + private void applyTab3NameView(LinearLayout linearLayout, TextView titleTextView, int postType) { + switch (postType) { + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_subreddit_name); + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_multi_reddit_name); + break; + case SharedPreferencesUtils.MAIN_PAGE_TAB_POST_TYPE_USER: + linearLayout.setVisibility(View.VISIBLE); + titleTextView.setText(R.string.settings_tab_username); + break; + default: + linearLayout.setVisibility(View.GONE); } } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - activity = (SettingsActivity) context; + activity = (Activity) context; } -} +}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/DownloadLocationPreferenceFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/DownloadLocationPreferenceFragment.java new file mode 100644 index 00000000..50c436eb --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/DownloadLocationPreferenceFragment.java @@ -0,0 +1,115 @@ +package ml.docilealligator.infinityforreddit.Settings; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import javax.inject.Inject; +import javax.inject.Named; + +import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; + +import static android.content.Intent.ACTION_OPEN_DOCUMENT_TREE; + +public class DownloadLocationPreferenceFragment extends PreferenceFragmentCompat { + private static final int IMAGE_DOWNLOAD_LOCATION_REQUEST_CODE = 10; + private static final int GIF_DOWNLOAD_LOCATION_REQUEST_CODE = 11; + private static final int VIDEO_DOWNLOAD_LOCATION_REQUEST_CODE = 12; + + Preference imageDownloadLocationPreference; + Preference gifDownloadLocationPreference; + Preference videoDownloadLocationPreference; + private Activity activity; + @Inject + @Named("default") + SharedPreferences sharedPreferences; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + ((Infinity) activity.getApplication()).getAppComponent().inject(this); + setPreferencesFromResource(R.xml.download_location_preferences, rootKey); + imageDownloadLocationPreference = findPreference(SharedPreferencesUtils.IMAGE_DOWNLOAD_LOCATION); + gifDownloadLocationPreference = findPreference(SharedPreferencesUtils.GIF_DOWNLOAD_LOCATION); + videoDownloadLocationPreference = findPreference(SharedPreferencesUtils.VIDEO_DOWNLOAD_LOCATION); + + if (imageDownloadLocationPreference != null) { + String downloadLocation = sharedPreferences.getString(SharedPreferencesUtils.IMAGE_DOWNLOAD_LOCATION, ""); + if (!downloadLocation.equals("")) { + imageDownloadLocationPreference.setSummary(downloadLocation); + } + + imageDownloadLocationPreference.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT_TREE); + intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + startActivityForResult(intent, IMAGE_DOWNLOAD_LOCATION_REQUEST_CODE); + return true; + }); + } + + if (gifDownloadLocationPreference != null) { + String downloadLocation = sharedPreferences.getString(SharedPreferencesUtils.GIF_DOWNLOAD_LOCATION, ""); + if (!downloadLocation.equals("")) { + gifDownloadLocationPreference.setSummary(downloadLocation); + } + + gifDownloadLocationPreference.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT_TREE); + intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + startActivityForResult(intent, GIF_DOWNLOAD_LOCATION_REQUEST_CODE); + return true; + }); + } + + if (videoDownloadLocationPreference != null) { + String downloadLocation = sharedPreferences.getString(SharedPreferencesUtils.VIDEO_DOWNLOAD_LOCATION, ""); + if (!downloadLocation.equals("")) { + videoDownloadLocationPreference.setSummary(downloadLocation); + } + + videoDownloadLocationPreference.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT_TREE); + intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + startActivityForResult(intent, VIDEO_DOWNLOAD_LOCATION_REQUEST_CODE); + return true; + }); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == Activity.RESULT_OK && data != null) { + if (requestCode == IMAGE_DOWNLOAD_LOCATION_REQUEST_CODE) { + sharedPreferences.edit().putString(SharedPreferencesUtils.IMAGE_DOWNLOAD_LOCATION, data.getDataString()).apply(); + if (imageDownloadLocationPreference != null) { + imageDownloadLocationPreference.setSummary(data.getDataString()); + } + } else if (requestCode == GIF_DOWNLOAD_LOCATION_REQUEST_CODE) { + sharedPreferences.edit().putString(SharedPreferencesUtils.GIF_DOWNLOAD_LOCATION, data.getDataString()).apply(); + if (gifDownloadLocationPreference != null) { + gifDownloadLocationPreference.setSummary(data.getDataString()); + } + } else if (requestCode == VIDEO_DOWNLOAD_LOCATION_REQUEST_CODE) { + sharedPreferences.edit().putString(SharedPreferencesUtils.VIDEO_DOWNLOAD_LOCATION, data.getDataString()).apply(); + if (videoDownloadLocationPreference != null) { + videoDownloadLocationPreference.setSummary(data.getDataString()); + } + } + } + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + activity = (Activity) context; + } +}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/MainPreferenceFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/MainPreferenceFragment.java index aa1b77d0..3a11855a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/MainPreferenceFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/MainPreferenceFragment.java @@ -17,6 +17,7 @@ import javax.inject.Named; import ml.docilealligator.infinityforreddit.Event.ChangeNSFWBlurEvent; import ml.docilealligator.infinityforreddit.Event.ChangeNSFWEvent; +import ml.docilealligator.infinityforreddit.Event.ChangeSavePostFeedScrolledPositionEvent; import ml.docilealligator.infinityforreddit.Event.ChangeSpoilerBlurEvent; import ml.docilealligator.infinityforreddit.Event.RecreateActivityEvent; import ml.docilealligator.infinityforreddit.Infinity; @@ -28,6 +29,9 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat { @Inject @Named("default") SharedPreferences sharedPreferences; + @Inject + @Named("post_feed_scrolled_position_cache") + SharedPreferences cache; private Activity activity; @Override @@ -35,11 +39,22 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat { setPreferencesFromResource(R.xml.main_preferences, rootKey); ((Infinity) activity.getApplication()).getAppComponent().inject(this); + SwitchPreference savePostFeedScrolledPositionSwitch = findPreference(SharedPreferencesUtils.SAVE_FRONT_PAGE_SCROLLED_POSITION); SwitchPreference confirmToExitSwitch = findPreference(SharedPreferencesUtils.CONFIRM_TO_EXIT); SwitchPreference nsfwSwitch = findPreference(SharedPreferencesUtils.NSFW_KEY); SwitchPreference blurNSFWSwitch = findPreference(SharedPreferencesUtils.BLUR_NSFW_KEY); SwitchPreference blurSpoilerSwitch = findPreference(SharedPreferencesUtils.BLUR_SPOILER_KEY); + if (savePostFeedScrolledPositionSwitch != null) { + savePostFeedScrolledPositionSwitch.setOnPreferenceChangeListener((preference, newValue) -> { + if (!(Boolean) newValue) { + cache.edit().clear().apply(); + } + EventBus.getDefault().post(new ChangeSavePostFeedScrolledPositionEvent((Boolean) newValue)); + return true; + }); + } + if (confirmToExitSwitch != null) { confirmToExitSwitch.setOnPreferenceChangeListener((preference, newValue) -> { EventBus.getDefault().post(new RecreateActivityEvent()); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/NumberOfColumnsInPostFeedPreferenceFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/NumberOfColumnsInPostFeedPreferenceFragment.java new file mode 100644 index 00000000..04052e07 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Settings/NumberOfColumnsInPostFeedPreferenceFragment.java @@ -0,0 +1,14 @@ +package ml.docilealligator.infinityforreddit.Settings; + +import android.os.Bundle; + +import androidx.preference.PreferenceFragmentCompat; + +import ml.docilealligator.infinityforreddit.R; + +public class NumberOfColumnsInPostFeedPreferenceFragment extends PreferenceFragmentCompat { + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.number_of_columns_in_post_feed_preferences, rootKey); + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubreddit/SubscribedSubredditDao.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubreddit/SubscribedSubredditDao.java index aa62e088..225c4cb4 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubreddit/SubscribedSubredditDao.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubreddit/SubscribedSubredditDao.java @@ -19,15 +19,15 @@ public interface SubscribedSubredditDao { @Query("SELECT * from subscribed_subreddits WHERE username = :accountName ORDER BY name COLLATE NOCASE ASC") LiveData<List<SubscribedSubredditData>> getAllSubscribedSubreddits(String accountName); - @Query("SELECT * from subscribed_subreddits WHERE username = :accountName ORDER BY name COLLATE NOCASE ASC") + @Query("SELECT * from subscribed_subreddits WHERE username = :accountName COLLATE NOCASE ORDER BY name COLLATE NOCASE ASC") List<SubscribedSubredditData> getAllSubscribedSubredditsList(String accountName); - @Query("SELECT * from subscribed_subreddits WHERE username = :accountName AND is_favorite = 1 ORDER BY name COLLATE NOCASE ASC") + @Query("SELECT * from subscribed_subreddits WHERE username = :accountName COLLATE NOCASE AND is_favorite = 1 ORDER BY name COLLATE NOCASE ASC") LiveData<List<SubscribedSubredditData>> getAllFavoriteSubscribedSubreddits(String accountName); - @Query("SELECT * from subscribed_subreddits WHERE name = :subredditName AND username = :accountName COLLATE NOCASE LIMIT 1") + @Query("SELECT * from subscribed_subreddits WHERE name = :subredditName COLLATE NOCASE AND username = :accountName COLLATE NOCASE LIMIT 1") SubscribedSubredditData getSubscribedSubreddit(String subredditName, String accountName); - @Query("DELETE FROM subscribed_subreddits WHERE name = :subredditName AND username = :accountName") + @Query("DELETE FROM subscribed_subreddits WHERE name = :subredditName COLLATE NOCASE AND username = :accountName COLLATE NOCASE") void deleteSubscribedSubreddit(String subredditName, String accountName); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserDao.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserDao.java index 661eb988..66660b8c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserDao.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserDao.java @@ -13,18 +13,18 @@ public interface SubscribedUserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void insert(SubscribedUserData subscribedUserData); - @Query("SELECT * FROM subscribed_users WHERE username = :accountName ORDER BY name COLLATE NOCASE ASC") + @Query("SELECT * FROM subscribed_users WHERE username = :accountName COLLATE NOCASE ORDER BY name COLLATE NOCASE ASC") LiveData<List<SubscribedUserData>> getAllSubscribedUsers(String accountName); - @Query("SELECT * FROM subscribed_users WHERE username = :accountName ORDER BY name COLLATE NOCASE ASC") + @Query("SELECT * FROM subscribed_users WHERE username = :accountName COLLATE NOCASE ORDER BY name COLLATE NOCASE ASC") List<SubscribedUserData> getAllSubscribedUsersList(String accountName); - @Query("SELECT * FROM subscribed_users WHERE username = :accountName AND is_favorite = 1 ORDER BY name COLLATE NOCASE ASC") + @Query("SELECT * FROM subscribed_users WHERE username = :accountName COLLATE NOCASE AND is_favorite = 1 ORDER BY name COLLATE NOCASE ASC") LiveData<List<SubscribedUserData>> getAllFavoriteSubscribedUsers(String accountName); - @Query("SELECT * FROM subscribed_users WHERE name = :name AND username = :accountName COLLATE NOCASE LIMIT 1") + @Query("SELECT * FROM subscribed_users WHERE name = :name COLLATE NOCASE AND username = :accountName COLLATE NOCASE LIMIT 1") SubscribedUserData getSubscribedUser(String name, String accountName); - @Query("DELETE FROM subscribed_users WHERE name = :name AND username = :accountName") + @Query("DELETE FROM subscribed_users WHERE name = :name COLLATE NOCASE AND username = :accountName COLLATE NOCASE") void deleteSubscribedUser(String name, String accountName); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/User/BlockUser.java b/app/src/main/java/ml/docilealligator/infinityforreddit/User/BlockUser.java new file mode 100644 index 00000000..ca6dd1d1 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/User/BlockUser.java @@ -0,0 +1,40 @@ +package ml.docilealligator.infinityforreddit.User; + +import androidx.annotation.NonNull; + +import java.util.HashMap; +import java.util.Map; + +import ml.docilealligator.infinityforreddit.API.RedditAPI; +import ml.docilealligator.infinityforreddit.Utils.APIUtils; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +public class BlockUser { + public interface BlockUserListener { + void success(); + void failed(); + } + + public static void blockUser(Retrofit oauthRetrofit, String accessToken, String username, BlockUserListener blockUserListener) { + Map<String, String> params = new HashMap<>(); + params.put(APIUtils.NAME_KEY, username); + oauthRetrofit.create(RedditAPI.class).blockUser(APIUtils.getOAuthHeader(accessToken), params).enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { + if (response.isSuccessful()) { + blockUserListener.success(); + } else { + blockUserListener.failed(); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + blockUserListener.failed(); + } + }); + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/APIUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/APIUtils.java index 1b00e57a..8f54b256 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/APIUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/APIUtils.java @@ -35,13 +35,13 @@ public class APIUtils { public static final String DURATION_KEY = "duration"; public static final String DURATION = "permanent"; public static final String SCOPE_KEY = "scope"; - public static final String SCOPE = "identity edit flair history modconfig modflair modlog modposts modwiki mysubreddits privatemessages read report save submit subscribe vote wikiedit wikiread"; + public static final String SCOPE = "identity edit flair history modconfig modflair modlog modposts modwiki mysubreddits privatemessages read report save submit subscribe vote wikiedit wikiread creddits modcontributors modmail modothers livemanage account modself"; public static final String ACCESS_TOKEN_KEY = "access_token"; public static final String AUTHORIZATION_KEY = "Authorization"; public static final String AUTHORIZATION_BASE = "bearer "; public static final String USER_AGENT_KEY = "User-Agent"; - public static final String USER_AGENT = "android:ml.docilealligator.infinityforreddit:v3.2.0 (by /u/Hostilenemy)"; + public static final String USER_AGENT = "android:ml.docilealligator.infinityforreddit:v4.0.1 (by /u/Hostilenemy)"; public static final String GRANT_TYPE_KEY = "grant_type"; public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token"; @@ -71,12 +71,14 @@ public class APIUtils { public static final String FLAIR_TEXT_KEY = "flair_text"; public static final String SPOILER_KEY = "spoiler"; public static final String NSFW_KEY = "nsfw"; + public static final String CROSSPOST_FULLNAME_KEY = "crosspost_fullname"; public static final String KIND_KEY = "kind"; public static final String KIND_SELF = "self"; public static final String KIND_LINK = "link"; public static final String KIND_IMAGE = "image"; public static final String KIND_VIDEO = "video"; public static final String KIND_VIDEOGIF = "videogif"; + public static final String KIND_CROSSPOST = "crosspost"; public static final String FILEPATH_KEY = "filepath"; public static final String MIMETYPE_KEY = "mimetype"; @@ -95,6 +97,8 @@ public class APIUtils { public static final String SUBJECT_KEY = "subject"; public static final String TO_KEY = "to"; + public static final String NAME_KEY = "name"; + public static Map<String, String> getHttpBasicAuthHeader() { Map<String, String> params = new HashMap<>(); String credentials = String.format("%s:%s", APIUtils.CLIENT_ID, ""); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/GetPathUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/GetPathUtils.java new file mode 100644 index 00000000..1ccb6b47 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/GetPathUtils.java @@ -0,0 +1,238 @@ +package ml.docilealligator.infinityforreddit.Utils; + +import android.annotation.TargetApi; +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.provider.DocumentsContract; +import android.provider.MediaStore; + +import androidx.core.content.ContextCompat; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class GetPathUtils { + + private static final String PATH_TREE = "tree"; + private static final String PRIMARY_TYPE = "primary"; + private static final String RAW_TYPE = "raw"; + + @TargetApi(Build.VERSION_CODES.KITKAT) + public static String getFilePathFromUri(final Context context, final Uri uri) { + + // DocumentProvider + if (DocumentsContract.isDocumentUri(context, uri)) { + // ExternalStorageProvider + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + //Timber.d("docId -> %s", docId); + final String[] split = docId.split(":"); + final String type = split[0]; + + if (PRIMARY_TYPE.equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } else { + // TODO handle non-primary volumes + StringBuilder path = new StringBuilder(); + String pathSegment[] = docId.split(":"); + return path.append(getRemovableStorageRootPath(context, pathSegment[0])).append(File.separator).append(pathSegment[1]).toString(); + } + } else if (isDownloadsDocument(uri)) { // DownloadsProvider + + final String id = DocumentsContract.getDocumentId(uri); + + if (id.contains("raw:")) { + return id.substring(id.indexOf(File.separator)); + } else { + Uri contentUri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + + return getDataColumn(context, contentUri, null, null); + } + + } else if (isMediaDocument(uri)) { // MediaProvider + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + + final String selection = "_id=?"; + final String[] selectionArgs = new String[]{ + split[1] + }; + + return getDataColumn(context, contentUri, selection, selectionArgs); + } + } else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general) + return getDataColumn(context, uri, null, null); + } else if ("file".equalsIgnoreCase(uri.getScheme())) { // File + return uri.getPath(); + } + + return null; + } + + /** + * Get the value of the data column for this Uri. This is useful for + * MediaStore Uris, and other file-based ContentProviders. + * + * @param context The context. + * @param uri The Uri to query. + * @param selection (Optional) Filter used in the query. + * @param selectionArgs (Optional) Selection arguments used in the query. + * @return The value of the _data column, which is typically a file path. + */ + public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + + Cursor cursor = null; + final String column = MediaStore.MediaColumns.DATA; + final String[] projection = {column}; + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, + null); + if (cursor != null && cursor.moveToFirst()) { + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } finally { + if (cursor != null) + cursor.close(); + } + + return null; + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is ExternalStorageProvider. + */ + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is DownloadsProvider. + */ + public static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is MediaProvider. + */ + public static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + /** + * @param uri + * @return file path of Uri + */ + public static String getDirectoryPathFromUri(Context context, Uri uri) { + + if ("file".equals(uri.getScheme())) { + return uri.getPath(); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT + && isTreeUri(uri)) { + + String treeId = getTreeDocumentId(uri); + + if (treeId != null) { + String[] paths = treeId.split(":"); + String type = paths[0]; + String subPath = paths.length == 2 ? paths[1] : ""; + + if (RAW_TYPE.equalsIgnoreCase(type)) { + return treeId.substring(treeId.indexOf(File.separator)); + } else if (PRIMARY_TYPE.equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + File.separator + subPath; + } else { + StringBuilder path = new StringBuilder(); + String[] pathSegment = treeId.split(":"); + if (pathSegment.length == 1) { + path.append(getRemovableStorageRootPath(context, paths[0])); + } else { + String rootPath = getRemovableStorageRootPath(context, paths[0]); + path.append(rootPath).append(File.separator).append(pathSegment[1]); + } + + return path.toString(); + } + } + } + return null; + } + + private static String getRemovableStorageRootPath(Context context, String storageId) { + StringBuilder rootPath = new StringBuilder(); + File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null); + for (File fileDir : externalFilesDirs) { + if (fileDir.getPath().contains(storageId)) { + String[] pathSegment = fileDir.getPath().split(File.separator); + for (String segment : pathSegment) { + if (segment.equals(storageId)) { + rootPath.append(storageId); + break; + } + rootPath.append(segment).append(File.separator); + } + //rootPath.append(fileDir.getPath().split("/Android")[0]); // faster + break; + } + } + return rootPath.toString(); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public static List<String> getListRemovableStorage(Context context) { + + List<String> paths = new ArrayList<>(); + + File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null); + for (File fileDir : externalFilesDirs) { + if (Environment.isExternalStorageRemovable(fileDir)) { + String path = fileDir.getPath(); + if (path.contains("/Android")) { + paths.add(path.substring(0, path.indexOf("/Android"))); + } + } + } + + return paths; + } + + //https://github.com/rcketscientist/DocumentActivity/blob/master/library/src/main/java/com/anthonymandra/framework/DocumentUtil.java#L56 + /** + * Extract the via {@link DocumentsContract.Document#COLUMN_DOCUMENT_ID} from the given URI. + * From {@link DocumentsContract} but return null instead of throw + */ + public static String getTreeDocumentId(Uri uri) { + final List<String> paths = uri.getPathSegments(); + if (paths.size() >= 2 && PATH_TREE.equals(paths.get(0))) { + return paths.get(1); + } + return null; + } + + public static boolean isTreeUri(Uri uri) { + final List<String> paths = uri.getPathSegments(); + return (paths.size() == 2 && PATH_TREE.equals(paths.get(0))); + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/SharedPreferencesUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/SharedPreferencesUtils.java index 768db21a..16df65e4 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/SharedPreferencesUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/SharedPreferencesUtils.java @@ -44,10 +44,6 @@ public class SharedPreferencesUtils { public static final String SORT_TYPE_SHARED_PREFERENCES_FILE = "ml.docilealligator.infinityforreddit.sort_type"; public static final String SORT_TYPE_BEST_POST = "sort_type_best_post"; public static final String SORT_TIME_BEST_POST = "sort_time_best_post"; - public static final String SORT_TYPE_ALL_POST = "sort_type_all_post"; - public static final String SORT_TIME_ALL_POST = "sort_time_all_post"; - public static final String SORT_TYPE_POPULAR_POST = "sort_type_popular_post"; - public static final String SORT_TIME_POPULAR_POST = "sort_time_popular_post"; public static final String SORT_TYPE_SEARCH_POST = "sort_type_search_post"; public static final String SORT_TIME_SEARCH_POST = "sort_time_search_post"; public static final String SORT_TYPE_SUBREDDIT_POST_BASE = "sort_type_subreddit_post_"; @@ -73,6 +69,10 @@ public class SharedPreferencesUtils { public static final int POST_LAYOUT_CARD = 0; public static final int POST_LAYOUT_COMPACT = 1; + public static final String FRONT_PAGE_SCROLLED_POSITION_SHARED_PREFERENCES_FILE = "ml.docilealligator.infinityforreddit.front_page_scrolled_position"; + public static final String FRONT_PAGE_SCROLLED_POSITION_FRONT_PAGE_BASE = "_front_page"; + public static final String FRONT_PAGE_SCROLLED_POSITION_ANONYMOUS = ".anonymous"; + public static final String PULL_NOTIFICATION_TIME = "pull_notification_time"; public static final String SHOW_ELAPSED_TIME_KEY = "show_elapsed_time"; public static final String TIME_FORMAT_KEY = "time_format"; @@ -80,6 +80,8 @@ public class SharedPreferencesUtils { public static final String DEFAULT_POST_LAYOUT_KEY = "default_post_layout"; public static final String SHOW_DIVIDER_IN_COMPACT_LAYOUT = "show_divider_in_compact_layout"; public static final String SHOW_THUMBNAIL_ON_THE_LEFT_IN_COMPACT_LAYOUT = "show_thumbnail_on_the_left_in_compact_layout"; + public static final String NUMBER_OF_COLUMNS_IN_POST_FEED_PORTRAIT = "number_of_columns_in_post_feed_portrait"; + public static final String NUMBER_OF_COLUMNS_IN_POST_FEED_LANDSCAPE = "number_of_columns_in_post_feed_landscape"; public static final String SWIPE_RIGHT_TO_GO_BACK = "swipe_to_go_back_from_post_detail"; public static final String VOLUME_KEYS_NAVIGATE_COMMENTS = "volume_keys_navigate_comments"; public static final String VOLUME_KEYS_NAVIGATE_POSTS = "volume_keys_navigate_posts"; @@ -112,24 +114,49 @@ public class SharedPreferencesUtils { public static final String DELETE_ALL_SORT_TYPE_DATA_IN_DATABASE = "delete_all_sort_type_data_in_database"; public static final String DELETE_ALL_POST_LAYOUT_DATA_IN_DATABASE = "delete_all_post_layout_data_in_database"; public static final String DELETE_ALL_THEMES_IN_DATABASE = "delete_all_themes_in_database"; + public static final String DELETE_FRONT_PAGE_SCROLLED_POSITIONS_IN_DATABASE = "delete_front_page_scrolled_positions_in_database"; + public static final String DELETE_ALL_LEGACY_SETTINGS = "delete_all_legacy_settings"; public static final String RESET_ALL_SETTINGS = "reset_all_settings"; - public static final String MAIN_PAGE_TAB_1_TITLE = "main_page_tab_1_title"; - public static final String MAIN_PAGE_TAB_2_TITLE = "main_page_tab_2_title"; - public static final String MAIN_PAGE_TAB_3_TITLE = "main_page_tab_3_title"; - public static final String MAIN_PAGE_TAB_1_POST_TYPE = "main_page_tab_1_post_type"; - public static final String MAIN_PAGE_TAB_2_POST_TYPE = "main_page_tab_2_post_type"; - public static final String MAIN_PAGE_TAB_3_POST_TYPE = "main_page_tab_3_post_type"; - public static final String MAIN_PAGE_TAB_1_NAME = "main_page_tab_1_name"; - public static final String MAIN_PAGE_TAB_2_NAME = "main_page_tab_2_name"; - public static final String MAIN_PAGE_TAB_3_NAME = "main_page_tab_3_name"; - public static final String MAIN_PAGE_TAB_POST_TYPE_HOME = "0"; - public static final String MAIN_PAGE_TAB_POST_TYPE_POPULAR = "1"; - public static final String MAIN_PAGE_TAB_POST_TYPE_ALL = "2"; - public static final String MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT = "3"; - public static final String MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT = "4"; - public static final String MAIN_PAGE_TAB_POST_TYPE_USER = "5"; + public static final String IMAGE_DOWNLOAD_LOCATION = "image_download_location"; + public static final String GIF_DOWNLOAD_LOCATION = "gif_download_location"; + public static final String VIDEO_DOWNLOAD_LOCATION = "video_download_location"; + + public static final String MAIN_PAGE_TABS_SHARED_PREFERENCES_FILE = "ml.docilealligator.infinityforreddit.main_page_tabs"; + public static final String MAIN_PAGE_TAB_1_TITLE = "_main_page_tab_1_title"; + public static final String MAIN_PAGE_TAB_2_TITLE = "_main_page_tab_2_title"; + public static final String MAIN_PAGE_TAB_3_TITLE = "_main_page_tab_3_title"; + public static final String MAIN_PAGE_TAB_1_POST_TYPE = "_main_page_tab_1_post_type"; + public static final String MAIN_PAGE_TAB_2_POST_TYPE = "_main_page_tab_2_post_type"; + public static final String MAIN_PAGE_TAB_3_POST_TYPE = "_main_page_tab_3_post_type"; + public static final String MAIN_PAGE_TAB_1_NAME = "_main_page_tab_1_name"; + public static final String MAIN_PAGE_TAB_2_NAME = "_main_page_tab_2_name"; + public static final String MAIN_PAGE_TAB_3_NAME = "_main_page_tab_3_name"; + public static final int MAIN_PAGE_TAB_POST_TYPE_HOME = 0; + public static final int MAIN_PAGE_TAB_POST_TYPE_POPULAR = 1; + public static final int MAIN_PAGE_TAB_POST_TYPE_ALL = 2; + public static final int MAIN_PAGE_TAB_POST_TYPE_SUBREDDIT = 3; + public static final int MAIN_PAGE_TAB_POST_TYPE_MULTIREDDIT = 4; + public static final int MAIN_PAGE_TAB_POST_TYPE_USER = 5; + public static final String START_AUTOPLAY_VISIBLE_AREA_OFFSET_PORTRAIT = "start_autoplay_visible_area_offset_portrait"; public static final String START_AUTOPLAY_VISIBLE_AREA_OFFSET_LANDSCAPE = "start_autoplay_visible_area_offset_landscape"; public static final String MUTE_NSFW_VIDEO = "mute_nsfw_video"; public static final String VIDEO_PLAYER_IGNORE_NAV_BAR = "video_player_ignore_nav_bar"; + public static final String SAVE_FRONT_PAGE_SCROLLED_POSITION = "save_front_page_scrolled_position"; + + //Legacy Settings + public static final String MAIN_PAGE_TAB_1_TITLE_LEGACY = "main_page_tab_1_title"; + public static final String MAIN_PAGE_TAB_2_TITLE_LEGACY = "main_page_tab_2_title"; + public static final String MAIN_PAGE_TAB_3_TITLE_LEGACY = "main_page_tab_3_title"; + public static final String MAIN_PAGE_TAB_1_POST_TYPE_LEGACY = "main_page_tab_1_post_type"; + public static final String MAIN_PAGE_TAB_2_POST_TYPE_LEGACY = "main_page_tab_2_post_type"; + public static final String MAIN_PAGE_TAB_3_POST_TYPE_LEGACY = "main_page_tab_3_post_type"; + public static final String MAIN_PAGE_TAB_1_NAME_LEGACY = "main_page_tab_1_name"; + public static final String MAIN_PAGE_TAB_2_NAME_LEGACY = "main_page_tab_2_name"; + public static final String MAIN_PAGE_TAB_3_NAME_LEGACY = "main_page_tab_3_name"; + + public static final String SORT_TYPE_ALL_POST_LEGACY = "sort_type_all_post"; + public static final String SORT_TIME_ALL_POST_LEGACY = "sort_time_all_post"; + public static final String SORT_TYPE_POPULAR_POST_LEGACY = "sort_type_popular_post"; + public static final String SORT_TIME_POPULAR_POST_LEGACY = "sort_time_popular_post"; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/Utils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/Utils.java index 14cdb57a..f07363d9 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/Utils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/Utils.java @@ -32,8 +32,40 @@ public class Utils { private static final long YEAR_MILLIS = 12 * MONTH_MILLIS; public static String modifyMarkdown(String markdown) { - return markdown.replaceAll("((?<=[\\s])|^)/{0,1}[rRuU]/\\w+/{0,1}", "[$0]($0)") - .replaceAll("\\^\\w+", "$0^"); + StringBuilder regexed = new StringBuilder(markdown.replaceAll("((?<=[\\s])|^)/[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com$0)").replaceAll("((?<=[\\s])|^)[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com/$0)")); + + /*int startIndex = 0; + + Pattern pattern = Pattern.compile("\\^.+"); + Matcher matcher = pattern.matcher(regexed); + // Check all occurrences + while (matcher.find(startIndex)) { + int count = 0; + Pattern pattern2 = Pattern.compile("(\\^\\([^)]+\\))"); + Matcher matcher2 = pattern2.matcher(matcher.group()); + if (matcher2.find()) { + regexed.setCharAt(matcher2.end() + matcher.start() - 1, '^'); + regexed.deleteCharAt(matcher2.start() + matcher.start() + 1); + + startIndex = matcher.start() + matcher2.end(); + String substring = regexed.substring(matcher.start() + matcher2.start() + 1, matcher.start() + matcher2.end() - 2); + String trimmedSubstring = substring.trim(); + regexed.replace(matcher.start() + matcher2.start() + 1, matcher.start() + matcher2.end() - 2, trimmedSubstring); + startIndex -= (substring.length() - trimmedSubstring.length()); + continue; + } + + regexed.insert(matcher.end(), '^'); + + for (int i = matcher.end() - 1; i >= matcher.start() + 1; i--) { + if (regexed.charAt(i) == '^') { + regexed.deleteCharAt(i); + count++; + } + } + startIndex = matcher.end() - count; + }*/ + return regexed.toString(); } public static CharSequence trimTrailingWhitespace(CharSequence source) { |