From 12be59df3177cacd51ebb29a3b05367836969ed4 Mon Sep 17 00:00:00 2001 From: flofriday Date: Fri, 1 Mar 2024 14:12:31 +0100 Subject: [PATCH 1/2] Refactor comments, imports and some code pieces I know that might come of as rude as it wasn't requested but it really shouldn't. I just wanted to read all parts of the app and stumbled upon a couple of things I wanted to fix. If you have any suggestions I am more than willing to revert some changes here. --- .../com/gw/swipeback/SwipeBackLayout.java | 2 +- .../harmonichackernews/AboutActivity.java | 2 - .../harmonichackernews/BaseActivity.java | 1 - .../harmonichackernews/CommentsActivity.java | 11 +- .../harmonichackernews/CommentsFragment.java | 176 +++++++++--------- .../CommentsSearchDialogFragment.java | 39 ---- .../harmonichackernews/ComposeActivity.java | 12 +- .../LoginDialogFragment.java | 1 - .../harmonichackernews/SettingsActivity.java | 34 ++-- .../SplitPlaceholderActivity.java | 12 +- .../harmonichackernews/StoriesFragment.java | 38 ++-- .../SubmissionsActivity.java | 6 +- .../UserDialogFragment.java | 10 +- .../adapters/CommentSearchAdapter.java | 8 +- .../adapters/CommentsRecyclerViewAdapter.java | 40 ++-- .../adapters/StoryRecyclerViewAdapter.java | 39 ++-- .../harmonichackernews/data/ArxivInfo.java | 24 +-- .../linkpreview/ArxivAbstractGetter.java | 4 +- .../linkpreview/GitHubInfoGetter.java | 13 +- .../linkpreview/WikipediaGetter.java | 2 +- .../network/ArchiveOrgUrlGetter.java | 3 - .../network/FaviconLoader.java | 5 +- .../network/JSONParser.java | 74 ++++---- .../network/NetworkComponent.java | 5 +- .../network/UserActions.java | 4 +- .../VolleyOkHttp3StackInterceptors.java | 10 +- .../utils/AccountUtils.java | 60 +++--- .../utils/ArxivResolver.java | 33 ++-- .../EncryptedSharedPreferencesHelper.java | 8 +- .../utils/FileDownloader.java | 5 +- .../utils/SettingsUtils.java | 14 +- .../utils/SplitChangeHandler.java | 74 ++++---- .../harmonichackernews/utils/ThemeUtils.java | 12 +- .../simon/harmonichackernews/utils/Utils.java | 38 ++-- .../harmonichackernews/utils/ViewUtils.java | 9 +- 35 files changed, 347 insertions(+), 481 deletions(-) diff --git a/app/src/main/java/com/gw/swipeback/SwipeBackLayout.java b/app/src/main/java/com/gw/swipeback/SwipeBackLayout.java index 64e5d8cd..72e074ae 100644 --- a/app/src/main/java/com/gw/swipeback/SwipeBackLayout.java +++ b/app/src/main/java/com/gw/swipeback/SwipeBackLayout.java @@ -60,7 +60,7 @@ public class SwipeBackLayout extends ViewGroup { private int leftOffset = 0; private int topOffset = 0; - //important constant + // important constant private float autoFinishedVelocityLimit = 3000f; private int touchedEdge = ViewDragHelper.INVALID_POINTER; diff --git a/app/src/main/java/com/simon/harmonichackernews/AboutActivity.java b/app/src/main/java/com/simon/harmonichackernews/AboutActivity.java index 3668402e..07ff0096 100644 --- a/app/src/main/java/com/simon/harmonichackernews/AboutActivity.java +++ b/app/src/main/java/com/simon/harmonichackernews/AboutActivity.java @@ -5,12 +5,10 @@ import android.net.Uri; import android.os.Bundle; import android.view.View; -import android.widget.ScrollView; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; -import com.gw.swipeback.SwipeBackLayout; import com.simon.harmonichackernews.utils.ThemeUtils; import com.simon.harmonichackernews.utils.Utils; diff --git a/app/src/main/java/com/simon/harmonichackernews/BaseActivity.java b/app/src/main/java/com/simon/harmonichackernews/BaseActivity.java index e7961e6d..9c4b0d7b 100644 --- a/app/src/main/java/com/simon/harmonichackernews/BaseActivity.java +++ b/app/src/main/java/com/simon/harmonichackernews/BaseActivity.java @@ -1,6 +1,5 @@ package com.simon.harmonichackernews; -import android.os.Bundle; import android.view.MotionEvent; import android.view.View; diff --git a/app/src/main/java/com/simon/harmonichackernews/CommentsActivity.java b/app/src/main/java/com/simon/harmonichackernews/CommentsActivity.java index 81b92de3..7d352aa4 100644 --- a/app/src/main/java/com/simon/harmonichackernews/CommentsActivity.java +++ b/app/src/main/java/com/simon/harmonichackernews/CommentsActivity.java @@ -31,7 +31,7 @@ protected void onCreate(Bundle savedInstanceState) { ThemeUtils.setupTheme(this, swipeBack); /*this is a long story. On CommentsActivity, the default theme is dependent on the android version. - For 24-29, we set SwipeBack as the defaul theme and do nothing more + For 24-29, we set SwipeBack as the default theme and do nothing more For 30-33, we set AppTheme as the default and perhaps switch to SwipeBack if the user wants to, but in that case we indicate translucency manually which makes it so that SwipeBack can peek to MainActivity For 34+, translucent = true is set automatically in the onResume (after a delay) which makes the peek work @@ -85,10 +85,10 @@ public void onSwitchView(boolean isAtWebView) { } } - //we only need to do the translucent setting on Android 14 and above as its purpose is to - //make the predictive back animation nice (when we peek back from a deeper activity, + // We only need to do the translucent setting on Android 14 and above as its purpose is to + // make the predictive back animation nice (when we peek back from a deeper activity, // CommentsActivity cannot be transparent). The theme already sets the activity to translucent - //so when we animate in we are transparent which is important! + // so when we animate in we are transparent which is important! @Override protected void onResume() { super.onResume(); @@ -102,7 +102,8 @@ public void run() { } } - //if we set translucency to false immediately onPause we can trigger animations by accident so we delay things a little + // If we set translucency to false immediately onPause we can trigger animations by accident so + // we delay things a little @Override protected void onPause() { super.onPause(); diff --git a/app/src/main/java/com/simon/harmonichackernews/CommentsFragment.java b/app/src/main/java/com/simon/harmonichackernews/CommentsFragment.java index 90482d5e..74a19e68 100644 --- a/app/src/main/java/com/simon/harmonichackernews/CommentsFragment.java +++ b/app/src/main/java/com/simon/harmonichackernews/CommentsFragment.java @@ -91,12 +91,12 @@ import com.simon.harmonichackernews.data.WikipediaInfo; import com.simon.harmonichackernews.linkpreview.ArxivAbstractGetter; import com.simon.harmonichackernews.linkpreview.GitHubInfoGetter; +import com.simon.harmonichackernews.linkpreview.WikipediaGetter; +import com.simon.harmonichackernews.network.ArchiveOrgUrlGetter; import com.simon.harmonichackernews.network.JSONParser; import com.simon.harmonichackernews.network.NetworkComponent; import com.simon.harmonichackernews.network.UserActions; -import com.simon.harmonichackernews.linkpreview.WikipediaGetter; import com.simon.harmonichackernews.utils.AccountUtils; -import com.simon.harmonichackernews.network.ArchiveOrgUrlGetter; import com.simon.harmonichackernews.utils.CommentSorter; import com.simon.harmonichackernews.utils.DialogUtils; import com.simon.harmonichackernews.utils.FileDownloader; @@ -223,7 +223,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { } else { story.loaded = false; story.id = -1; - //check if url intercept + // check if url intercept Intent intent = requireActivity().getIntent(); if (intent != null) { if (Intent.ACTION_VIEW.equalsIgnoreCase(intent.getAction())) { @@ -239,7 +239,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { story.url = ""; story.score = 0; } - } catch(Exception e) { + } catch (Exception e) { e.printStackTrace(); Toast.makeText(getContext(), "Unable to parse story", Toast.LENGTH_SHORT).show(); requireActivity().finish(); @@ -288,7 +288,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat webViewBackdrop = view.findViewById(R.id.comments_webview_backdrop); if (story.title == null) { - //Empty view for tablets + // Empty view for tablets view.findViewById(R.id.comments_empty).setVisibility(View.VISIBLE); bottomSheet.setVisibility(View.GONE); webViewContainer.setVisibility(View.GONE); @@ -300,17 +300,16 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat backPressedCallback = new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { - if (BottomSheetBehavior.from(bottomSheet).getState() == BottomSheetBehavior.STATE_COLLAPSED) { - if (webView.canGoBack()) { - if (downloadButton.getVisibility() == View.VISIBLE && webView.getVisibility() == View.GONE) { - webView.setVisibility(View.VISIBLE); - downloadButton.setVisibility(View.GONE); - } else { - webView.goBack(); - } - return; + if (BottomSheetBehavior.from(bottomSheet).getState() == BottomSheetBehavior.STATE_COLLAPSED && webView.canGoBack()) { + if (downloadButton.getVisibility() == View.VISIBLE && webView.getVisibility() == View.GONE) { + webView.setVisibility(View.VISIBLE); + downloadButton.setVisibility(View.GONE); + } else { + webView.goBack(); } + return; } + requireActivity().finish(); if (!SettingsUtils.shouldDisableCommentsSwipeBack(getContext()) && !Utils.isTablet(getResources())) { requireActivity().overridePendingTransition(0, R.anim.activity_out_animation); @@ -323,8 +322,8 @@ public void handleOnBackPressed() { swipeRefreshLayout.setOnRefreshListener(this::refreshComments); ViewUtils.setUpSwipeRefreshWithStatusBarOffset(swipeRefreshLayout); - // this is how much the bottom sheet sticks up by default and also decides height of webview - //We want to watch for navigation bar height changes (tablets on Android 12L can cause + // This is how much the bottom sheet sticks up by default and also decides height of WebView + // We want to watch for navigation bar height changes (tablets on Android 12L can cause // these) ViewCompat.setOnApplyWindowInsetsListener(view, new OnApplyWindowInsetsListener() { @@ -366,7 +365,7 @@ public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowIn webViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), ThemeUtils.getBackgroundColorResource(requireContext()))); comments = new ArrayList<>(); - comments.add(new Comment()); //header + comments.add(new Comment()); // header username = AccountUtils.getAccountUsername(getContext()); @@ -378,7 +377,7 @@ public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowIn Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.ime()); FrameLayout.LayoutParams scrollParams = (FrameLayout.LayoutParams) scrollNavigation.getLayoutParams(); - scrollParams.setMargins(0,0,0, insets.bottom + Utils.pxFromDpInt(getResources(), 16)); + scrollParams.setMargins(0, 0, 0, insets.bottom + Utils.pxFromDpInt(getResources(), 16)); return windowInsets; } @@ -395,10 +394,16 @@ public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowIn scrollIcon.setOnClickListener(null); scrollNext.setOnClickListener((v) -> scrollNext()); - scrollNext.setOnLongClickListener(v -> {scrollLast(); return true;}); + scrollNext.setOnLongClickListener(v -> { + scrollLast(); + return true; + }); scrollPrev.setOnClickListener((v) -> scrollPrevious()); - scrollPrev.setOnLongClickListener(v -> {scrollTop(); return true;}); + scrollPrev.setOnLongClickListener(v -> { + scrollTop(); + return true; + }); initializeRecyclerView(); @@ -407,11 +412,11 @@ public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowIn loadStoryAndComments(story.id, cachedResponse); - //if this isn't here, the addition of the text appears to scroll the recyclerview down a little + // if this isn't here, the addition of the text appears to scroll the recyclerview down a little recyclerView.scrollToPosition(0); if (cachedResponse != null) { - handleJsonResponse(story.id, cachedResponse,false, false, !showWebsite); + handleJsonResponse(story.id, cachedResponse, false, false, !showWebsite); } } @@ -428,7 +433,7 @@ private void updateBottomSheetMargin(int navbarHeight) { BottomSheetBehavior.from(bottomSheet).setPeekHeight(standardMargin + navbarHeight); CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - params.setMargins(0,0, 0, standardMargin + navbarHeight); + params.setMargins(0, 0, 0, standardMargin + navbarHeight); webViewContainer.setLayoutParams(params); @@ -440,8 +445,8 @@ private void updateBottomSheetMargin(int navbarHeight) { @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); - //this is to make sure that action buttons in header get updated padding on rotations... - //yes its ugly, I know + // this is to make sure that action buttons in header get updated padding on rotations... + // yes its ugly, I know if (getContext() != null && Utils.isTablet(getResources()) && adapter != null) { adapter.notifyItemChanged(0); } @@ -481,7 +486,7 @@ private void initializeRecyclerView() { final RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(index); if (holder != null && !adapter.collapseParent && holder instanceof CommentsRecyclerViewAdapter.ItemViewHolder) { - //if we can reach the ViewHolder (which we should), we can animate the + // if we can reach the ViewHolder (which we should), we can animate the // hiddenIndicator ourselves to get around a FULL item refresh (which flashes // all the text which we don't want) offset = 1; @@ -491,7 +496,7 @@ private void initializeRecyclerView() { hiddenIndicator.setText("+" + (lastChildIndex - index)); if (comment.expanded) { - //fade out + // fade out hiddenIndicator.setVisibility(View.VISIBLE); hiddenIndicator.setAlpha(1f); hiddenIndicator.animate() @@ -504,7 +509,7 @@ public void onAnimationEnd(Animator animation) { } }); } else { - //fade in + // fade in hiddenIndicator.setVisibility(View.VISIBLE); hiddenIndicator.setAlpha(0f); hiddenIndicator.animate() @@ -518,17 +523,17 @@ public void onAnimationEnd(Animator animation) { if (lastChildIndex != index || adapter.collapseParent) { // + 1 since if we have 1 subcomment we have changed the parent and the child - adapter.notifyItemRangeChanged(index+1, lastChildIndex - index + 1-offset); + adapter.notifyItemRangeChanged(index + 1, lastChildIndex - index + 1 - offset); } - //next couple of lines makes it so that if we hide parents and click the comment at - //the top of the screen, we scroll down to the next comment automatically - //this is only applicable if we're hiding a comment + // next couple of lines makes it so that if we hide parents and click the comment at + // the top of the screen, we scroll down to the next comment automatically + // this is only applicable if we're hiding a comment if (layoutManager != null && !comment.expanded && adapter.collapseParent) { int firstVisible = layoutManager.findFirstVisibleItemPosition(); int clickedIndex = comments.indexOf(comment); - //if we clicked the top one and the new top level comment exists + // if we clicked the top one and the new top level comment exists if (clickedIndex == firstVisible && comments.size() > lastChildIndex + 1) { smoothScroller.setTargetPosition(lastChildIndex + 1); layoutManager.startSmoothScroll(smoothScroller); @@ -577,15 +582,15 @@ public void onActionClicked(int flag, View clickedView) { break; case CommentsRecyclerViewAdapter.FLAG_ACTION_CLICK_INVERT: - //this whole thing should only be visible for SDK_INT larger than Q (29) - //We first check the "new" version of dark mode, algorithmic darkening + // This whole thing should only be visible for SDK_INT larger than Q (29) + // We first check the "new" version of dark mode, algorithmic darkening // this requires the isDarkMode thing to be true for the theme which we // have set if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { WebSettingsCompat.setAlgorithmicDarkeningAllowed(webView.getSettings(), !WebSettingsCompat.isAlgorithmicDarkeningAllowed(webView.getSettings())); } else if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { - //I don't know why but this seems to always be true whenever we - //are at or above android 10 + // I don't know why but this seems to always be true whenever we + // are at or above android 10 if (WebSettingsCompat.getForceDark(webView.getSettings()) == WebSettingsCompat.FORCE_DARK_ON) { WebSettingsCompat.setForceDark(webView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); } else { @@ -612,8 +617,8 @@ public void onActionClicked(int flag, View clickedView) { public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (integratedWebview) { - //Shouldn't be neccessary but once I was stuck in comments and couldn't swipe up. - //this just updates a flag so there's no performance impact + // Shouldn't be neccessary but once I was stuck in comments and couldn't swipe up. + // This just updates a flag so there's no performance impact if (dy != 0 && callback != null) { callback.onSwitchView(false); } @@ -633,7 +638,7 @@ protected int getVerticalSnapPreference() { @Override public int calculateDyToMakeVisible(View view, int snapPreference) { - //this is to make sure that scrollTo calls work properly + // This is to make sure that scrollTo calls work properly return super.calculateDyToMakeVisible(view, snapPreference) + topInset; } @@ -644,8 +649,8 @@ public int calculateDyToMakeVisible(View view, int snapPreference) { } if (!SettingsUtils.shouldUseCommentsScrollbar(getContext())) { - //for some reason, I could only get the scrollbars to show up when they are enabled via - //xml but disabling them in java worked so this is an okay solution... + // For some reason, I could only get the scrollbars to show up when they are enabled via + // xml but disabling them in java worked so this is an okay solution... recyclerView.setVerticalScrollBarEnabled(false); } @@ -664,12 +669,12 @@ public void onSlide(@NonNull View view, float slideOffset) { // Updating padding (of recyclerview) doesn't work because it causes incorrect scroll position for recycler. // Updating scroll together with padding causes severe lags and other problems. // So don't update padding at all on slide and instead just change whole view position (by translationY on recyclerView) - //... is something you could do but this means that the touch target of the recyclerview is not aligned with the view - //so we go back to the padding but instead just put a view above the recyclerview (a spacer) and change its height! - //... is what you could do if you were stupid! This would mean that the recyclerView starts BELOW the status bar - //breaking transparent status bar. Instead, the spacing needs to be _within_ the recyclerview header! - //NOTE: this also needs to be set in onBindViewHolder of the adapter to stay up to date if the header item - //should be refreshed + // ... is something you could do but this means that the touch target of the recyclerview is not aligned with the view + // so we go back to the padding but instead just put a view above the recyclerview (a spacer) and change its height! + // ... is what you could do if you were stupid! This would mean that the recyclerView starts BELOW the status bar + // breaking transparent status bar. Instead, the spacing needs to be _within_ the recyclerview header! + // NOTE: this also needs to be set in onBindViewHolder of the adapter to stay up to date if the header item + // should be refreshed loadHeaderSpacer(); if (headerSpacer != null) { headerSpacer.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, Math.round(topInset * slideOffset))); @@ -717,15 +722,15 @@ private void initializeWebView() { BottomSheetBehavior.from(bottomSheet).addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { - if (callback != null) { - callback.onSwitchView(newState == BottomSheetBehavior.STATE_COLLAPSED); + if (callback != null) { + callback.onSwitchView(newState == BottomSheetBehavior.STATE_COLLAPSED); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { - //onSlide gets called when if we're just scrolling the scrollview in the sheet, - //we only want to start loading if we're actually sliding up the thing! + // onSlide gets called when if we're just scrolling the scrollview in the sheet, + // we only want to start loading if we're actually sliding up the thing! if (!startedLoading && slideOffset < 0.9999) { startedLoading = true; loadUrl(story.url); @@ -733,11 +738,11 @@ public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); - //This is because we are now for sure not using swipeRefresh + // This is because we are now for sure not using swipeRefresh try { ((FrameLayout) swipeRefreshLayout.getParent()).removeView(swipeRefreshLayout); } catch (Exception e) { - //this will crash if we have already done this, which is fine + // This will crash if we have already done this, which is fine } if (blockAds && TextUtils.isEmpty(Utils.adservers)) { @@ -758,7 +763,7 @@ public void onSlide(@NonNull View bottomSheet, float slideOffset) { webView.getSettings().setDatabaseEnabled(true); webView.getSettings().setUseWideViewPort(true); webView.getSettings().setLoadWithOverviewMode(true); - + webView.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String url, String userAgent, @@ -867,7 +872,7 @@ private void showDownloadButton(String url, String contentDisposition, String mi downloadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - //just download via notification as usual + // Just download via notification as usual try { DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); @@ -951,7 +956,7 @@ public void onStart() { if (bottomSheet != null) { bottomSheet.setBackgroundColor(ContextCompat.getColor(ctx, ThemeUtils.getBackgroundColorResource(ctx))); } - if (webViewContainer != null){ + if (webViewContainer != null) { webViewContainer.setBackgroundColor(ContextCompat.getColor(ctx, ThemeUtils.getBackgroundColorResource(ctx))); } } @@ -968,7 +973,7 @@ public void onStart() { public void onResume() { super.onResume(); - if (lastLoaded != 0 && (System.currentTimeMillis() - lastLoaded) > 1000*60*60 && !Utils.timeInSecondsMoreThanTwoHoursAgo(story.time)) { + if (lastLoaded != 0 && (System.currentTimeMillis() - lastLoaded) > 1000 * 60 * 60 && !Utils.timeInSecondsMoreThanTwoHoursAgo(story.time)) { if (adapter != null && !adapter.showUpdate) { adapter.showUpdate = true; adapter.notifyItemChanged(0); @@ -985,18 +990,18 @@ public void onStop() { if (MainActivity.commentsScrollProgresses == null) { MainActivity.commentsScrollProgresses = new ArrayList<>(); } - //let's check all scrollProgresses in memory to see if we should change an active - //object + // Let's check all scrollProgresses in memory to see if we should change an active + // object for (int i = 0; i < MainActivity.commentsScrollProgresses.size(); i++) { CommentsScrollProgress scrollProgress = MainActivity.commentsScrollProgresses.get(i); if (scrollProgress.storyId == story.id) { - // if we find, overwrite the old thing and stop completely + // If we find, overwrite the old thing and stop completely MainActivity.commentsScrollProgresses.set(i, recordScrollProgress()); return; } } - //if we didn't find anything, let's add it ourselves + // If we didn't find anything, let's add it ourselves MainActivity.commentsScrollProgresses.add(recordScrollProgress()); } } @@ -1044,7 +1049,7 @@ private void restoreScrollProgress(CommentsScrollProgress scrollProgress) { } public void destroyWebView() { - //nuclear + // Nuclear if (webView != null) { webViewContainer.removeAllViews(); webView.clearHistory(); @@ -1102,7 +1107,7 @@ private void loadStoryAndComments(final int id, final String oldCachedResponse) StringRequest stringRequest = new StringRequest(Request.Method.GET, url, response -> { if (TextUtils.isEmpty(oldCachedResponse) || !oldCachedResponse.equals(response)) { - handleJsonResponse(id, response,true, oldCachedResponse == null, false); + handleJsonResponse(id, response, true, oldCachedResponse == null, false); } swipeRefreshLayout.setRefreshing(false); }, error -> { @@ -1137,7 +1142,7 @@ public void onSuccess(ArxivInfo arxivInfo) { @Override public void onFailure(String reason) { - //no-op + // no-op } }); } else if (GitHubInfoGetter.isValidGitHubUrl(story.url) && SettingsUtils.shouldUseLinkPreviewGithub(getContext())) { @@ -1152,7 +1157,7 @@ public void onSuccess(RepoInfo repoInfo) { @Override public void onFailure(String reason) { - //no op + // no op } }); } else if (WikipediaGetter.isValidWikipediaUrl(story.url) && SettingsUtils.shouldUseLinkPreviewWikipedia(getContext())) { @@ -1167,7 +1172,7 @@ public void onSuccess(WikipediaInfo wikipediaInfo) { @Override public void onFailure(String reason) { - //no op + // no op } }); } @@ -1196,9 +1201,7 @@ private void loadPollOptions() { StringRequest stringRequest = new StringRequest(Request.Method.GET, url, response -> { try { - for (int i = 0; i < story.pollOptionArrayList.size(); i++) { - PollOption pollOption = story.pollOptionArrayList.get(i); - + for (PollOption pollOption : story.pollOptionArrayList) { if (pollOption.id == optionId) { pollOption.loaded = true; @@ -1239,7 +1242,7 @@ private void handleJsonResponse(final int id, final String response, final boole JSONArray children = jsonObject.getJSONArray("children"); - //we run the defauly sorting + // We run the default sorting boolean addedNewComment = false; for (int i = 0; i < children.length(); i++) { boolean added = JSONParser.readChildAndParseSubchilds(children.getJSONObject(i), comments, adapter, 0, story.kids); @@ -1247,12 +1250,12 @@ private void handleJsonResponse(final int id, final String response, final boole addedNewComment = true; } } - //if non default, do full refresh after the sorting below! + // If non default, do full refresh after the sorting below! if (addedNewComment && !SettingsUtils.getPreferredCommentSorting(getContext()).equals("Default")) { adapter.notifyItemRangeChanged(1, comments.size()); } - //and then perhaps apply an updated sorting + // And then perhaps apply an updated sorting CommentSorter.sort(getContext(), comments); boolean storyChanged = JSONParser.updateStoryInformation(story, jsonObject, forceHeaderRefresh, oldCommentCount, comments.size()); @@ -1263,7 +1266,7 @@ private void handleJsonResponse(final int id, final String response, final boole integratedWebview = prefIntegratedWebview && story.isLink; if (integratedWebview && !initializedWebView) { - //it's the first time, so we need to re-initialize the recyclerview too + // It's the first time, so we need to re-initialize the recyclerview too initializeWebView(); initializeRecyclerView(); } @@ -1279,17 +1282,17 @@ private void handleJsonResponse(final int id, final String response, final boole adapter.loadingFailed = false; adapter.loadingFailedServerError = false; - //Seems like loading went well, lets cache the result + // Seems like loading went well, lets cache the result if (cache) { Utils.cacheStory(getContext(), id, response); } else if (restoreScroll) { - //if we're not caching the result, this means we just loaded an old cache. - //let's see if we can recover the scroll position. + // If we're not caching the result, this means we just loaded an old cache. + // Let's see if we can recover the scroll position. if (MainActivity.commentsScrollProgresses != null && !MainActivity.commentsScrollProgresses.isEmpty()) { - //we check all of the caches to see if one has the same story ID + // We check all of the caches to see if one has the same story ID for (CommentsScrollProgress scrollProgress : MainActivity.commentsScrollProgresses) { if (scrollProgress.storyId == story.id) { - //jackpot! Let's restore the state + // Jackpot! Let's restore the state restoreScrollProgress(scrollProgress); } } @@ -1298,7 +1301,7 @@ private void handleJsonResponse(final int id, final String response, final boole } catch (JSONException e) { e.printStackTrace(); - //Show some error, remove things? + // Show some error, remove things? adapter.loadingFailed = true; adapter.loadingFailedServerError = false; adapter.notifyItemChanged(0); @@ -1315,7 +1318,7 @@ public void clickBrowser() { intent.setData(Uri.parse(webView.getUrl())); startActivity(intent); } catch (Exception e) { - //if we're at a PDF or something like that, just do the original URL + // If we're at a PDF or something like that, just do the original URL intent.setData(Uri.parse(story.url)); startActivity(intent); } @@ -1459,10 +1462,10 @@ private int findFirstVisiblePosition() { int height = firstVisibleView.getHeight(); int scrolled = height - Math.abs(top); - //there is a topInset-sized padding at the top of the recyclerview (the + // There is a topInset-sized padding at the top of the recyclerview (the // recyclerview extends behind the status bar) and as such // findFirstVisiblePosition() may return the view that is hidden behind the - //status bar. If we have scrolled so short, then firstVisible should get a ++ + // status bar. If we have scrolled so short, then firstVisible should get a ++ if (scrolled <= topInset) { firstVisible++; } @@ -1523,7 +1526,7 @@ private void scrollLast() { private void updateNavigationVisibility() { if (showNavButtons) { - //If was gone and shouldn't be now, animate in + // If was gone and shouldn't be now, animate in if (comments != null && comments.size() > 1 && scrollNavigation.getVisibility() == View.GONE) { scrollNavigation.setVisibility(View.VISIBLE); @@ -1568,7 +1571,7 @@ public void onItemClick(Comment comment, int pos, View view) { ListAdapter adapter = new ArrayAdapter>(ctx, R.layout.comment_dialog_item, R.id.comment_dialog_text, - items){ + items) { public View getView(int position, View convertView, ViewGroup parent) { TextView view = (TextView) super.getView(position, convertView, parent); @@ -1657,7 +1660,7 @@ public void onPageFinished(WebView view, String url) { webViewBackdrop.setVisibility(View.GONE); if (BottomSheetBehavior.from(bottomSheet).getState() == BottomSheetBehavior.STATE_COLLAPSED) { - //if we are at the webview and we just loaded, recheck the canGoBack status + // If we are at the webview and we just loaded, recheck the canGoBack status toggleBackPressedCallback(webView != null && webView.canGoBack()); } } @@ -1815,6 +1818,7 @@ protected void finalize() throws Throwable { interface Callbacks { void onFailure(); + void onLoad(); } } diff --git a/app/src/main/java/com/simon/harmonichackernews/CommentsSearchDialogFragment.java b/app/src/main/java/com/simon/harmonichackernews/CommentsSearchDialogFragment.java index c7a34247..e0adf42f 100644 --- a/app/src/main/java/com/simon/harmonichackernews/CommentsSearchDialogFragment.java +++ b/app/src/main/java/com/simon/harmonichackernews/CommentsSearchDialogFragment.java @@ -1,68 +1,29 @@ package com.simon.harmonichackernews; -import static com.simon.harmonichackernews.SubmissionsActivity.KEY_USER; - -import android.annotation.SuppressLint; import android.app.Dialog; -import android.content.Context; -import android.content.Intent; -import android.graphics.Color; -import android.graphics.drawable.GradientDrawable; -import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.text.Editable; -import android.text.Html; -import android.text.SpannableString; -import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; -import android.text.method.LinkMovementMethod; -import android.text.style.ClickableSpan; import android.view.LayoutInflater; import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDialogFragment; -import androidx.core.content.ContextCompat; -import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.android.volley.DefaultRetryPolicy; -import com.android.volley.Request; -import com.android.volley.RequestQueue; -import com.android.volley.toolbox.StringRequest; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.textfield.TextInputEditText; import com.simon.harmonichackernews.adapters.CommentSearchAdapter; import com.simon.harmonichackernews.data.Comment; -import com.simon.harmonichackernews.network.NetworkComponent; -import com.simon.harmonichackernews.utils.ThemeUtils; -import com.simon.harmonichackernews.utils.Utils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.sufficientlysecure.htmltextview.HtmlTextView; -import org.sufficientlysecure.htmltextview.OnClickATagListener; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; import java.util.List; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class CommentsSearchDialogFragment extends AppCompatDialogFragment { diff --git a/app/src/main/java/com/simon/harmonichackernews/ComposeActivity.java b/app/src/main/java/com/simon/harmonichackernews/ComposeActivity.java index 31520712..6d70e022 100644 --- a/app/src/main/java/com/simon/harmonichackernews/ComposeActivity.java +++ b/app/src/main/java/com/simon/harmonichackernews/ComposeActivity.java @@ -204,8 +204,8 @@ public WindowInsetsAnimationCompat.BoundsCompat onStart(@NonNull WindowInsetsAni backPressedCallback = new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { - //This thing should only be enabled when we want to show the dialog, otherwise - //we just do the default back behavior (which is predictive back) + // This thing should only be enabled when we want to show the dialog, otherwise + // we just do the default back behavior (which is predictive back) AlertDialog dialog = new MaterialAlertDialogBuilder(editText.getContext()) .setMessage(type == TYPE_POST ? "Discard post?" : "Discard comment?") .setPositiveButton("Discard", new DialogInterface.OnClickListener() { @@ -225,15 +225,11 @@ public void onClick(DialogInterface dialog, int whichButton) { @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); - //Make sure scrollview never takes up more than 1/3 of screen height + // Make sure scrollview never takes up more than 1/3 of screen height ViewGroup.LayoutParams layout = replyingScrollView.getLayoutParams(); int dp160 = Utils.pxFromDpInt(getResources(), 160); int screenHeightThird = Resources.getSystem().getDisplayMetrics().heightPixels / 3; - if (dp160 > screenHeightThird) { - layout.height = screenHeightThird; - } else { - layout.height = dp160; - } + layout.height = Math.min(dp160, screenHeightThird); replyingScrollView.setLayoutParams(layout); } diff --git a/app/src/main/java/com/simon/harmonichackernews/LoginDialogFragment.java b/app/src/main/java/com/simon/harmonichackernews/LoginDialogFragment.java index 13e5ec6a..21d6560f 100644 --- a/app/src/main/java/com/simon/harmonichackernews/LoginDialogFragment.java +++ b/app/src/main/java/com/simon/harmonichackernews/LoginDialogFragment.java @@ -4,7 +4,6 @@ import android.os.Bundle; import android.text.Editable; import android.text.TextUtils; -import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; diff --git a/app/src/main/java/com/simon/harmonichackernews/SettingsActivity.java b/app/src/main/java/com/simon/harmonichackernews/SettingsActivity.java index 584e031e..01694d34 100644 --- a/app/src/main/java/com/simon/harmonichackernews/SettingsActivity.java +++ b/app/src/main/java/com/simon/harmonichackernews/SettingsActivity.java @@ -3,17 +3,12 @@ import android.app.Activity; import android.content.Intent; import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.ListView; import android.widget.Toast; import androidx.activity.OnBackPressedCallback; @@ -28,7 +23,6 @@ import com.google.android.material.snackbar.Snackbar; import com.google.android.material.timepicker.MaterialTimePicker; import com.google.android.material.timepicker.TimeFormat; -import com.gw.swipeback.SwipeBackLayout; import com.simon.harmonichackernews.data.Bookmark; import com.simon.harmonichackernews.utils.SettingsUtils; import com.simon.harmonichackernews.utils.ThemeUtils; @@ -74,10 +68,8 @@ public void handleOnBackPressed() { getOnBackPressedDispatcher().addCallback(this, backPressedCallback); backPressedCallback.setEnabled(false); - if (getIntent() != null) { - if (getIntent().getBooleanExtra(EXTRA_REQUEST_RESTART, false)) { - backPressedCallback.setEnabled(true); - } + if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_REQUEST_RESTART, false)) { + backPressedCallback.setEnabled(true); } } @@ -98,7 +90,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { findPreference("pref_default_story_type").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { + public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { if (getActivity() != null && getActivity() instanceof SettingsActivity) { ((SettingsActivity) getActivity()).backPressedCallback.setEnabled(true); } @@ -108,7 +100,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { findPreference("pref_compact_view").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { + public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { changePrefStatus(findPreference("pref_show_points"), !(boolean) newValue); changePrefStatus(findPreference("pref_show_comments_count"), !(boolean) newValue); changePrefStatus(findPreference("pref_thumbnails"), !(boolean) newValue); @@ -119,7 +111,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { findPreference("pref_foldable_support").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { + public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { if (getActivity() != null && getActivity() instanceof SettingsActivity) { ((SettingsActivity) getActivity()).backPressedCallback.setEnabled(true); } @@ -136,7 +128,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { findPreference("pref_transparent_status_bar").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { + public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { Intent intent = new Intent(getContext(), SettingsActivity.class); intent.putExtra(EXTRA_REQUEST_RESTART, true); requireContext().startActivity(intent); @@ -198,7 +190,7 @@ public void onClick(View view) { findPreference("pref_export_bookmarks").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(@NonNull Preference preference) { String textToSave = SettingsUtils.readStringFromSharedPreferences(requireContext(), Utils.KEY_SHARED_PREFERENCES_BOOKMARKS); @@ -226,7 +218,7 @@ public boolean onPreferenceClick(Preference preference) { findPreference("pref_import_bookmarks").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(@NonNull Preference preference) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("text/plain"); @@ -239,7 +231,7 @@ public boolean onPreferenceClick(Preference preference) { findPreference("pref_clear_clicked_stories").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(@NonNull Preference preference) { Set set = SettingsUtils.readIntSetFromSharedPreferences(requireContext(), Utils.KEY_SHARED_PREFERENCES_CLICKED_IDS); int oldCount = set.size(); @@ -261,7 +253,7 @@ public boolean onPreferenceClick(Preference preference) { findPreference("pref_about").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(@NonNull Preference preference) { startActivity(new Intent(getContext(), AboutActivity.class)); return false; @@ -288,8 +280,8 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { try { String content = Utils.readFileContent(getContext(), data.getData()); ArrayList bookmarks = Utils.loadBookmarks(true, content); - if (bookmarks.size() > 0) { - //save the new bookmarks + if (!bookmarks.isEmpty()) { + // save the new bookmarks SettingsUtils.saveStringToSharedPreferences(getContext(), Utils.KEY_SHARED_PREFERENCES_BOOKMARKS, content); Toast.makeText(getContext(), "Loaded " + bookmarks.size() + " bookmarks", Toast.LENGTH_SHORT).show(); } else { @@ -321,7 +313,7 @@ private void updateTimedRangeSummary() { int[] nighttimeHours = Utils.getNighttimeHours(getContext()); if (DateFormat.is24HourFormat(getContext())) { - findPreference("pref_theme_timed_range").setSummary((nighttimeHours[0] < 10 ? "0" : "") + nighttimeHours[0] + ":" + (nighttimeHours[1] < 10 ? "0" : "") + nighttimeHours[1] + " - " + (nighttimeHours[2] < 10 ? "0" : "") + nighttimeHours[2] + ":" + (nighttimeHours[3] < 10 ? "0" : "") + nighttimeHours[3]); + findPreference("pref_theme_timed_range").setSummary((nighttimeHours[0] < 10 ? "0" : "") + nighttimeHours[0] + ":" + (nighttimeHours[1] < 10 ? "0" : "") + nighttimeHours[1] + " - " + (nighttimeHours[2] < 10 ? "0" : "") + nighttimeHours[2] + ":" + (nighttimeHours[3] < 10 ? "0" : "") + nighttimeHours[3]); } else { SimpleDateFormat df = new SimpleDateFormat("h:mm a"); diff --git a/app/src/main/java/com/simon/harmonichackernews/SplitPlaceholderActivity.java b/app/src/main/java/com/simon/harmonichackernews/SplitPlaceholderActivity.java index fa694240..8ad5c69c 100644 --- a/app/src/main/java/com/simon/harmonichackernews/SplitPlaceholderActivity.java +++ b/app/src/main/java/com/simon/harmonichackernews/SplitPlaceholderActivity.java @@ -8,10 +8,10 @@ public class SplitPlaceholderActivity extends AppCompatActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - ThemeUtils.setupTheme(this); - setContentView(R.layout.activity_split_placeholder); - } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeUtils.setupTheme(this); + setContentView(R.layout.activity_split_placeholder); + } } \ No newline at end of file diff --git a/app/src/main/java/com/simon/harmonichackernews/StoriesFragment.java b/app/src/main/java/com/simon/harmonichackernews/StoriesFragment.java index a6fb4c23..efe820f8 100644 --- a/app/src/main/java/com/simon/harmonichackernews/StoriesFragment.java +++ b/app/src/main/java/com/simon/harmonichackernews/StoriesFragment.java @@ -5,10 +5,8 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.content.Intent; -import android.graphics.Color; import android.os.Bundle; import android.text.TextUtils; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -207,7 +205,7 @@ private void setupAdapter() { SettingsUtils.getPreferredFaviconProvider(getContext()), null, getPreferredTypeIndex() - ); + ); adapter.setOnLinkClickListener(position -> { if (position == RecyclerView.NO_POSITION) { @@ -290,7 +288,7 @@ public boolean onLongClick(View v, int position, int x, int y) { popupMenu.getMenu().add(oldClicked ? "Mark as unread" : "Mark as read").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override - public boolean onMenuItemClick(MenuItem item) { + public boolean onMenuItemClick(@NonNull MenuItem item) { story.clicked = !oldClicked; if (oldClicked) { clickedIds.remove(story.id); @@ -305,7 +303,7 @@ public boolean onMenuItemClick(MenuItem item) { popupMenu.getMenu().add(oldBookmarked ? "Remove bookmark" : "Bookmark").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override - public boolean onMenuItemClick(MenuItem item) { + public boolean onMenuItemClick(@NonNull MenuItem item) { if (oldBookmarked) { Utils.removeBookmark(ctx, story.id); if (adapter.type == SettingsUtils.getBookmarksIndex(ctx.getResources())) { @@ -328,10 +326,10 @@ public boolean onMenuItemClick(MenuItem item) { fieldPopup.setAccessible(true); Object menuPopupHelper = fieldPopup.get(popupMenu); - //the reason for the -10 - height/3 thing is so match the popup location better - //with the press location - for some reason this is necessary. + // the reason for the -10 - height/3 thing is so match the popup location better + // with the press location - for some reason this is necessary. int targetX = x - Utils.pxFromDpInt(getResources(), 56); - int targetY = y - topInset - Utils.pxFromDpInt(getResources(), 10) - v.getHeight()/3; + int targetY = y - topInset - Utils.pxFromDpInt(getResources(), 10) - v.getHeight() / 3; menuPopupHelper.getClass().getDeclaredMethod("show", int.class, int.class).invoke(menuPopupHelper, targetX, targetY); } catch (Exception e) { @@ -365,7 +363,7 @@ public void onResume() { long timeDiff = System.currentTimeMillis() - lastLoaded; // if more than 1 hr - if (timeDiff > 1000*60*60 && !adapter.searching && adapter.type != SettingsUtils.getBookmarksIndex(getResources()) && !currentTypeIsAlgolia()) { + if (timeDiff > 1000 * 60 * 60 && !adapter.searching && adapter.type != SettingsUtils.getBookmarksIndex(getResources()) && !currentTypeIsAlgolia()) { showUpdateButton(); } @@ -442,7 +440,7 @@ public void onDestroyView() { } private void clickedComments(int position) { - //prevent double clicks + // prevent double clicks long now = System.currentTimeMillis(); if (now - lastClick > CLICK_INTERVAL) { lastClick = now; @@ -484,7 +482,7 @@ private void loadStory(Story story, final int attempt) { return; } - //lets check if we should remove the post because of filter + // lets check if we should remove the post because of filter for (String phrase : filterWords) { if (story.title.toLowerCase().contains(phrase.toLowerCase())) { stories.remove(story); @@ -503,7 +501,7 @@ private void loadStory(Story story, final int attempt) { } } - //or because it's a job + // or because it's a job if (hideJobs && adapter.type != SettingsUtils.getJobsIndex(getResources()) && (story.isJob || story.by.equals("whoishiring"))) { stories.remove(story); adapter.notifyItemRemoved(index); @@ -574,19 +572,19 @@ public void attemptRefresh() { swipeRefreshLayout.setRefreshing(true); - //cancel all ongoing + // cancel all ongoing queue.cancelAll(requestTag); if (currentTypeIsAlgolia()) { - //algoliaStuff + // algoliaStuff int currentTime = (int) (System.currentTimeMillis() / 1000); int startTime = currentTime; if (adapter.type == 1) { - startTime = currentTime - 60*60*24; + startTime = currentTime - 60 * 60 * 24; } else if (adapter.type == 2) { - startTime = currentTime - 60*60*48; + startTime = currentTime - 60 * 60 * 48; } else if (adapter.type == 3) { - startTime = currentTime - 60*60*24*7; + startTime = currentTime - 60 * 60 * 24 * 7; } loadTopStoriesSince(startTime); @@ -597,7 +595,7 @@ public void attemptRefresh() { lastLoaded = System.currentTimeMillis(); if (adapter.type == SettingsUtils.getBookmarksIndex(getResources())) { - //lets load bookmarks instead - or rather add empty stories with correct id:s and start loading them + // lets load bookmarks instead - or rather add empty stories with correct id:s and start loading them adapter.notifyItemRangeRemoved(1, stories.size() + 1); loadedTo = 0; @@ -643,7 +641,7 @@ public void attemptRefresh() { } Story s = new Story("Loading...", id, false, clickedIds.contains(id)); - //let's try to fill this with old information if possible + // let's try to fill this with old information if possible String cachedResponse = Utils.loadCachedStory(getContext(), id); if (cachedResponse != null && !cachedResponse.equals(JSONParser.ALGOLIA_ERROR_STRING)) { @@ -686,7 +684,7 @@ private void updateSearchStatus() { swipeRefreshLayout.setEnabled(!adapter.searching); if (adapter.searching) { - //cancel all ongoing + // cancel all ongoing queue.cancelAll(requestTag); swipeRefreshLayout.setRefreshing(false); diff --git a/app/src/main/java/com/simon/harmonichackernews/SubmissionsActivity.java b/app/src/main/java/com/simon/harmonichackernews/SubmissionsActivity.java index 0e8ba93f..2661b465 100644 --- a/app/src/main/java/com/simon/harmonichackernews/SubmissionsActivity.java +++ b/app/src/main/java/com/simon/harmonichackernews/SubmissionsActivity.java @@ -3,9 +3,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; -import android.view.View; -import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; @@ -15,13 +13,11 @@ import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.StringRequest; -import com.gw.swipeback.SwipeBackLayout; import com.simon.harmonichackernews.adapters.StoryRecyclerViewAdapter; import com.simon.harmonichackernews.data.Story; import com.simon.harmonichackernews.network.JSONParser; import com.simon.harmonichackernews.network.NetworkComponent; import com.simon.harmonichackernews.utils.SettingsUtils; -import com.simon.harmonichackernews.utils.SplitChangeHandler; import com.simon.harmonichackernews.utils.ThemeUtils; import com.simon.harmonichackernews.utils.Utils; import com.simon.harmonichackernews.utils.ViewUtils; @@ -55,7 +51,7 @@ protected void onCreate(Bundle savedInstanceState) { RecyclerView recyclerView = findViewById(R.id.submissions_recyclerview); submissions = new ArrayList<>(); - //header + // header submissions.add(new Story()); queue = NetworkComponent.getRequestQueueInstance(this); diff --git a/app/src/main/java/com/simon/harmonichackernews/UserDialogFragment.java b/app/src/main/java/com/simon/harmonichackernews/UserDialogFragment.java index 71437f6d..0ea16adf 100644 --- a/app/src/main/java/com/simon/harmonichackernews/UserDialogFragment.java +++ b/app/src/main/java/com/simon/harmonichackernews/UserDialogFragment.java @@ -2,11 +2,8 @@ import static com.simon.harmonichackernews.SubmissionsActivity.KEY_USER; -import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Intent; -import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.text.Html; import android.text.SpannableString; @@ -43,7 +40,6 @@ import java.util.Calendar; import java.util.Date; -import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -86,13 +82,13 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { final String userName = (bundle != null && !TextUtils.isEmpty(bundle.getString(EXTRA_USER_NAME))) ? bundle.getString(EXTRA_USER_NAME) : null; if (userName != null) { - //lets create a request and fill in the data when we have it + // lets create a request and fill in the data when we have it String url = "https://hacker-news.firebaseio.com/v0/user/" + userName + ".json"; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, response -> { try { - //lets try to parse the response + // lets try to parse the response JSONObject jsonObject = new JSONObject(response); nameTextview.setText(jsonObject.getString("id")); int karma = jsonObject.getInt("karma"); @@ -145,7 +141,7 @@ public boolean onClick(View widget, String spannedText, @Nullable String href) { }); container.setVisibility(View.VISIBLE); - } catch(Exception e) { + } catch (Exception e) { loadingProgress.setVisibility(View.GONE); errorLayout.setVisibility(View.VISIBLE); container.setVisibility(View.GONE); diff --git a/app/src/main/java/com/simon/harmonichackernews/adapters/CommentSearchAdapter.java b/app/src/main/java/com/simon/harmonichackernews/adapters/CommentSearchAdapter.java index f49d9842..1291c626 100644 --- a/app/src/main/java/com/simon/harmonichackernews/adapters/CommentSearchAdapter.java +++ b/app/src/main/java/com/simon/harmonichackernews/adapters/CommentSearchAdapter.java @@ -1,13 +1,11 @@ package com.simon.harmonichackernews.adapters; import android.graphics.drawable.RippleDrawable; -import android.text.Html; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; @@ -28,7 +26,7 @@ public class CommentSearchAdapter extends RecyclerView.Adapter comments; + private final List comments; private String searchTerm; public ItemClickListener itemClickListener; @@ -64,7 +62,7 @@ public CommentViewHolder(View view) { markedColor = ThemeUtils.isDarkMode(view.getContext()) ? "#fce205" : "#cc7722"; - //this is illegal according to some but works according to all + // this is illegal according to some but works according to all // the issue is that HtmlTextView hijacks clicks heavily final RippleDrawable rippleDrawable = (RippleDrawable) container.getBackground(); @@ -104,7 +102,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int } @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { if (!(holder instanceof CommentSearchAdapter.CommentViewHolder)) { return; } diff --git a/app/src/main/java/com/simon/harmonichackernews/adapters/CommentsRecyclerViewAdapter.java b/app/src/main/java/com/simon/harmonichackernews/adapters/CommentsRecyclerViewAdapter.java index 5ee73f2d..6284d150 100644 --- a/app/src/main/java/com/simon/harmonichackernews/adapters/CommentsRecyclerViewAdapter.java +++ b/app/src/main/java/com/simon/harmonichackernews/adapters/CommentsRecyclerViewAdapter.java @@ -6,11 +6,8 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.drawable.Drawable; import android.text.Html; -import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -32,7 +29,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.TooltipCompat; -import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; import androidx.fragment.app.FragmentManager; import androidx.preference.PreferenceManager; @@ -52,14 +48,12 @@ import com.simon.harmonichackernews.utils.FontUtils; import com.simon.harmonichackernews.utils.ThemeUtils; import com.simon.harmonichackernews.utils.Utils; -import com.squareup.picasso.Picasso; import org.jetbrains.annotations.NotNull; import org.sufficientlysecure.htmltextview.HtmlTextView; import org.sufficientlysecure.htmltextview.OnClickATagListener; import java.util.List; -import java.util.Objects; public class CommentsRecyclerViewAdapter extends RecyclerView.Adapter { @@ -407,7 +401,7 @@ public void onClick(View view) { width /= 2; } - //16 is base padding, then add 12 for each comment + // 16 is base padding, then add 12 for each comment params.setMargins( Math.min(Utils.pxFromDpInt(ctx.getResources(), 16 + 12 * comment.depth), Math.round(((float) width) * 0.6f)), Utils.pxFromDpInt(ctx.getResources(), comment.depth > 0 && !collapseParent ? 10 : 6), @@ -465,7 +459,7 @@ public void onClick(View view) { itemViewHolder.commentHiddenText.setTypeface(FontUtils.activeRegular); } - itemViewHolder.commentBody.setVisibility( (!comment.expanded && collapseParent) ? GONE : View.VISIBLE); + itemViewHolder.commentBody.setVisibility((!comment.expanded && collapseParent) ? GONE : View.VISIBLE); itemViewHolder.commentHiddenText.setVisibility((!comment.expanded && collapseParent) ? View.VISIBLE : GONE); if (comment.expanded) { @@ -473,7 +467,7 @@ public void onClick(View view) { itemViewHolder.commentHiddenCount.setVisibility(GONE); } else { // if not expanded, only show (and set text) if subCommentCount > 0 - //TODO should this be precomputed? + // TODO should this be precomputed? int subCommentCount = getIndexOfLastChild(comment.depth, position) - position; if (subCommentCount > 0) { @@ -511,7 +505,7 @@ public class ItemViewHolder extends RecyclerView.ViewHolder { public ItemViewHolder(View view) { super(view); - commentBody = view.findViewById(R.id.comment_body); + commentBody = view.findViewById(R.id.comment_body); commentBy = view.findViewById(R.id.comment_by); commentByTime = view.findViewById(R.id.comment_by_time); commentHiddenCount = view.findViewById(R.id.comment_hidden_count); @@ -537,7 +531,7 @@ public ItemViewHolder(View view) { commentBody.setOnClickATagListener(new OnClickATagListener() { @Override public boolean onClick(View widget, String spannedText, @Nullable String href) { - if (disableCommentATagClick) return true ; + if (disableCommentATagClick) return true; Utils.openLinkMaybeHN(widget.getContext(), href); return true; @@ -644,7 +638,7 @@ public HeaderViewHolder(View view) { arxivAbstract = view.findViewById(R.id.comments_header_arxiv_abstract); infoContainer = view.findViewById(R.id.comments_header_info_container); infoHeader = view.findViewById(R.id.comments_header_info_header); - emptyView = view.findViewById(R.id.comments_header_empty); + emptyView = view.findViewById(R.id.comments_header_empty); emptyViewText = view.findViewById(R.id.comments_header_empty_text); headerView = view.findViewById(R.id.comments_header); loadingIndicator = view.findViewById(R.id.comments_header_loading); @@ -704,7 +698,7 @@ public HeaderViewHolder(View view) { serverErrorSwitchApiButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - //This switches off the algolia API + // This switches off the algolia API SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(view.getContext()); prefs.edit().putBoolean("pref_algolia_api", false).apply(); @@ -768,12 +762,12 @@ public void onStateChanged(@NonNull View bottomSheet, int newState) { @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { - //0 when small, 1 when opened - sheetButtonsContainer.setAlpha((1-slideOffset)*(1-slideOffset)*(1-slideOffset)); - sheetButtonsContainer.getLayoutParams().height = Math.round((1-slideOffset) * (SHEET_ITEM_HEIGHT + navbarHeight)); + // 0 when small, 1 when opened + sheetButtonsContainer.setAlpha((1 - slideOffset) * (1 - slideOffset) * (1 - slideOffset)); + sheetButtonsContainer.getLayoutParams().height = Math.round((1 - slideOffset) * (SHEET_ITEM_HEIGHT + navbarHeight)); sheetButtonsContainer.requestLayout(); - float headerAlpha = Math.min(1, slideOffset*slideOffset*20); + float headerAlpha = Math.min(1, slideOffset * slideOffset * 20); actionsContainer.setAlpha(headerAlpha); headerView.setAlpha(headerAlpha); } @@ -785,7 +779,7 @@ public void onSlide(@NonNull View bottomSheet, float slideOffset) { sheetButtonsContainer.getLayoutParams().height = 0; sheetButtonsContainer.requestLayout(); } else { - //make sure we set correct height when starting on the webview + // Make sure we set correct height when starting on the WebView sheetButtonsContainer.getLayoutParams().height = SHEET_ITEM_HEIGHT + navbarHeight; sheetButtonsContainer.requestLayout(); } @@ -854,11 +848,11 @@ public int getIndexOfLastChild(int commentDepth, int pos) { private boolean shouldShow(Comment comment) { /* - * Try to call shouldShow() on the parent if parent is expanded - * if parent is not expanded the return false. - * - * If parent is -1 (top level) always show - * */ + * Try to call shouldShow() on the parent if parent is expanded + * if parent is not expanded the return false. + * + * If parent is -1 (top level) always show + * */ if (comment.parent == -1) { return true; diff --git a/app/src/main/java/com/simon/harmonichackernews/adapters/StoryRecyclerViewAdapter.java b/app/src/main/java/com/simon/harmonichackernews/adapters/StoryRecyclerViewAdapter.java index 4a895768..b36aefcc 100644 --- a/app/src/main/java/com/simon/harmonichackernews/adapters/StoryRecyclerViewAdapter.java +++ b/app/src/main/java/com/simon/harmonichackernews/adapters/StoryRecyclerViewAdapter.java @@ -4,7 +4,6 @@ import android.content.Context; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; -import android.text.Layout; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -19,7 +18,6 @@ import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; import android.widget.ImageButton; @@ -34,7 +32,6 @@ import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.button.MaterialButton; import com.simon.harmonichackernews.R; import com.simon.harmonichackernews.data.Story; import com.simon.harmonichackernews.network.FaviconLoader; @@ -43,18 +40,14 @@ import com.simon.harmonichackernews.utils.ThemeUtils; import com.simon.harmonichackernews.utils.Utils; import com.simon.harmonichackernews.utils.ViewUtils; -import com.squareup.picasso.Picasso; import org.jetbrains.annotations.NotNull; import org.sufficientlysecure.htmltextview.HtmlTextView; import org.sufficientlysecure.htmltextview.OnClickATagListener; -import java.lang.reflect.Array; -import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; public class StoryRecyclerViewAdapter extends RecyclerView.Adapter { @@ -178,7 +171,7 @@ public void onBindViewHolder(@NotNull final RecyclerView.ViewHolder holder, int final String commentCountText; if (showCommentsCount) { commentCountText = Integer.toString(storyViewHolder.story.descendants); - } else if (storyViewHolder.story.descendants > 0){ + } else if (storyViewHolder.story.descendants > 0) { commentCountText = "•"; } else { commentCountText = ""; @@ -186,7 +179,6 @@ public void onBindViewHolder(@NotNull final RecyclerView.ViewHolder holder, int storyViewHolder.commentsView.setText(commentCountText); String host = ""; - try { if (storyViewHolder.story.url != null) { host = Utils.getDomainName(storyViewHolder.story.url); @@ -195,11 +187,8 @@ public void onBindViewHolder(@NotNull final RecyclerView.ViewHolder holder, int host = "Unknown"; } - String ptsString = " points"; - if (storyViewHolder.story.score == 1) { - ptsString = " point"; - } if (showPoints && !storyViewHolder.story.isComment) { + String ptsString = storyViewHolder.story.score == 1 ? " point" : " points"; storyViewHolder.metaView.setText(storyViewHolder.story.score + ptsString + " • " + host + " • " + storyViewHolder.story.getTimeFormatted()); } else { storyViewHolder.metaView.setText(host + " • " + storyViewHolder.story.getTimeFormatted()); @@ -302,7 +291,6 @@ public void onBindViewHolder(@NotNull final RecyclerView.ViewHolder holder, int } else if (holder instanceof CommentViewHolder) { final CommentViewHolder commentViewHolder = (CommentViewHolder) holder; - final Context ctx = commentViewHolder.itemView.getContext(); Story story = stories.get(position); @@ -423,23 +411,23 @@ public MainHeaderViewHolder(View view) { retryButton = view.findViewById(R.id.stories_header_retry_button); loadingIndicator = view.findViewById(R.id.stories_header_loading_indicator); - retryButton.setOnClickListener( (v) -> refreshListener.onRefresh()); + retryButton.setOnClickListener((v) -> refreshListener.onRefresh()); moreButton.setOnClickListener(moreClickListener); searchEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) { - if (actionId == EditorInfo.IME_ACTION_SEARCH) { - doSearch(); - - if (textView != null) { - InputMethodManager imm = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - return true; + if (actionId != EditorInfo.IME_ACTION_SEARCH) { + return false; + } + + doSearch(); + if (textView != null) { + InputMethodManager imm = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } - return false; + return true; } }); @@ -517,7 +505,7 @@ public CommentViewHolder(View view) { GradientDrawable gradientDrawable = new GradientDrawable( GradientDrawable.Orientation.TOP_BOTTOM, - new int[] {Color.TRANSPARENT, ContextCompat.getColor(ctx, ThemeUtils.getBackgroundColorResource(ctx))}); + new int[]{Color.TRANSPARENT, ContextCompat.getColor(ctx, ThemeUtils.getBackgroundColorResource(ctx))}); scrim.setBackground(gradientDrawable); @@ -593,6 +581,7 @@ public void setSearchListener(SearchListener searchListener) { public interface SearchListener { void onQueryTextSubmit(String query); + void onSearchStatusChanged(); } diff --git a/app/src/main/java/com/simon/harmonichackernews/data/ArxivInfo.java b/app/src/main/java/com/simon/harmonichackernews/data/ArxivInfo.java index 566f90aa..08bee896 100644 --- a/app/src/main/java/com/simon/harmonichackernews/data/ArxivInfo.java +++ b/app/src/main/java/com/simon/harmonichackernews/data/ArxivInfo.java @@ -1,5 +1,7 @@ package com.simon.harmonichackernews.data; +import android.text.TextUtils; + import com.simon.harmonichackernews.utils.ArxivResolver; public class ArxivInfo { @@ -14,15 +16,7 @@ public class ArxivInfo { public String publishedDate; public String concatNames() { - if (authors.length == 0) { - return ""; - } - - String allNames = authors[0]; - for (int i = 1; i < authors.length; i++) { - allNames = allNames + ", " + authors[i]; - } - return allNames; + return TextUtils.join(", ", authors); } public String formatDate() { @@ -30,16 +24,12 @@ public String formatDate() { } public String formatSubjects() { - String allSubjects = ArxivResolver.resolveFull(primaryCategory); - - if (secondaryCategories.length == 0) { - return allSubjects; - } + StringBuilder allSubjects = new StringBuilder(ArxivResolver.resolveFull(primaryCategory)); - for (int i = 0; i < secondaryCategories.length; i++) { - allSubjects = allSubjects + "; " + ArxivResolver.resolveFull(secondaryCategories[i]); + for (String secondaryCategory : secondaryCategories) { + allSubjects.append("; ").append(ArxivResolver.resolveFull(secondaryCategory)); } - return allSubjects; + return allSubjects.toString(); } public String getPDFURL() { diff --git a/app/src/main/java/com/simon/harmonichackernews/linkpreview/ArxivAbstractGetter.java b/app/src/main/java/com/simon/harmonichackernews/linkpreview/ArxivAbstractGetter.java index 55f3fc18..b9f5cf6e 100644 --- a/app/src/main/java/com/simon/harmonichackernews/linkpreview/ArxivAbstractGetter.java +++ b/app/src/main/java/com/simon/harmonichackernews/linkpreview/ArxivAbstractGetter.java @@ -7,7 +7,6 @@ import com.android.volley.RequestQueue; import com.android.volley.toolbox.StringRequest; import com.simon.harmonichackernews.data.ArxivInfo; -import com.simon.harmonichackernews.data.RepoInfo; import com.simon.harmonichackernews.network.NetworkComponent; import com.simon.harmonichackernews.utils.ArxivResolver; @@ -17,7 +16,6 @@ import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -89,7 +87,7 @@ public static void getAbstract(String url, Context ctx, GetterCallback callback) // Convert author list to array String[] authorsArray = authorList.toArray(new String[0]); - //API 23 does not support Java 8 so we do this by hand + // API 23 does not support Java 8 so we do this by hand List secondaryCategoriesFiltered = new ArrayList<>(); for (String category : secondaryCategoryList) { if (ArxivResolver.isArxivSubjet(category)) { diff --git a/app/src/main/java/com/simon/harmonichackernews/linkpreview/GitHubInfoGetter.java b/app/src/main/java/com/simon/harmonichackernews/linkpreview/GitHubInfoGetter.java index ea1b9bab..306e3cd8 100644 --- a/app/src/main/java/com/simon/harmonichackernews/linkpreview/GitHubInfoGetter.java +++ b/app/src/main/java/com/simon/harmonichackernews/linkpreview/GitHubInfoGetter.java @@ -2,21 +2,15 @@ import android.content.Context; import android.text.TextUtils; -import android.util.Xml; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.StringRequest; -import com.simon.harmonichackernews.data.ArxivInfo; import com.simon.harmonichackernews.data.RepoInfo; import com.simon.harmonichackernews.network.NetworkComponent; import org.json.JSONObject; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import java.io.IOException; -import java.io.StringReader; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -90,17 +84,16 @@ public static void getInfo(String githubUrl, Context ctx, GetterCallback callbac private static String readJsonProp(JSONObject jsonObject, String key) { String input = jsonObject.optString(key); - if (TextUtils.isEmpty(input)) { - return null; - } - if (input.equals("null")) { + if (TextUtils.isEmpty(input) || input.equals("null")) { return null; } + return input; } public interface GetterCallback { void onSuccess(RepoInfo repoInfo); + void onFailure(String reason); } diff --git a/app/src/main/java/com/simon/harmonichackernews/linkpreview/WikipediaGetter.java b/app/src/main/java/com/simon/harmonichackernews/linkpreview/WikipediaGetter.java index ddc09bf3..98050295 100644 --- a/app/src/main/java/com/simon/harmonichackernews/linkpreview/WikipediaGetter.java +++ b/app/src/main/java/com/simon/harmonichackernews/linkpreview/WikipediaGetter.java @@ -30,7 +30,6 @@ public static void getInfo(String wikipediaUrl, Context ctx, WikipediaGetter.Get try { String title = wikipediaUrl.split("en.wikipedia.org/wiki/")[1]; - //String apiUrl = "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&titles=" + title; String apiUrl = "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&titles=" + title; StringRequest stringRequest = new StringRequest(Request.Method.GET, apiUrl, @@ -81,6 +80,7 @@ public static void getInfo(String wikipediaUrl, Context ctx, WikipediaGetter.Get public interface GetterCallback { void onSuccess(WikipediaInfo wikiInfo); + void onFailure(String reason); } } diff --git a/app/src/main/java/com/simon/harmonichackernews/network/ArchiveOrgUrlGetter.java b/app/src/main/java/com/simon/harmonichackernews/network/ArchiveOrgUrlGetter.java index 81b5bc4a..6ed960dd 100644 --- a/app/src/main/java/com/simon/harmonichackernews/network/ArchiveOrgUrlGetter.java +++ b/app/src/main/java/com/simon/harmonichackernews/network/ArchiveOrgUrlGetter.java @@ -5,9 +5,6 @@ import com.android.volley.RequestQueue; import com.android.volley.toolbox.StringRequest; -import com.simon.harmonichackernews.data.ArxivInfo; -import com.simon.harmonichackernews.network.NetworkComponent; - import org.json.JSONObject; diff --git a/app/src/main/java/com/simon/harmonichackernews/network/FaviconLoader.java b/app/src/main/java/com/simon/harmonichackernews/network/FaviconLoader.java index fd1407bd..52451c52 100644 --- a/app/src/main/java/com/simon/harmonichackernews/network/FaviconLoader.java +++ b/app/src/main/java/com/simon/harmonichackernews/network/FaviconLoader.java @@ -6,7 +6,6 @@ import androidx.core.content.ContextCompat; import com.simon.harmonichackernews.R; -import com.simon.harmonichackernews.utils.SettingsUtils; import com.simon.harmonichackernews.utils.Utils; import com.squareup.picasso.Picasso; @@ -33,11 +32,11 @@ private static String getFaviconUrl(String host, String faviconProvider) { case "Favicon kit": return "https://api.faviconkit.com/" + host; case "Google": - return "https://www.google.com/s2/favicons?domain="+ host + "&sz=128"; + return "https://www.google.com/s2/favicons?domain=" + host + "&sz=128"; case "DuckDuckGo": return "https://icons.duckduckgo.com/ip3/" + host + ".ico"; default: - return "https://www.google.com/s2/favicons?domain="+ host + "&sz=128"; + return "https://www.google.com/s2/favicons?domain=" + host + "&sz=128"; } } diff --git a/app/src/main/java/com/simon/harmonichackernews/network/JSONParser.java b/app/src/main/java/com/simon/harmonichackernews/network/JSONParser.java index cc323e82..1e599349 100644 --- a/app/src/main/java/com/simon/harmonichackernews/network/JSONParser.java +++ b/app/src/main/java/com/simon/harmonichackernews/network/JSONParser.java @@ -6,7 +6,6 @@ import com.simon.harmonichackernews.data.Comment; import com.simon.harmonichackernews.data.Story; import com.simon.harmonichackernews.utils.StoryUpdate; -import com.simon.harmonichackernews.utils.Utils; import org.json.JSONArray; import org.json.JSONException; @@ -43,7 +42,7 @@ public static List algoliaJsonToStories(String response) throws JSONExcep story.loadingFailed = false; story.clicked = false; - if (hit.has("url") && !hit.getString("url").equals("null") &&!hit.getString("url").equals("")) { + if (hit.has("url") && !hit.getString("url").equals("null") && !hit.getString("url").isEmpty()) { story.url = hit.getString("url"); story.isLink = true; } else { @@ -113,7 +112,7 @@ public static boolean updateStoryWithHNJson(String response, Story story) throws } if (jsonObject.has("type") && jsonObject.getString("type").equals("poll") && jsonObject.has("parts")) { - JSONArray pollOptionsJson = jsonObject.getJSONArray("parts"); + JSONArray pollOptionsJson = jsonObject.getJSONArray("parts"); int[] pollOptions = new int[pollOptionsJson.length()]; for (int i = 0; i < pollOptionsJson.length(); i++) { pollOptions[i] = pollOptionsJson.getInt(i); @@ -158,7 +157,7 @@ public static boolean updateStoryWithHNCommentJson(JSONObject jsonObject, Story return false; } - //setting score to -1 means it doesn't get shown + // setting the score to -1 means it doesn't get shown story.update( jsonObject.getString("by"), jsonObject.getInt("id"), @@ -201,14 +200,13 @@ public static boolean updateStoryWithHNCommentJson(JSONObject jsonObject, Story public static void updatePdfProperties(Story story) { if (story.url.endsWith(".pdf") || story.title.endsWith("[pdf]") || story.title.endsWith("(pdf)")) { story.pdfTitle = story.title; - if (story.pdfTitle.endsWith(" [pdf]")) { - story.pdfTitle = story.pdfTitle.substring(0, story.pdfTitle.length() - 6); - } else if (story.pdfTitle.endsWith("[pdf]")) { - story.pdfTitle = story.pdfTitle.substring(0, story.pdfTitle.length() - 5); - } else if (story.pdfTitle.endsWith(" (pdf)")) { - story.pdfTitle = story.pdfTitle.substring(0, story.pdfTitle.length() - 6); - } else if (story.pdfTitle.endsWith("(pdf)")) { - story.pdfTitle = story.pdfTitle.substring(0, story.pdfTitle.length() - 5); + + String[] suffixes = {" [pdf]", "[pdf]", " (pdf)", "(pdf)"}; + for (String suffix : suffixes) { + if (story.pdfTitle.endsWith(suffix)) { + story.pdfTitle = story.pdfTitle.substring(0, story.pdfTitle.length() - suffix.length()); + break; + } } } } @@ -253,7 +251,7 @@ public static boolean updateStoryInformation(Story story, JSONObject item, boole story.text = preprocessHtml(item.getString("text")); } - story.descendants = newCommentCount - 1; //-1 for header + story.descendants = newCommentCount - 1; // -1 for header story.id = item.getInt("id"); story.score = item.optInt("points", 0); story.by = item.getString("author"); @@ -271,7 +269,7 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List * Remark: Right now we're only updating old comments, not deleting those who are not there * anymore but that is probably just nice */ - //this is to be able to say if we should resort the list if we use non-default sorting + // this is to be able to say if we should resort the list if we use non-default sorting boolean placedNew = false; if (!child.has("text") || child.getString("text").equals("null")) { @@ -291,7 +289,7 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List comment.id = child.getInt("id"); comment.children = children == null ? 0 : children.length(); - //Let's see if a comment with this ID already is placed, in that case we'll just replace it and call notifyitemchanged + // Let's see if a comment with this ID already is placed, in that case we'll just replace it and call notifyitemchanged boolean newComment = true; for (int i = 1; i < comments.size(); i++) { @@ -309,12 +307,12 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List if (newComment) { placedNew = true; - //now for placing, if it's a top level comment we should attempt to follow the prioList + // now for placing, if it's a top level comment we should attempt to follow the prioList if (comment.depth == 0) { int prioIndex = -1; if (prioTop != null) { - //only attempt to change the index if priotop is nonnull + // only attempt to change the index if priotop is nonnull for (int i = 0; i < prioTop.length; i++) { if (prioTop[i] == comment.id) { prioIndex = i; @@ -324,7 +322,7 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List } if (prioIndex == -1) { - //add it last + // add it last comments.add(comments.size(), comment); adapter.notifyItemInserted(comments.size() - 1); } else { @@ -332,43 +330,43 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List comments.add(1, comment); adapter.notifyItemInserted(1); } else { - //lets find the last top level comment which has priority higher than prioIndex + // lets find the last top level comment which has priority higher than prioIndex int prioBeforeIndex = -1; for (int i = 0; i < comments.size(); i++) { - //search all comments... + // search all comments... if (comments.get(i).depth == 0) { - //and only care about top level ones... + // and only care about top level ones... int searchId = comments.get(i).id; - //and check if its id + // and check if its id for (int j = 0; j < prioIndex; j++) { - //is higher priority + // is higher priority if (prioTop[j] == searchId) { - //if so, lets save the index + // if so, lets save the index prioBeforeIndex = i; break; } } } } - //if we are priority and can't find anything with higher priority, we should be placed at the top + // if we are priority and can't find anything with higher priority, we should be placed at the top if (prioBeforeIndex == -1) { comments.add(1, comment); adapter.notifyItemInserted(1); } else { - //otherwise, lets search for the next depth = 0 after the comment with higher priority + // otherwise, lets search for the next depth = 0 after the comment with higher priority int newLocation = -1; - //we found parent, lets start searching for when it ends + // we found parent, lets start searching for when it ends for (int i = prioBeforeIndex + 1; i < comments.size(); i++) { if (comments.get(i).depth == 0) { - //next time we find a depth zero comment, need to insert ours there + // next time we find a depth zero comment, need to insert ours there newLocation = i; break; } } - //if we didn't find a new location, then just place it at the bottom + // if we didn't find a new location, then just place it at the bottom if (newLocation == -1) { comments.add(comments.size(), comment); adapter.notifyItemInserted(comments.size() - 1); @@ -380,7 +378,7 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List } } } else { - //if it's not a top level comment, let's find its parent and place so that top answers have many children + // if it's not a top level comment, let's find its parent and place so that top answers have many children boolean foundParent = false; for (int i = 1; i < comments.size(); i++) { @@ -395,7 +393,7 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List * */ foundParent = true; - //having found the parent, lets keep going until we find a comment with fewer children or depth goes up + // having found the parent, lets keep going until we find a comment with fewer children or depth goes up boolean placed = false; for (int j = 1; j < comments.size() - i; j++) { Comment candidate = comments.get(i + j); @@ -415,7 +413,7 @@ public static boolean readChildAndParseSubchilds(JSONObject child, List } } - //and if we can't find the parent, lets put it at the bottom + // and if we can't find the parent, lets put it at the bottom if (!foundParent) { comments.add(comments.size(), comment); adapter.notifyItemInserted(comments.size() - 1); @@ -438,10 +436,8 @@ public static boolean updateStoryWithAlgoliaResponse(Story story, String respons try { JSONObject item = new JSONObject(response); - //for comment count we need to manually count - JSONArray children = item.getJSONArray("children"); - - story.descendants = children.length(); + // for comment count we need to manually count + story.descendants = item.getJSONArray("children").length(); story.time = item.getInt("created_at_i"); story.title = item.getString("title"); @@ -471,19 +467,19 @@ public static String preprocessHtml(String input) { input = input.replace("", "
").replace("", "
"); if (input.contains("
")) {
-            for (int i = 0; i < input.length()-2; i++) {
+            for (int i = 0; i < input.length() - 2; i++) {
                 if (input.charAt(i) == ' ') {
                     String upUntilNow = input.substring(0, i);
                     if (upUntilNow.contains("
")) {
                         if (upUntilNow.lastIndexOf("
") > upUntilNow.lastIndexOf("
")) { - input = upUntilNow + " " + input.substring(i+1); + input = upUntilNow + " " + input.substring(i + 1); } } } else if (input.charAt(i) == '\n') { String upUntilNow = input.substring(0, i); if (upUntilNow.contains("
")) {
                         if (upUntilNow.lastIndexOf("
") > upUntilNow.lastIndexOf("
")) { - input = upUntilNow + "
" + input.substring(i+1); + input = upUntilNow + "
" + input.substring(i + 1); } } diff --git a/app/src/main/java/com/simon/harmonichackernews/network/NetworkComponent.java b/app/src/main/java/com/simon/harmonichackernews/network/NetworkComponent.java index 972f9e47..42cb2fc3 100644 --- a/app/src/main/java/com/simon/harmonichackernews/network/NetworkComponent.java +++ b/app/src/main/java/com/simon/harmonichackernews/network/NetworkComponent.java @@ -1,14 +1,13 @@ package com.simon.harmonichackernews.network; import android.content.Context; -import android.os.Build; import android.os.Looper; +import androidx.annotation.NonNull; + import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; import com.simon.harmonichackernews.BuildConfig; -import com.simon.harmonichackernews.data.ArxivInfo; -import com.simon.harmonichackernews.data.RepoInfo; import java.io.IOException; diff --git a/app/src/main/java/com/simon/harmonichackernews/network/UserActions.java b/app/src/main/java/com/simon/harmonichackernews/network/UserActions.java index 6afd2fec..2df3bfcf 100644 --- a/app/src/main/java/com/simon/harmonichackernews/network/UserActions.java +++ b/app/src/main/java/com/simon/harmonichackernews/network/UserActions.java @@ -224,8 +224,8 @@ public void run() { } public static void showFailureDetailDialog(Context ctx, String summary, String response) { - //We need to try-catch this because it is called asynchronously and if the app has been - //closed we cannot show a dialog. Instead of checking for this, we can just try-catch! :) + // We need to try-catch this because it is called asynchronously and if the app has been + // closed we cannot show a dialog. Instead of checking for this, we can just try-catch! :) try { AlertDialog dialog = new MaterialAlertDialogBuilder(ctx) .setTitle(summary) diff --git a/app/src/main/java/com/simon/harmonichackernews/network/VolleyOkHttp3StackInterceptors.java b/app/src/main/java/com/simon/harmonichackernews/network/VolleyOkHttp3StackInterceptors.java index c277c3d4..6ad93f6a 100644 --- a/app/src/main/java/com/simon/harmonichackernews/network/VolleyOkHttp3StackInterceptors.java +++ b/app/src/main/java/com/simon/harmonichackernews/network/VolleyOkHttp3StackInterceptors.java @@ -27,7 +27,6 @@ public class VolleyOkHttp3StackInterceptors extends BaseHttpStack { private static final RequestBody EMPTY_REQUEST = RequestBody.create(new byte[0]); public VolleyOkHttp3StackInterceptors() { - } @@ -35,7 +34,7 @@ private static void setConnectionParametersForRequest(okhttp3.Request.Builder bu throws AuthFailureError { switch (request.getMethod()) { case Request.Method.DEPRECATED_GET_OR_POST: - // Ensure backwards compatibility. Volley assumes a request with a null body is a GET. + // Ensure backwards compatibility. Volley assumes a request with a null body is a GET. byte[] postBody = request.getBody(); if (postBody != null) { builder.post(RequestBody.create(postBody, MediaType.parse(request.getBodyContentType()))); @@ -93,10 +92,10 @@ public HttpResponse executeRequest(Request request, Map addit okHttpRequestBuilder.url(request.getUrl()); Map headers = request.getHeaders(); - for (Map.Entry header: headers.entrySet()) { + for (Map.Entry header : headers.entrySet()) { okHttpRequestBuilder.addHeader(header.getKey(), header.getValue()); } - for (Map.Entry header: additionalHeaders.entrySet()) { + for (Map.Entry header : additionalHeaders.entrySet()) { okHttpRequestBuilder.addHeader(header.getKey(), header.getValue()); } @@ -105,7 +104,7 @@ public HttpResponse executeRequest(Request request, Map addit OkHttpClient client = clientBuilder.build(); okhttp3.Request okHttpRequest = okHttpRequestBuilder.build(); Call okHttpCall = client.newCall(okHttpRequest); - // todo: close response. Note that it is not as simple as adding try-with-resources because + // TODO: close response. Note that it is not as simple as adding try-with-resources because // that would close the response before Volley has had a chance to consume it. At the same // time, not closing the response is also wrong because it will not be closed at all. // Volley closes only input stream created from response body's which is not the same as @@ -118,6 +117,7 @@ public HttpResponse executeRequest(Request request, Map addit InputStream content = body == null ? null : body.byteStream(); int contentLength = body == null ? 0 : (int) body.contentLength(); List
responseHeaders = mapHeaders(okHttpResponse.headers()); + //okHttpResponse.close(); return new HttpResponse(code, responseHeaders, contentLength, content); } diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/AccountUtils.java b/app/src/main/java/com/simon/harmonichackernews/utils/AccountUtils.java index cb283bd9..b7ec1291 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/AccountUtils.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/AccountUtils.java @@ -2,23 +2,12 @@ import android.content.Context; import android.content.SharedPreferences; -import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.KeyProperties; import android.text.TextUtils; -import android.util.Log; import androidx.fragment.app.FragmentManager; -import androidx.security.crypto.EncryptedSharedPreferences; -import androidx.security.crypto.MasterKey; import com.simon.harmonichackernews.LoginDialogFragment; -import org.w3c.dom.Text; - -import java.io.File; -import java.io.IOException; -import java.security.GeneralSecurityException; - import kotlin.Triple; public class AccountUtils { @@ -32,7 +21,6 @@ public class AccountUtils { public final static int FAILURE_MODE_NO_PASSWORD = 4; - public static String getAccountUsername(Context ctx) { return SettingsUtils.readStringFromSharedPreferences(ctx, KEY_UNENCRYPTED_SHARED_PREFERENCES_USERNAME); } @@ -59,7 +47,7 @@ public static Triple getAccountDetails(Context ctx) { String password = sharedPreferences.getString(KEY_ENCRYPTED_SHARED_PREFERENCES_PASSWORD, null); if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) { - //note we're not logging the password + // note we're not logging the password Utils.log("Empty check: username " + TextUtils.isEmpty(username) + ", pass:" + TextUtils.isEmpty(password)); } @@ -71,7 +59,7 @@ public static Triple getAccountDetails(Context ctx) { return new Triple<>(username, password, FAILURE_MODE_NO_PASSWORD); } - //last resort, all is well, still send migration status + // last resort, all is well, still send migration status return new Triple<>(username, password, FAILURE_MODE_NONE); } @@ -104,28 +92,28 @@ public static void showLoginPrompt(FragmentManager fm) { } public static boolean handlePossibleError(Triple account, FragmentManager fm, Context ctx) { - if (account.getThird() != AccountUtils.FAILURE_MODE_NONE) { - if (fm != null) { - AccountUtils.showLoginPrompt(fm); - } - - switch (account.getThird()) { - case AccountUtils.FAILURE_MODE_MAINKEY: - Utils.toast("Login failed, cause: Couldn't get AndroidX MasterKey", ctx); - break; - case AccountUtils.FAILURE_MODE_ENCRYPTED_PREFERENCES_EXCEPTION: - Utils.toast("Login failed, cause: EncryptedSharedPreferences threw exception", ctx); - break; - case AccountUtils.FAILURE_MODE_NO_USERNAME: - Utils.toast("Login failed, cause: No saved username", ctx); - break; - case AccountUtils.FAILURE_MODE_NO_PASSWORD: - Utils.toast("Login failed, cause: No saved password", ctx); - break; - } - return true; + if (account.getThird() == AccountUtils.FAILURE_MODE_NONE) { + return false; + } + + if (fm != null) { + AccountUtils.showLoginPrompt(fm); + } + + switch (account.getThird()) { + case AccountUtils.FAILURE_MODE_MAINKEY: + Utils.toast("Login failed, cause: Couldn't get AndroidX MasterKey", ctx); + break; + case AccountUtils.FAILURE_MODE_ENCRYPTED_PREFERENCES_EXCEPTION: + Utils.toast("Login failed, cause: EncryptedSharedPreferences threw exception", ctx); + break; + case AccountUtils.FAILURE_MODE_NO_USERNAME: + Utils.toast("Login failed, cause: No saved username", ctx); + break; + case AccountUtils.FAILURE_MODE_NO_PASSWORD: + Utils.toast("Login failed, cause: No saved password", ctx); + break; } - //no error - return false; + return true; } } diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/ArxivResolver.java b/app/src/main/java/com/simon/harmonichackernews/utils/ArxivResolver.java index 018558a9..8c484a4b 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/ArxivResolver.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/ArxivResolver.java @@ -8,7 +8,7 @@ public class ArxivResolver { private static final Map ARXIV_SUBJECTS = new HashMap<>(); static { - //Computer Science + // Computer Science ARXIV_SUBJECTS.put("cs.AI", "Artificial Intelligence"); ARXIV_SUBJECTS.put("cs.AR", "Hardware Architecture"); ARXIV_SUBJECTS.put("cs.CC", "Computational Complexity"); @@ -50,18 +50,18 @@ public class ArxivResolver { ARXIV_SUBJECTS.put("cs.SI", "Social and Information Networks"); ARXIV_SUBJECTS.put("cs.SY", "Systems and Control"); -//Economics + // Economics ARXIV_SUBJECTS.put("econ.EM", "Econometrics"); ARXIV_SUBJECTS.put("econ.GN", "General Economics"); ARXIV_SUBJECTS.put("econ.TH", "Theoretical Economics"); - //Electrical Engineering and Systems Science + // Electrical Engineering and Systems Science ARXIV_SUBJECTS.put("eess.AS", "Audio and Speech Processing"); ARXIV_SUBJECTS.put("eess.IV", "Image and Video Processing"); ARXIV_SUBJECTS.put("eess.SP", "Signal Processing"); ARXIV_SUBJECTS.put("eess.SY", "Systems and Control"); -//Mathematics + // Mathematics ARXIV_SUBJECTS.put("math.AC", "Commutative Algebra"); ARXIV_SUBJECTS.put("math.AG", "Algebraic Geometry"); ARXIV_SUBJECTS.put("math.AP", "Analysis of PDEs"); @@ -95,7 +95,7 @@ public class ArxivResolver { ARXIV_SUBJECTS.put("math.SP", "Spectral Theory"); ARXIV_SUBJECTS.put("math.ST", "Statistics Theory"); -//ASTROPHYSICS + // ASTROPHYSICS ARXIV_SUBJECTS.put("astro-ph.CO", "Cosmology and Nongalactic Astrophysics"); ARXIV_SUBJECTS.put("astro-ph.EP", "Earth and Planetary Astrophysics"); ARXIV_SUBJECTS.put("astro-ph.GA", "Astrophysics of Galaxies"); @@ -103,7 +103,7 @@ public class ArxivResolver { ARXIV_SUBJECTS.put("astro-ph.IM", "Instrumentation and Methods for Astrophysics"); ARXIV_SUBJECTS.put("astro-ph.SR", "Solar and Stellar Astrophysics"); -//CONDENSED MATTER + // CONDENSED MATTER ARXIV_SUBJECTS.put("cond-mat.dis-nn", "Disordered Systems and Neural Networks"); ARXIV_SUBJECTS.put("cond-mat.mes-hall", "Mesoscale and Nanoscale Physics"); ARXIV_SUBJECTS.put("cond-mat.mtrl-sci", "Materials Science"); @@ -114,30 +114,30 @@ public class ArxivResolver { ARXIV_SUBJECTS.put("cond-mat.str-el", "Strongly Correlated Electrons"); ARXIV_SUBJECTS.put("cond-mat.supr-con", "Superconductivity"); -//GENERAL RELATIVITY AND QUANTUM COSMOLOGY + // GENERAL RELATIVITY AND QUANTUM COSMOLOGY ARXIV_SUBJECTS.put("gr-qc", "General Relativity and Quantum Cosmology"); -//HIGH ENERGY PHYSICS + // HIGH ENERGY PHYSICS ARXIV_SUBJECTS.put("hep-ex", "High Energy Physics - Experiment"); ARXIV_SUBJECTS.put("hep-lat", "High Energy Physics - Lattice"); ARXIV_SUBJECTS.put("hep-ph", "High Energy Physics - Phenomenology"); ARXIV_SUBJECTS.put("hep-th", "High Energy Physics - Theory"); -//MATHEMATICAL PHYSICS + // MATHEMATICAL PHYSICS ARXIV_SUBJECTS.put("math-ph", "Mathematical Physics"); -//NONLINEAR SCIENCES + // NONLINEAR SCIENCES ARXIV_SUBJECTS.put("nlin.AO", "Adaptation and Self-Organizing Systems"); ARXIV_SUBJECTS.put("nlin.CD", "Chaotic Dynamics"); ARXIV_SUBJECTS.put("nlin.CG", "Cellular Automata and Lattice Gases"); ARXIV_SUBJECTS.put("nlin.PS", "Pattern Formation and Solitons"); ARXIV_SUBJECTS.put("nlin.SI", "Exactly Solvable and Integrable Systems"); -//NUCLEAR + // NUCLEAR ARXIV_SUBJECTS.put("nucl-ex", "Nuclear Experiment"); ARXIV_SUBJECTS.put("nucl-th", "Nuclear Theory"); -//PHYSICS + // PHYSICS ARXIV_SUBJECTS.put("physics.acc-ph", "Accelerator Physics"); ARXIV_SUBJECTS.put("physics.ao-ph", "Atmospheric and Oceanic Physics"); ARXIV_SUBJECTS.put("physics.app-ph", "Applied Physics"); @@ -161,10 +161,10 @@ public class ArxivResolver { ARXIV_SUBJECTS.put("physics.soc-ph", "Physics and Society"); ARXIV_SUBJECTS.put("physics.space-ph", "Space Physics"); -//QUANTUM PHYSICS + // QUANTUM PHYSICS ARXIV_SUBJECTS.put("quant-ph", "Quantum Physics"); -//Quantitative Biology + // Quantitative Biology ARXIV_SUBJECTS.put("q-bio.BM", "Biomolecules"); ARXIV_SUBJECTS.put("q-bio.CB", "Cell Behavior"); ARXIV_SUBJECTS.put("q-bio.GN", "Genomics"); @@ -176,7 +176,7 @@ public class ArxivResolver { ARXIV_SUBJECTS.put("q-bio.SC", "Subcellular Processes"); ARXIV_SUBJECTS.put("q-bio.TO", "Tissues and Organs"); -//Quantitative Finance + // Quantitative Finance ARXIV_SUBJECTS.put("q-fin.CP", "Computational Finance"); ARXIV_SUBJECTS.put("q-fin.EC", "Economics"); ARXIV_SUBJECTS.put("q-fin.GN", "General Finance"); @@ -187,7 +187,7 @@ public class ArxivResolver { ARXIV_SUBJECTS.put("q-fin.ST", "Statistical Finance"); ARXIV_SUBJECTS.put("q-fin.TR", "Trading and Market Microstructure"); -//Statistics + // Statistics ARXIV_SUBJECTS.put("stat.AP", "Applications"); ARXIV_SUBJECTS.put("stat.CO", "Computation"); ARXIV_SUBJECTS.put("stat.ME", "Methodology"); @@ -198,6 +198,7 @@ public class ArxivResolver { /** * Resolves the arXiv subject abbreviation to its full name. + * * @param abbreviation the arXiv subject abbreviation. * @return the full name of the subject, or null if the abbreviation is not recognized. */ diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/EncryptedSharedPreferencesHelper.java b/app/src/main/java/com/simon/harmonichackernews/utils/EncryptedSharedPreferencesHelper.java index 82f2164c..0317a653 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/EncryptedSharedPreferencesHelper.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/EncryptedSharedPreferencesHelper.java @@ -10,8 +10,6 @@ import androidx.security.crypto.MasterKey; import java.io.File; -import java.io.IOException; -import java.security.GeneralSecurityException; import java.security.KeyStore; public class EncryptedSharedPreferencesHelper { @@ -24,14 +22,12 @@ public class EncryptedSharedPreferencesHelper { public static SharedPreferences getEncryptedSharedPreferences(Context ctx) throws Exception { try { - SharedPreferences sp = createSharedPreferences(ctx); - return sp; + return createSharedPreferences(ctx); } catch (Exception e) { e.printStackTrace(); try { deleteSharedPreferences(ctx); - SharedPreferences sp = createSharedPreferences(ctx); - return sp; + return createSharedPreferences(ctx); } catch (Exception otherException) { otherException.printStackTrace(); throw new Exception(); diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/FileDownloader.java b/app/src/main/java/com/simon/harmonichackernews/utils/FileDownloader.java index 489528f5..b8a5299b 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/FileDownloader.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/FileDownloader.java @@ -6,6 +6,7 @@ import android.os.Looper; import android.text.TextUtils; +import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.simon.harmonichackernews.network.NetworkComponent; @@ -56,12 +57,12 @@ public void downloadFile(String url, String mimeType, FileDownloaderCallback cal NetworkComponent.getOkHttpClientInstance().newCall(request).enqueue(new Callback() { @Override - public void onFailure(Call call, IOException e) { + public void onFailure(@NonNull Call call, @NonNull IOException e) { mMainHandler.post(() -> callback.onFailure(call, e)); } @Override - public void onResponse(Call call, Response response) { + public void onResponse(@NonNull Call call, @NonNull Response response) { try { BufferedSink sink = Okio.buffer(Okio.sink(outputFile)); sink.writeAll(response.body().source()); diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/SettingsUtils.java b/app/src/main/java/com/simon/harmonichackernews/utils/SettingsUtils.java index b2d11805..2cb8ed80 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/SettingsUtils.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/SettingsUtils.java @@ -203,11 +203,6 @@ public static boolean shouldSwapCommentLongPressTap(Context ctx) { return getBooleanPref("pref_comments_swap_long", false, ctx); } - - public static boolean shouldUseAlgolia(Context ctx) { - return getBooleanPref("pref_algolia_api", true, ctx); - } - public static boolean getBooleanPref(String key, boolean backup, Context ctx) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); return prefs.getBoolean(key, backup); @@ -216,6 +211,7 @@ public static boolean getBooleanPref(String key, boolean backup, Context ctx) { public static int getPreferredCommentTextSize(Context ctx) { return Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(ctx).getString("pref_comment_text_size", "15")); } + public static String getPreferredStoryType(Context ctx) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); return prefs.getString("pref_default_story_type", "Top Stories"); @@ -232,26 +228,26 @@ public static String getPreferredFaviconProvider(Context ctx) { } public static int getBookmarksIndex(Resources res) { - String[] sortingOptions = res.getStringArray(R.array.sorting_options); + String[] sortingOptions = res.getStringArray(R.array.sorting_options); for (int i = sortingOptions.length - 1; i >= 0; i--) { if (sortingOptions[i].equals("Bookmarks")) { return i; } } - //fallback + // fallback return sortingOptions.length - 1; } public static int getJobsIndex(Resources res) { - String[] sortingOptions = res.getStringArray(R.array.sorting_options); + String[] sortingOptions = res.getStringArray(R.array.sorting_options); for (int i = sortingOptions.length - 1; i >= 0; i--) { if (sortingOptions[i].equals("HN Jobs")) { return i; } } - //fallback + // fallback return sortingOptions.length - 2; } diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/SplitChangeHandler.java b/app/src/main/java/com/simon/harmonichackernews/utils/SplitChangeHandler.java index 855ce780..323db85e 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/SplitChangeHandler.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/SplitChangeHandler.java @@ -14,41 +14,41 @@ @OptIn(markerClass = androidx.window.core.ExperimentalWindowApi.class) public class SplitChangeHandler { - private final SplitControllerCallbackAdapter splitCallbackAdapter; - private final SwipeBackLayout layout; - private boolean isWithinSplit = false; - - public SplitChangeHandler(Activity activity, SwipeBackLayout swipeBackLayout) { - this.splitCallbackAdapter = new SplitControllerCallbackAdapter(SplitController.getInstance(activity)); - this.layout = swipeBackLayout; - //Note: I (Simon) removed this line as swipeBack needs a transparent background in - //order to display the activity behind it - //swipeBackLayout.setBackgroundColor(ContextCompat.getColor(activity, ThemeUtils.getBackgroundColorResource(activity))); - - splitCallbackAdapter.addSplitListener( - activity, - Runnable::run, - this::onSplitListUpdate - ); - } - - private void onSplitListUpdate(List splitInfoList) { - for (SplitInfo split : splitInfoList) { - if (!split.getSplitAttributes().getSplitType().equals(SplitType.SPLIT_TYPE_EXPAND)) { - isWithinSplit = true; - break; - } - isWithinSplit = false; - } - - layout.setMaskAlpha(isWithinSplit ? 0 : 125); - } - - public boolean isWithinSplit() { - return isWithinSplit; - } - - public void teardown() { - splitCallbackAdapter.removeSplitListener(this::onSplitListUpdate); - } + private final SplitControllerCallbackAdapter splitCallbackAdapter; + private final SwipeBackLayout layout; + private boolean isWithinSplit = false; + + public SplitChangeHandler(Activity activity, SwipeBackLayout swipeBackLayout) { + this.splitCallbackAdapter = new SplitControllerCallbackAdapter(SplitController.getInstance(activity)); + this.layout = swipeBackLayout; + // Note: I (Simon) removed this line as swipeBack needs a transparent background in + // order to display the activity behind it + // swipeBackLayout.setBackgroundColor(ContextCompat.getColor(activity, ThemeUtils.getBackgroundColorResource(activity))); + + splitCallbackAdapter.addSplitListener( + activity, + Runnable::run, + this::onSplitListUpdate + ); + } + + private void onSplitListUpdate(List splitInfoList) { + for (SplitInfo split : splitInfoList) { + if (!split.getSplitAttributes().getSplitType().equals(SplitType.SPLIT_TYPE_EXPAND)) { + isWithinSplit = true; + break; + } + isWithinSplit = false; + } + + layout.setMaskAlpha(isWithinSplit ? 0 : 125); + } + + public boolean isWithinSplit() { + return isWithinSplit; + } + + public void teardown() { + splitCallbackAdapter.removeSplitListener(this::onSplitListUpdate); + } } diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/ThemeUtils.java b/app/src/main/java/com/simon/harmonichackernews/utils/ThemeUtils.java index 9c800d04..a297b811 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/ThemeUtils.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/ThemeUtils.java @@ -4,10 +4,8 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.view.Window; -import android.view.WindowManager; import androidx.activity.ComponentActivity; import androidx.activity.EdgeToEdge; @@ -50,13 +48,13 @@ public static void setupTheme(ComponentActivity activity, boolean swipeBack, boo String theme = getPreferredTheme(activity); switch (theme) { case "material_daynight": - //below 30, default on comments is swipeBack so if we don't use it we need to change to a normal theme + // below 30, default on comments is swipeBack so if we don't use it we need to change to a normal theme if (Build.VERSION.SDK_INT < 30) { if (!swipeBack) { activity.setTheme(R.style.AppThemeMaterialDayNight); } } else { - //at and above 30, the default is AppTheme so if we use swipeBack we need to change + // at and above 30, the default is AppTheme so if we use swipeBack we need to change if (swipeBack) { activity.setTheme(R.style.ThemeSwipeBackNoActionBarMaterialDayNight); } @@ -80,7 +78,7 @@ public static void setupTheme(ComponentActivity activity, boolean swipeBack, boo case "white": activity.setTheme(swipeBack ? R.style.ThemeSwipeBackNoActionBarWhite : R.style.AppThemeWhite); break; - //needed because of comment activity where the default is AppTheme, now swipeBack + // needed because of comment activity where the default is AppTheme, now swipeBack case "dark": activity.setTheme(swipeBack ? R.style.Theme_Swipe_Back_NoActionBar : R.style.AppTheme); @@ -122,7 +120,7 @@ public static boolean isDarkMode(Context ctx, String theme) { } return theme.equals("amoled") || theme.equals("dark") || theme.equals("gray") || theme.equals("material_dark"); } - + public static boolean isDarkMode(Context ctx) { String theme = getPreferredTheme(ctx); return isDarkMode(ctx, theme); @@ -160,7 +158,7 @@ public static int getBackgroundColorResource(Context ctx) { public static String getPreferredTheme(Context ctx) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); if (SettingsUtils.shouldUseSpecialNighttimeTheme(ctx)) { - //check time + // check time Calendar currentCalendar = Calendar.getInstance(); int[] nighttimeHours = Utils.getNighttimeHours(ctx); diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/Utils.java b/app/src/main/java/com/simon/harmonichackernews/utils/Utils.java index ea725134..1542a81e 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/Utils.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/Utils.java @@ -91,19 +91,19 @@ public static void log(String s) { } public static void log(long i) { - Log.d("HARMONIC_TAG", "" + i); + Log.d("HARMONIC_TAG", String.valueOf(i)); } public static void log(int i) { - Log.d("HARMONIC_TAG", "" + i); + Log.d("HARMONIC_TAG", String.valueOf(i)); } public static void log(float i) { - Log.d("HARMONIC_TAG", "" + i); + Log.d("HARMONIC_TAG", String.valueOf(i)); } public static void log(boolean b) { - Log.d("HARMONIC_TAG", "" + b); + Log.d("HARMONIC_TAG", String.valueOf(b)); } public static void toast(String s, Context ctx) { @@ -152,8 +152,9 @@ public static void cacheStory(Context ctx, int id, String data) { if (cachedStories == null) { cachedStories = new HashSet<>(); } - //if there already exists a story with the same id, remove it from list of cached since we're only saving the latest one - if (cachedStories.size() > 0) { + // if there already exists a story with the same id, remove it from list of cached since + // we're only saving the latest one + if (!cachedStories.isEmpty()) { for (Iterator iterator = cachedStories.iterator(); iterator.hasNext();) { String cached = iterator.next(); String[] idAndDate = cached.split("-"); @@ -165,7 +166,7 @@ public static void cacheStory(Context ctx, int id, String data) { cachedStories.add(id + "-" + System.currentTimeMillis()); if (cachedStories.size() > 100) { - //If we have a lot of stories, lets delete the oldest one + // If we have a lot of stories, lets delete the oldest one long oldestTime = -1; int oldestId = -1; for (String cachedStory : cachedStories) { @@ -197,7 +198,7 @@ public static ArrayList loadBookmarks(boolean sorted, String bookmarks ArrayList bookmarks = new ArrayList<>(); - if (bookmarksString == null || bookmarksString.length() == 0) { + if (bookmarksString == null || bookmarksString.isEmpty()) { return bookmarks; } @@ -260,18 +261,13 @@ public static void addBookmark(Context ctx, int id) { public static void removeBookmark(Context ctx, int id) { ArrayList bookmarks = loadBookmarks(ctx, false); - int badIndex = -1; - - for (int i = 0; i < bookmarks.size(); i++) { - if (bookmarks.get(i).id == id) { - badIndex = i; + for (Bookmark bookmark: bookmarks) { + if (bookmark.id == id) { + bookmarks.remove(bookmark); + break; } } - if (badIndex != -1) { - bookmarks.remove(badIndex); - } - saveBookmarks(ctx, bookmarks); } @@ -309,7 +305,7 @@ public static ArrayList getFilterDomains(Context ctx) { public static boolean isFirstAppStart(Context ctx) { SharedPreferences sharedPref = ctx.getSharedPreferences(GLOBAL_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE); - if (sharedPref.getBoolean(KEY_SHARED_PREFERENCES_FIRST_TIME, true) && SettingsUtils.readIntSetFromSharedPreferences(ctx, Utils.KEY_SHARED_PREFERENCES_CLICKED_IDS).size() == 0) { + if (sharedPref.getBoolean(KEY_SHARED_PREFERENCES_FIRST_TIME, true) && SettingsUtils.readIntSetFromSharedPreferences(ctx, Utils.KEY_SHARED_PREFERENCES_CLICKED_IDS).isEmpty()) { sharedPref.edit().putBoolean(KEY_SHARED_PREFERENCES_FIRST_TIME, false).apply(); return true; } @@ -432,12 +428,12 @@ public static void launchInExternalBrowser(Context ctx, String url) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); ctx.startActivity(browserIntent); } catch (Exception e) { - //failed for the first time, let's try to guess a fix to the url + // failed for the first time, let's try to guess a fix to the url try { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(URLUtil.guessUrl(url))); ctx.startActivity(browserIntent); } catch (Exception e1) { - //automated fix didn't work, let's try to do it manually + // automated fix didn't work, let's try to do it manually try { if (!url.startsWith("http://") && !url.startsWith("https://")) url = "http://" + url; @@ -464,7 +460,7 @@ public static boolean downloadPDF(Context context, String pdfUrl) { } public static boolean isCustomTabSupported(Context context) { - return getCustomTabsPackages(context).size() > 0; + return !getCustomTabsPackages(context).isEmpty(); } /** diff --git a/app/src/main/java/com/simon/harmonichackernews/utils/ViewUtils.java b/app/src/main/java/com/simon/harmonichackernews/utils/ViewUtils.java index b1e0e5c8..e23a4da1 100644 --- a/app/src/main/java/com/simon/harmonichackernews/utils/ViewUtils.java +++ b/app/src/main/java/com/simon/harmonichackernews/utils/ViewUtils.java @@ -1,12 +1,8 @@ package com.simon.harmonichackernews.utils; -import android.content.Context; import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.TextWatcher; -import android.util.TypedValue; import android.view.View; import android.widget.TextView; @@ -48,7 +44,7 @@ public static void setUpSwipeRefreshWithStatusBarOffset(SwipeRefreshLayout layou * Requests that insets should be applied to this view once it is attached. *

* Copied from {@link com.google.android.material.internal.ViewUtils#requestApplyInsetsWhenAttached(View)} - * */ + */ public static void requestApplyInsetsWhenAttached(@NonNull View view) { if (ViewCompat.isAttachedToWindow(view)) { // We're already attached, just request as normal. @@ -64,7 +60,8 @@ public void onViewAttachedToWindow(@NonNull View v) { } @Override - public void onViewDetachedFromWindow(View v) {} + public void onViewDetachedFromWindow(View v) { + } }); } } From 37ff02e820c466b483a09682ed3350f40dbb81ea Mon Sep 17 00:00:00 2001 From: Simon Halvdansson Date: Sun, 21 Apr 2024 01:12:52 +0200 Subject: [PATCH 2/2] New gradle --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index eb5f6b57..656f7119 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { } plugins { - id('com.android.application') version '8.2.0' apply false + id('com.android.application') version '8.3.2' apply false id 'org.jetbrains.kotlin.android' version '1.8.0' apply false } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d9c23f9f..f72940c0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Sat Nov 12 13:07:01 CET 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME