From 55e2f63d6bf9c2019302a1a58ed8da72a3a9c832 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 1 Oct 2019 11:02:35 +0300 Subject: [PATCH 01/53] RecentFragment crash fix --- .../gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index 6e14b79b..1160692d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -128,7 +128,7 @@ public class RecentFragment extends BaseFragment { @Override public void onDestroy() { super.onDestroy(); - if (recentTask.isRunning()) + if (recentTask!=null && recentTask.isRunning()) recentTask.cancel(true); } From 0d8ccd3669ba1867e9d40615f3ace7ed2eb826cb Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 1 Oct 2019 13:22:32 +0300 Subject: [PATCH 02/53] Added dialog upon logout --- .../gr/thmmy/mthmmy/base/BaseActivity.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index a4ea57dd..c7c7360d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -428,7 +428,7 @@ public abstract class BaseActivity extends AppCompatActivity { if (!sessionManager.isLoggedIn()) //When logged out or if user is guest startLoginActivity(); else - new LogoutTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground() + showLogoutDialog(); } else if (drawerItem.equals(ABOUT_ID)) { if (!(BaseActivity.this instanceof AboutActivity)) { Intent intent = new Intent(BaseActivity.this, AboutActivity.class); @@ -543,6 +543,17 @@ public abstract class BaseActivity extends AppCompatActivity { //} } } + + private void showLogoutDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); + builder.setTitle("Logout"); + builder.setMessage("Are you sure that you want to logout?"); + builder.setPositiveButton("Yes", (dialogInterface, i) -> { + new LogoutTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground() + }); + builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); + builder.create().show(); + } //-----------------------------------------LOGOUT END----------------------------------------------- //---------------------------------------------BOOKMARKS-------------------------------------------- @@ -557,23 +568,20 @@ public abstract class BaseActivity extends AppCompatActivity { protected void setTopicBookmark(MenuItem thisPageBookmarkMenuButton) { this.thisPageBookmarkMenuButton = thisPageBookmarkMenuButton; - if (thisPageBookmark.matchExists(topicsBookmarked)) { + if (thisPageBookmark.matchExists(topicsBookmarked)) thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_true_accent_24dp); - } else { + else thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_false_accent_24dp); - } } protected void refreshTopicBookmark() { - if (thisPageBookmarkMenuButton == null) { - return; - } + if (thisPageBookmarkMenuButton == null) return; + loadSavedBookmarks(); - if (thisPageBookmark.matchExists(topicsBookmarked)) { + if (thisPageBookmark.matchExists(topicsBookmarked)) thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_true_accent_24dp); - } else { + else thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_false_accent_24dp); - } } protected void topicMenuBookmarkClick() { From 5f67364515b9f556a8a814da3564123ba0da1b12 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 1 Oct 2019 16:12:10 +0300 Subject: [PATCH 03/53] Bookmarks cleanup --- .../bookmarks/BookmarksActivity.java | 40 +++-- ...rdFragment.java => BookmarksFragment.java} | 88 ++++++---- .../bookmarks/BookmarksTopicFragment.java | 158 ------------------ 3 files changed, 81 insertions(+), 205 deletions(-) rename app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/{BookmarksBoardFragment.java => BookmarksFragment.java} (65%) delete mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksTopicFragment.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java index 3a00881c..ef2b79b6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java @@ -29,6 +29,9 @@ import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; //TODO proper handling with adapter etc. //TODO after clicking bookmark and then back button should return to this activity public class BookmarksActivity extends BaseActivity { + private static final String TOPIC_URL = "https://www.thmmy.gr/smf/index.php?topic="; + private static final String BOARD_URL = "https://www.thmmy.gr/smf/index.php?board="; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -48,8 +51,8 @@ public class BookmarksActivity extends BaseActivity { //Creates the adapter that will return a fragment for each section of the activity SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); - sectionsPagerAdapter.addFragment(BookmarksTopicFragment.newInstance(1, Bookmark.arrayListToString(getTopicsBookmarked())), "Topics"); - sectionsPagerAdapter.addFragment(BookmarksBoardFragment.newInstance(2, Bookmark.arrayListToString(getBoardsBookmarked())), "Boards"); + sectionsPagerAdapter.addFragment(BookmarksFragment.newInstance(1, Bookmark.arrayListToString(getTopicsBookmarked()), BookmarksFragment.Type.TOPIC), "Topics"); + sectionsPagerAdapter.addFragment(BookmarksFragment.newInstance(2, Bookmark.arrayListToString(getBoardsBookmarked()), BookmarksFragment.Type.BOARD), "Boards"); //Sets up the ViewPager with the sections adapter. ViewPager viewPager = findViewById(R.id.bookmarks_container); @@ -65,44 +68,57 @@ public class BookmarksActivity extends BaseActivity { super.onResume(); } - public boolean onTopicInteractionListener(String interactionType, Bookmark bookmarkedTopic) { + public boolean onFragmentRowInteractionListener(BookmarksFragment.Type type, String interactionType, Bookmark bookmark) { + if(type== BookmarksFragment.Type.TOPIC) + return onTopicInteractionListener(interactionType, bookmark); + else if (type==BookmarksFragment.Type.BOARD) + return onBoardInteractionListener(interactionType, bookmark); + + return false; + } + + private boolean onTopicInteractionListener(String interactionType, Bookmark bookmarkedTopic) { switch (interactionType) { - case BookmarksTopicFragment.INTERACTION_CLICK_TOPIC_BOOKMARK: + case BookmarksFragment.INTERACTION_CLICK_TOPIC_BOOKMARK: Intent intent = new Intent(BookmarksActivity.this, TopicActivity.class); Bundle extras = new Bundle(); - extras.putString(BUNDLE_TOPIC_URL, "https://www.thmmy.gr/smf/index.php?topic=" + extras.putString(BUNDLE_TOPIC_URL, TOPIC_URL + bookmarkedTopic.getId() + "." + 2147483647); extras.putString(BUNDLE_TOPIC_TITLE, bookmarkedTopic.getTitle()); intent.putExtras(extras); startActivity(intent); break; - case BookmarksTopicFragment.INTERACTION_TOGGLE_TOPIC_NOTIFICATION: + case BookmarksFragment.INTERACTION_TOGGLE_TOPIC_NOTIFICATION: return toggleNotification(bookmarkedTopic); - case BookmarksTopicFragment.INTERACTION_REMOVE_TOPIC_BOOKMARK: + case BookmarksFragment.INTERACTION_REMOVE_TOPIC_BOOKMARK: removeBookmark(bookmarkedTopic); Toast.makeText(BookmarksActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show(); break; + default: + break; } return true; } - public boolean onBoardInteractionListener(String interactionType, Bookmark bookmarkedBoard) { + private boolean onBoardInteractionListener(String interactionType, Bookmark bookmarkedBoard) { switch (interactionType) { - case BookmarksBoardFragment.INTERACTION_CLICK_BOARD_BOOKMARK: + case BookmarksFragment.INTERACTION_CLICK_BOARD_BOOKMARK: Intent intent = new Intent(BookmarksActivity.this, BoardActivity.class); Bundle extras = new Bundle(); - extras.putString(BUNDLE_BOARD_URL, "https://www.thmmy.gr/smf/index.php?board=" + extras.putString(BUNDLE_BOARD_URL, BOARD_URL + bookmarkedBoard.getId() + ".0"); extras.putString(BUNDLE_BOARD_TITLE, bookmarkedBoard.getTitle()); intent.putExtras(extras); startActivity(intent); break; - case BookmarksBoardFragment.INTERACTION_TOGGLE_BOARD_NOTIFICATION: + case BookmarksFragment.INTERACTION_TOGGLE_BOARD_NOTIFICATION: return toggleNotification(bookmarkedBoard); - case BookmarksBoardFragment.INTERACTION_REMOVE_BOARD_BOOKMARK: + case BookmarksFragment.INTERACTION_REMOVE_BOARD_BOOKMARK: removeBookmark(bookmarkedBoard); Toast.makeText(BookmarksActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show(); break; + default: + break; } return true; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksBoardFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java similarity index 65% rename from app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksBoardFragment.java rename to app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java index 814586ea..67de4c2e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksBoardFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java @@ -21,38 +21,53 @@ import java.util.ArrayList; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.model.Bookmark; -/** - * A {@link Fragment} subclass. - * Use the {@link BookmarksBoardFragment#newInstance} factory method to - * create an instance of this fragment. - */ -public class BookmarksBoardFragment extends Fragment { +public class BookmarksFragment extends Fragment { + enum Type {TOPIC, BOARD} private static final String ARG_SECTION_NUMBER = "SECTION_NUMBER"; - private static final String ARG_BOARD_BOOKMARKS = "BOARD_BOOKMARKS"; + private static final String ARG_BOOKMARKS = "BOOKMARKS"; + + static final String INTERACTION_CLICK_TOPIC_BOOKMARK = "CLICK_TOPIC_BOOKMARK"; + static final String INTERACTION_TOGGLE_TOPIC_NOTIFICATION = "TOGGLE_TOPIC_NOTIFICATION"; + static final String INTERACTION_REMOVE_TOPIC_BOOKMARK = "REMOVE_TOPIC_BOOKMARK"; static final String INTERACTION_CLICK_BOARD_BOOKMARK = "CLICK_BOARD_BOOKMARK"; static final String INTERACTION_TOGGLE_BOARD_NOTIFICATION = "TOGGLE_BOARD_NOTIFICATION"; static final String INTERACTION_REMOVE_BOARD_BOOKMARK= "REMOVE_BOARD_BOOKMARK"; - private ArrayList boardBookmarks = null; + private ArrayList bookmarks = null; + private Type type; + private String interactionClick, interactionToggle, interactionRemove; + + private Drawable notificationsEnabledButtonImage; + private Drawable notificationsDisabledButtonImage; - private static Drawable notificationsEnabledButtonImage; - private static Drawable notificationsDisabledButtonImage; + public BookmarksFragment() {/* Required empty public constructor */} - // Required empty public constructor - public BookmarksBoardFragment() { } + private BookmarksFragment(Type type) { + this.type=type; + if(type==Type.TOPIC){ + this.interactionClick=INTERACTION_CLICK_TOPIC_BOOKMARK; + this.interactionToggle=INTERACTION_TOGGLE_TOPIC_NOTIFICATION; + this.interactionRemove=INTERACTION_REMOVE_TOPIC_BOOKMARK; + } + else if (type==Type.BOARD){ + this.interactionClick=INTERACTION_CLICK_BOARD_BOOKMARK; + this.interactionToggle=INTERACTION_TOGGLE_BOARD_NOTIFICATION; + this.interactionRemove=INTERACTION_REMOVE_BOARD_BOOKMARK; + } + } /** * Use ONLY this factory method to create a new instance of - * this fragment using the provided parameters. + * the desired fragment using the provided parameters. * * @return A new instance of fragment Forum. */ - public static BookmarksBoardFragment newInstance(int sectionNumber, String boardBookmarks) { - BookmarksBoardFragment fragment = new BookmarksBoardFragment(); + protected static BookmarksFragment newInstance(int sectionNumber, String bookmarks, Type type) { + BookmarksFragment fragment = new BookmarksFragment(type); Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); - args.putString(ARG_BOARD_BOOKMARKS, boardBookmarks); + args.putString(ARG_BOOKMARKS, bookmarks); fragment.setArguments(args); return fragment; } @@ -61,9 +76,9 @@ public class BookmarksBoardFragment extends Fragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { - String bundledBoardBookmarks = getArguments().getString(ARG_BOARD_BOOKMARKS); - if (bundledBoardBookmarks != null) { - boardBookmarks = Bookmark.stringToArrayList(bundledBoardBookmarks); + String bundledBookmarks = getArguments().getString(ARG_BOOKMARKS); + if (bundledBookmarks != null) { + bookmarks = Bookmark.stringToArrayList(bundledBookmarks); } } @@ -83,47 +98,45 @@ public class BookmarksBoardFragment extends Fragment { Bundle savedInstanceState) { // Inflates the layout for this fragment final View rootView = layoutInflater.inflate(R.layout.fragment_bookmarks, container, false); - //bookmarks_board_container + //bookmarks container final LinearLayout bookmarksLinearView = rootView.findViewById(R.id.bookmarks_container); - if(this.boardBookmarks != null && !this.boardBookmarks.isEmpty()) { - for (final Bookmark bookmarkedBoard : boardBookmarks) { - if (bookmarkedBoard != null && bookmarkedBoard.getTitle() != null) { + if(this.bookmarks != null && !this.bookmarks.isEmpty()) { + for (final Bookmark bookmark : bookmarks) { + if (bookmark != null && bookmark.getTitle() != null) { final LinearLayout row = (LinearLayout) layoutInflater.inflate( R.layout.fragment_bookmarks_row, bookmarksLinearView, false); row.setOnClickListener(view -> { Activity activity = getActivity(); - if (activity instanceof BookmarksActivity){ - ((BookmarksActivity) activity).onBoardInteractionListener(INTERACTION_CLICK_BOARD_BOOKMARK, bookmarkedBoard); - } + if (activity instanceof BookmarksActivity) + ((BookmarksActivity) activity).onFragmentRowInteractionListener(type, interactionClick, bookmark); }); - ((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedBoard.getTitle()); + ((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmark.getTitle()); final ImageButton notificationsEnabledButton = row.findViewById(R.id.toggle_notification); - if (!bookmarkedBoard.isNotificationsEnabled()) { + if (!bookmark.isNotificationsEnabled()) { notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); } notificationsEnabledButton.setOnClickListener(view -> { Activity activity = getActivity(); if (activity instanceof BookmarksActivity) { - if (((BookmarksActivity) activity).onBoardInteractionListener(INTERACTION_TOGGLE_BOARD_NOTIFICATION, bookmarkedBoard)) { + if (((BookmarksActivity) activity).onFragmentRowInteractionListener(type, interactionToggle, bookmark)) notificationsEnabledButton.setImageDrawable(notificationsEnabledButtonImage); - } else { + else notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); - } } }); (row.findViewById(R.id.remove_bookmark)).setOnClickListener(view -> { Activity activity = getActivity(); if (activity instanceof BookmarksActivity){ - ((BookmarksActivity) activity).onBoardInteractionListener(INTERACTION_REMOVE_BOARD_BOOKMARK, bookmarkedBoard); - boardBookmarks.remove(bookmarkedBoard); + ((BookmarksActivity) activity).onFragmentRowInteractionListener(type, interactionRemove, bookmark); + bookmarks.remove(bookmark); } row.setVisibility(View.GONE); - if (boardBookmarks.isEmpty()){ + if (bookmarks.isEmpty()){ bookmarksLinearView.addView(bookmarksListEmptyMessage()); } }); @@ -142,7 +155,11 @@ public class BookmarksBoardFragment extends Fragment { LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); params.setMargins(0, 12, 0, 0); emptyBookmarksCategory.setLayoutParams(params); - emptyBookmarksCategory.setText(getString(R.string.empty_board_bookmarks)); + if(type==Type.TOPIC) + emptyBookmarksCategory.setText(getString(R.string.empty_topic_bookmarks)); + else if(type==Type.BOARD) + emptyBookmarksCategory.setText(getString(R.string.empty_board_bookmarks)); + emptyBookmarksCategory.setTypeface(emptyBookmarksCategory.getTypeface(), Typeface.BOLD); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) emptyBookmarksCategory.setTextColor(this.getContext().getColor(R.color.primary_text)); @@ -153,4 +170,5 @@ public class BookmarksBoardFragment extends Fragment { emptyBookmarksCategory.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); return emptyBookmarksCategory; } + } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksTopicFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksTopicFragment.java deleted file mode 100644 index e9081fbd..00000000 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksTopicFragment.java +++ /dev/null @@ -1,158 +0,0 @@ -package gr.thmmy.mthmmy.activities.bookmarks; - -import android.app.Activity; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; - -import java.util.ArrayList; - -import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.model.Bookmark; - -/** - * A {@link Fragment} subclass. - * Use the {@link BookmarksTopicFragment#newInstance} factory method to - * create an instance of this fragment. - */ -public class BookmarksTopicFragment extends Fragment { - private static final String ARG_SECTION_NUMBER = "SECTION_NUMBER"; - private static final String ARG_TOPIC_BOOKMARKS = "TOPIC_BOOKMARKS"; - - static final String INTERACTION_CLICK_TOPIC_BOOKMARK = "CLICK_TOPIC_BOOKMARK"; - static final String INTERACTION_TOGGLE_TOPIC_NOTIFICATION = "TOGGLE_TOPIC_NOTIFICATION"; - static final String INTERACTION_REMOVE_TOPIC_BOOKMARK = "REMOVE_TOPIC_BOOKMARK"; - - ArrayList topicBookmarks = null; - - private static Drawable notificationsEnabledButtonImage; - private static Drawable notificationsDisabledButtonImage; - - // Required empty public constructor - public BookmarksTopicFragment() { - } - - /** - * Use ONLY this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @return A new instance of fragment Forum. - */ - public static BookmarksTopicFragment newInstance(int sectionNumber, String topicBookmarks) { - BookmarksTopicFragment fragment = new BookmarksTopicFragment(); - Bundle args = new Bundle(); - args.putInt(ARG_SECTION_NUMBER, sectionNumber); - args.putString(ARG_TOPIC_BOOKMARKS, topicBookmarks); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - String bundledTopicBookmarks = getArguments().getString(ARG_TOPIC_BOOKMARKS); - if (bundledTopicBookmarks != null) { - topicBookmarks = Bookmark.stringToArrayList(bundledTopicBookmarks); - } - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - notificationsEnabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_on, null); - else - notificationsEnabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_on, null); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - notificationsDisabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_off, null); - else - notificationsDisabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_off, null); - } - - @Override - public View onCreateView(@NonNull LayoutInflater layoutInflater, ViewGroup container, - Bundle savedInstanceState) { - // Inflates the layout for this fragment - final View rootView = layoutInflater.inflate(R.layout.fragment_bookmarks, container, false); - //bookmarks_topic_container - final LinearLayout bookmarksLinearView = rootView.findViewById(R.id.bookmarks_container); - - if(this.topicBookmarks != null && !this.topicBookmarks.isEmpty()) { - for (final Bookmark bookmarkedTopic : topicBookmarks) { - if (bookmarkedTopic != null && bookmarkedTopic.getTitle() != null) { - final LinearLayout row = (LinearLayout) layoutInflater.inflate( - R.layout.fragment_bookmarks_row, bookmarksLinearView, false); - row.setOnClickListener(view -> { - Activity activity = getActivity(); - if (activity instanceof BookmarksActivity) { - ((BookmarksActivity) activity).onTopicInteractionListener(INTERACTION_CLICK_TOPIC_BOOKMARK, bookmarkedTopic); - } - }); - ((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedTopic.getTitle()); - - final ImageButton notificationsEnabledButton = row.findViewById(R.id.toggle_notification); - if (!bookmarkedTopic.isNotificationsEnabled()) { - notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); - } - - notificationsEnabledButton.setOnClickListener(view -> { - Activity activity = getActivity(); - if (activity instanceof BookmarksActivity) { - if (((BookmarksActivity) activity).onTopicInteractionListener(INTERACTION_TOGGLE_TOPIC_NOTIFICATION, bookmarkedTopic)) { - notificationsEnabledButton.setImageDrawable(notificationsEnabledButtonImage); - } else { - notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); - } - } - }); - (row.findViewById(R.id.remove_bookmark)).setOnClickListener(view -> { - Activity activity = getActivity(); - if (activity instanceof BookmarksActivity) { - ((BookmarksActivity) activity).onTopicInteractionListener(INTERACTION_REMOVE_TOPIC_BOOKMARK, bookmarkedTopic); - topicBookmarks.remove(bookmarkedTopic); - } - row.setVisibility(View.GONE); - - if (topicBookmarks.isEmpty()){ - bookmarksLinearView.addView(bookmarksListEmptyMessage()); - } - }); - bookmarksLinearView.addView(row); - } - } - } else { - bookmarksLinearView.addView(bookmarksListEmptyMessage()); - } - - - return rootView; - } - - private TextView bookmarksListEmptyMessage() { - TextView emptyBookmarksCategory = new TextView(this.getContext()); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - params.setMargins(0, 12, 0, 0); - emptyBookmarksCategory.setLayoutParams(params); - emptyBookmarksCategory.setText(getString(R.string.empty_topic_bookmarks)); - emptyBookmarksCategory.setTypeface(emptyBookmarksCategory.getTypeface(), Typeface.BOLD); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - emptyBookmarksCategory.setTextColor(this.getContext().getColor(R.color.primary_text)); - } else { - //noinspection deprecation - emptyBookmarksCategory.setTextColor(this.getContext().getResources().getColor(R.color.primary_text)); - } - emptyBookmarksCategory.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); - return emptyBookmarksCategory; - } -} From 979b385d438084a13ce8c23f9b5295b187d7bf11 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 1 Oct 2019 17:01:47 +0300 Subject: [PATCH 04/53] Bug fix (empty board bookmark title) --- .../java/gr/thmmy/mthmmy/activities/board/BoardActivity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index 6f3cea60..846a8961 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -96,7 +96,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo } thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), true); - setBoardBookmark(findViewById(R.id.bookmark)); + if (boardTitle != null && !Objects.equals(boardTitle, "")) + setBoardBookmark(findViewById(R.id.bookmark)); + createDrawer(); progressBar = findViewById(R.id.progressBar); From 73f30f5686a373ae7f62a94298ab5f1712c97f51 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 1 Oct 2019 17:19:18 +0300 Subject: [PATCH 05/53] Fix for AlertDialog window leak error --- .../gr/thmmy/mthmmy/activities/topic/TopicActivity.java | 9 +++++++-- app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index e0e52b3e..2bb084e3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -123,6 +123,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo private Snackbar snackbar; private TopicViewModel viewModel; private EmojiKeyboard emojiKeyboard; + private AlertDialog topicInfoDialog; //Fix for vector drawables on android <21 static { @@ -253,8 +254,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo usersViewing.setText(HTMLUtils.getSpannableFromHtml(this, topicViewers)); }); builder.setView(infoDialog); - AlertDialog dialog = builder.create(); - dialog.show(); + topicInfoDialog = builder.create(); + topicInfoDialog.show(); return true; case R.id.menu_share: Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND); @@ -312,6 +313,10 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo @Override protected void onDestroy() { super.onDestroy(); + if(topicInfoDialog!=null){ + topicInfoDialog.dismiss(); + topicInfoDialog=null; + } recyclerView.setAdapter(null); viewModel.stopLoading(); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index c7c7360d..22357d76 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -548,7 +548,7 @@ public abstract class BaseActivity extends AppCompatActivity { AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); builder.setTitle("Logout"); builder.setMessage("Are you sure that you want to logout?"); - builder.setPositiveButton("Yes", (dialogInterface, i) -> { + builder.setPositiveButton("Yep", (dialogInterface, i) -> { new LogoutTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground() }); builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); From 0c54623b43d24727e8d0f4dbfdbbaeb8bfcaf52b Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 3 Oct 2019 16:55:39 +0300 Subject: [PATCH 06/53] Added option to display relative time --- app/build.gradle | 1 + app/src/main/assets/apache_libraries.html | 6 + .../activities/main/recent/RecentAdapter.java | 34 ++- .../main/recent/RecentFragment.java | 27 +- .../activities/main/unread/UnreadAdapter.java | 26 +- .../main/unread/UnreadFragment.java | 21 +- .../activities/settings/SettingsActivity.java | 1 + .../activities/settings/SettingsFragment.java | 21 +- .../gr/thmmy/mthmmy/base/BaseApplication.java | 14 +- .../gr/thmmy/mthmmy/utils/DateTimeUtils.java | 64 +++++ .../mthmmy/utils/RelativeTimeTextView.java | 249 ++++++++++++++++++ .../utils/parsing/ThmmyDateTimeParser.java | 63 +++++ .../main/res/layout/fragment_recent_row.xml | 2 +- .../main/res/layout/fragment_unread_row.xml | 2 +- app/src/main/res/values/attrs.xml | 3 + app/src/main/res/values/strings.xml | 12 + .../res/xml-v21/app_preferences_guest.xml | 43 +++ .../main/res/xml-v21/app_preferences_user.xml | 66 +++++ .../res/xml-v26/app_preferences_guest.xml | 10 +- .../main/res/xml-v26/app_preferences_user.xml | 18 +- .../main/res/xml/app_preferences_guest.xml | 10 +- app/src/main/res/xml/app_preferences_user.xml | 18 +- 22 files changed, 631 insertions(+), 80 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java create mode 100644 app/src/main/res/xml-v21/app_preferences_guest.xml create mode 100644 app/src/main/res/xml-v21/app_preferences_user.xml diff --git a/app/build.gradle b/app/build.gradle index a4f3e951..f059e070 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -90,6 +90,7 @@ dependencies { implementation 'com.squareup.picasso:picasso:2.5.2' implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' implementation 'org.jsoup:jsoup:1.10.3' //TODO: Warning: upgrading from 1.10.3 will break stuff! + implementation 'joda-time:joda-time:2.10.4' implementation 'com.github.franmontiel:PersistentCookieJar:1.0.1' implementation 'com.github.PhilJay:MPAndroidChart:3.0.3' implementation 'com.mikepenz:materialdrawer:6.1.1' diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index 911a8e50..d88ed36e 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -71,6 +71,12 @@
  • Grgit v3.0.0 (Copyright ©2018 Andrew Oberstar)
  • +
  • +
    Joda-Time v2.10.4 (Copyright ©2002-2019 Joda.org)
    +
  • +
  • +
    android-storage v2.1.0
    +
  • OkHttpProfiler v1.0.5
  • diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java index 15589d45..0bd447f6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java @@ -1,6 +1,5 @@ package gr.thmmy.mthmmy.activities.main.recent; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -12,8 +11,10 @@ import androidx.recyclerview.widget.RecyclerView; import java.util.List; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; +import gr.thmmy.mthmmy.utils.RelativeTimeTextView; /** @@ -21,12 +22,10 @@ import gr.thmmy.mthmmy.model.TopicSummary; * specified {@link RecentFragment.RecentFragmentInteractionListener}. */ class RecentAdapter extends RecyclerView.Adapter { - private final Context context; private final List recentList; private final RecentFragment.RecentFragmentInteractionListener mListener; - RecentAdapter(Context context, @NonNull List topicSummaryList, BaseFragment.FragmentInteractionListener listener) { - this.context = context; + RecentAdapter(@NonNull List topicSummaryList, BaseFragment.FragmentInteractionListener listener) { this.recentList = topicSummaryList; mListener = (RecentFragment.RecentFragmentInteractionListener) listener; } @@ -43,22 +42,21 @@ class RecentAdapter extends RecyclerView.Adapter { @Override public void onBindViewHolder(final ViewHolder holder, final int position) { holder.mTitleView.setText(recentList.get(position).getSubject()); - holder.mDateTimeView.setText(recentList.get(position).getDateTimeModified()); - holder.mUserView.setText(recentList.get(position).getLastUser()); - - holder.topic = recentList.get(position); - holder.mView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + String dateTimeString = recentList.get(position).getDateTimeModified(); + if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) + holder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + else + holder.mDateTimeView.setText(dateTimeString); - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - mListener.onRecentFragmentInteraction(holder.topic); //? - - } + holder.mUserView.setText(recentList.get(position).getLastUser()); + holder.topic = recentList.get(position); + holder.mView.setOnClickListener(v -> { + if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + mListener.onRecentFragmentInteraction(holder.topic); //? } }); } @@ -72,7 +70,7 @@ class RecentAdapter extends RecyclerView.Adapter { final View mView; final TextView mTitleView; final TextView mUserView; - final TextView mDateTimeView; + final RelativeTimeTextView mDateTimeView; public TopicSummary topic; ViewHolder(View view) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index 1160692d..a1f21281 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -1,6 +1,7 @@ package gr.thmmy.mthmmy.activities.main.recent; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -34,6 +35,9 @@ import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Response; import timber.log.Timber; +import static gr.thmmy.mthmmy.utils.DateTimeUtils.convertDateTime; +import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp; + /** * A {@link BaseFragment} subclass. @@ -100,7 +104,7 @@ public class RecentFragment extends BaseFragment { // Set the adapter if (rootView instanceof RelativeLayout) { progressBar = rootView.findViewById(R.id.progressBar); - recentAdapter = new RecentAdapter(getActivity(), topicSummaries, fragmentInteractionListener); + recentAdapter = new RecentAdapter(topicSummaries, fragmentInteractionListener); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext()); @@ -186,18 +190,19 @@ public class RecentFragment extends BaseFragment { String dateTime = recent.get(i + 2).text(); pattern = Pattern.compile("\\[(.*)]"); matcher = pattern.matcher(dateTime); - if (matcher.find()) { + if (matcher.find()){ dateTime = matcher.group(1); - if (dateTime.contains(" am") || dateTime.contains(" pm") || - dateTime.contains(" πμ") || dateTime.contains(" μμ")) { - dateTime = dateTime.replaceAll(":[0-5][0-9] ", " "); - } else { - dateTime = dateTime.substring(0, dateTime.lastIndexOf(":")); - } - if (!dateTime.contains(",")) { - dateTime = dateTime.replaceAll(".+? ([0-9])", "$1"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP + && BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { + dateTime=convertDateTime(dateTime, false); + String timestamp = convertToTimestamp(dateTime); + if(timestamp!=null) + dateTime=timestamp; } - } else + else + dateTime=convertDateTime(dateTime, true); + } + else throw new ParseException("Parsing failed (dateTime)"); fetchedRecent.add(new TopicSummary(link, title, lastUser, dateTime)); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java index 3818145a..d213e480 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java @@ -11,8 +11,10 @@ import androidx.recyclerview.widget.RecyclerView; import java.util.List; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; +import gr.thmmy.mthmmy.utils.RelativeTimeTextView; class UnreadAdapter extends RecyclerView.Adapter { private final List unreadList; @@ -65,19 +67,21 @@ class UnreadAdapter extends RecyclerView.Adapter { final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder; viewHolder.mTitleView.setText(unreadList.get(holder.getAdapterPosition()).getSubject()); - viewHolder.mDateTimeView.setText(unreadList.get(holder.getAdapterPosition()).getDateTimeModified()); - viewHolder.mUserView.setText(unreadList.get(position).getLastUser()); + String dateTimeString=unreadList.get(holder.getAdapterPosition()).getDateTimeModified(); + if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) + viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + else + viewHolder.mDateTimeView.setText(dateTimeString); + + viewHolder.mUserView.setText(unreadList.get(position).getLastUser()); viewHolder.topic = unreadList.get(holder.getAdapterPosition()); - viewHolder.mView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - mListener.onUnreadFragmentInteraction(viewHolder.topic); //? - } + viewHolder.mView.setOnClickListener(v -> { + if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + mListener.onUnreadFragmentInteraction(viewHolder.topic); //? } }); } else if (holder instanceof UnreadAdapter.MarkReadViewHolder) { @@ -107,7 +111,7 @@ class UnreadAdapter extends RecyclerView.Adapter { final View mView; final TextView mTitleView; final TextView mUserView; - final TextView mDateTimeView; + final RelativeTimeTextView mDateTimeView; public TopicSummary topic; ViewHolder(View view) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 1db4131e..950ca27a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -2,6 +2,7 @@ package gr.thmmy.mthmmy.activities.main.unread; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -24,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; @@ -36,6 +38,9 @@ import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; +import static gr.thmmy.mthmmy.utils.DateTimeUtils.convertDateTime; +import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp; + /** * A {@link BaseFragment} subclass. * Activities that contain this fragment must implement the @@ -211,17 +216,19 @@ public class UnreadFragment extends BaseFragment { Element lastUserAndDate = information.get(6); String lastUser = lastUserAndDate.select("a").text(); String dateTime = lastUserAndDate.select("span").html(); - //dateTime = dateTime.replace("
    ", ""); dateTime = dateTime.substring(0, dateTime.indexOf("
    ")); dateTime = dateTime.replace("", ""); dateTime = dateTime.replace("", ""); - if (dateTime.contains(" am") || dateTime.contains(" pm") || - dateTime.contains(" πμ") || dateTime.contains(" μμ")) - dateTime = dateTime.replaceAll(":[0-5][0-9] ", " "); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP + && BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { + dateTime=convertDateTime(dateTime, false); + String timestamp = convertToTimestamp(dateTime); + if(timestamp!=null) + dateTime=timestamp; + } else - dateTime = dateTime.substring(0, dateTime.lastIndexOf(":")); - if (!dateTime.contains(",")) - dateTime = dateTime.replaceAll(".+? ([0-9])", "$1"); + dateTime=convertDateTime(dateTime, true); fetchedTopicSummaries.add(new TopicSummary(link, title, lastUser, dateTime)); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java index c9637dd0..6414a497 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java @@ -9,6 +9,7 @@ import gr.thmmy.mthmmy.base.BaseActivity; public class SettingsActivity extends BaseActivity { public static final String DEFAULT_HOME_TAB = "pref_app_main_default_tab_key"; + public static final String DISPLAY_RELATIVE_TIME = "pref_app_display_relative_time_key"; public static final String NOTIFICATION_LED_KEY = "pref_notification_led_enable_key"; public static final String NOTIFICATION_VIBRATION_KEY = "pref_notification_vibration_enable_key"; public static final String POSTING_APP_SIGNATURE_ENABLE_KEY = "pref_posting_app_signature_enable_key"; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java index ec5907b6..edd06356 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java @@ -42,6 +42,8 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared public static final String SELECTED_RINGTONE = "selectedRingtoneKey"; private static final String SILENT_SELECTED = "STFU"; + private static final String UNREAD = "Unread"; + private SharedPreferences settingsFile; private PREFS_TYPE prefs_type = PREFS_TYPE.NOT_SET; @@ -65,7 +67,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared defaultHomeTabValues.add("1"); if(isLoggedIn = BaseApplication.getInstance().getSessionManager().isLoggedIn()){ - defaultHomeTabEntries.add("Unread"); + defaultHomeTabEntries.add(UNREAD); defaultHomeTabValues.add("2"); } } @@ -171,16 +173,16 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared if(isLoggedIn&& prefs_type==PREFS_TYPE.GUEST) { prefs_type = PREFS_TYPE.USER; setPreferencesFromResource(R.xml.app_preferences_user, getPreferenceScreen().getKey()); - if(!defaultHomeTabEntries.contains("Unread")){ - defaultHomeTabEntries.add("Unread"); + if(!defaultHomeTabEntries.contains(UNREAD)){ + defaultHomeTabEntries.add(UNREAD); defaultHomeTabValues.add("2"); } } else if(!isLoggedIn&&prefs_type==PREFS_TYPE.USER){ prefs_type = PREFS_TYPE.GUEST; setPreferencesFromResource(R.xml.app_preferences_guest,getPreferenceScreen().getKey()); - if(defaultHomeTabEntries.contains("Unread")){ - defaultHomeTabEntries.remove("Unread"); + if(defaultHomeTabEntries.contains(UNREAD)){ + defaultHomeTabEntries.remove(UNREAD); defaultHomeTabValues.remove("2"); } } @@ -201,7 +203,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared BaseApplication.getInstance().startFirebaseCrashlyticsCollection(); else { Timber.i("Crashlytics collection will be disabled after restarting."); - Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This change will take effect once you restart the app.", Toast.LENGTH_SHORT).show(); + displayRestartAppToTakeEffectToast(); } } else if (key.equals(getString(R.string.pref_privacy_analytics_enable_key))) { enabled = sharedPreferences.getBoolean(key, false); @@ -210,6 +212,13 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared Timber.i("Analytics collection enabled."); else Timber.i("Analytics collection disabled."); + } else if (key.equals(getString(R.string.pref_app_display_relative_time_key)) + && BaseApplication.getInstance().isDisplayRelativeTimeEnabled()!=sharedPreferences.getBoolean(key, false)){ + displayRestartAppToTakeEffectToast(); } } + + private void displayRestartAppToTakeEffectToast(){ + Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This change will take effect once you restart the app.", Toast.LENGTH_SHORT).show(); + } } \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index ba0e6a0f..64ad4996 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -49,6 +49,8 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import timber.log.Timber; +import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELATIVE_TIME; + public class BaseApplication extends Application { private static BaseApplication baseApplication; //BaseApplication singleton @@ -60,6 +62,8 @@ public class BaseApplication extends Application { private OkHttpClient client; private SessionManager sessionManager; + private boolean displayRelativeTime; + //TODO: maybe use PreferenceManager.getDefaultSharedPreferences here as well? private static final String SHARED_PREFS = "ThmmySharedPrefs"; @@ -104,12 +108,11 @@ public class BaseApplication extends Application { .addInterceptor(chain -> { Request request = chain.request(); HttpUrl oldUrl = chain.request().url(); - if (Objects.equals(chain.request().url().host(), "www.thmmy.gr")) { - if (!oldUrl.toString().contains("theme=4")) { + if (Objects.equals(chain.request().url().host(), "www.thmmy.gr") + && !oldUrl.toString().contains("theme=4")) { //Probably works but needs more testing: HttpUrl newUrl = oldUrl.newBuilder().addQueryParameter("theme", "4").build(); request = request.newBuilder().url(newUrl).build(); - } } return chain.proceed(request); }) @@ -173,6 +176,8 @@ public class BaseApplication extends Application { DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics(); dpWidth = displayMetrics.widthPixels / displayMetrics.density; + + displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, false); } //Getters @@ -192,6 +197,9 @@ public class BaseApplication extends Application { return dpWidth; } + public boolean isDisplayRelativeTimeEnabled() { + return displayRelativeTime; + } //--------------------Firebase-------------------- diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java new file mode 100644 index 00000000..7802f931 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java @@ -0,0 +1,64 @@ +package gr.thmmy.mthmmy.utils; + +import static android.text.format.DateUtils.DAY_IN_MILLIS; +import static android.text.format.DateUtils.HOUR_IN_MILLIS; +import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static android.text.format.DateUtils.YEAR_IN_MILLIS; + +public class DateTimeUtils { + //TODO: move this function to ThmmyDateTimeParser class once KitKat support is dropped + public static String convertDateTime(String dateTime, boolean removeSeconds){ + //Convert e.g. Today at 12:16:48 -> 12:16:48, but October 03, 2019, 16:40:18 remains as is + if (!dateTime.contains(",")) + dateTime = dateTime.replaceAll(".+? ([0-9])", "$1"); + + //Remove seconds + if(removeSeconds) + dateTime = dateTime.replaceAll("(.+?)(:[0-5][0-9])($|\\s)", "$1$3"); + + return dateTime; + } + + private static final long MONTH_IN_MILLIS = DAY_IN_MILLIS*30; + private static final long DECADE_IN_MILLIS = YEAR_IN_MILLIS*10; + + static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution) { + boolean past = (now >= time); + long duration = Math.abs(now - time); + String format; + long count; + if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) { + count = duration / SECOND_IN_MILLIS; + format = "%d sec"; + } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) { + count = duration / MINUTE_IN_MILLIS; + format = "%d min"; + } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) { + count = duration / HOUR_IN_MILLIS; + format = "%d hour"; + if(count>1) + format = format + 's'; + } else if (duration < MONTH_IN_MILLIS && minResolution < MONTH_IN_MILLIS) { + count = duration / DAY_IN_MILLIS; + format = "%d day"; + if(count>1) + format = format + 's'; + } else if (duration < YEAR_IN_MILLIS && minResolution < YEAR_IN_MILLIS) { + count = duration / MONTH_IN_MILLIS; + format = "%d month"; + if(count>1) + format = format + 's'; + } else if (duration < DECADE_IN_MILLIS && minResolution < DECADE_IN_MILLIS) { + count = duration / YEAR_IN_MILLIS; + format = "%d year"; + if(count>1) + format = format + 's'; + } + else + return past ? "a long time ago": "in the distant future"; + + format = past ? format : "in " + format; + return String.format(format, (int) count); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java b/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java new file mode 100644 index 00000000..083408c4 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java @@ -0,0 +1,249 @@ +package gr.thmmy.mthmmy.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.format.DateUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TextView; + +import java.lang.ref.WeakReference; + +import gr.thmmy.mthmmy.R; + +import static gr.thmmy.mthmmy.utils.DateTimeUtils.getRelativeTimeSpanString; + +/** + * A modified version of https://github.com/curioustechizen/android-ago + */ +@SuppressLint("AppCompatCustomView") +public class RelativeTimeTextView extends TextView { + + private static final long INITIAL_UPDATE_INTERVAL = DateUtils.MINUTE_IN_MILLIS; + + private long mReferenceTime; + private Handler mHandler = new Handler(); + private UpdateTimeRunnable mUpdateTimeTask; + private boolean isUpdateTaskRunning = false; + + public RelativeTimeTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public RelativeTimeTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + TypedArray a = context.getTheme().obtainStyledAttributes(attrs, + R.styleable.RelativeTimeTextView, 0, 0); + String referenceTimeText; + try { + referenceTimeText = a.getString(R.styleable.RelativeTimeTextView_reference_time); + } finally { + a.recycle(); + } + + try { + mReferenceTime = Long.valueOf(referenceTimeText); + } catch (NumberFormatException nfe) { + /* + * TODO: Better exception handling + */ + mReferenceTime = -1L; + } + + setReferenceTime(mReferenceTime); + + } + + /** + * Sets the reference time for this view. At any moment, the view will render a relative time period relative to the time set here. + *

    + * This value can also be set with the XML attribute {@code reference_time} + * @param referenceTime The timestamp (in milliseconds since epoch) that will be the reference point for this view. + */ + public void setReferenceTime(long referenceTime) { + this.mReferenceTime = referenceTime; + + /* + * Note that this method could be called when a row in a ListView is recycled. + * Hence, we need to first stop any currently running schedules (for example from the recycled view. + */ + stopTaskForPeriodicallyUpdatingRelativeTime(); + + /* + * Instantiate a new runnable with the new reference time + */ + initUpdateTimeTask(); + + /* + * Start a new schedule. + */ + startTaskForPeriodicallyUpdatingRelativeTime(); + + /* + * Finally, update the text display. + */ + updateTextDisplay(); + } + + private void updateTextDisplay() { + /* + * TODO: Validation, Better handling of negative cases + */ + if (this.mReferenceTime == -1L) + return; + setText(getRelativeTimeDisplayString(mReferenceTime, System.currentTimeMillis())); + } + + /** + * Get the text to display for relative time. + *
    + * @param referenceTime The reference time passed in through {@link #setReferenceTime(long)} or through {@code reference_time} attribute + * @param now The current time + * @return The display text for the relative time + */ + protected CharSequence getRelativeTimeDisplayString(long referenceTime, long now) { + long difference = now - referenceTime; + return (difference >= 0 && difference<=DateUtils.MINUTE_IN_MILLIS) ? + "just now" : + getRelativeTimeSpanString( + mReferenceTime, + now, + DateUtils.MINUTE_IN_MILLIS); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + startTaskForPeriodicallyUpdatingRelativeTime(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stopTaskForPeriodicallyUpdatingRelativeTime(); + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if (visibility == GONE || visibility == INVISIBLE) { + stopTaskForPeriodicallyUpdatingRelativeTime(); + } else { + startTaskForPeriodicallyUpdatingRelativeTime(); + } + } + + private void startTaskForPeriodicallyUpdatingRelativeTime() { + if(mUpdateTimeTask.isDetached()) initUpdateTimeTask(); + mHandler.post(mUpdateTimeTask); + isUpdateTaskRunning = true; + } + + private void initUpdateTimeTask() { + mUpdateTimeTask = new UpdateTimeRunnable(this, mReferenceTime); + } + + private void stopTaskForPeriodicallyUpdatingRelativeTime() { + if(isUpdateTaskRunning) { + mUpdateTimeTask.detach(); + mHandler.removeCallbacks(mUpdateTimeTask); + isUpdateTaskRunning = false; + } + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.referenceTime = mReferenceTime; + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + SavedState ss = (SavedState)state; + mReferenceTime = ss.referenceTime; + super.onRestoreInstanceState(ss.getSuperState()); + } + + public static class SavedState extends BaseSavedState { + + private long referenceTime; + + public SavedState(Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeLong(referenceTime); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + + private SavedState(Parcel in) { + super(in); + referenceTime = in.readLong(); + } + } + + private static class UpdateTimeRunnable implements Runnable { + + private long mRefTime; + private final WeakReference weakRefRttv; + + UpdateTimeRunnable(RelativeTimeTextView rttv, long refTime) { + this.mRefTime = refTime; + weakRefRttv = new WeakReference<>(rttv); + } + + boolean isDetached() { + return weakRefRttv.get() == null; + } + + void detach() { + weakRefRttv.clear(); + } + + @Override + public void run() { + RelativeTimeTextView rttv = weakRefRttv.get(); + if (rttv == null) return; + long difference = Math.abs(System.currentTimeMillis() - mRefTime); + long interval = INITIAL_UPDATE_INTERVAL; + if (difference > DateUtils.WEEK_IN_MILLIS) { + interval = DateUtils.WEEK_IN_MILLIS; + } else if (difference > DateUtils.DAY_IN_MILLIS) { + interval = DateUtils.DAY_IN_MILLIS; + } else if (difference > DateUtils.HOUR_IN_MILLIS) { + interval = DateUtils.HOUR_IN_MILLIS; + } + rttv.updateTextDisplay(); + rttv.mHandler.postDelayed(this, interval); + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java new file mode 100644 index 00000000..9524e5fe --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java @@ -0,0 +1,63 @@ +package gr.thmmy.mthmmy.utils.parsing; + + +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.DateTimeFormatterBuilder; +import org.joda.time.format.DateTimeParser; + +import java.util.Locale; + +import gr.thmmy.mthmmy.base.BaseApplication; +import timber.log.Timber; + +@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) +public class ThmmyDateTimeParser { + private static final DateTimeParser[] parsers = { + DateTimeFormat.forPattern("HH:mm:ss").getParser(), + DateTimeFormat.forPattern("HH:mm:ss a").getParser(), + DateTimeFormat.forPattern("MMMM d, Y, HH:mm:ss").getParser(), + DateTimeFormat.forPattern("MMMM d, Y, HH:mm:ss a").getParser() + }; + + private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder() + .append(null, parsers) + .toFormatter(); + + private static final Locale greekLocale = Locale.forLanguageTag("el-GR"); + private static final Locale englishLocale = Locale.forLanguageTag("en-US"); + + public static String convertToTimestamp(String thmmyDateTime){ + DateTimeZone dtz; + if(!BaseApplication.getInstance().getSessionManager().isLoggedIn()) + dtz = DateTimeZone.forID("Europe/Athens"); + else + dtz = DateTimeZone.getDefault(); + + //Add today's date for the first two cases + if(Character.isDigit(thmmyDateTime.charAt(0))) + thmmyDateTime = (new DateTime()).toString("MMMM d, Y, ") + thmmyDateTime; + + DateTime dateTime; + try{ + dateTime=formatter.withZone(dtz).withLocale(greekLocale).parseDateTime(thmmyDateTime); + } + catch (IllegalArgumentException e1){ + Timber.i("Parsing DateTime using Greek Locale failed."); + try{ + dateTime=formatter.withZone(dtz).withLocale(englishLocale).parseDateTime(thmmyDateTime); + } + catch (IllegalArgumentException e2){ + Timber.e("Couldn't parse DateTime %s", thmmyDateTime); + return null; + } + } + return Long.toString(dateTime.getMillis()); + } +} diff --git a/app/src/main/res/layout/fragment_recent_row.xml b/app/src/main/res/layout/fragment_recent_row.xml index 7d136a4e..07041cc5 100644 --- a/app/src/main/res/layout/fragment_recent_row.xml +++ b/app/src/main/res/layout/fragment_recent_row.xml @@ -32,7 +32,7 @@ android:layout_below="@+id/title" android:layout_toEndOf="@+id/dateTime"/> - - + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fabd3e8a..8446551f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,26 +168,38 @@ Settings App + pref_app_main_default_tab_key Default home tab Sets a home screen tab as default Default home tab + pref_app_display_relative_time_key + Display relative time + Considering that you haven\'t set some weird custom time format Notifications + pref_notification_vibration_enable_key Vibration + pref_notification_led_enable_key Notifications led Enables/disables the notifications led (if the device has one) + pref_notifications_select_sound_key Notifications sound Sets your preferred notification sound Posting + pref_category_posting_key + pref_posting_app_signature_enable_key App signature Appends a \"sent from mTHMMY\" message to your posts Uploading + pref_category_uploading_key + pref_uploading_app_signature_enable_key App signature Appends an \"uploaded from mTHMMY\" message to the descriptions of your uploads Privacy + pref_category_privacy_key pref_privacy_crashlytics_enable_key Crash data reports Automatically send us anonymized reports of errors and crashes diff --git a/app/src/main/res/xml-v21/app_preferences_guest.xml b/app/src/main/res/xml-v21/app_preferences_guest.xml new file mode 100644 index 00000000..78c7c8ca --- /dev/null +++ b/app/src/main/res/xml-v21/app_preferences_guest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml-v21/app_preferences_user.xml b/app/src/main/res/xml-v21/app_preferences_user.xml new file mode 100644 index 00000000..c132270f --- /dev/null +++ b/app/src/main/res/xml-v21/app_preferences_user.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml-v26/app_preferences_guest.xml b/app/src/main/res/xml-v26/app_preferences_guest.xml index 942c2692..78c7c8ca 100644 --- a/app/src/main/res/xml-v26/app_preferences_guest.xml +++ b/app/src/main/res/xml-v26/app_preferences_guest.xml @@ -10,14 +10,20 @@ android:dialogTitle="@string/pref_app_main_default_tab_dialog_title" android:entries="@array/pref_app_main_default_tab_entries" android:entryValues="@array/pref_app_main_default_tab_values" - android:key="pref_app_main_default_tab_key" + android:key="@string/pref_app_main_default_tab_key" android:title="@string/pref_title_app_main_default_tab" android:summary="@string/pref_summary_app_main_default_tab" app:iconSpaceReserved="false" /> + + @@ -21,24 +21,24 @@ app:iconSpaceReserved="false"> @@ -21,48 +21,48 @@ app:iconSpaceReserved="false"> Date: Thu, 3 Oct 2019 20:20:55 +0300 Subject: [PATCH 07/53] Prevent NumberFormatException crash --- .../activities/main/recent/RecentAdapter.java | 9 ++++++- .../activities/main/unread/UnreadAdapter.java | 25 +++++++++++-------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java index 0bd447f6..8d66209e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java @@ -15,6 +15,7 @@ import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.utils.RelativeTimeTextView; +import timber.log.Timber; /** @@ -45,7 +46,13 @@ class RecentAdapter extends RecyclerView.Adapter { String dateTimeString = recentList.get(position).getDateTimeModified(); if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) - holder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + try{ + holder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + } + catch(NumberFormatException e){ + Timber.e(e, "Invalid number format."); + holder.mDateTimeView.setText(dateTimeString); + } else holder.mDateTimeView.setText(dateTimeString); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java index d213e480..9312178f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java @@ -15,6 +15,7 @@ import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.utils.RelativeTimeTextView; +import timber.log.Timber; class UnreadAdapter extends RecyclerView.Adapter { private final List unreadList; @@ -69,8 +70,15 @@ class UnreadAdapter extends RecyclerView.Adapter { viewHolder.mTitleView.setText(unreadList.get(holder.getAdapterPosition()).getSubject()); String dateTimeString=unreadList.get(holder.getAdapterPosition()).getDateTimeModified(); - if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) - viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()){ + try{ + viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + } + catch(NumberFormatException e){ + Timber.e(e, "Invalid number format."); + viewHolder.mDateTimeView.setText(dateTimeString); + } + } else viewHolder.mDateTimeView.setText(dateTimeString); @@ -89,14 +97,11 @@ class UnreadAdapter extends RecyclerView.Adapter { markReadViewHolder.text.setText(unreadList.get(holder.getAdapterPosition()).getSubject()); markReadViewHolder.topic = unreadList.get(holder.getAdapterPosition()); - markReadViewHolder.mView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - markReadListener.onMarkReadInteraction(unreadList.get(holder.getAdapterPosition()).getTopicUrl()); - } + markReadViewHolder.mView.setOnClickListener(v -> { + if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + markReadListener.onMarkReadInteraction(unreadList.get(holder.getAdapterPosition()).getTopicUrl()); } }); } From 38396f1d663378ca8b2426b6a53729a491f30a5c Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 3 Oct 2019 21:48:16 +0300 Subject: [PATCH 08/53] DateTime parsing fixes --- .../activities/main/recent/RecentAdapter.java | 2 +- .../utils/parsing/ThmmyDateTimeParser.java | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java index 8d66209e..ecfcf64c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java @@ -50,7 +50,7 @@ class RecentAdapter extends RecyclerView.Adapter { holder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); } catch(NumberFormatException e){ - Timber.e(e, "Invalid number format."); + Timber.e(e, "Invalid number format: %s", dateTimeString); holder.mDateTimeView.setText(dateTimeString); } else diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java index 9524e5fe..f5f1a0aa 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java @@ -13,6 +13,8 @@ import org.joda.time.format.DateTimeFormatterBuilder; import org.joda.time.format.DateTimeParser; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseApplication; import timber.log.Timber; @@ -21,9 +23,9 @@ import timber.log.Timber; public class ThmmyDateTimeParser { private static final DateTimeParser[] parsers = { DateTimeFormat.forPattern("HH:mm:ss").getParser(), - DateTimeFormat.forPattern("HH:mm:ss a").getParser(), + DateTimeFormat.forPattern("KK:mm:ss a").getParser(), DateTimeFormat.forPattern("MMMM d, Y, HH:mm:ss").getParser(), - DateTimeFormat.forPattern("MMMM d, Y, HH:mm:ss a").getParser() + DateTimeFormat.forPattern("MMMM d, Y, KK:mm:ss a").getParser() }; private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder() @@ -33,6 +35,8 @@ public class ThmmyDateTimeParser { private static final Locale greekLocale = Locale.forLanguageTag("el-GR"); private static final Locale englishLocale = Locale.forLanguageTag("en-US"); + private static final Pattern pattern = Pattern.compile("\\s(1[2-9]|2[0-3]:)"); + public static String convertToTimestamp(String thmmyDateTime){ DateTimeZone dtz; if(!BaseApplication.getInstance().getSessionManager().isLoggedIn()) @@ -41,16 +45,26 @@ public class ThmmyDateTimeParser { dtz = DateTimeZone.getDefault(); //Add today's date for the first two cases - if(Character.isDigit(thmmyDateTime.charAt(0))) + if(thmmyDateTime.charAt(2)==':') thmmyDateTime = (new DateTime()).toString("MMMM d, Y, ") + thmmyDateTime; + // For the stupid format 23:54:12 pm + Matcher matcher = pattern.matcher(thmmyDateTime); + if (matcher.find()) + thmmyDateTime = thmmyDateTime.replaceAll("\\s(am|pm|π.μ.|α.μ.)",""); + + DateTime dateTime; try{ + thmmyDateTime = thmmyDateTime.replace("am","π.μ."); + thmmyDateTime = thmmyDateTime.replace("pm","μ.μ."); dateTime=formatter.withZone(dtz).withLocale(greekLocale).parseDateTime(thmmyDateTime); } catch (IllegalArgumentException e1){ - Timber.i("Parsing DateTime using Greek Locale failed."); + Timber.d("Parsing DateTime using Greek Locale failed."); try{ + thmmyDateTime = thmmyDateTime.replace("π.μ.","am"); + thmmyDateTime = thmmyDateTime.replace("μ.μ.","pm"); dateTime=formatter.withZone(dtz).withLocale(englishLocale).parseDateTime(thmmyDateTime); } catch (IllegalArgumentException e2){ From f4a343b1123e867af3ad65586478b67574451992 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 4 Oct 2019 18:50:58 +0300 Subject: [PATCH 09/53] Fixes for relative time, added test --- app/build.gradle | 5 + app/src/main/assets/apache_libraries.html | 4 +- app/src/main/assets/epl_libraries.html | 261 ++++++++++++++++++ app/src/main/assets/mit_libraries.html | 6 +- .../mthmmy/activities/AboutActivity.java | 39 +-- .../utils/parsing/ThmmyDateTimeParser.java | 51 ++-- app/src/main/res/layout/activity_about.xml | 19 +- app/src/main/res/values/strings.xml | 1 + .../parsing/ThmmyDateTimeParserTest.java | 84 ++++++ 9 files changed, 428 insertions(+), 42 deletions(-) create mode 100644 app/src/main/assets/epl_libraries.html create mode 100644 app/src/test/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParserTest.java diff --git a/app/build.gradle b/app/build.gradle index f059e070..c9fd8891 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -104,6 +104,11 @@ dependencies { implementation 'net.gotev:uploadservice:3.5.2' implementation 'net.gotev:uploadservice-okhttp:3.4.2' //TODO: Warning: v.3.5 depends on okhttp 3.13! implementation 'com.itkacher.okhttpprofiler:okhttpprofiler:1.0.5' //Plugin: https://plugins.jetbrains.com/plugin/11249-okhttp-profiler + testImplementation 'junit:junit:4.12' + testImplementation 'org.powermock:powermock-core:2.0.2' + testImplementation 'org.powermock:powermock-module-junit4:2.0.2' + testImplementation 'org.powermock:powermock-api-mockito2:2.0.2' + testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1' } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index d88ed36e..a75e08f3 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -1,5 +1,4 @@ - + + + +

      +
    • +
      JUnit v4.12 (Copyright © 2002-2019, JUnit)
      +
    • +
    + + +
    +

    Eclipse Public License v1.0

    +
    +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
    +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
    +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
    +
    +1. DEFINITIONS
    +
    +"Contribution" means:
    +
    +      a) in the case of the initial Contributor, the initial code and
    +         documentation distributed under this Agreement, and
    +      b) in the case of each subsequent Contributor:
    +
    +      i) changes to the Program, and
    +
    +      ii) additions to the Program;
    +
    +      where such changes and/or additions to the Program originate from and are
    +distributed by that particular Contributor. A Contribution 'originates' from a
    +Contributor if it was added to the Program by such Contributor itself or anyone
    +acting on such Contributor's behalf. Contributions do not include additions to
    +the Program which: (i) are separate modules of software distributed in
    +conjunction with the Program under their own license agreement, and (ii) are
    +not derivative works of the Program.
    +
    +"Contributor" means any person or entity that distributes the Program.
    +
    +"Licensed Patents " mean patent claims licensable by a Contributor which are
    +necessarily infringed by the use or sale of its Contribution alone or when
    +combined with the Program.
    +
    +"Program" means the Contributions distributed in accordance with this Agreement.
    +
    +"Recipient" means anyone who receives the Program under this Agreement,
    +including all Contributors.
    +
    +2. GRANT OF RIGHTS
    +
    +      a) Subject to the terms of this Agreement, each Contributor hereby grants
    +Recipient a non-exclusive, worldwide, royalty-free copyright license to
    +reproduce, prepare derivative works of, publicly display, publicly perform,
    +distribute and sublicense the Contribution of such Contributor, if any, and
    +such derivative works, in source code and object code form.
    +
    +      b) Subject to the terms of this Agreement, each Contributor hereby grants
    +Recipient a non-exclusive, worldwide, royalty-free patent license under
    +Licensed Patents to make, use, sell, offer to sell, import and otherwise
    +transfer the Contribution of such Contributor, if any, in source code and
    +object code form. This patent license shall apply to the combination of the
    +Contribution and the Program if, at the time the Contribution is added by the
    +Contributor, such addition of the Contribution causes such combination to be
    +covered by the Licensed Patents. The patent license shall not apply to any
    +other combinations which include the Contribution. No hardware per se is
    +licensed hereunder.
    +
    +      c) Recipient understands that although each Contributor grants the
    +licenses to its Contributions set forth herein, no assurances are provided by
    +any Contributor that the Program does not infringe the patent or other
    +intellectual property rights of any other entity. Each Contributor disclaims
    +any liability to Recipient for claims brought by any other entity based on
    +infringement of intellectual property rights or otherwise. As a condition to
    +exercising the rights and licenses granted hereunder, each Recipient hereby
    +assumes sole responsibility to secure any other intellectual property rights
    +needed, if any. For example, if a third party patent license is required to
    +allow Recipient to distribute the Program, it is Recipient's responsibility to
    +acquire that license before distributing the Program.
    +
    +      d) Each Contributor represents that to its knowledge it has sufficient
    +copyright rights in its Contribution, if any, to grant the copyright license
    +set forth in this Agreement.
    +
    +3. REQUIREMENTS
    +
    +A Contributor may choose to distribute the Program in object code form under
    +its own license agreement, provided that:
    +
    +      a) it complies with the terms and conditions of this Agreement; and
    +
    +      b) its license agreement:
    +
    +      i) effectively disclaims on behalf of all Contributors all warranties and
    +conditions, express and implied, including warranties or conditions of title
    +and non-infringement, and implied warranties or conditions of merchantability
    +and fitness for a particular purpose;
    +
    +      ii) effectively excludes on behalf of all Contributors all liability for
    +damages, including direct, indirect, special, incidental and consequential
    +damages, such as lost profits;
    +
    +      iii) states that any provisions which differ from this Agreement are
    +offered by that Contributor alone and not by any other party; and
    +
    +      iv) states that source code for the Program is available from such
    +Contributor, and informs licensees how to obtain it in a reasonable manner on
    +or through a medium customarily used for software exchange.
    +
    +When the Program is made available in source code form:
    +
    +      a) it must be made available under this Agreement; and
    +
    +      b) a copy of this Agreement must be included with each copy of the
    +Program.
    +
    +Contributors may not remove or alter any copyright notices contained within the
    +Program.
    +
    +Each Contributor must identify itself as the originator of its Contribution, if
    +any, in a manner that reasonably allows subsequent Recipients to identify the
    +originator of the Contribution.
    +
    +4. COMMERCIAL DISTRIBUTION
    +
    +Commercial distributors of software may accept certain responsibilities with
    +respect to end users, business partners and the like. While this license is
    +intended to facilitate the commercial use of the Program, the Contributor who
    +includes the Program in a commercial product offering should do so in a manner
    +which does not create potential liability for other Contributors. Therefore, if
    +a Contributor includes the Program in a commercial product offering, such
    +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
    +every other Contributor ("Indemnified Contributor") against any losses, damages
    +and costs (collectively "Losses") arising from claims, lawsuits and other legal
    +actions brought by a third party against the Indemnified Contributor to the
    +extent caused by the acts or omissions of such Commercial Contributor in
    +connection with its distribution of the Program in a commercial product
    +offering. The obligations in this section do not apply to any claims or Losses
    +relating to any actual or alleged intellectual property infringement. In order
    +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
    +Contributor in writing of such claim, and b) allow the Commercial Contributor
    +to control, and cooperate with the Commercial Contributor in, the defense and
    +any related settlement negotiations. The Indemnified Contributor may
    +participate in any such claim at its own expense.
    +
    +For example, a Contributor might include the Program in a commercial product
    +offering, Product X. That Contributor is then a Commercial Contributor. If that
    +Commercial Contributor then makes performance claims, or offers warranties
    +related to Product X, those performance claims and warranties are such
    +Commercial Contributor's responsibility alone. Under this section, the
    +Commercial Contributor would have to defend claims against the other
    +Contributors related to those performance claims and warranties, and if a court
    +requires any other Contributor to pay any damages as a result, the Commercial
    +Contributor must pay those damages.
    +
    +5. NO WARRANTY
    +
    +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
    +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
    +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
    +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
    +Recipient is solely responsible for determining the appropriateness of using
    +and distributing the Program and assumes all risks associated with its exercise
    +of rights under this Agreement, including but not limited to the risks and
    +costs of program errors, compliance with applicable laws, damage to or loss of
    +data, programs or equipment, and unavailability or interruption of operations.
    +
    +6. DISCLAIMER OF LIABILITY
    +
    +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
    +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
    +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
    +WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
    +GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    +
    +7. GENERAL
    +
    +If any provision of this Agreement is invalid or unenforceable under applicable
    +law, it shall not affect the validity or enforceability of the remainder of the
    +terms of this Agreement, and without further action by the parties hereto, such
    +provision shall be reformed to the minimum extent necessary to make such
    +provision valid and enforceable.
    +
    +If Recipient institutes patent litigation against any
    +entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
    +Program itself (excluding combinations of the Program with other software or
    +hardware) infringes such Recipient's patent(s), then such Recipient's rights
    +granted under Section 2(b) shall terminate as of the date such litigation is
    +filed.
    +
    +All Recipient's rights under this Agreement shall terminate if it fails to
    +comply with any of the material terms or conditions of this Agreement and does
    +not cure such failure in a reasonable period of time after becoming aware of
    +such noncompliance. If all Recipient's rights under this Agreement terminate,
    +Recipient agrees to cease use and distribution of the Program as soon as
    +reasonably practicable. However, Recipient's obligations under this Agreement
    +and any licenses granted by Recipient relating to the Program shall continue
    +and survive.
    +
    +Everyone is permitted to copy and distribute copies of this Agreement, but in
    +order to avoid inconsistency the Agreement is copyrighted and may only be
    +modified in the following manner. The Agreement Steward reserves the right to
    +publish new versions (including revisions) of this Agreement from time to time.
    +No one other than the Agreement Steward has the right to modify this Agreement.
    +The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to
    +serve as the Agreement Steward to a suitable separate entity. Each new version
    +of the Agreement will be given a distinguishing version number. The Program
    +(including Contributions) may always be distributed subject to the version of
    +the Agreement under which it was received. In addition, after a new version of
    +the Agreement is published, Contributor may elect to distribute the Program
    +(including its Contributions) under the new version. Except as expressly stated
    +in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
    +the intellectual property of any Contributor under this Agreement, whether
    +expressly, by implication, estoppel or otherwise. All rights in the Program not
    +expressly granted under this Agreement are reserved.
    +
    +This Agreement is governed by the laws of the State of New York and the
    +intellectual property laws of the United States of America. No party to this
    +Agreement will bring a legal action under this Agreement more than one year
    +after the cause of action arose. Each party waives its rights to a jury trial
    +in any resulting litigation.
    +
    + + + diff --git a/app/src/main/assets/mit_libraries.html b/app/src/main/assets/mit_libraries.html index e5681966..b3cdee88 100644 --- a/app/src/main/assets/mit_libraries.html +++ b/app/src/main/assets/mit_libraries.html @@ -1,5 +1,4 @@ - + + + + + + +
    +

    Glide License

    +
    +License for everything not in third_party and not otherwise marked:
    +
    +Copyright 2014 Google, Inc. All rights reserved.
    +
    +Redistribution and use in source and binary forms, with or without modification, are
    +permitted provided that the following conditions are met:
    +
    +   1. Redistributions of source code must retain the above copyright notice, this list of
    +         conditions and the following disclaimer.
    +
    +   2. Redistributions in binary form must reproduce the above copyright notice, this list
    +         of conditions and the following disclaimer in the documentation and/or other materials
    +         provided with the distribution.
    +
    +THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
    +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR
    +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    +
    +The views and conclusions contained in the software and documentation are those of the
    +authors and should not be interpreted as representing official policies, either expressed
    +or implied, of Google, Inc.
    +---------------------------------------------------------------------------------------------
    +License for third_party/disklrucache:
    +
    +Copyright 2012 Jake Wharton
    +Copyright 2011 The Android Open Source Project
    +
    +Licensed under the Apache License, Version 2.0 (the "License");
    +you may not use this file except in compliance with the License.
    +You may obtain a copy of the License at
    +
    +   http://www.apache.org/licenses/LICENSE-2.0
    +
    +Unless required by applicable law or agreed to in writing, software
    +distributed under the License is distributed on an "AS IS" BASIS,
    +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +See the License for the specific language governing permissions and
    +limitations under the License.
    +---------------------------------------------------------------------------------------------
    +License for third_party/gif_decoder:
    +
    +Copyright (c) 2013 Xcellent Creations, Inc.
    +
    +Permission is hereby granted, free of charge, to any person obtaining
    +a copy of this software and associated documentation files (the
    +"Software"), to deal in the Software without restriction, including
    +without limitation the rights to use, copy, modify, merge, publish,
    +distribute, sublicense, and/or sell copies of the Software, and to
    +permit persons to whom the Software is furnished to do so, subject to
    +the following conditions:
    +
    +The above copyright notice and this permission notice shall be
    +included in all copies or substantial portions of the Software.
    +
    +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    +---------------------------------------------------------------------------------------------
    +License for third_party/gif_encoder/AnimatedGifEncoder.java and
    +third_party/gif_encoder/LZWEncoder.java:
    +
    +No copyright asserted on the source code of this class. May be used for any
    +purpose, however, refer to the Unisys LZW patent for restrictions on use of
    +the associated LZWEncoder class. Please forward any corrections to
    +kweiner@fmsware.com.
    +
    +-----------------------------------------------------------------------------
    +License for third_party/gif_encoder/NeuQuant.java
    +
    +Copyright (c) 1994 Anthony Dekker
    +
    +NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. See
    +"Kohonen neural networks for optimal colour quantization" in "Network:
    +Computation in Neural Systems" Vol. 5 (1994) pp 351-367. for a discussion of
    +the algorithm.
    +
    +Any party obtaining a copy of these files from the author, directly or
    +indirectly, is granted, free of charge, a full and unrestricted irrevocable,
    +world-wide, paid up, royalty-free, nonexclusive right and license to deal in
    +this software and documentation files (the "Software"), including without
    +limitation the rights to use, copy, modify, merge, publish, distribute,
    +sublicense, and/or sell copies of the Software, and to permit persons who
    +receive copies from any such party to do so, with the only requirement being
    +that this copyright notice remain intact.
    +
    + + + diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java index 0f3e9981..1919608f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java @@ -151,6 +151,10 @@ public class AboutActivity extends BaseActivity { title=getString(R.string.epl_libraries); fileUrl="file:///android_asset/epl_libraries.html"; break; + case "OTHER": + title=getString(R.string.other_libraries); + fileUrl="file:///android_asset/other_libraries.html"; + break; default: break; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index 6eff1d27..9435fecc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -1,7 +1,6 @@ package gr.thmmy.mthmmy.activities.main.recent; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 53b7d20b..8b11cc3e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -2,7 +2,6 @@ package gr.thmmy.mthmmy.activities.main.unread; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java index d2a4d1cb..5b401f01 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java @@ -1,5 +1,7 @@ package gr.thmmy.mthmmy.activities.profile.latestPosts; +import android.annotation.SuppressLint; +import android.content.Context; import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; @@ -16,6 +18,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.model.TopicSummary; +import gr.thmmy.mthmmy.utils.WebViewOnTouchClickListener; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; /** @@ -26,11 +29,13 @@ class LatestPostsAdapter extends RecyclerView.Adapter { private static final int VIEW_TYPE_EMPTY = -1; private static final int VIEW_TYPE_ITEM = 0; private static final int VIEW_TYPE_LOADING = 1; + private final Context context; private final LatestPostsFragment.LatestPostsFragmentInteractionListener interactionListener; private final ArrayList parsedTopicSummaries; - LatestPostsAdapter(BaseFragment.FragmentInteractionListener interactionListener, + LatestPostsAdapter(Context context, BaseFragment.FragmentInteractionListener interactionListener, ArrayList parsedTopicSummaries) { + this.context = context; this.interactionListener = (LatestPostsFragment.LatestPostsFragmentInteractionListener) interactionListener; this.parsedTopicSummaries = parsedTopicSummaries; } @@ -64,6 +69,7 @@ class LatestPostsAdapter extends RecyclerView.Adapter { return null; } + @SuppressLint("ClickableViewAccessibility") @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { if (holder instanceof LatestPostViewHolder) { @@ -75,6 +81,7 @@ class LatestPostsAdapter extends RecyclerView.Adapter { latestPostViewHolder.post.setBackgroundColor(Color.argb(1, 255, 255, 255)); latestPostViewHolder.post.loadDataWithBaseURL("file:///android_asset/" , topic.getPost(), "text/html", "UTF-8", null); + latestPostViewHolder.post.setOnTouchListener(new WebViewOnTouchClickListener(context)); latestPostViewHolder.latestPostsRow.setOnClickListener(v -> { if (interactionListener != null) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java index 11a1cb7c..b23cc601 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java @@ -6,7 +6,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import android.widget.Toast; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; @@ -86,7 +85,7 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View rootView = inflater.inflate(R.layout.fragment_latest_posts, container, false); - latestPostsAdapter = new LatestPostsAdapter(fragmentInteractionListener, parsedTopicSummaries); + latestPostsAdapter = new LatestPostsAdapter(this.getContext(), fragmentInteractionListener, parsedTopicSummaries); RecyclerView mainContent = rootView.findViewById(R.id.profile_latest_posts_recycler); mainContent.setAdapter(latestPostsAdapter); final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index 0e885cc3..327fe44d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -73,6 +73,7 @@ import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CircleTransform; +import gr.thmmy.mthmmy.utils.WebViewOnTouchClickListener; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.utils.parsing.ThmmyParser; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; @@ -362,6 +363,7 @@ class TopicAdapter extends RecyclerView.Adapter { //Post's WebView parameters holder.post.setClickable(true); holder.post.setWebViewClient(new LinkLauncher()); + holder.post.setOnTouchListener(new WebViewOnTouchClickListener(context)); //noinspection ConstantConditions loadAvatar(currentPost.getThumbnailURL(), holder.thumbnail); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForEditTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForEditTask.java index 6c971d33..5438132e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForEditTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForEditTask.java @@ -10,7 +10,6 @@ import org.jsoup.select.Selector; import java.io.IOException; import gr.thmmy.mthmmy.base.BaseApplication; -import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyTask.java index 4f1f160c..b45bf50c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyTask.java @@ -10,7 +10,6 @@ import org.jsoup.select.Selector; import java.io.IOException; import gr.thmmy.mthmmy.base.BaseApplication; -import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 22357d76..bd21f61b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -390,7 +390,7 @@ public abstract class BaseActivity extends AppCompatActivity { DrawerBuilder drawerBuilder = new DrawerBuilder() .withActivity(this) .withToolbar(toolbar) - .withDrawerWidthDp((int) BaseApplication.getInstance().getDpWidth() / 2) + .withDrawerWidthDp((int) BaseApplication.getInstance().getWidthInDp() / 2) .withSliderBackgroundColor(ContextCompat.getColor(this, R.color.primary_light)) .withAccountHeader(accountHeader) .withOnDrawerItemClickListener((view, position, drawerItem) -> { diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index 64ad4996..c52a8c98 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -68,7 +68,9 @@ public class BaseApplication extends Application { private static final String SHARED_PREFS = "ThmmySharedPrefs"; //Display Metrics - private static float dpWidth; + private static float widthDp; + private static int widthPxl, heightPxl; + public static BaseApplication getInstance() { return baseApplication; } @@ -175,7 +177,11 @@ public class BaseApplication extends Application { }); DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics(); - dpWidth = displayMetrics.widthPixels / displayMetrics.density; + + widthPxl = displayMetrics.widthPixels; + widthDp = widthPxl / displayMetrics.density; + + heightPxl = displayMetrics.heightPixels; displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, false); } @@ -193,8 +199,16 @@ public class BaseApplication extends Application { return sessionManager; } - public float getDpWidth() { - return dpWidth; + public float getWidthInDp() { + return widthDp; + } + + public int getWidthInPixels() { + return widthPxl; + } + + public int getHeightInPixels() { + return heightPxl; } public boolean isDisplayRelativeTimeEnabled() { diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index a907e057..36def1de 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -19,7 +19,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import gr.thmmy.mthmmy.utils.parsing.ParseException; -import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import okhttp3.Cookie; import okhttp3.FormBody; import okhttp3.HttpUrl; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java index 950d9934..9ae5a309 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java @@ -11,7 +11,6 @@ import java.io.IOException; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.utils.parsing.ParseException; -import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java b/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java new file mode 100644 index 00000000..43a5b40e --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java @@ -0,0 +1,79 @@ +package gr.thmmy.mthmmy.utils; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.Window; +import android.webkit.WebView; + +import com.bumptech.glide.Glide; +import com.github.chrisbanes.photoview.PhotoView; + +import gr.thmmy.mthmmy.base.BaseApplication; + +/** + * Workaround for WebView's inability to send onClick events (sends only onLongClickEvents) + * If an image is find when clicking it will be inflated as a zoomed/zoomable/pinchable PhotoView + */ +public class WebViewOnTouchClickListener implements View.OnTouchListener { + private final static int screenWidth = BaseApplication.getInstance().getWidthInPixels(); + private final static int screenHeight = BaseApplication.getInstance().getHeightInPixels(); + + private final static long MAX_TOUCH_DURATION = 100; + private final Context context; + private long downTime; + + public WebViewOnTouchClickListener(Context context){ + this.context = context; + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + downTime = event.getEventTime(); + break; + case MotionEvent.ACTION_UP: + if(event.getEventTime() - downTime <= MAX_TOUCH_DURATION) + onClick((WebView) v); + break; + default: + break; + } + return false; + } + + private void onClick(WebView webView){ + WebView.HitTestResult result = webView.getHitTestResult(); + if(result.getType() == WebView.HitTestResult.IMAGE_TYPE){ + String imageURL = result.getExtra(); + showImage(imageURL); + } + webView.performClick(); + } + + private void showImage(String url) { + Dialog builder = new Dialog(context); + builder.requestWindowFeature(Window.FEATURE_NO_TITLE); + builder.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + builder.getWindow().setBackgroundDrawable( + new ColorDrawable(android.graphics.Color.TRANSPARENT)); + + PhotoView photoView = new PhotoView(context); + photoView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + photoView.getLayoutParams().width = screenWidth; + photoView.getLayoutParams().height = screenHeight; + + Glide.with(context).load(url).fitCenter().into(photoView); + builder.addContentView(photoView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + builder.show(); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java index f5198410..50ca9870 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java @@ -1,9 +1,7 @@ package gr.thmmy.mthmmy.utils.parsing; -import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; -import org.jsoup.nodes.TextNode; import org.jsoup.select.Elements; import java.util.ArrayList; @@ -11,8 +9,6 @@ import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; -import timber.log.Timber; - /** * This class consists exclusively of static classes (enums) and methods (excluding methods of inner * classes). It can be used to resolve a page's language and state or fix embedded videos html code diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index f41fe45f..87d99723 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -142,11 +142,22 @@ android:textColor="@color/accent" /> + + Apache v2.0 License libraries The MIT License libraries Eclipse Public License v1.0 libraries + Other libraries Contact Do not hesitate to contact us for any matter either by email at thmmynolife@gmail.com, or by joining our discord server at https://discord.gg/CVt3yrn. Open Source From 3c513fc201c1939914b1398875d06391c8724bd5 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 18 May 2020 12:17:53 +0300 Subject: [PATCH 23/53] Fix Uploads' Take Photo for Android 10 --- app/src/main/AndroidManifest.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fd302031..a808255e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -9,7 +10,7 @@ - + + android:requestLegacyExternalStorage="true" + android:theme="@style/AppTheme" + tools:ignore="UnusedAttribute"> @@ -67,6 +70,7 @@ android:name=".activities.LoginActivity" android:configChanges="orientation|screenSize|keyboardHidden" android:launchMode="singleTop" + tools:ignore="LockedOrientationActivity" android:screenOrientation="portrait" android:theme="@style/AppTheme.NoActionBar" android:windowSoftInputMode="adjustPan" /> From 338776d61522af9cb3b224f3e6f86983991d546e Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 18 May 2020 13:39:13 +0300 Subject: [PATCH 24/53] Up libs, libraries popup cleanup --- app/build.gradle | 16 +++---- app/src/main/AndroidManifest.xml | 2 +- app/src/main/assets/apache_libraries.html | 42 +++---------------- app/src/main/assets/epl_libraries.html | 34 +-------------- app/src/main/assets/libraries_style.css | 28 +++++++++++++ app/src/main/assets/mit_libraries.html | 34 +-------------- app/src/main/assets/other_libraries.html | 36 +--------------- .../mthmmy/activities/AboutActivity.java | 22 ++++++---- .../gr/thmmy/mthmmy/base/BaseActivity.java | 30 +++---------- .../gr/thmmy/mthmmy/utils/io/AssetUtils.java | 39 +++++++++++++++++ build.gradle | 2 +- 11 files changed, 106 insertions(+), 179 deletions(-) create mode 100644 app/src/main/assets/libraries_style.css create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/io/AssetUtils.java diff --git a/app/build.gradle b/app/build.gradle index 981f79dd..5df924a7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'io.fabric' android { compileSdkVersion 29 - buildToolsVersion = '29.0.2' + buildToolsVersion = '29.0.3' defaultConfig { vectorDrawables.useSupportLibrary = true @@ -75,17 +75,17 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(":emojis") implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.preference:preference:1.1.0' + implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.legacy:legacy-preference-v14:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-beta01' + implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.exifinterface:exifinterface:1.1.0-rc01' - implementation 'com.google.android.material:material:1.0.0' - implementation 'com.google.firebase:firebase-core:17.0.0' - implementation 'com.google.firebase:firebase-messaging:19.0.1' + implementation 'androidx.exifinterface:exifinterface:1.2.0' + implementation 'com.google.android.material:material:1.1.0' + implementation 'com.google.firebase:firebase-analytics:17.4.1' + implementation 'com.google.firebase:firebase-messaging:20.1.7' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.snatik:storage:2.1.0' implementation 'com.squareup.okhttp3:okhttp:3.12.0' //TODO: Warning: okhttp has dropped support for Android v.19 since okhttp 3.13! diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a808255e..66be4558 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ - + - - - - - + + + + +
    • OkHttp v3.14.2 (Copyright ©2019 Square, Inc.)
      diff --git a/app/src/main/assets/epl_libraries.html b/app/src/main/assets/epl_libraries.html index 5cbc1519..23802d2c 100644 --- a/app/src/main/assets/epl_libraries.html +++ b/app/src/main/assets/epl_libraries.html @@ -1,38 +1,6 @@ - + diff --git a/app/src/main/assets/libraries_style.css b/app/src/main/assets/libraries_style.css new file mode 100644 index 00000000..39372a93 --- /dev/null +++ b/app/src/main/assets/libraries_style.css @@ -0,0 +1,28 @@ +body { + font-family: sans-serif; + background-color: #333333; +} + +pre { + background-color: #3C3C3C; + color: #757575; + padding: 1em; + margin-left: 1em; + margin-right: 1em; + white-space: pre-wrap; + word-wrap: break-word; +} + +h4, h5 { + display: inline; + padding: 1em; +} + +a, h4, h5 { + color: #26A69A; + word-wrap: break-word; +} + +li { + color: #26A69A; +} \ No newline at end of file diff --git a/app/src/main/assets/mit_libraries.html b/app/src/main/assets/mit_libraries.html index a1cce5c6..cd30b2cb 100644 --- a/app/src/main/assets/mit_libraries.html +++ b/app/src/main/assets/mit_libraries.html @@ -1,38 +1,6 @@ - + diff --git a/app/src/main/assets/other_libraries.html b/app/src/main/assets/other_libraries.html index 53edb44c..59b89569 100644 --- a/app/src/main/assets/other_libraries.html +++ b/app/src/main/assets/other_libraries.html @@ -1,38 +1,6 @@ - + @@ -83,7 +51,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java index 1919608f..8ff6dfe5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java @@ -1,7 +1,9 @@ package gr.thmmy.mthmmy.activities; +import android.annotation.SuppressLint; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.text.SpannableString; @@ -26,6 +28,7 @@ import gr.thmmy.mthmmy.BuildConfig; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.utils.io.AssetUtils; public class AboutActivity extends BaseActivity { private static final int TIME_INTERVAL = 1000; @@ -137,31 +140,35 @@ public class AboutActivity extends BaseActivity { public void displayLibraries(View v) { String libraryType = v.getTag().toString(); - String title="", fileUrl=""; + String title="", fileName=""; switch(libraryType) { case "APACHE": title=getString(R.string.apache_v2_0_libraries); - fileUrl="file:///android_asset/apache_libraries.html"; + fileName="apache_libraries.html"; break; case "MIT": title=getString(R.string.the_mit_libraries); - fileUrl="file:///android_asset/mit_libraries.html"; + fileName="mit_libraries.html"; break; case "EPL": title=getString(R.string.epl_libraries); - fileUrl="file:///android_asset/epl_libraries.html"; + fileName="epl_libraries.html"; break; case "OTHER": title=getString(R.string.other_libraries); - fileUrl="file:///android_asset/other_libraries.html"; + fileName="other_libraries.html"; break; default: break; } + String htmlContent = AssetUtils.readFileToText(this,fileName); + LayoutInflater inflater = LayoutInflater.from(this); WebView webView = (WebView) inflater.inflate(R.layout.dialog_licenses, coordinatorLayout, false); - webView.loadUrl(fileUrl); + webView.setBackgroundColor(Color.argb(1, 255, 255, 255)); + webView.loadDataWithBaseURL("file:///android_asset/", htmlContent, "text/html", "UTF-8", null); + int width = (int) (getResources().getDisplayMetrics().widthPixels * 0.95); int height = (int) (getResources().getDisplayMetrics().heightPixels * 0.95); alertDialog = new AlertDialog.Builder(this, R.style.AppTheme_Dark_Dialog) @@ -173,9 +180,10 @@ public class AboutActivity extends BaseActivity { alertDialog.getWindow().setLayout(width, height); } + @SuppressLint("SourceLockedOrientationActivity") private void showEasterEgg(){ if(getResources().getConfiguration().orientation==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){ - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //TODO: why? appBar.setVisibility(View.INVISIBLE); mainContent.setVisibility(View.INVISIBLE); easterEggImage.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index bd21f61b..6068304a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -45,10 +45,7 @@ import com.snatik.storage.Storage; import net.gotev.uploadservice.UploadService; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; import java.util.ArrayList; import gr.thmmy.mthmmy.R; @@ -67,6 +64,7 @@ import gr.thmmy.mthmmy.services.DownloadHelper; import gr.thmmy.mthmmy.services.UploadsReceiver; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.FileUtils; +import gr.thmmy.mthmmy.utils.io.AssetUtils; import gr.thmmy.mthmmy.viewmodel.BaseViewModel; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.OkHttpClient; @@ -840,32 +838,14 @@ public abstract class BaseActivity extends AppCompatActivity { privacyPolicyTextView.setPadding(30, 20, 30, 20); privacyPolicyTextView.setTextColor(ContextCompat.getColor(this, R.color.primary_text)); SpannableConfiguration configuration = SpannableConfiguration.builder(this).linkResolver(new LinkResolverDef()).build(); - StringBuilder stringBuilder = new StringBuilder(); - BufferedReader reader = null; - try { - reader = new BufferedReader(new InputStreamReader(getAssets().open("PRIVACY.md"))); - String line; - - while ((line = reader.readLine()) != null) { - stringBuilder.append(line); - stringBuilder.append("\n"); - } - Markwon.setMarkdown(privacyPolicyTextView, configuration, stringBuilder.toString()); + + String privacyPolicy = AssetUtils.readFileToText(BaseActivity.this,"PRIVACY.md"); + if(privacyPolicy!=null){ + Markwon.setMarkdown(privacyPolicyTextView, configuration, privacyPolicy); AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); builder.setView(privacyPolicyTextView); builder.setPositiveButton("Close", (dialogInterface, i) -> dialogInterface.dismiss()); builder.show(); - } catch (IOException e) { - Timber.e(e, "Error reading Privacy Policy from assets."); - } catch (Exception e) { - Timber.e(e, "Error in Privacy Policy dialog."); - } finally { - try { - if (reader != null) - reader.close(); - } catch (IOException e) { - Timber.e(e, "Error in Privacy Policy dialog (closing reader)."); - } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/io/AssetUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/io/AssetUtils.java new file mode 100644 index 00000000..2ceb81d4 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/io/AssetUtils.java @@ -0,0 +1,39 @@ +package gr.thmmy.mthmmy.utils.io; + +import android.content.Context; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import timber.log.Timber; + +public class AssetUtils { + public static String readFileToText(Context context, String fileName) { + StringBuilder stringBuilder = new StringBuilder(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(context.getAssets().open(fileName))); + String line; + + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + stringBuilder.append("\n"); + } + return stringBuilder.toString(); + } catch (IOException e) { + Timber.e(e, "IO error reading file %s from assets.", fileName); + } catch (Exception e) { + Timber.e(e, "Error reading file %s from assets.", fileName); + } finally { + try { + if (reader != null) + reader.close(); + } catch (IOException e) { + Timber.e(e, "Error in AssetUtils (closing reader)."); + } + } + return null; + } +} + diff --git a/build.gradle b/build.gradle index efe5d780..d68e60f8 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.6.3' - classpath 'com.google.gms:google-services:4.3.2' + classpath 'com.google.gms:google-services:4.3.3' classpath 'io.fabric.tools:gradle:1.29.0' classpath 'org.ajoberstar.grgit:grgit-core:3.1.1' // Also change in app/gradle/grgit.gradle classpath "com.github.ben-manes:gradle-versions-plugin:0.21.0" From 540fda984d781d510b3a4f4812d3da97f3e354c4 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 18 May 2020 14:02:58 +0300 Subject: [PATCH 25/53] Adjust color of letters in yellow glow --- app/src/main/assets/style.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/assets/style.css b/app/src/main/assets/style.css index 7415c141..f2b8c557 100644 --- a/app/src/main/assets/style.css +++ b/app/src/main/assets/style.css @@ -537,4 +537,12 @@ img color: #a51111 !important; } +span[style="background-color: yellow;"] +{ + color: black !important; +} +[style="color: white;"] > span[style="background-color: yellow;"] +{ + color: white !important; +} From 82b37217e19684372a8047a161fc0a6d27d1d1de Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 18 May 2020 16:07:32 +0300 Subject: [PATCH 26/53] Up OkHttp (bugfix release) --- app/build.gradle | 2 +- app/src/main/assets/apache_libraries.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5df924a7..9eff4099 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -88,7 +88,7 @@ dependencies { implementation 'com.google.firebase:firebase-messaging:20.1.7' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.snatik:storage:2.1.0' - implementation 'com.squareup.okhttp3:okhttp:3.12.0' //TODO: Warning: okhttp has dropped support for Android v.19 since okhttp 3.13! + implementation 'com.squareup.okhttp3:okhttp:3.12.12' //TODO: Warning: okhttp has dropped support for Android v.19 since okhttp 3.13! implementation 'com.squareup.picasso:picasso:2.5.2' implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' implementation 'org.jsoup:jsoup:1.10.3' //TODO: Warning: upgrading from 1.10.3 will break stuff! diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index af0e7ce6..e2addec6 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -6,7 +6,7 @@
      • -
        OkHttp v3.14.2 (Copyright ©2019 Square, Inc.)
        +
        OkHttp v3.12.12 (Copyright ©2019 Square, Inc.)
      • Picasso v2.5.2 (Copyright ©2013 Square, Inc.)
        From 8c00dcf052448ae07d4a58460c23d412063b161f Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 20 May 2020 11:51:21 +0300 Subject: [PATCH 27/53] Adaptive launcher icons --- app/src/main/ic_launcher-playstore.png | Bin 0 -> 13022 bytes .../res/drawable/ic_launcher_foreground.xml | 23 ++++++++++++++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 ++++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 ++++ app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2491 -> 1152 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 2743 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1536 -> 805 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 1664 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3408 -> 1998 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 4224 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 5348 -> 2979 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 6554 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 7674 -> 4560 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 9747 bytes .../res/values/ic_launcher_background.xml | 4 +++ 15 files changed, 37 insertions(+) create mode 100644 app/src/main/ic_launcher-playstore.png create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/ic_launcher_background.xml diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..589b4e57ff20a1396c874929d6f8f8a6bd352007 GIT binary patch literal 13022 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000..d24184d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..7353dbd1 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..7353dbd1 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 574423f07b4640a8d99b39118ce7580b504fc18d..dd0aa1f5bca1cab1a326a5e387638243647bc226 100755 GIT binary patch delta 1132 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 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..69b75862b1fa029f0435368e9ded9f40f2be22ec GIT binary patch literal 2743 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index daf77a41820316cf53dd5e46d2cfdb0c68738256..cfb924c4360c83c110090b22c1b4ca25bfa16f13 100755 GIT binary patch delta 783 zcmV+q1MvKS45bE;BYy(yNklHMd3fu>eQf{EM zv^;Dz(CR`;8q>HjO;by#Ew<4ZO&4wqzP^DA6WzG+12t-^E?t=8IU_WvKyGd14(3ks z&)k_gbLaoN^9W&jdW^(z%H?t;ODzXlUpqT07JdpuSl!*oFWfs1xSj zP~W{?uP&mo$wLj`qaX;U8@>LLXvb5ILFcj4XX->R(fiBSJs`lB{{H?8jb57qxLhtL zcG~3>U_cW9uYWVp*VpGZ01N;FzyL4+41kURL}zCpl1a1YNHz=V)tT-AkV7Gudh`HN zlq6QBdTQ?|fD(y7Xnai5VDzPF$&m4;F<4LS^%>FfzQ9=GU;weX>yUq5h3v*U zOm98>Q+PaPH!Bdp!PINBK=JKNQ9H%ab9}xCm+o&ie=q9F<1LuFw{b84DG*>MNjp>V zVgaHvd4HH(S%zRd);5;fDUQBwdab;-yqZZ020;vm{{0>ZC&$suDomDcw_ZLC%ZTD= zZ^ViPJ~pu^%aDIj#aYN{`vTF@yv~5b;keimpnhq9lxGm&6K@wB9)FK#$8NVfS^_j&F&%fi-LJ4CH`hz# zMG%D7=|BHJi<}d`wzzDv9)*)oP8~ zY_^P^LJyD%PDHLkV1kZtct`*M delta 1519 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 KMNUMnLSTXfU>e5& literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index c48ce65d5ff2392e2ef297c68f71838823682b97..ac34512e5b6806123e032eb5cfc00d3482869d72 100755 GIT binary patch delta 1985 zcma*o`#;l<0>|;sQf@IRCf2YN$t}!e3)4pQMMNc+OhPl#gofEiGNy7Jm3Bccp&PlC zl4~oQOD^duWV9Ul61h+3`*@tk`Sm=`^S9SO@P5D5=uyhj0cG->2zH*-Pd~ZwZi6RO zUb~~*aT-a;8u!z!*_Mq;Un4}4lxQ_rR%%kx`QT6+mb0m;KdB-+!tNEVq#}qkghIPy zP@i7mrNqrHOm#y@Dz<+Ir!?7L9-W8ruMLD@x_lGA9P#Wp?j4*y!63*MJ-!Y~w zN&yO`!;X1n(zi%pt9}dE{=S=EsND^FjHaB}kGwl=e(AZ~5nb17%z#eABymJyVey(f-d@#X7q7aaVtI6=c8T1mw&bHwDDKZUJ@zQbgc?N1~oQ&NEm#ng2Rp;=4m#&NL2D zj>oIx{9_%XRB{udHbo9SLa!OFrN@=8Z1_0xJcPiiAdr#_o&qI%bGbH^RP5+LE zSq%XQ6~qUr{pl%?1;%&uBgT3+ocO7;cw0Vi$jbce*~0bd)NREBhkwkSR4&_@_+?DS z-q5aK)a zmuWX&Qk6wucvweONpkWJRpP-~5ZCtBLs466OAjqPpNh!NQOHxXft+w;QXh}h?Z^oY zNqZk4H|G{PeSi=YVhXIZ9YYyEIfBI4Hds$|xaqVh^J(5U3`{sznYDw9e~+&vHCWoM z=A2Sb^wspYQB*KmvqNYOAtPtlWbOO(Ey;R%X1@ixa&++ zkj^q)!EvDVy&QIn|0&;beruOyI0I8nrc>MbfaXBm zXMON-LBw2*$f_n__0{}Sbh6Kxr<8UWm)#D;aV5m%isc1ELP?p|I!8X@F!8Tq4s0q~ zF{>$buar1?xq=5_ti|Lr3V0Ys*{@6YR*e)CWdT7mEBHP0cxy4nk%Ub57K~RsQP)u0 zT2yU1Tz0+ovrEEC=~t6cD({K89GBC7pUEr?b3*Yrm&SYP_7mBP7jSC4q zv<)b4uf+}d{jm$9o82-|eHJ^@Xz}!tpVFsrA6%;bUHX!%`+a@P(^I1PSE*206H@q< zZ#vy>Rne?B-?d;7{L)@+L(}S|;_XN1uI-_3PD>g;Zn7y2E)(y_v%IFH)j{8-0{*S| z!DLFW`_Po-JFa~F1sJ1+lXBv$CGSuJwDRTZuHZjWs@p?6p}T;_tQWt@)#hr*t${|- zX5@*;H(oC{_rto>EZBQqxJ{iqY_Hy-3O|7DyZ#neoKtx-_sk?3jT__Xve^2$BWgvm zm6{oEW;jF4Uzx|)wfK1E6OY&S1z>sQ(FA5^Z@ar+VuImz__Jg|WS`7_N=Z+F4Cy+I zNfw@&$CQ|yVPfZC*+5ixi}aq&%A4i)4&BrcClN??8qXU2uv>8CakJl#zpdwIxTrIp zw>7!wz8m~{u$w-$FY(NL4=1^YjF20eR2N?8G4_L&?k%Mj(u|f-p^tu0(cS z+xOKR*s4D@i1!vT-j{BCnl+Gx4Sl(R zY616LG;WWMk6*eZdXrrXV8@-Qd{=4s9&6?EwW+D8P>&tW9J9Fr*>L5i%jbl4UEy$=B@yUxzOU-|I?^C%38`Moh z-L+t$YFK?tQI)ce!wZ}qPN~CQx9#0K3#|}_W(czfhB)$!hr$`{cG}VJ(0~3mr?{Ey zAQ}~m#bcwRqiK(u`V!tIgnx08is(_^UP{!I4Ha3k7w)E2knzo{;pnaGC zp=qkLiSV%!66Mndn?#tVp>3+5f^MK~#k5;XAz2NC_m>0;34Z~aI8H*|?LE(P|2r4o_9eMTIyv~xcjw>ld4A8!nL7Z-9GlK2O{SBrt*tG`mvRG}`kI@Y{SE<%0bL`O zwF2~V6T9-^(uT`LT)aq%*C8M>==B2ZdXr!qH6r1CT#h3lZPS_n1f4v5hXB1W4W~d6 zas-#gbV-(!CV$}H6u{TmNDUfs*_-O9kkSDBo+L|*6%w^KRrx|n5%6{Ra@gj;rzIk! zBm+-??-v?B8IAJ70VJVe(h-2*?-X)V2$SC^S#L!me6}Y5fiDztQx8+i{6do6wJian ztUNZ!wBAf^*kx7ODp?4Az3}`(nEFOiw9X0=To#s>$A6{?_#pb1&qc(iHv$Cshhch} zUqpg0Ed)$+@GT)ha=^EYgcr=@1j!`$)Y+bKa8EojyG($ul$wrBOw4gBg4;xsHP!3< zL~LnUS((()(cw*21ndEOjgakVdxS(=n*&6n5d1=sbh9074H@B; zjZ$>lDt`%@DpSo=+D;=<r1?7?JWbhtD~Zi**vg|tfh&ggJKmqpDd&xhhQtHDj{k%Y-0Lmne6r5Aq$7{T`B z=EB0AzkrOQA_xtSK-Z_|AT%}x5DGEa?wlN0xJzE&I{aJk`!4c&-o{==4t{)cM1Z2} zNPj?1`2q$vI5Y%#ODb4u6wN1say9FVR`>(7P`*A;>q;(+44U@giQQkU#|W-@XGwj~>BL$0I0O zwNhT^a_OE+Q&SVaMrcH%t`9%wva&L0XlO8un@}3vB)lRX0=948KJKKn|F*LH%zs_H z5JtMY;aO`N6Vrd^E)-N(L)RzgI0@%fEauILoH5J+{-$Oq{>Bd4j*Kt?flDp2&SPIdB;;3DF)6f;mZ2w4n2@4Z zRz;K{GV(d+ec6d2t;l6g`Y0d&IQx*G0*DhEP-3V)U@gOM(j zpL_Qqgam}}{h_B%S&}FZjP>_JcIjMr{P$B38Xc8ue|+t2xdMeNYtlQ~wC_)r$+_;fn zV`;zE6yQyOujGKJ!#G>WPu83gmY=?xw;5RWZXy6*pWVI78lSsl3I5&6F*oXAcWFB`$6z&+DY17 z@te2d-X9J_*SXI)5`Wmk$!o-L?yH-B#5v;XFW-idzCIX3o#){k?uVwM87M1D8h*_s z?1Q6!fl=HhsFRG-V07n}btzB6M&*aRzhL=z`C;#;1;Hf`AH#0==|>;)Xkrw%Q-P%j z!2Qs_pUY4cxc(;cfS91##XN>RQ!`WH(@*3}Xg{m@Tb=z-^M4g4Kk9Y_Fv$?U-*@vC zRyemA)KECEw2hFVS+BjyJ;T`b8}k1262JB}0r`CXwL+>x=vbR^0+fza%v^ZqA{m+{ zL4c_4Cv5bPRU%hEo&Pu`S3lv$5<0JbHvEe!`=@H?iwANwv}z?cYZPJX{=zPEN{J94 z_QU(YeJc?d0e`1^kqGdPo7RaFq;{X?EpxxWffHZn>3_;iQDlar<1b1{rL$EM?0ESZ zgn&;YKYCFV<=AR6=APgRk1NK_hD5JH@A3OlI%Y!(fuHr{=RxTYHsP^@@bItial^>p zFUom(jA$|uQ2y4>AahnRxRx)29Q-n%(d4+jA74hgx__YagHtf@@FCA{NHP@pDX6YO z`DsyWf3uOM5a2(50cO4aDn}OO3+jqpL_k&+Cw#ihnUCeFWJZQG7-SX~Lnd7mLIQ@d zdvAa57#|-*RD?OYE&*pj?}`}iU>L)g2p}71ZIc@xt$f6pXlcN<=vTYp);s%P;K4&a zQIa1|UVk1B+MaqplB3M5)M;esnP|!i(0K;h+aV+_3=Zx>{(QA zjrE;E=+DsMnHg}zHQp~j{x6jO{4JRK zy$x``@sH}YT}6I+u=)umSh0je6c7m{Lxrnq;eW}$Kjg?F`Jv00RL0)>-R~iA?Yiu( zW}HfqGgOM%YhPyxdh)Li<^AbMrS|_6hZEq_^CG&=O2e>$hwW;DF)a-usnciu7n-5u z+w1wnL!!Q?&Xwgy+k7QZZ7CI#DnoPTK&YdG$);&3O-%z=ufZsKe^B%hrpsp}q2uHS z&wrD!e*W@C?1Tj~;u0E4hp2F*bcCGv7xn)C4j{h!6KAqPWl@)E8?M z;f-20(oPlWF}WySIrLbb+mq~2GMrhnoPQ6;@*`$Hi8f72HAMM@W=2KWU(m5;ERcUi zL5-d&rxtuKbs!k|+|R}$;H;qr$_h}ZQEF=Du`(q@`ZWVJU+P@nisNZ!LljwArE?)` z?pLrcsFg2sVuFrX>RQog#&B>w0*9!Cv_gKgV2Emnm@;H$}rJ(e|nCS@Gv%l zd?6Y@^2_@8@HsR{!5Y zTzy6*i0nX0z!%9_=_`^3h^8k<`muDz&*=S)x`7$#6XM>tL9W?TvQZ8Y5RA_Bt3Qr2SEEbsUobkqeGHSemk3F{|S^cI0>P zjJxiS>9~gOm?ipxA^h{Z4z7k1?>fY7&=LX!3FlJQoK1e)Z1hgL@%{{8E9hLdbZne8 z8j&7#924)}#cgapcW~A<8hKMe#35>6ut^o!r= za;GiQ`VCe*SIp|iSk=MQf0&OKmp5$p7%L44<${E%m>1qf;CETM!+&Hx%CG^Z&W&G5 za<(Sp39HF|n5XhskI5VjG|%6gtOq`)>T$M{@xh+t?Yolk0MC>YAV?taiHIFGC!$RN zpOTAEDZiDJhKQeny&eWc9)BQJz^9FXFf!@|5$Wn5lwT|yNcFSiZ9za-R1gVt%gnkY zOB4Z3UVb*!-fmk0B1bfIR5`5`GL=XbMbbiv^diW&2xzm@ceNz}QA*lEvD8G76s2nM kC98CF%rVETvi}P(0CLv|%twZh5dZ)H07*qoM6N<$g60^BegFUf diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..7026f78c5b2d86fb4c22a977503415a106bdae1a GIT binary patch literal 4224 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 M07*qoM6N<$f@(geH2?qr literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index ef352f406ad09acbe3fad01d8462284ea4638c08..f82b9f4493cda48b75810f90b3bfbbe29c5a942c 100755 GIT binary patch literal 4560 zcmd5=cU05Qvj2k82}OFOiPEJBxfE%k_t1L)0TF@}sZmIXAgCBYq>9p{hu)>5XeiP< zNR=iX1q_6C^ZW0<_s2W;&$s8y&YrU~yPw&enJq6(O>{xDU|IkGK>B)G<|N+n4^dN+ zYV+BLQ~pLM9%DFga##9f$^ZL8V-sQ8GT>6);C%;g1d=%=u(&|P_>7^6E+ll<-sh7AOg zUs+fgAgHv5EjX;FdvnrLMtydX{;!x$6tk(h`G~5Dii-bAcLI;dC7UuJ)xqL3e<;b9 z^7+&4QiH0p&rB|=mSrzqz1qrW%lCfj*&9K@*g>~@;VI5vEBlsH##O6e!lTTM*m-HO z6=5IYd2Vu&zrP(3&9O+c{Mrb1@w;)Yk9Z)_F#8s#wsJ#4+sx?~ld?r>YWToe`mb?c zzFk;sb>8`-&pVJp8@a2D#{yT&MF%}n8J`L533$unRJ{fr<(v}QyS{#X7`#C@rOHDq z9Zm0Fd?MA9Xl&+0o!MA~%8LPAug8x&)CaeZ2TqO^G^3bQO*aj0n07vAv|(muKFQQ! z-LX71l+75;06z$P$Gv-U#tr^Z9_lfE z5kPrE4%W;wE4jh^6$3IGS_^9{c68gVlLISF)2*>yr1+pJQX|Sqa|Re>$^z zPniJn#lYS)I~=ZEC71p3@O9ebpED4UQ({tLE<3kkwphDT@tQXhfmSYbNKhmhb(|@r z(rArU3nY}_Hn*g#ro;S7KA9aALiHXa+SE!s+FKpiN*yI9IsE2CP&DM~K)CSva54Qz z>gHbCHH%cfGc5_FlXnJO&X#+@+Kls31$>v?QHUU?@>+hncs^eyZj#Ew{MxrYxV7gM z;~xkM*1ttX-%j4l=xOzN)H>7`egKgoN^G7m@|Q@8jFTDO0oIl|H59Zi^**pq$S$pU_3`wu?;bNv@K z2Y(|(An47Nmw&+KS+R*(C4V$e?>l9eZ{7Lsp}(URws(C5yjVBvc91XlE@FQVeOHR4 zX(Xz>oL8Sk=%ErrA9_BPkQ6lwjU?c3HO^1C8G_d?Jt2-U=Ii0dDP*@XYJ21nPdf_QBd48j`)5Q95=c3;p7|k&OAr1;Xin+wUt_-J8E9%P2We7r;Zh@ zh`oky*W7I+ai}@Xl8oic;8rQ8R5{N%FlnW>MT3wsQLp5>EObM+;orGyn%`&Pj+78+ z$5fdxkGTU{i&(2<-y4Ku7%-GWgIuTFDLQ%+x{p+ z-ZvLxsY1*E`A}@Gn*JT^%Q`h%yy*hvyPw9ejiB}GR+X;P`Df1Sgyl))sm09^Tm`JS z8WnbqFvkMN-77Y$8&YFm+@5D7I%g);xwMU~7eNH6=vR%{36 z#YDDGW|#3p6z1o(e<>8lb+fXgn?~ufLir%N^w_9(0D*jYMC@86u$HyO15CjCJT)2` z#M<==17c!bWy{iKR$7tAF1kNqQ0)wZySOMl$MNE2=F5qSQZDU!?=MO0Z0`|@)hI_2CFjUC<$;mvE z^p#nH_|~~$;bYX!%4=9JB$`kr09?&J3PtyaqYB+Z8eH$?3iXS%ojGE$_gUuax!+Ru zzmwRoo^JL#`4;n-+~uH7jTCPQuW!G!a|4h2rJWD(l4ZMZ>8$6a$%B&<%GdagZ6{ds zO}JqIwYqqLTIjrxA!kAB@x$B{vCe&q%;^FIT4C~dCyqz}z=u4vdrnZ2;8q4PrYgL2 zq_4RA;o*_(-#1pOd$A*&M)gYs*Fk@Wg`1?{#^ud&>k=)xz!z)mBV{L4Y6&OLRwAoN z?pWIr;8&Jlk0i!%fRj7rjo0s58&9`cjZ{>9PrXLk^FQfr%i2AiWE$RQXgl+q2sQR$ zW`K_hfOwWNu2$!cjIL&j=c(r&9603D>qSWupINL|=8vQjO-5XwoV5Iq1AYPQvvo#F zffmk49SH2dYHoy7B7LFP_-1U9qA$|75;ySOd(QIqO-%`&W1jn?wPrzN<9)I zOd#M_v zPL-x0J~7LSjE1{=%!u&YjrF@r&+6h8_9Rl=@9s6T+iPyUTfBfjajNJQ4V|dbQZ#F9 zB*$!>g8`$hIKIBPb`jS=k5QzOYNe|K0wQCnn_x!Nvn0uq!xjt|H zGG5yciL|}?AoYT}_hx4mFY%^AHiz(d&wy;kpKrqPzHJQUkDUa<#}g0ig!I#&CGJ)} z^2C?hw4|$f9ptJPY3r`97k}-;T0`FUm2a-`P&s@nycKp^d?X83BkU0V=lj76%k;7B zG}eRKBFU0j8TZZpP}W+l$BA8Q-Xd=mXx$rpf?!lOp9{-ehZKJFLLEe^Wk-XLZ#sRW9$u$$1EKoWo~odZ9IG zeVdYaQwu9^7FCk)QOHjhG&X6G^V(#DVU`RW`;7TD9=+#hNNp%!s#+@DDrbbS3>v%6Izenp-GwwSW#gU+j_L!eV1#BWE0dR0BVw z;m!luJ`&v+Bn76fG@%n!FL}2u40sdwPTr>Nos&t)=|uCgJ?VnvulNg5oX293^+QtK zC4~zw_GA(5klO6B3ODz?tzeiTXJ++5$@gD#h5w|UPyM^E+7xi?+$#J!8eO&wwHea$ zYpar$$q!7r3r_T5D!vR`a~_bm#43YpQjFM35$V#6{o~pFD z+rYWk&M<#?A!iD|o0V{b)-{YcJNvi$eIm(LC91)$+9CDfW#$eFigAD`T7q1ibUyw+ zASz&;23WNL4tM98Wog-%nG-(J5yi=})30EPii#FAG&SiKAr>1mS1^^8l_taold32p zJ&%m**LIqJ-W;CJ#n33qbDPPtTmVxXCCkt{}A8=>n}^@Xkz~ zaEpiX193q58Y@-<5zWXc?V=kLR4aGSS}Kz<1(A0mC2&MTNB08+CBfz5>)0-(sr)OB zHsEK&*-lU>l$p5xhJimJ z3_w!x-f`Nz-*UhCu&~^EvBJK!j?zneIm+|fT+pbo_;8*VCpr#`J=2buTBy4ibNNts z23woH%<(>T4r)59`HM&IBv{Re|HhvU<274f7e2H*ZEhe>%Q>aPdm9%DehKGP_kT6< zqNAhZE6ICcyVErf9>?>lu$!SvXpw*uMtBi~{EDQ=d@0S_G>jDMF0X4p{h%&9YFEY2 zS;UsFW@(fv2?wB9iYwY&QnvE|V1}1XIjMkT($?0TNB}d9Q2!_{E?QYlJ8OGZH`Oz} zGTUA$$Oy6nGDjotL?bi*2oiC(`N|>#^v%1v&M6;8S?st?N!AVJS-HTZOR-sGPS$Uo zqTdFUzfImqy<6ak{Oi$IU(>S`2^v4f$aD2-ind$7_^rXX{MuzXc>sTR2i1R;X&)6= zAi9O6Ka`_EpF_{qkrT?m-F;rM}){c;fBk_tqR#m8fJ8c77h*p^D*DkIRD1BWGDspCW005{^nyLo>ddL5gl=xpYm~$oh*O+|N zp7}iXaPWC;{lXqV+IiU6BT#PEj`jxj)^>hg{r2(za3>R`ihSZbyJK$dNo(|~O@T8Z zA%QyttrRmQ_KlIUjOcK|JyGq6#lG;!va8{wwCTOP`kmGO0yFG@3crN`R_oBpw#1;W zy42vU)>UeG^uerg+aEkFFZI3~ z24aKRWdz}#hLe<1(-Q&?>%^^70fes(*d}e47t~RXML**Y^oSM~Dg-(^t5SC*KuQhx zcL#2tR}Y;TA{kC-7?~LXvrW1DF2xkFhkL!^0O>0)(N$6)&iZdw^1wpBW)%QGkw`QW zW!5~n%wIlD`qX?#E+-9tbsI>mJTr}2pP&`kS^g#N{LxX=pzO?QGs`0Zmx56O5G5)T zMIj(W*sqUbjof5LRt9bX%nl#ol6i05agP?3>DJbmf~}JQCHeOED-fL8C>+Rne5Koe z#Ljaa69?RxO{wj#bp>PD$J5(af2oguc}C{DR6ajHFV4xydD#bf(|er7WggSIgZ*ul z48U2}{IHLni#u0$LcB(4?Qi3*aQODMU*zM(s;HPeRa>tD)tNK_Md%li{!T7bf$J*b z&(bdhNteVU#OVNRbGSTDvG`V+{4aPzV@G86GGrk_5Jp#-FD^U{FI-DEHV96PTnQzS zxidSusUHtm83pTKoH7k>NosipCWcw10UfSMrcVZcNY}_vBl;2#lO)7QYx1tR;wVD} z`4mx{VTgwVdgFZv(JkCn@)lPymrHIY&;M}U+E$+yg?7nCR1a*^BSqYK{-Nn^VcW-_ z6_5Z|p-Sfsf;Or!moIWd_d3JPQ6DI&i*@Ha5Ua!M@J&H5aHCLgFj$DM7{t zq=*}&Lr{zUbP{yrtiTJ70L6KMM0nm~<|$tT1S*Jk4MkH>Mw&=Y^cVDs=9nW&=@qeB zIQR&t385Q4NmNw}H)&+>70_i{^lK8~x;3zp_+pA35ZnKo9iU88J>lx}8N}QE-0We9 z2x=n7M0kB`6U0{7k(&1jfdZY&=?AnX}8#BYKMP#>rLJ|&>xR7kr6aej2 zVje%^D=J`SDK6Af%7$^R!Q|vVCG#)LOf&;bsk72_jn0G0!A`74htGpsO?~0s#DAwR z>lC9LgNC7TMQ@)5mz~YHZWcf~2MM}LcZ<1N-JKEy0Qj|6o!B@>5j*NpSX=_ePDjxA@>8m4y%@`H@Y`;o|k$ zy>8+?5a|Vh3%eTdvu&}2v7)*8lD!Y|q?(X%=y*O^U7sp6a|lUk4@@^d-^x6nSMF>p z{%Tdpaca3AuwWA-Ip2GjS}^_dd-bx%@--PL7Mh~H%gn@-enJJvl%9x4q^yB(f(;ye zFkX+#0lKn{@9foIDCnz3Ub@UY+2v|}K>$w~SJa-jn4jO;8x1Xl58UX~uV%AXt+P}( zPL&yd{iZ12?NC_Q6HG(`yidknV>6t-WGktn%^c85QFM-$jf7wIl|J*{Mr2e5i`LSw z5`aHVmlZkKjHxdA6Ld2pMPE?=MRVeD-8W#{nNr{fdx5=s#_TWS%M$EzZmBIpkIVLW z{!@gDy*J!bkTBXH^Y`fd)T90{toLhY6%`Z;T_B#L0{(y)3_~p;0%ArZCqGNeMn|tl zF}@#v{On)1XdVNTeMO9kDU~NwwcU-P^GfvfN&8ws%F`{aIPjj*VW41QThZ zCko1LR(rD|bxOeUx_ywR&*HK1$6gx)@b)f?X#(&I)wP4YjIL=UEloYs!^^^wX2UDTHDz1ZuCza#hU zTW_!V$KJ6qeNnt)9T_HF+;L`SHP08l={qvCURz7bhTc@IDC$laNFIPi&%GKPo?H^S zqsS4j=yk?BsHgXta)BL?3_783xe3id3LE734h5N4vKqmqY)fw{J_I#2H_t5h!~|t! z8L3!M0SeY2tHBhZo%b4S2emNDf!ucwwzmFLxZL@?^JU}H?GGQ0Fe^=LJ|q_qa=}0E z@PO?e?DN&n(*LkBFQd(w?$Ct@1_p1gI;s(^N5}BR&7zn4G$sj%m8-q@y4O|lZ7+99 zLoDfvX>YE<1xPv!rg!e|GaJ9_3BVV-CA0L?TaFBwa}j=KZh0 zh+4+Q{8Wn`s_1ngL~Mwsc#Q;2yXz_1&x$J%)Sp8QtO(}&;5*y?U&1X-p7^H0 zS6B*^%CEewuk|wFcod+@1_Q>%ThoTk8!)Snw8Zny*rQ^q|JY6 zgZE2~W=@VWsQj;wr+T(kU<#}KwgQ8D8WX|TmIr~vr|hw|q~k01Nq4Qe?ETQF6ZJ8M zACTDA%THCmwaz&bTJimbJwAVG^0~2D`)xYwH;#n`Gx&|d?%*v(&la*>B2`)ZNL$YF z)cWl?02E91Z0&e^iXvuPeYgFFkP!>tkrNfQ@&gsFggJt6jd4Pxz;PFF2xyUY@~iZR zqR`aF(Ur7khejLIc;}?9kQ}+6m!*LJvS^`R=A;!2=xyq21tN2hX|jI9#35LsHImsS z^>d_*OWly3;cL2{6|tFW*z<%3LKvXLTW)zxy0 z2(j23t$su8kn;9u9pyx}N@HAi0MN&0)bwRb&SLXj_K&Rlr9u}F2_k{AM6l7J7s^_j zxi&d2F5b9K{wYAk1_e7ofrrIw_hk3Xc$~+SC4<(rtLyu0B}tS0e-!A@w~J_?0YR%T zVemDg#n(TtLGaz_YEIXe`;?e&3Q93oYkM^7=I9r1Wxw>=3x1Kx7C_q_^fP2@EQaJk zEp_P@8uMTA9zUG)9p_Ek*%A^N26#^Gr&+HLiUjFIFX6djzdzPfFr*0#4efHoRUwHB z7Ks)ctM{`?sQ96wog?U_N(0;XrK4s*M8tMGm2pt}-W&ol( zE(Bz!20@B*qDWE7+8=?T3tx!T&{fA%n=qAu%47@PoGbR#)1HpO8dBCPa`%e(?3PF~ z&{L%w7MLgtlo(tl#|SQ5lqx%CAS#J0M;E3d((-7oA5F6V$U53^!-sS5=cOojogThW zF0CuKQsiaXzUCl%p5>T3gr$wTCLDr0zItiV0=Fj1%EWZf>MWFj{rA__ z)Jc}1&9<{Sv@^(T9_05gL(QAp>y(Fwro*ie^*4JahKdZ(-H7 z-}mUAq^DzI#%*|@Ko&m28SjYyc&eQrfukeocz#RXU@MAqo%wIQsfYEj)Er{=6X}Kb zStJqt+tc3Ogbz8$oZ6i7;iopk^5Y0Kx=zUAkanM+A6V&bD+Y4?<;7BH(V5RG0XGKk z*5Z~7o6dYWUEwj$X%RvXQg|_&<^1W5vxKHEC?Z_aLe&qncwL1w)8Fo903qD)8jr=W z%?v)O6lOyCbbOhi!~QB|z}ok&P?6^RH-u^Vx8QdA#{MJI8CBFC`wmsD6{A7U zO#S3tDrF`P5%3J7AuEH8j;;bX!5C2`TW7*n*ZyIp@j|#j(cp{h-j+bVqNbl4lW+Hm zVbmL~2>x4ZFn!sjyem)AO|qTMv9J*d(o>ca&tcsegj&#my<$}@%D=L=VL`@qHmfr`cN_`al^IA@d8ki{1pzM8-KXN*EZuI`RJ&42d@ zli=^Y=o`IdM*SmLIqi|}U7b5BbYsX0lV96HsH^g<4x0t;jT7M;r-~*u%^Bc z*D;13I8jM7C}54}Hic2!(>%pJYA;)}bb=@=i6+c*ZCQ;CpYin7VUiw^=V6KONE9JC z8_CbIsu||gDNocH;(%U#yE%$4{!!mwQS*wv2b9y6C2;k|^|hGf6-WRv`e+RKB!n0{ zO#J?^Ik7;Wwjh*-D~|AoV&R~Ru6oz#Lv>w^5_f96*4?v%!>jA!)SIx6!E1$+T&Zft zPatN6)sM6K7e2Q7pfX8(fi$|ds+&8%%))<1N_nlY*9aSeJ9q^?N8)D5Sg47NiT>_2 zMMW$~u{s31;Ws{>?!3G_o4yE;rVdQKA&YkJuz78~8O0Zurs-Wpko>O2`3YQ)Mw+2KqcNv2cltl)oViTixDOdjxs@{%`mA^f`iGs)LAOmVs`$JRjMHzU6&9;*W}$;1uXbe0CaeVcs?Bi1R1v z0Ie@`*wWh^sLZdA*bh&cJ4$*o%W#74uPq-cy6#TU_08qO<0fZiVxH~)~;E~ya(daJK?|+*2$R-@@ zVqh%hkzEwYd?@{g)NV|y^Hg&7=vp7UZ1UGIiI^pQj*{65fGTu@B6HzXE=k-rSP1>Y zb9we6*DMzg)_oVb)-=&%7d4jupA-F%UQl$eS)m1?c;-G#zER=NXxVm`ywQ~@2~NjeG>}PTE@>a;=%bS*+f(pB(cZ(1+mx|H@=cl6 ziKCftprikq1Fe;M;0&={9Px}3p8@TM?_J4;uL?1BWcy~~E<39a;QJee1z$%mie}si z{`2ha@cF86uX{suo-tAjqwzOKdTF3^3AKZ{J3(Utzzd7V_6}i1HUXZHAh(08Kt)MD zhrY$wmJ4yoSBnq<#$kczyik7o>wH63^ZJP##hjxs-P|1AJz2r}5Ry$0&>ebyzjWr$ z{wf_&E*7u>Iw=qLTAKK3cal5=JYSP1Tx`WqCy=HHYd)|Wee z`m(2w{A0l7ltTq8zF(BHveedgr(5rntr5?EWho(R4%#XowBKt1^Qj)w_&bv|zV911 zMWdi8Vi0a}Qs}>LPNq~WcoEhtsft1m#Ip_4ye*W^=l+<2z5LGmcg3e*C6^vW<4sC93mO4zO`bAB&cVAg{hsOq%eC3rJRD~-8$2S_;R}SI;9Z?L z$R}%Y$5Hw$oidCNwtekldpZt%qH=Ikefrz6&>}E=`0)DRm~M>AJni(M2PfGEg)#d} zJ>jD>H~dGAS0@ZNLii%YOVWn;VpX(s?#xmz;+M zx2gxiy2a2c!7o zK*kA~ij`Se0gzP~P|*s2kw_1!A`&Tn#E;qFH}&@%MpJW-Ldfo6cW)rj{FnLk^Iuy?d_!V~ zt~!YIKG%L{Z)Fl`dwtxf-pYa5b#DDQrPOn!Sx(}a>r-t&`!dO}gVz}@|Ax6l!OL06 zalzyu-M1#@+voCNh3dw#@wu)7BC`Z&Rf4fYgC>*W$%DyjK|u*r=WuO z0|2xIB6!xaD>Wwih3XZW5KWho@7f+@Z!BOOnS}MhA)kkln|US4P=!+azBL2mhNb%*m8GnSqTbjN)32@S zQ%Uq?+?Ez>{dKrzL&&AFSZa!Az0bfeQ|qnweuoSS7@QQmC6>`)L#a8Nx5Wzdi@Bu6 z6dkzj&_NxWxvYBMYBNLMS!cXnq1m2YWFjJRGc+Ffqo<2zH7Ex(*{PIWv<+oz&o8!( zdp~XqUO*^Djxvtl36PRgJ6nje*val~w>RJVp7pgps*84<-H7 zTli9oyrMg{(RRIkeSHs%RMwCCf`WqfKEEjKrXdbZq-WjdpBfgM3sbl3V|TRwPLE%? zU^it^Z-on)yG?jhq}-gYf$|vAtc5R#xce!dxoAHUqN>tSCDI~fv4tz!iKWGdo3&Sn=9a*j&m@a; z&ocr*yoq0==)UG3iwN-zzWi}0x;|y^^r>SqL(F^t*17jeM9wZp$@p%Kvi4x^w!l9?jiMqKs z2CK3XBZ}lPft!b)~sD76l<|w5s-jj z#FfEOO5idZ6}WL0uMHpw6U{(y7Ms_TV2`7Q{zu%NhW(%cHm<;Rz}Fm>wqHU4aFNCv zJWtLe{*AUwQ%s0k=9eb@ozo-E^}zSWq}_hRD++}7wMyF+i28+VND@5R6#FGY+XlJBkU6LI)OYIj1YgGIc9#mZPmz`JupVk%0Wejb+~#>NM&J zy+i=Uh)-D4uIh3{It%wc`Tai=C>eq9fTR2StzIK`c`|ecBDJ(?BX}R(<%L0;HIh7Q z)M+%H6=-ES;;rJP`-^HX0+M{jXSm`e^0dxR1pUIE8DCQ&rONNZ7Drg{njT6@h>8VY zKuHNh6a6uk{&5E4QPpbqRNe$R6KIU<$$o>lm?X|W$J0(~p&pomHQPe`fSccd zL4n@kU$6104ye<}3D@D(TL^}p9e~#-5+?J`Zs__jA90w$g@W_O2^3=`55ZWs2I@TDrzBV8-PDQS6$EvNAUZge<~$<;<80vy z{O9t#S4t+2Q=ynMUs9sz4_t@~PHMBx9QK60i2knIz%rEbE%1FwyZ{J)5Jk%-7#L6c l@y#19`2TY~6K@!-0F${pl>!iYpMPd9fKt;{tx&cK{Xf}kj&lG2 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..99e5591e5e0c67bc1a8e9af6c0097d2d7adf84ca GIT binary patch literal 9747 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..f2269c54 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #333333 + \ No newline at end of file From ed5a532aec976647db9ccb9c34ebf62e009ea395 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 25 May 2020 21:52:20 +0300 Subject: [PATCH 28/53] Launcher icon improvements --- README.md | 2 +- app/src/main/ic_launcher-playstore.png | Bin 13022 -> 12316 bytes .../res/drawable/ic_launcher_foreground.xml | 37 ++++++++++-------- app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 1152 -> 1380 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 1905 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 2743 -> 2994 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 805 -> 954 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 1213 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 1664 -> 1829 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 1998 -> 2099 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 2739 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 4224 -> 4238 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 2979 -> 3122 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 4482 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 6554 -> 6635 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 4560 -> 4396 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 6299 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 9747 -> 9592 bytes 18 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png diff --git a/README.md b/README.md index 0eb2123e..fc28062a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Discord Channel](https://img.shields.io/badge/discord-public@mTHMMY-738bd7.svg?style=flat)][discord-server] ![Last Commit](https://img.shields.io/github/last-commit/ThmmyNoLife/mTHMMY/develop.svg?style=flat) -![mTHMMY logo](app/src/main/res/mipmap-xhdpi/ic_launcher.png) +![mTHMMY logo](app/src/main/res/mipmap-xhdpi/ic_launcher_round.png) A mobile app for [thmmy.gr](https://www.thmmy.gr). diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index 589b4e57ff20a1396c874929d6f8f8a6bd352007..a386c74eef65b9eee5df98f3f94b427e7747004e 100644 GIT binary patch literal 12316 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 literal 13022 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 diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index d24184d3..4625291a 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,23 +1,26 @@ - + android:viewportWidth="1039.6812" + android:viewportHeight="1039.6812"> + - - - + android:pathData="M0,358.69a358.58,358.69 0,1 0,717.16 0a358.58,358.69 0,1 0,-717.16 0z" + android:fillColor="#333"/> + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index dd0aa1f5bca1cab1a326a5e387638243647bc226..8313c78ae3a1ad0abfabc60ae68a8e166c7f64f0 100755 GIT binary patch delta 1362 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 delta 2736 zcmV;h3QzU27q=CVBYz5hNklJ#A!a6LNrskvS<5E=O)|?!0Bomc`la_B8zFkmPwBuldqvP#o&6>t$6{Rg1uQ zb7f`a*Fb|ymo9w=|6c-q2>J~4UrC?IvP-NZ>mFiT_M!Lbtu#*gAwd~cgX-$)1TfeS z`Y9N^0uqy?D}Mm%752%#b@eshkZC6|y2vkCvZNMFJPn3E))@qI4*U))LOln|KsQa~ z;5EH2%S~W?%rQ8Yu71-_qVzk52{(a}izY@CgO15ckO^SD{36G8H>W8zz)EUh8?rFb zvu0r2+;zW^?0eW$ewK4F&(HD$6A9PO4}kuoPdbpmjDH1`Hs*EC$=zHn1qZ)TpjWlY z-mnUkaY&!TYn-E{AgO_%@1;2Zhnkc>?28{I%AoM)0~DSNTe+RktEILv<4YCE+8#lym*~oK~f?qZO-)|1jh*^1eMnT z(qez9TYs2L7Zz#;IT*n)gY?g`va%SR$4LRCx$+x9433lGuBfPZU0aLtUA55J{tyC3 zXkm#cFE9V9PpYPpJ*a9XI=iOD79jzU;svU9t*EFdPv_YyfY8y)At*ggQUqJ{Bel}$ zm1+UqWTPf=1*(&mk-DZ_jr1iY3I-g zX!(S;NK>yIc9+L z2*s;3)_ca3BK1%X6@M~=)XT|OL(P6R)}p`hm<9;OqT;`;RIln4E5z-`9uuo~-{n+p zuYau-n~ok4H7(7SsTrKpm5hvxBpnm8_iDD^M8Y9g}uH`Y(739TKeuBQM={KMehrzMg6*w z>#S!LK*hzyFPrU7IXDiZ4Y(#3Ci>bs(;x5qed>bV2z^n`J~_Ru|I!$S{@l;b+uE&vfVs{pENYcWLRp3*nhC(mKf>V z2adW(iINn0v+Bl1H#TdR(as7Z4S+IrFQ(kQ4FCn)%`=_oef~Lkr$BJXP3fxTkojyr|DrW#b^G3kbORK4!%7n{Fz%E|(b%zJ6d-2vxw*NI5DRz7>Kvx}{?68! zgerr)VoSH^{@xQK>gP-JjdpC$en!%hts~j~B;zAWj`Uyx-n^Swm{%2zM;_79(HW@x zoo8-I@+HtgAC`eS?cL%YL#jnd;U4+azSzRhOK*Y=6HtVu_~&7JpW zMqgE5FSee3TC~8(_r5eZX)k1WLG)7(NvKYn}AZDggRvJFw5l+1$lUzDN-557MoBiGRUZFIQ2d!WS)CRD{YO z_*2cuMBnS@Mce+p{z-Jdv|IGOabDc^jr&~E6<^g0@y~}aF?_Kqe9Rq1@M2sjiseHz ze=nR-HGDPB?vh=GAM|4WQZH!ES@JG1828b0BrN%QW!Y!Kqi5J%f%Kx2yifQ7gWRK) z2q}7Nro6lW2@S@L&3fkp|rI0Q)CMrb(N+~9-c zAu1{=CVvoLa0rtfXG1i1V!*4@86+JXsMQdHK}t^c!i5WC1G&*R%x1Ik%LiEr2?-l8 z@MXDC%`x4!WJ)p&GHlK!&RNbq;Jcv12M_peNqHh|oU*cvne0XBn@t4%Fuy+psPB zkkZ0F(>aDrID_XSOQsDn^B7=Cu=ws@4&V5r_k#;w!cc)sqfRTl%~}%AS%zzsti!sp z4cn%&FB!DX3+m5wxdCe~?>1u+s7E~4Vz?G8fuoVnkd!XVcrB52*+xpr+)x5#A}PZj qCOu8Kl!gdN^JLi^w~v7>JpKobm~rsSKG^vH0000 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index cfb924c4360c83c110090b22c1b4ca25bfa16f13..07d9462b6690569ed87900d63392c5b4a8b8a936 100755 GIT binary patch delta 933 zcmV;W16us02D%53BYy*dNklCwb9sf*Le!Y`NygK5Xi6=2vQd zL@tNYa^mJR5W9)O@VXGXDz&6ULI^J;rJ}I)VVYaIP@|7OK`KAG>_SfGJZ&;%vsVe< zr+ObaJiO=Qd49k5J?Fgd_Qb?UgX3Yd*kcu6Fl+|<_J5%8GB$)~#nEIk?bGY^ z3Zv0@Pz<5H2}2}o>w?F?IFwG5Ih1*kWiE&%P6!EROixem#sJ_+Qd3iV5Zbn=1VY7v z&T=I1g@SPYfwG*ImL`hO-h?4Y;HyTX*&mK|)u4)}8J!Me&>{uVB4Xe95C$Z$l$4Zo zBpho*0&2Bdg?~W{oDxVDM1a>PkeHaLl?X@#BmxqF|A2tOXoQTMoK-ryCO!WI3E2F;(}Lv?Qt)7fryvTM?loofOmmo9>5W{QDz z2Yhf0Q>S74B{WQof@e0s?A#KdJa;@E2FJq(kneFr(|^YqsO-1~O&_M=WcwASC;Qs^ z;D$iK`6j&k0VulA3MPvM>R)-GG2mxJvdhbup6uku9RZ`+47Gy;Q0IN}>kebFp1R(_ za-Ry=l%37=WG6rJ=ZZjX-8q)~rR{AiI!k2*%l|4Y;!q1EJNc16KLik*y}ys8OlDEx zs+LN%kbhNLvZ5n9`H{a~z;aF9Q7_`ws?dQ$ZvKpR`=Znd+(iPnj=Zg{eG6;MXfDR z)pY}0zA>;=lnY7=@*{tWqj*|}){C?cVX)(T`hRxUlCH4u&!vzdBLke+>z&@G(D=>| zRoyqiU@{5&)IdM-r#OnIb!fdUuL0`q)FK$)YGOti5lu-$U9Wm|JYPACx$j$K*VbN$bgNSX9 zkTbH_`1tr_tc4++PPc%M?mIoc;JlT>_9P65WmqPYQToIRJ*gz7hY}JJ^5k-PnV5nY z@(GKOyT6viE)*HcUXeu>#Io^&cPbXl!5*Dr%6bJW4Iai%bXGMAn_HMd3fu>eQf{EM zv^;Dz(CR`;8q>HjO;by#Ew<4ZO&4wqzP^DA6WzG+12t-^E?t=8IU_WvKyGd14(3ks z&)k_gbLaoN^9W&jdW^(z%H?t;ODzXlUpqT07JdpuSl!*oFWfs1xSj zP~W{?uP&mo$wLj`qaX;U8@>LLXvb5ILFcj4XX->R(fiBSJs`lB{{H?8jb57qxLhtL zcG~3>U_cW9uYWVp*VpGZ01N;FzyL4+41kURL}zCpl1a1YNHz=V)tT-AkV7Gudh`HN zlq6QBdTQ?|fD(y7Xnai5VDzPF$&m4;F<4LS^%>FfzQ9=GU;weX>yUq5h3v*U zOm98>Q+PaPH!Bdp!PINBK=JKNQ9H%ab9}xCm+o&ie=q9F<1LuFw{b84DG*>MNjp>V zVgaHvd4HH(S%zRd);5;fDUQBwdab;-yqZZ020;vm{{0>ZC&$suDomDcw_ZLC%ZTD= zZ^ViPJ~pu^%aDIj#aYN{`vTF@yv~5b;keimpnhq9lxGm&6K@wB9)FK#$8NVfS^_j&F&%fi-LJ4CH`hz# zMG%D7=|BHJi<}d`wzzDv9)*)oP8~ zY_^P^LJyD%PDHLkV1h88czpl> diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..fc5ba8c39230d704e8e18d83a4675e9d76e90ec4 GIT binary patch literal 1213 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz1|<8_!p|}=u(Wu(IEGZ*dON4vKR8_G_}}?2 zelv0$b+YDus<>d9WgY8oL77<<>nzZPPff2&ubQT?0Va8 zY5knz`n~GgpLQ*sTDR|{`IO>({g>}A7r%S|eYg6Ws8#_d4#gH^LfcbRRFvubVZG@L z5(gOA40sG070*Bk53hD=Vx3ak`_^# zwV2U$=c>(zEv^+lu1?iy0e4i!Hxg zzxpyoS=j5p{bePA>Srkaac^pF*-EjHPhUJQ&v;ePGHX`PA*;*(GD>b5AN$0-j7cZm z?bWv#nm=mw)m=4is@yr)@M3mdUXQxJ?DhBEyzjR%{(kWJJi|7b12vnzZDQO1^p2$R zkG10ZGv0?5-Ff@H`<^=g=Ibe^Io9eluD!YKD%+Y(YtM4jg}U#SyZzy`Zt(t%FK-Cm zUQ^QEl**CwEjmggT59jx>-$Yv<8=FH9-pc#pD%dtRn}$GrjIk;HKpv^p7&Zk^1s`{ z7@-3}kCPV#|*6-#VHSEdXAqxu*s&*Fl#$={0-?tMP^c`pLHfL znlL~8DD&l+^L(y`8rV*qy3K99pUkt#k>~b&yL#F7sXMKMDl~VP$@~bcNZGLUNSM^{?cuv&&Z$DMGSXb^}`|=9d0_;P+}n>#lA3bE{|8e06$1pKh*HW*^$1-nFwf{ZoYv8j_OLxEFdwcY}kDXAwtWHJz#++IE zH!iew^IcZm!WV14D|z?E+ylZ~7uS~Oyst6PsQR~0KT1EgphRrPU%S6gtoG&4IIi87 zziVP=+phN(^KNX}#xZ@(Z-zETa290-=T|mpj_s-EgJoQ#JPc-{lmx(n;a>J%{ud(b VUy`F4cL9qf22WQ%mvv4FO#qWCL0SL+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index 096dfa34fdf683fdb39c89625dea3a25e01786bb..a9a75fdac8b99c078bd4bb9d50289f81c117ad44 100644 GIT binary patch delta 1814 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 UhZm8bqaHihS~*%)o5N8505^u{g8%>k literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index 7026f78c5b2d86fb4c22a977503415a106bdae1a..e52998313cdc30da89131006e728519b860af42f 100644 GIT binary patch literal 4238 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 literal 4224 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 rfBRJ8jgO7euCCX3|D!lU2LkXFWvh$SR~Wz delta 2897 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 literal 6554 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 M07*qoM6N<$f@(geH2?qr diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index f82b9f4493cda48b75810f90b3bfbbe29c5a942c..9286a161283d985ae9d92133924f914100874c99 100755 GIT binary patch literal 4396 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 h=D+%_uzlm0qrB}Rt>AOFH`I;9p{hu)>5XeiP< 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 AjsO4v literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index 99e5591e5e0c67bc1a8e9af6c0097d2d7adf84ca..f0cca60ae083371c6dc03c7889e05f9ea6b6a996 100644 GIT binary patch literal 9592 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 From beeb7400b0fcbffb5398981180bb41d7dcfc0b25 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 26 May 2020 00:12:56 +0300 Subject: [PATCH 29/53] Clean up --- .../res/mipmap-hdpi/ic_launcher_foreground.png | Bin 1905 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_foreground.png | Bin 1213 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_foreground.png | Bin 2739 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_foreground.png | Bin 4482 -> 0 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 6299 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png delete mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png delete mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png delete mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png delete mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index d23b493ae5c6e3e57a5a3d88a8268c67e61597e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1905 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 VUy`F4cL9qf22WQ%mvv4FO#qWCL0SL+ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index d14d3a413643f041e4a816358fb49900ac27a84f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2739 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 UhZm8bqaHihS~*%)o5N8505^u{g8%>k diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 20763a106c607b841114b952d76273d337be3d52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4482 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 AjsO4v From d5ed7f81c7a8bc981b9be4ace17ac4e4b07a6291 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 26 May 2020 22:42:08 +0300 Subject: [PATCH 30/53] Optimizations & Cleanup --- .../activities/board/BoardActivity.java | 14 ++--- .../mthmmy/activities/board/BoardAdapter.java | 4 +- .../activities/main/recent/RecentAdapter.java | 21 +++---- .../main/recent/RecentFragment.java | 18 +----- .../activities/main/unread/UnreadAdapter.java | 22 ++++---- .../main/unread/UnreadFragment.java | 13 ----- .../mthmmy/activities/topic/TopicParser.java | 11 ++++ .../gr/thmmy/mthmmy/base/BaseApplication.java | 2 +- .../java/gr/thmmy/mthmmy/model/Topic.java | 39 +++---------- .../gr/thmmy/mthmmy/model/TopicSummary.java | 55 ++++++++++++++----- .../utils/parsing/ThmmyDateTimeParser.java | 26 +++++---- app/src/main/res/values/strings.xml | 2 +- .../res/xml-v26/app_preferences_guest.xml | 2 +- .../main/res/xml-v26/app_preferences_user.xml | 2 +- .../main/res/xml/app_preferences_guest.xml | 2 +- app/src/main/res/xml/app_preferences_user.xml | 2 +- .../parsing/ThmmyDateTimeParserTest.java | 48 ++++++++++++++-- 17 files changed, 159 insertions(+), 124 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index 846a8961..b625980a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -277,7 +277,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo if (topicRows != null && !topicRows.isEmpty()) { for (Element topicRow : topicRows) { if (!Objects.equals(topicRow.className(), "titlebg")) { - String pTopicUrl, pSubject, pStartedBy, pLastPost, pLastPostUrl, pStats; + String pTopicUrl, pSubject, pStarter, pLastUser="", pLastPostDateTime="00:00:00", pLastPost, pLastPostUrl, pStats; boolean pLocked = false, pSticky = false, pUnread = false; Elements topicColumns = topicRow.select(">td"); { @@ -292,21 +292,21 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo if (column.select("a[id^=newicon]").first() != null) pUnread = true; } - pStartedBy = topicColumns.get(3).text(); + pStarter = topicColumns.get(3).text(); pStats = "Replies: " + topicColumns.get(4).text() + ", Views: " + topicColumns.get(5).text(); pLastPost = topicColumns.last().text(); if (pLastPost.contains("by")) { - pLastPost = pLastPost.substring(0, pLastPost.indexOf("by")) + - "\n" + pLastPost.substring(pLastPost.indexOf("by")); + pLastPostDateTime = pLastPost.substring(0, pLastPost.indexOf("by") -1); + pLastUser = pLastPost.substring(pLastPost.indexOf("by") + 3); } else if (pLastPost.contains("από")) { - pLastPost = pLastPost.substring(0, pLastPost.indexOf("από")) + - "\n" + pLastPost.substring(pLastPost.indexOf("από")); + pLastPostDateTime = pLastPost.substring(0, pLastPost.indexOf("από") - 1); + pLastUser = pLastPost.substring(pLastPost.indexOf("από") + 4); } else { Timber.wtf("Board parsing about to fail. pLastPost came with: %s", pLastPost); } pLastPostUrl = topicColumns.last().select("a:has(img)").first().attr("href"); - tempTopics.add(new Topic(pTopicUrl, pSubject, pStartedBy, pLastPost, pLastPostUrl, + tempTopics.add(new Topic(pTopicUrl, pSubject, pStarter, pLastUser, pLastPostDateTime, pLastPostUrl, pStats, pLocked, pSticky, pUnread)); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java index 2e864229..b016c5e4 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java @@ -187,7 +187,7 @@ class BoardAdapter extends RecyclerView.Adapter { topicViewHolder.topicRow.setOnClickListener(view -> { Intent intent = new Intent(context, TopicActivity.class); Bundle extras = new Bundle(); - extras.putString(BUNDLE_TOPIC_URL, topic.getUrl()); + extras.putString(BUNDLE_TOPIC_URL, topic.getTopicUrl()); extras.putString(BUNDLE_TOPIC_TITLE, topic.getSubject()); intent.putExtras(extras); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); @@ -232,7 +232,7 @@ class BoardAdapter extends RecyclerView.Adapter { topicViewHolder.topicSubject.setText(lockedSticky); topicViewHolder.topicStartedBy.setText(context.getString(R.string.topic_started_by, topic.getStarter())); topicViewHolder.topicStats.setText(topic.getStats()); - topicViewHolder.topicLastPost.setText(context.getString(R.string.topic_last_post, topic.getLastPostDateAndTime())); + topicViewHolder.topicLastPost.setText(context.getString(R.string.topic_last_post, topic.getLastPostDateTime(), topic.getLastUser())); topicViewHolder.topicLastPost.setOnClickListener(view -> { Intent intent = new Intent(context, TopicActivity.class); Bundle extras = new Bundle(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java index ecfcf64c..4a805f8b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java @@ -42,22 +42,23 @@ class RecentAdapter extends RecyclerView.Adapter { @Override public void onBindViewHolder(final ViewHolder holder, final int position) { - holder.mTitleView.setText(recentList.get(position).getSubject()); - - String dateTimeString = recentList.get(position).getDateTimeModified(); - if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) + TopicSummary topicSummary = recentList.get(position); + holder.mTitleView.setText(topicSummary.getSubject()); + if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()){ + String timestamp = topicSummary.getLastPostTimestamp(); try{ - holder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + holder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp)); } catch(NumberFormatException e){ - Timber.e(e, "Invalid number format: %s", dateTimeString); - holder.mDateTimeView.setText(dateTimeString); + Timber.e(e, "Invalid number format: %s", timestamp); + holder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); } + } else - holder.mDateTimeView.setText(dateTimeString); + holder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); - holder.mUserView.setText(recentList.get(position).getLastUser()); - holder.topic = recentList.get(position); + holder.mUserView.setText(topicSummary.getLastUser()); + holder.topic = topicSummary; holder.mView.setOnClickListener(v -> { if (null != mListener) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index 9435fecc..c266660a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -34,9 +34,6 @@ import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Response; import timber.log.Timber; -import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertDateTime; -import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp; - /** * A {@link BaseFragment} subclass. @@ -189,21 +186,12 @@ public class RecentFragment extends BaseFragment { String dateTime = recent.get(i + 2).text(); pattern = Pattern.compile("\\[(.*)]"); matcher = pattern.matcher(dateTime); - if (matcher.find()){ - dateTime = matcher.group(1); - if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { - dateTime=convertDateTime(dateTime, false); - String timestamp = convertToTimestamp(dateTime); - if(timestamp!=null) - dateTime=timestamp; - } - else - dateTime=convertDateTime(dateTime, true); - } + if (matcher.find()) + fetchedRecent.add(new TopicSummary(link, title, lastUser, matcher.group(1))); else throw new ParseException("Parsing failed (dateTime)"); - fetchedRecent.add(new TopicSummary(link, title, lastUser, dateTime)); + } return fetchedRecent; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java index 9312178f..745469e8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java @@ -36,7 +36,7 @@ class UnreadAdapter extends RecyclerView.Adapter { @Override public int getItemViewType(int position) { - if (unreadList.get(position).getDateTimeModified() == null) return VIEW_TYPE_MARK_READ; + if (unreadList.get(position).getLastPostDateTime() == null) return VIEW_TYPE_MARK_READ; return unreadList.get(position).getTopicUrl() == null ? VIEW_TYPE_NADA : VIEW_TYPE_ITEM; } @@ -61,29 +61,29 @@ class UnreadAdapter extends RecyclerView.Adapter { @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { + TopicSummary topicSummary = unreadList.get(holder.getAdapterPosition()); if (holder instanceof UnreadAdapter.EmptyViewHolder) { final UnreadAdapter.EmptyViewHolder emptyViewHolder = (UnreadAdapter.EmptyViewHolder) holder; - emptyViewHolder.text.setText(unreadList.get(holder.getAdapterPosition()).getDateTimeModified()); + emptyViewHolder.text.setText(topicSummary.getLastPostDateTime()); } else if (holder instanceof UnreadAdapter.ViewHolder) { final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder; - viewHolder.mTitleView.setText(unreadList.get(holder.getAdapterPosition()).getSubject()); - - String dateTimeString=unreadList.get(holder.getAdapterPosition()).getDateTimeModified(); + viewHolder.mTitleView.setText(topicSummary.getSubject()); if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()){ + String timestamp = topicSummary.getLastPostTimestamp(); try{ - viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(dateTimeString)); + viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp)); } catch(NumberFormatException e){ - Timber.e(e, "Invalid number format."); - viewHolder.mDateTimeView.setText(dateTimeString); + Timber.e(e, "Invalid number format: %s", timestamp); + viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); } } else - viewHolder.mDateTimeView.setText(dateTimeString); + viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); - viewHolder.mUserView.setText(unreadList.get(position).getLastUser()); - viewHolder.topic = unreadList.get(holder.getAdapterPosition()); + viewHolder.mUserView.setText(topicSummary.getLastUser()); + viewHolder.topic = topicSummary; viewHolder.mView.setOnClickListener(v -> { if (null != mListener) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 8b11cc3e..cafbb996 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.List; import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; @@ -37,9 +36,6 @@ import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; -import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertDateTime; -import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp; - /** * A {@link BaseFragment} subclass. * Activities that contain this fragment must implement the @@ -219,15 +215,6 @@ public class UnreadFragment extends BaseFragment { dateTime = dateTime.replace("", ""); dateTime = dateTime.replace("", ""); - if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { - dateTime=convertDateTime(dateTime, false); - String timestamp = convertToTimestamp(dateTime); - if(timestamp!=null) - dateTime=timestamp; - } - else - dateTime=convertDateTime(dateTime, true); - fetchedTopicSummaries.add(new TopicSummary(link, title, lastUser, dateTime)); } Element topBar = document.select("table:not(.bordercolor):not(#bodyarea):has(td.middletext)").first(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java index 1a7922ff..901ce553 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java @@ -18,6 +18,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; @@ -25,6 +26,8 @@ import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; +import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp; + /** * Singleton used for parsing a topic. @@ -175,6 +178,7 @@ public class TopicParser { p_specialRank, p_gender, p_personalText, p_numberOfPosts, p_postLastEditDate, p_postURL, p_deletePostURL, p_editPostURL; int p_postNum, p_postIndex, p_numberOfStars, p_userColor; + long p_timestamp; boolean p_isDeleted = false, p_isUserMentionedInPost = false; ArrayList p_attachedFiles; @@ -191,6 +195,7 @@ public class TopicParser { p_postLastEditDate = null; p_deletePostURL = null; p_editPostURL = null; + p_timestamp = 0; //Language independent parsing //Finds thumbnail url @@ -267,6 +272,12 @@ public class TopicParser { p_postDate = p_postDate.substring(p_postDate.indexOf("στις:") + 6 , p_postDate.indexOf(" »")); + if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { + String timestamp = convertToTimestamp(p_postDate); + if(timestamp!=null) + p_timestamp = Long.valueOf(timestamp); + } + //Finds post's reply index number Element postNum = thisRow.select("div.smalltext:matches(Απάντηση #)").first(); if (postNum == null) { //Topic starter diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index c52a8c98..f19bac9e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -183,7 +183,7 @@ public class BaseApplication extends Application { heightPxl = displayMetrics.heightPixels; - displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, false); + displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, true); } //Getters diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Topic.java b/app/src/main/java/gr/thmmy/mthmmy/model/Topic.java index 207e2c2e..5397a511 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Topic.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Topic.java @@ -8,7 +8,7 @@ package gr.thmmy.mthmmy.model; * not, whether it's sticky or not and whether it contains an unread post or not.. */ public class Topic extends TopicSummary { - private final String lastPostUrl, stats; + private final String lastPostUrl, starter, stats; private final boolean locked, sticky, unread; // Suppresses default constructor @@ -16,6 +16,7 @@ public class Topic extends TopicSummary { private Topic() { super(); this.lastPostUrl = null; + this.starter = null; this.stats = null; this.locked = false; this.sticky = false; @@ -29,57 +30,31 @@ public class Topic extends TopicSummary { * @param topicUrl this topic's url * @param subject this topic's subject * @param starter this topic starter's username - * @param lastPost username of topic's last post's author + * @param lastUser username of topic's last post's author * @param lastPostUrl url of topic's last post * @param stats this topic's view and reply stats * @param locked whether this topic is locked or not * @param sticky whether this topic is sticky or not * @param unread whether this topic contains an unread post or not */ - public Topic(String topicUrl, String subject, String starter, String lastPost, String lastPostUrl, + public Topic(String topicUrl, String subject, String starter, String lastUser, String LastPostDateTime, String lastPostUrl, String stats, boolean locked, boolean sticky, boolean unread) { - super(topicUrl, subject, starter, lastPost); + super(topicUrl, subject, lastUser, LastPostDateTime); this.lastPostUrl = lastPostUrl; + this.starter = starter; this.stats = stats; this.locked = locked; this.sticky = sticky; this.unread = unread; } - /** - * Gets this topic's url. - * - * @return this topic's url - */ - public String getUrl() { - return topicUrl; - } - - /** - * Gets this topic's subject. - * - * @return this topic's subject - */ - public String getSubject() { - return subject; - } - /** * Gets this topic's starter username. * * @return this topic's starter username */ public String getStarter() { - return lastUser; - } - - /** - * Gets this topic's last post's date and time. - * - * @return last post's date and time - */ - public String getLastPostDateAndTime() { - return dateTimeModified; + return starter; } /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/TopicSummary.java b/app/src/main/java/gr/thmmy/mthmmy/model/TopicSummary.java index 87e323c7..5374cc6a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/TopicSummary.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/TopicSummary.java @@ -1,5 +1,8 @@ package gr.thmmy.mthmmy.model; +import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp; +import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.simplifyDateTime; + /** * Class that defines the summary of a topic. All member variables are declared final (thus no * setters are supplied). Class has one constructor and getter methods for all variables. @@ -7,10 +10,12 @@ package gr.thmmy.mthmmy.model; * time of this topic's last post.. */ public class TopicSummary { - final String topicUrl; - final String subject; - final String lastUser; - final String dateTimeModified; + private final String topicUrl; + private final String subject; + private final String lastUser; + private final String lastPostDateTime; + private final String lastPostSimplifiedDateTime; + private final String lastPostTimestamp; // Suppresses default constructor @SuppressWarnings("unused") @@ -18,23 +23,27 @@ public class TopicSummary { this.topicUrl = null; this.subject = null; this.lastUser = null; - this.dateTimeModified = null; + this.lastPostDateTime = null; + this.lastPostSimplifiedDateTime = null; + this.lastPostTimestamp = null; } /** - * Constructor specifying all class variables necessary to summarise this topic. All variables + * Constructor specifying all class variables necessary to summarize this topic. All variables * are declared final, once assigned they can not change. * * @param topicUrl this topic's url * @param subject this topic's subject - * @param lastUser username of this topic's last author - * @param dateTimeModified this topic's date and time of last post + * @param lastUser username of this topic's last post's author + * @param lastPostDateTime this topic's date and time of last post */ - public TopicSummary(String topicUrl, String subject, String lastUser, String dateTimeModified) { + public TopicSummary(String topicUrl, String subject, String lastUser, String lastPostDateTime) { this.topicUrl = topicUrl; this.subject = subject; this.lastUser = lastUser; - this.dateTimeModified = dateTimeModified; + this.lastPostDateTime = lastPostDateTime; + this.lastPostTimestamp = convertToTimestamp(lastPostDateTime); + this.lastPostSimplifiedDateTime = simplifyDateTime(lastPostDateTime); } /** @@ -56,9 +65,9 @@ public class TopicSummary { } /** - * Gets username of this topic's last author. + * Gets username of this topic's last post's author. * - * @return username of last author + * @return username of last post's author */ public String getLastUser() { return lastUser; @@ -69,7 +78,25 @@ public class TopicSummary { * * @return this topic's date and time of last post */ - public String getDateTimeModified() { - return dateTimeModified; + public String getLastPostDateTime() { + return lastPostDateTime; + } + + /** + * Gets this topic's simplified date and time of last post. + * + * @return this topic's simplified date and time of last post + */ + public String getLastPostSimplifiedDateTime() { + return lastPostSimplifiedDateTime; + } + + /** + * Gets the timestamp of this topic's last post. + * + * @return the timestamp of this topic's last post + */ + public String getLastPostTimestamp() { + return lastPostTimestamp; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java index 01014ec6..e9813de2 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java @@ -46,11 +46,14 @@ public class ThmmyDateTimeParser { String originalDateTime = thmmyDateTime; DateTimeZone dtz = getDtz(); - //Add today's date for the first two cases + // Remove any unnecessary "Today at" strings + thmmyDateTime = purifyTodayDateTime(thmmyDateTime); + + // Add today's date for the first two cases if(thmmyDateTime.charAt(2)==':') thmmyDateTime = (new DateTime()).toString("MMMM d, Y, ") + thmmyDateTime; - //Don't even ask + // Don't even ask if(thmmyDateTime.contains("am")) thmmyDateTime = thmmyDateTime.replaceAll("\\s00:"," 12:"); @@ -84,16 +87,19 @@ public class ThmmyDateTimeParser { return timestamp; } - public static String convertDateTime(String dateTime, boolean removeSeconds){ - //Convert e.g. Today at 12:16:48 -> 12:16:48, but October 03, 2019, 16:40:18 remains as is - if (!dateTime.contains(",")) - dateTime = dateTime.replaceAll(".+? ([0-9])", "$1"); + public static String simplifyDateTime(String dateTime){ + return removeSeconds(purifyTodayDateTime(dateTime)); + } - //Remove seconds - if(removeSeconds) - dateTime = dateTime.replaceAll("(.+?)(:[0-5][0-9])($|\\s)", "$1$3"); + // Converts e.g. Today at 12:16:48 -> 12:16:48, but October 03, 2019, 16:40:18 remains as is + @VisibleForTesting + static String purifyTodayDateTime(String dateTime){ + return dateTime.replaceAll("(Today at |Σήμερα στις )(.+)", "$2"); + } - return dateTime; + // Converts e.g. 12:16:48 -> 12:16, October 03, 2019, 16:40:18 -> 12:16 October 03, 2019, 16:40 + private static String removeSeconds(String dateTime){ + return dateTime.replaceAll("(.*):\\d+(.*)", "$1$2"); } @VisibleForTesting diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e78b502b..c87f02e9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -41,7 +41,7 @@ Subject Started by: %1$s Stats - Last post on: %1$s + Last post on: %1$s\nby %2$s Share diff --git a/app/src/main/res/xml-v26/app_preferences_guest.xml b/app/src/main/res/xml-v26/app_preferences_guest.xml index 78c7c8ca..1e04ec41 100644 --- a/app/src/main/res/xml-v26/app_preferences_guest.xml +++ b/app/src/main/res/xml-v26/app_preferences_guest.xml @@ -15,7 +15,7 @@ android:summary="@string/pref_summary_app_main_default_tab" app:iconSpaceReserved="false" /> Date: Wed, 27 May 2020 00:02:50 +0300 Subject: [PATCH 31/53] UnreadFragment improvements --- .../activities/main/unread/UnreadAdapter.java | 116 ++++------------- .../main/unread/UnreadFragment.java | 120 +++++++++++++----- app/src/main/res/drawable/ic_mark_as_read.xml | 5 + app/src/main/res/layout/fragment_unread.xml | 60 ++++++--- .../res/layout/fragment_unread_empty_row.xml | 19 --- .../layout/fragment_unread_mark_read_row.xml | 17 --- app/src/main/res/values/strings.xml | 1 + 7 files changed, 164 insertions(+), 174 deletions(-) create mode 100644 app/src/main/res/drawable/ic_mark_as_read.xml delete mode 100644 app/src/main/res/layout/fragment_unread_empty_row.xml delete mode 100644 app/src/main/res/layout/fragment_unread_mark_read_row.xml diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java index 745469e8..c9568fb7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java @@ -20,91 +20,50 @@ import timber.log.Timber; class UnreadAdapter extends RecyclerView.Adapter { private final List unreadList; private final UnreadFragment.UnreadFragmentInteractionListener mListener; - private final MarkReadInteractionListener markReadListener; - - private final int VIEW_TYPE_ITEM = 0; - private final int VIEW_TYPE_NADA = 1; - private final int VIEW_TYPE_MARK_READ = 2; UnreadAdapter(@NonNull List topicSummaryList, - BaseFragment.FragmentInteractionListener listener, - MarkReadInteractionListener markReadInteractionListener) { + BaseFragment.FragmentInteractionListener listener) { this.unreadList = topicSummaryList; mListener = (UnreadFragment.UnreadFragmentInteractionListener) listener; - markReadListener = markReadInteractionListener; - } - - @Override - public int getItemViewType(int position) { - if (unreadList.get(position).getLastPostDateTime() == null) return VIEW_TYPE_MARK_READ; - return unreadList.get(position).getTopicUrl() == null ? VIEW_TYPE_NADA : VIEW_TYPE_ITEM; } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - if (viewType == VIEW_TYPE_ITEM) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.fragment_unread_row, parent, false); - return new ViewHolder(view); - } else if (viewType == VIEW_TYPE_NADA) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.fragment_unread_empty_row, parent, false); - return new EmptyViewHolder(view); - } else if (viewType == VIEW_TYPE_MARK_READ) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.fragment_unread_mark_read_row, parent, false); - return new MarkReadViewHolder(view); - } - return null; + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.fragment_unread_row, parent, false); + return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { TopicSummary topicSummary = unreadList.get(holder.getAdapterPosition()); - if (holder instanceof UnreadAdapter.EmptyViewHolder) { - final UnreadAdapter.EmptyViewHolder emptyViewHolder = (UnreadAdapter.EmptyViewHolder) holder; - emptyViewHolder.text.setText(topicSummary.getLastPostDateTime()); - } else if (holder instanceof UnreadAdapter.ViewHolder) { - final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder; + final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder; - viewHolder.mTitleView.setText(topicSummary.getSubject()); - if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()){ - String timestamp = topicSummary.getLastPostTimestamp(); - try{ - viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp)); - } - catch(NumberFormatException e){ - Timber.e(e, "Invalid number format: %s", timestamp); - viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); - } + viewHolder.mTitleView.setText(topicSummary.getSubject()); + if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()){ + String timestamp = topicSummary.getLastPostTimestamp(); + try{ + viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp)); } - else + catch(NumberFormatException e){ + Timber.e(e, "Invalid number format: %s", timestamp); viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); + } + } + else + viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); - viewHolder.mUserView.setText(topicSummary.getLastUser()); - viewHolder.topic = topicSummary; - - viewHolder.mView.setOnClickListener(v -> { - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - mListener.onUnreadFragmentInteraction(viewHolder.topic); //? - } - }); - } else if (holder instanceof UnreadAdapter.MarkReadViewHolder) { - final UnreadAdapter.MarkReadViewHolder markReadViewHolder = (UnreadAdapter.MarkReadViewHolder) holder; - markReadViewHolder.text.setText(unreadList.get(holder.getAdapterPosition()).getSubject()); - markReadViewHolder.topic = unreadList.get(holder.getAdapterPosition()); + viewHolder.mUserView.setText(topicSummary.getLastUser()); + viewHolder.topic = topicSummary; - markReadViewHolder.mView.setOnClickListener(v -> { - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - markReadListener.onMarkReadInteraction(unreadList.get(holder.getAdapterPosition()).getTopicUrl()); - } - }); - } + viewHolder.mView.setOnClickListener(v -> { + if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + mListener.onUnreadFragmentInteraction(viewHolder.topic); //? + } + }); } @Override @@ -127,29 +86,4 @@ class UnreadAdapter extends RecyclerView.Adapter { mDateTimeView = view.findViewById(R.id.dateTime); } } - - private static class EmptyViewHolder extends RecyclerView.ViewHolder { - final TextView text; - - EmptyViewHolder(View view) { - super(view); - text = view.findViewById(R.id.text); - } - } - - private static class MarkReadViewHolder extends RecyclerView.ViewHolder { - final View mView; - final TextView text; - public TopicSummary topic; - - MarkReadViewHolder(View view) { - super(view); - mView = view; - text = view.findViewById(R.id.mark_read); - } - } - - interface MarkReadInteractionListener { - void onMarkReadInteraction(String markReadLinkUrl); - } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index cafbb996..ffb0ede4 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -7,14 +7,18 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import android.widget.RelativeLayout; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; @@ -50,9 +54,13 @@ public class UnreadFragment extends BaseFragment { private MaterialProgressBar progressBar; private SwipeRefreshLayout swipeRefreshLayout; + private FloatingActionButton markAsReadFAB; + private TextView noUnreadTopicsTextView; + private UnreadAdapter unreadAdapter; private List topicSummaries; + private String markAsReadUrl = ""; private int numberOfPages = 0; private int loadedPages = 0; @@ -103,15 +111,21 @@ public class UnreadFragment extends BaseFragment { final View rootView = inflater.inflate(R.layout.fragment_unread, container, false); // Set the adapter - if (rootView instanceof RelativeLayout) { + if (rootView instanceof CoordinatorLayout) { progressBar = rootView.findViewById(R.id.progressBar); - unreadAdapter = new UnreadAdapter(topicSummaries, - fragmentInteractionListener, markReadLinkUrl -> { - if (!markReadTask.isRunning() && !unreadTask.isRunning()) { - markReadTask = new MarkReadTask(); - markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markReadLinkUrl); - } - }); + noUnreadTopicsTextView = rootView.findViewById(R.id.no_unread_topics); + markAsReadFAB = rootView.findViewById(R.id.unread_fab); + + if(topicSummaries.isEmpty()){ + hideMarkAsReadFAB(); + noUnreadTopicsTextView.setVisibility(View.VISIBLE); + } + else{ + noUnreadTopicsTextView.setVisibility(View.INVISIBLE); + showMarkAsReadFAB(); + } + + unreadAdapter = new UnreadAdapter(topicSummaries, fragmentInteractionListener); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext()); @@ -155,20 +169,56 @@ public class UnreadFragment extends BaseFragment { void onUnreadFragmentInteraction(TopicSummary topicSummary); } + private void showMarkAsReadFAB() { + markAsReadFAB.setOnClickListener(v -> { + if (!markReadTask.isRunning() && !unreadTask.isRunning()) + showMarkAsReadConfirmationDialog(); + }); + markAsReadFAB.show(); + markAsReadFAB.setTag(true); + } + + private void hideMarkAsReadFAB() { + markAsReadFAB.setOnClickListener(null); + markAsReadFAB.hide(); + markAsReadFAB.setTag(false); + } + + private void showMarkAsReadConfirmationDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppCompatAlertDialogStyle); + builder.setTitle("Mark all as read"); + builder.setMessage("Are you sure that you want to mark ALL topics as read?"); + builder.setPositiveButton("Yep", (dialogInterface, i) -> { + markReadTask = new MarkReadTask(); + markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markAsReadUrl); + }); + builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); + builder.create().show(); + } + //---------------------------------------ASYNC TASK----------------------------------- private void onUnreadTaskStarted() { progressBar.setVisibility(ProgressBar.VISIBLE); } - private void onUnreadTaskFinished(int resultCode, ArrayList fetchedUnread) { + private void onUnreadTaskFinished(int resultCode, UnreadTaskData unreadTaskData) { if (resultCode == NetworkResultCodes.SUCCESSFUL) { - if(fetchedUnread!=null && !fetchedUnread.isEmpty()){ + ArrayList fetchedUnread = unreadTaskData.getTopicSummaries(); + if(!fetchedUnread.isEmpty()){ if(loadedPages==0) topicSummaries.clear(); topicSummaries.addAll(fetchedUnread); - unreadAdapter.notifyDataSetChanged(); + markAsReadUrl = unreadTaskData.getMarkAsReadUrl(); + noUnreadTopicsTextView.setVisibility(View.INVISIBLE); + showMarkAsReadFAB(); + } + else { + topicSummaries.clear(); + hideMarkAsReadFAB(); + noUnreadTopicsTextView.setVisibility(View.VISIBLE); } + unreadAdapter.notifyDataSetChanged(); loadedPages++; if (loadedPages < numberOfPages) { unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); @@ -191,18 +241,17 @@ public class UnreadFragment extends BaseFragment { } } - private class UnreadTask extends NewParseTask> { - - UnreadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { + private class UnreadTask extends NewParseTask { + UnreadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected ArrayList parse(Document document, Response response) throws ParseException { + protected UnreadTaskData parse(Document document, Response response) throws ParseException { Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); ArrayList fetchedTopicSummaries = new ArrayList<>(); + String markAsReadUrl=""; if (!unread.isEmpty()) { - //topicSummaries.clear(); for (Element row : unread) { Elements information = row.select("td"); String link = information.last().select("a").first().attr("href"); @@ -222,7 +271,6 @@ public class UnreadFragment extends BaseFragment { Element pagesElement = null, markRead = null; if (topBar != null) { pagesElement = topBar.select("td.middletext").first(); - markRead = document.select("table:not(.bordercolor):not([width])").select("a") .first(); } @@ -236,26 +284,38 @@ public class UnreadFragment extends BaseFragment { } if (markRead != null && loadedPages == numberOfPages - 1) - fetchedTopicSummaries.add(new TopicSummary(markRead.attr("href"), markRead.text(), null, - null)); - } else { - String message = document.select("table.bordercolor[cellspacing=1]").first().text(); - if (message.contains("No messages")) { //It's english - message = "No unread posts!"; - } else { //It's greek - message = "Δεν υπάρχουν μη αναγνωσμένα μηνύματα!"; - } - fetchedTopicSummaries.add(new TopicSummary(null, null, null, message)); + markAsReadUrl = markRead.attr("href"); + + return new UnreadTaskData(fetchedTopicSummaries, markAsReadUrl); } - return fetchedTopicSummaries; + + return new UnreadTaskData(new ArrayList<>(), markAsReadUrl); } @Override - protected int getResultCode(Response response, ArrayList data) { + protected int getResultCode(Response response, UnreadTaskData data) { return NetworkResultCodes.SUCCESSFUL; } } + private class UnreadTaskData { + ArrayList topicSummaries; + String markAsReadUrl; + + UnreadTaskData(ArrayList topicSummaries, String markAsReadUrl){ + this.topicSummaries = topicSummaries; + this.markAsReadUrl = markAsReadUrl; + } + + ArrayList getTopicSummaries() { + return topicSummaries; + } + + String getMarkAsReadUrl() { + return markAsReadUrl; + } + } + private class MarkReadTask extends AsyncTask { private static final int SUCCESS = 0; private static final int NETWORK_ERROR = 1; diff --git a/app/src/main/res/drawable/ic_mark_as_read.xml b/app/src/main/res/drawable/ic_mark_as_read.xml new file mode 100644 index 00000000..04b4b785 --- /dev/null +++ b/app/src/main/res/drawable/ic_mark_as_read.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/fragment_unread.xml b/app/src/main/res/layout/fragment_unread.xml index fc412190..41d018c5 100644 --- a/app/src/main/res/layout/fragment_unread.xml +++ b/app/src/main/res/layout/fragment_unread.xml @@ -1,28 +1,45 @@ - + android:layout_height="match_parent" + android:background="@color/background"> - - - + android:layout_height="match_parent"> + + + + + + - \ No newline at end of file + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_unread_empty_row.xml b/app/src/main/res/layout/fragment_unread_empty_row.xml deleted file mode 100644 index d5394258..00000000 --- a/app/src/main/res/layout/fragment_unread_empty_row.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_unread_mark_read_row.xml b/app/src/main/res/layout/fragment_unread_mark_read_row.xml deleted file mode 100644 index c825118c..00000000 --- a/app/src/main/res/layout/fragment_unread_mark_read_row.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c87f02e9..b0cae84b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,6 +23,7 @@ Unread Shoutbox Refresh + No unread topics! thmmy.gr From 4fd6a44bbbfc1278e33e388a56d3bcccd9afda8a Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 27 May 2020 12:04:23 +0300 Subject: [PATCH 32/53] Enable cleartext traffic for thmmy.gr --- app/src/main/AndroidManifest.xml | 1 + app/src/main/res/xml/network_security_config.xml | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 app/src/main/res/xml/network_security_config.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 66be4558..e36ad051 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,6 +19,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:requestLegacyExternalStorage="true" + android:networkSecurityConfig="@xml/network_security_config" android:theme="@style/AppTheme" tools:ignore="UnusedAttribute"> + + + + www.thmmy.gr + + From 80cbba140bf7b2ade11d02a9674ceb7f04d801de Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 27 May 2020 12:22:43 +0300 Subject: [PATCH 33/53] Crash fix (MainActivity fragments) --- .../activities/main/forum/ForumFragment.java | 17 +++++++++++------ .../activities/main/recent/RecentFragment.java | 11 +++++++---- .../activities/main/unread/UnreadFragment.java | 18 ++++++++++++++---- .../utils/parsing/ThmmyDateTimeParser.java | 2 +- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java index f366f295..86860ec1 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java @@ -158,19 +158,24 @@ public class ForumFragment extends BaseFragment { @Override public void onDestroy() { super.onDestroy(); - if (forumTask != null && forumTask.getStatus() != AsyncTask.Status.RUNNING) - forumTask.cancel(true); + if (forumTask!=null){ + try{ + if(forumTask.isRunning()) + forumTask.cancel(true); + } // Yes, it happens even though we checked + catch (NullPointerException ignored){ } + } } public interface ForumFragmentInteractionListener extends FragmentInteractionListener { void onForumFragmentInteraction(Board board); } - public void onForumTaskStarted() { + private void onForumTaskStarted() { progressBar.setVisibility(ProgressBar.VISIBLE); } - public void onForumTaskFinished(int resultCode, ArrayList fetchedCategories) { + private void onForumTaskFinished(int resultCode, ArrayList fetchedCategories) { if (resultCode == NetworkResultCodes.SUCCESSFUL) { categories.clear(); categories.addAll(fetchedCategories); @@ -191,8 +196,8 @@ public class ForumFragment extends BaseFragment { private class ForumTask extends NewParseTask> { private HttpUrl forumUrl = SessionManager.forumUrl; //may change upon collapse/expand - public ForumTask(OnTaskStartedListener onTaskStartedListener, - OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { + ForumTask(OnTaskStartedListener onTaskStartedListener, + OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { super(onTaskStartedListener, onParseTaskFinishedListener); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index c266660a..673dc32a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -85,7 +85,6 @@ public class RecentFragment extends BaseFragment { if (topicSummaries.isEmpty()) { recentTask = new RecentTask(this::onRecentTaskStarted, this::onRecentTaskFinished); recentTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.indexUrl.toString()); - } Timber.d("onActivityCreated"); } @@ -128,8 +127,13 @@ public class RecentFragment extends BaseFragment { @Override public void onDestroy() { super.onDestroy(); - if (recentTask!=null && recentTask.isRunning()) - recentTask.cancel(true); + if (recentTask!=null){ + try{ + if(recentTask.isRunning()) + recentTask.cancel(true); + } // Yes, it happens even though we checked + catch (NullPointerException ignored){ } + } } @@ -191,7 +195,6 @@ public class RecentFragment extends BaseFragment { else throw new ParseException("Parsing failed (dateTime)"); - } return fetchedRecent; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index ffb0ede4..8bac71ba 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -157,10 +157,20 @@ public class UnreadFragment extends BaseFragment { @Override public void onDestroy() { super.onDestroy(); - if (unreadTask!=null && unreadTask.isRunning()) - unreadTask.cancel(true); - if (markReadTask!=null && markReadTask.isRunning()) - markReadTask.cancel(true); + if (unreadTask!=null){ + try{ + if(unreadTask.isRunning()) + unreadTask.cancel(true); + } // Yes, it happens even though we checked + catch (NullPointerException ignored){ } + } + if (markReadTask!=null){ + try{ + if(markReadTask.isRunning()) + markReadTask.cancel(true); + } // Yes, it happens even though we checked + catch (NullPointerException ignored){ } + } if(topicSummaries!=null) topicSummaries.clear(); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java index e9813de2..3c398bd1 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java @@ -99,7 +99,7 @@ public class ThmmyDateTimeParser { // Converts e.g. 12:16:48 -> 12:16, October 03, 2019, 16:40:18 -> 12:16 October 03, 2019, 16:40 private static String removeSeconds(String dateTime){ - return dateTime.replaceAll("(.*):\\d+(.*)", "$1$2"); + return dateTime.replaceAll("(.*):\\d+($|\\s.*)", "$1$2"); } @VisibleForTesting From 64660b1ac6918a186ec2ea8abe79f139dde0994d Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 27 May 2020 14:04:19 +0300 Subject: [PATCH 34/53] Tiny Logo optimization --- app/src/main/ic_launcher-playstore.png | Bin 12316 -> 12355 bytes .../utils/WebViewOnTouchClickListener.java | 5 ++--- .../res/drawable/ic_launcher_foreground.xml | 4 ++-- app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 1380 -> 1420 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 2994 -> 2969 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 954 -> 954 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 1829 -> 1839 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 2099 -> 2044 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 4238 -> 4224 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 3122 -> 3122 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 6635 -> 6617 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 4396 -> 4466 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 9592 -> 9603 bytes 13 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index a386c74eef65b9eee5df98f3f94b427e7747004e..a2c59929a69f0025002f6cc89e2ae067c03ba0e6 100644 GIT binary patch literal 12355 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 Ue)`;3Xu5!vxt&?rMeqCn0m^lu)&Kwi literal 12316 zcmd_QXIzun*Dibm3OdS&g^r-3f=chwacCkL_`R|GDv3>2~9vjng|RX z1QJFe2r(cKilIcnfYi`SLUNzY{LlM5@9%v-J##*uPdD&muf6u(Yp-=(*V-{xtj+j; z5&H##Ab#^p##bST8~n%(?c)WXwFeX?1Sw9M8(+NkfVwbx6KiijrnwYqW2C+R>9NZ{ zo9mwb85#UO-cI5;X{gal^my?6+1R~;hxhJzUe>p$S+&Tf6{Y_1;%Sw2mpT3rJ}2}J zE%nv=bwn7vF;=oORYzd^b3@Xpv|D>10WcjG^shdKVCWtQ`d6QSIpwaa|8`0+P5@Hd z1MP#LNZ|SZ_`@A(`meX@|Jd(;J@daho&UYXT!u#f|E-EQwwqp~RNOGns0|Fw(8hY8 zZuy!MvQ)e$;Dt7t2-a_hyj*7{ZtPmLUjXv_9d*m!%AK9r`{J3DyS0(#Bi7>;1P= zqN=m7ReQCs?*{*13f6ANe_1n|flkthsg2Qyt&P=)tF<#a0U3_!t=E#%vv9f_SHv#d zJK@jTOkW+_>IzfcVbuAO2A}oDPUl!1C*j_nOGpUb+-yfLI#phf$4(Vj(?9>cf)-n* zA*$`GovYoe$KP(LadSfy!a08aV$Ar*>XkM^VW~_~!WMDU!sw>WTXl5Pi-K|wd&iR} zBK&ry)XNE1b^E2HR%ufH!u}%uqWIsHTs^(I~*iHn~*^``EUNGb5 z(BEdI6oK3s*dhx*95tW{9Q&^!{k@}ELL=LQ)$0_^RLm;Ncc0Vp=FO|D+&|P|;Bq|8 zB_KRnVvQ_3sE@}b#1%D zW(WpUHL3>Hsq_&9spprXtzDR{dA=+dU$VuobbAaopZ%usvOrC}f2;(a&}>7;(b6Wt zCMVP;XgK(RX{<1;#W9sXnTHm;gLrl#ibpE5Y;c)BDI-nKcK^Nc>yh@@roCsu6hlu9 z1)$ea9@vn=KQ>2F)_Fy|c(T$R5zcm+e{abzXHL}7cZT!)^Ahq(`z7{4SB`2AmRgDH zKTw?GUwWp;Eo87`Xhq%|O*=yHRr6!FpQm1+x{!g_lVugndSvz|hHT|L`t(3^qbzyo zFT4+jvupI-Zp@mwnq`*gfv9zBOAIOThaukO3nTGO@!5DQ+f9Fay{vB-xyCLd1TCad{V{M2} zZfvH?oDssj7P<&UzO&}c4d1mB+nFl4+sGBL&Ac+(=-s{*&YPw}ADM$s@wG27l4_Im zl|%*hKt&m~czpFvdLeOPY7@(vG{9x(=#;?QNNRQ9ncvkl;D)rHPktUy-_H$QqtDcB zb}nrHiWlv_8R_mzWX_iJrs3}gyEM)v+=W?rhjJAydG~NZ?^L$YJv^J{zllTn z4cMmq51K6u1birby{#T*_we-yOY?x`d`oeqEk^i_pd$>zd7WxkV<>8vhy5H5vDl6z zxNnlpBn)gAgA6Ra^@9*vN6V zELJ!9j|WZjr)quyn{;hnk1+me6UCTv4EW{V1u~12Q&so(t4#DIHs9vp4RK@I%W0k> zdk`#M$*`DM?*!kX)hAl^`;JV6E?0T@cmpMES=G?8GER`M=C7UQrfHsIn4=iAY`)VV zWR8BRrd#w;>paTIneZW-7OAF8pW7pUmhx-kmyF3cau8l7#1uGtTT`nmEHEE_wyUQ-AEZ6eKMnqxvM zz78&~WkI>KeOX0$TMaC%Epc;QRxzc0-63#q>&gQ*LgwUI=6R+Z)0+PY1R*Pz%5*vl zXWf!F0{6rv8|NN<=evliAcNw1l=1UeYpVC?{ zt55Ixut-&VIbQs5Y3q6Q(paPHz^_&1usd!LUas{TE5&vmk<0DQW#k^}SJ?+Cov%_E z-I|CJwwXy-SnwTPbQe4%au?~oN|Y7U`t5=T+&&M#sggNA#+ykPN(DEERQvfb_kWG{ zO7QphZ9C9i04kez=t>r=&|s&Y(6SVgf^eyusYdI{AFtJ_p z)g1PyAXX*GMzX>hE`%Mb%@YN=dY<*9_7tMT_dxYUyVYLa>{p-d4Jp!$n2T$KRK3_Hhg_b-Lc@2QH~=gB#Sxa*uG(!X*~QR?SKGA6!WeYgyaDm&fL#SC5SLB zQugNZQ*pl89aI4ZiF8>V@bj(zSl)u&CxK)h6ex#7^gWgfSAxo613ktsf85HHKy&3P z=Gg>ErhrhPG?a13p#x3r35-=6J3lmIo2I?9j9clbpRgGJH6r^1UtRo%<1S%gos)ma zVxZooy29R-!knfS!Z+7i+e911p2D6wl*AtBLU-~5BNyhiWlGqG6`MBzITV~p(!Vzz z%6DL@@X;s4wVklAr?GMDM&aJDwv8Y{VQ)EXBVpA%9Hp?uAfgj$-#uUnW5h7xnD+x< zd5Dpx(^)#}<-MeySa=L~3Q;gq;^1*QTn(4Gd5zg;q_w~7!3%V@GV)qEjC|pd|K!RJ z&WdGVF7GbPk?%3>anNF(U}`X(O2O?hP-WD*_I+Q@`-Z=0i4mc67oQHN-<+3y+^^!VPqd86A|*E@WuJvn^7PKvdd^m83Pn&c3% zfo*yW-$tWmW<>uMk1neuSIX^|V_smokip96e$#<8_@KO)_W~Q)PrtVz;2gblhaGnM;X0#T)YoRvehedl!4!8ZgLHWMEB?;K?JV8) z)+(m~4gc-R=QhT#3<$cP3ny~8y0R~k?(3%)xJ{@UZhkjhei>f0Vl!rTDBpR|Lv`YQ zG(e;zP&Ed7rcqK{hNqM|(8Ynj-^OFp& zE;qv@(XE__msFo_v2EA%TypM0U{gvAK2hJ1wGR?|WUjxhh_{*^3itW`^${hkt=1MU z_@?QO&{dZDQpF2*E(q_0hz}RyEaWBvoB#yK^GIgs zdWy3K=Um-5X1a7jT9vtQb9ibaKS2un=eR(&op0M}x7!_c!@;QpUyvIQhAm^$eGqV? z^3$qBV9Am}k0Vf`}UPZ&Cp$ONzPZIYB31Zo7_9mmCYi61q zQZ@h4aVPVz50yC;Uo4-?pC=zAw?7`AB&H+;Y*botT$_~q_1w4Fo0A1~<9VBQ0O}$+ z{>!bekg{VzHh4$&EX@xTN>vO#WcI_(jzi*jjU?$g*jKT{kOU3O~ zmc8+{(f@Jih;N$q`bY`=pbf5q#&)v)&dT?;F>qF(mF(c^&91I0>hrWF{M9Qi@CSbw z&BkupeT>8E!SxhqjZuvGjpap-f@)#jD!U<(Oqw7x%=V|+8Trk5!$jvnw-oxViTa*y zP5plJIjc*e1G{jZ+>bz}zupJ(PjN!nYPe$}V*`U7vVBe)>K)D; zAZ*^pWqMdfvc_rYc%NXLCV!7m(EX8X&ugPK$jUOguiiRQ9xLyH1NUV$ZU1k*owQ5% zx`0jB;^2+>SoYYNB)wNrDwfycJ3`4cDN?4NLTl8aF$+84FXfkXj5AG#r)KMlVn`S} zF5tjcFCpJXFPko1x!yYHyUgBnSTjA6IexoqiLEon{iR`>7}(wnGV#q&HbHlTBSlt- zPTd#KQ``v4WB5dty-fH)kV4fhyBI(& z%D3=^2})x`$SVZlTpweMNq#O@au8?Gs7fNMQR{WjC>gmL`>VMei3S_Vm?4y4?LhL@ zAoWeoI(l3#t@82NULd=>`>y*b-V6**&-Wwz>34$H$rO- z%W9)*yJ}7=p-!W`FB?6n07>xZ_%OUPj3x(tx)7G@W=0ztz^$XBMQ8s3c->0Z%U>`L zMR-(@u?j;uCV(_e4>g@NE=@ZC*!fY<8N}R|v1(u1nC{Vb{cR<{)XO?u+@wT$Is#CPu$mLsd^o1IJ5b;7BuX09F7i8=)SW5JH+q|_wylVp3T~BL zvEO;6ylI2IvynRiu$1v|D(O_ve9{$)B_;99BS1T!O?+ViewyVwH-zr} z*tqyvf18mCsA$K-vt9K0r}b;g&q}mI6{z~m6YbZ{PoiW{pPhCm%-k8o-?~nHIesE5 zNM^J-^F!U5Bb$NB(3c1Gu179NOo6oyTWMZv*2@J{sM3;GZg=Pna3_kY^08IudIi$v z$`)E7bnOkLcT`W|?*hhDW+jFtS)z`{;|fZhJlI;2CQ`50};V650gDq7k^9j^`oaTtjLpI^Zb3Qw}FjoDZ+@EnjljT-*W5r@!R0;sMki>D+ zHB)t_{q=(7NMqZw9uF2rO2+RpSs4YvZ`%%y=1gB}QeI>mOcUqYOZ9RUb8P}&9THGK zR&z|<`}Rr5uvC#fw_t7|8KE>hzmyh}6I3$%JS}*%rWhu%YnGYtx+9Uk4ktY--<{a4 zL@yVYTM#b~7D~^@^7GR@mNO5{lWG~*X=d;wCxm!irvwpNAq@gIVu?ec^yrr@9LBux z3pS=)rMz6_+7%7dtuk>_oaIet559JCKu>c>Dr;r%p5Guten8TxP3QO}n7VxrmzJ|; zB2JDz;qjepmx^bf;|wPw4V0!+g!`&d*?%Z;_n7rKI^%SNY6R7NKrx3Xe@=;J{ln)n zc0#1dvf0&scaJ!^B52;t8)I7?&yY+)LTR+{2<9ev;f3%&%ndiGdWGUd$xwa}cA4Y)}8h^eLFrAvGPr}r9l(T2%qM8RCDztvpr855 zI>ygDZ2@BivDkvCoX9*dFi_&CMDA4XM*KxUV%zs4#PzAk^xvdNbDjGU!C!y1>MJbV z8#1Opo4I|9r==E-a6S6$WPQzJ&1hA0f1K zmk*7z1$qyoc>8d9&nkH%$vK!8ANZJalM7dRLVBJ#kNs*Qa2}#VC(tzZ`W|!510}!KfhZ6KhGJJ2gtVlc+84$S?G1vT@GNb<;ih*ellYS!t9!L!Pr>9 z1;4DMpZzuZJW2`GlLp*IVHjf?FEtk63#8=H4gQZu(y818a}ZP?<2Mr%tCzAHNshf*3bV?jW}!{CR1bcil@If6Ek95;xp7V4nrrV+nOG5ClofgCBry<&Lu!F z${6J55l$S9$KtF@+%2^eFlJmYq(8W^6`h19tBWe3DkW)&C!kyVW{H%&tKIU!q`O~9 zA%(s17Z}YA4U0xsL$xRN;lq+nL+^*#4jK4|_U^Rrxi)#|yrf+$oe@t}GX)bTI};kE z*Rjja*^Uk9W*l|uOSZrQWr&*bFscsMzTsgFolRno>bnUKpF}*Qf1a;Q3Zht3Zcqx8 zV@csT94X-E!O~3(NR+?`MX8NQ} z&z@&$P*0JD^Kzy0H1bRn?7^=8RmQRMWoM6m%lYn}HTN)<(MGJzs52mI_Ec_lOwY({-}zWWCOoUrEg z?0Z;A?k>IU`}}LEgFQL1$?mp&C(j>XqrB zOCb0P?#Vfa2LK*dj-D*g#E@q{P$%xov3Oeh(BXw1K)D7oDJU)$C9xW#JKKf6>@aj; zzKuT42NB}maJS32ImSfC7?E@@=V?!bX{=a+i@Fb}qraC|vLdiSyN!$PHwxu=U0?jD zwJ%Dpu57`ru^_xNr{b>BGJ%J#y)mRoxX%6Tbxzlr82xTgWb$lFy7&yC$k_Mei{_-9 z;dJk5g43j=&Pe~K?Tu?cgRbtfz2U%Dr)(*=C@9MNT2r8q9SbW(@BH{AXLB2{mlrNK z$!o0|9b;!ra?EJcMa4z-(>ws@(G^BfepYc(9}M`jIMSrH53j2GsqacXzPk3j$cSwP$nLrmGby`3K2n69S({98_V#$J)|eFpo2us2%lb70Xm+bY{eLMi=@ zD9iZXy_Xk@O0Yp%iXVdm1GmWo$p{(gM@P*_aaV6Yt{i8F^zHUhRvGp3>j(L9H=710 z^cnJP443uJINxDxmqSFQ!!m7tOyxV2+OZ?_`X{UCk=wdpjkvm795y6=TZDCBamUYP zdt%l1Q#)f<1*x~TRv~mek0_R^5DH&@vRSxWhepI70m@`wX4}0Sf@aQ724Ty^$A4ra zuTl&tzvC+GDFKu_@_NhdG;yRJF+3hK*wSGIy&h?~@rjR7prsRVe(>?&$EXW;x4r;n z#`4om8=vjW=~1Q(jdRZL1nQ(&g2{p@|KP`qmz4{Ux7$UMDzcGA0JzLL-S+X)TX>NUV4j$Du(zR^-NUPNCWGu0v9i(hba^*seCakbWw z=-rEQiXxNi7~Sknp|K!GpuJzB!+1C%(}6R|2ngS?q!?37^XKGI7f_*1V;XHDi4_t^ z?RGalkgPrTIjwwtLdR81F25Yn4)WR6P(u^_*&8=zsntDJNjWhY(bUh&q4Fp#)I;5| zfL1VgekuuSIjfmYvr3JsQ&?-rs^7G8r#iz%DWXpQ4{ zJ#58oPYISc=Hl`S#NRcjdMf)Mfr0z-Mv&*4a2YnoJSZ;COZ}#D`;mMg2XHps8xH+$ z5t5pDe3}-LTa*ykS9~xhJGUUOwxl6enz(o;ilNed zAG}$e1Elg%?@@zO%=?lxN7U`Ml`!@1m*+2j5Ghgiac>lWiaz^DyJu?Bvvvl1Ukm`c z>fLa4K2(ntH8(OM^1LXeC|!c&mq*MSs8aBiBcjTzb{F-O#ocDv%3Mp^R`%BXx;c2XBt*ot*xLQ(EO5PMN1Puan}3ivg$Nh&{-I&C&xf2)R^naMna$)<;Zriw}E zSVN{*UWN(cpJ5sCE=d{PfscKZO_A?E_?(2U^f=B~NQIrQ+1R+YlUwtBQAb6dtz)mx zueF|3@#Sq2wWC7$3gsasoGt^ezeG~ZvHPHF5h~xGG4dDXQ`iyTz7F6tBAB)~c_*Y@ zYPzHQcoZ?sc;Tfu4}IvxhobGMU(kOEB2|e+euCVPb9Rw1=xUkB@N9U5n&5&5?>={j zIg6BAD^kc&tMa0(qBnAddxX@bY7iYASY?f%rV5Z>gOa%r#ouqVoU`kl9YmOeu0!%T zci3sNqC)flCrE2u6p)i^+pAn%FKZCROgS02*=t2A?;zxg*MFJj#G7>7+NcoUaaE}z z-ghHm(9tK?{%+5C89DDQp9Vl^Dfl~&GDT9)pw6Psk-i->SqQmy*0MeAOJ%%BZ^---gt%cPw=1^ME(X;|8OOBZK zMR{OS?8xAe;1kf5n{#Qy!U}SP)gKQ6o!L|pa?DdE!Zq~!<-~lf*{=@t7D4IMmDlf1 zh2r)QokZq51eJM_a#IhIg$5JrqlV0kpx4$pZa6@d`T~6TdO=%DqK}b*M|tDW@9rLU zBTQ$h1#@)SHYO&3CDH49h)&VU$~c-JQi%Zpu7{|8s_Z!N1!Q>K zhWGZ&Y^TP>qE`nmd^LDS>l+zO;hn59j*=Dr3cDQ_H6w%qjpQ-F(r?!brvT%<6iFR`pLm47eg=mV{o{YLHiCS{X8eZ}7KZxQ;1)@iy^6|mg zdY_-@|JbQe4qiuF539OWM-gF^mEP{wp(iIt6o};xbe?&n_3^f{sn>hAd3i%E(F&0uEe^ZhR88xm9ppJd z-kXLUE)A9D$p(!o8n%0Hj@U$uPe4ITG$_yoKm(s0LcEhk0e?`6q{T4d^hjZ(9ML7d zK?1(-b}F1D45dX{a2IwhSh#|X@K*W$p^hd8v!>l+hx)QK=0}t1k840bt?x@oc`xCb zJ;jaUf$NBDb2@iuSiAd3lL%6IAkdN%=Vzo9CC@$zrKLF#n1Q(cmORh&4H#XK6^@}m z&CfQsgSGxC*v0-Ew=ovMGCV@+!ZoS%J$SG8t!Y{`XK`hs*L(Vw<|OqsdM_mXSN3?R z?=Zport>o?;Z}sC#8qpjhbOy#d3wPH13HOotsm=~Y~!eLVqa8_5=2x9ubjk@vP7pu z%)W^Xfk9r3EKmvwh}xPg9je+V*;Xr-{$)U*;cuIrz9b+A$s~Cxca&{{haXe5Jm#5iMk^yO02B`eHk&eBbLJTPa49=#bcfy(=H>_gG&L zO539?B(Ghk>X}dDJ_a}Qhutq67#mv=^c@~)2+eltjJe7v%syEzCpv9|GT{&STzy)R zXdVAX#6r2i>o#4a>K{9tV^A6(XGqPegN-Zvphh(mhUy+)-z^C?{L0IyZ+13sabuF0 zj{4YLSCmDS{$DnRFiK^6nO8xtK_2;Gwo~opb#qV4D=zEZ*q1g6%LHd>7_**_fr~|L z<7|_)Q0zkFxpt5@d0T4?4Ss5<(p!#|8`WhqrHB7{eV{#Y zD*9wyQCm@m8(5YceXCV~pjpPnyaK#bK)Teb`D;BqOEQs71;R@52MvD;mh!Twqlo-a z%tCo%QtUMhuwF4x`ZB!DJ%wPFf_%gh=&NeE(`@Z_*;r6G@8`fMQ{^e-{G1M#p^>Fm zRe7Vva8H3C;`*JXRkhW3vTNe%+7%nIm8Nso<=WDcD#~elAb#ca9Jfy7V}mk~ga8h; zw43hkLsQ-sk&AjBg1n6!t03%yUJYNLr&MI%Z}Deoc}PB;D7uQeui|N&xl3! zkjnR37?U~$uh&v2<0)sP&Na;)D4097&a@P|J;+gAYCh`;wkNQ4j5* zR-@6gW4(+a1PZY`y=|3x!&r1HQz01pPJnMG@H1FBteGFPhp#vN3qo~wbaaIQn1 zkKf%DMEtVI9CJTcWR8`m%T5c%cP^&f&#$3(InQ^h-|^da5>wQ|q|}sbx-dZbLGS|j zUh}ySS0p06BEp~A1Se;FxK;X)Zo=Z&g>*-r`LW?-GZSBN9O(uF1np6g82WwbQAYhO{}EQi ztXti{4};l270+FcVl|)Z96uv6%;e<)?P<>pRh?37h@+JyuiHHu?W%=MQp6j5nE|0) zdUODkY0LJZ0mXfg+dZ4ez?&^c&Dz;-D;G;$Ejf8*GCZdINt-d5$~dH@D+}QMGr|62 zX&MnL4;2wn8ezGM^GS8KYkdzD7`M9A}idyNZ(g&PxcQX%O*jXrEd0R;= zmX@=f-jz!d0U3}i2iOZ(oIA7!GJT6~xAOh|b?eokzd)XC0_kjU0#bUn-!hIt zklB5mkdi8kdG7Nbar5JmqbM(b%00?`dl^^|sY(1RrW!zdmrX-#|DZDHXc(ii)a_WR zZ;Y+X{2jxj5=1^x0ZLYG{@})$?^4?-pOrYOdvD5kc2xfrcp^|^aP;!7G0FpbX<$x+ zSZ3o3%zb-xTr;0@-ip_)F3b^?sp;6LdeX$-EWr^8ZcG+(MG9<99&$OidTJf(lhabY zU~rSv+?S~>=jioVp^uoG?!beBcy1(D|UxJ-FP1Og*eo|2u=|PH2Rk|$Ch7a&xO%P3`Qqra$;a1PinOq zTwdp$>39^WMnuIsFC;*Qd&judQeWk9B!}Dm0|QNouXEvf#u_bM^q-WGou@1 zr+A`Mf^tdoVW{X!Y$Rxx00iHMD?jA8_|bkRM1wJ$sXh3<)*;=zrrnehPKh|vel?!F z%NlA_xgkLWsR?Lmy)BLikB#X_e^@^mVEO9}*5B$bOHYnu1m+}o9c*=~9~tB*OCxVn zjd-{s!)Z!7g@t$;?UhEv&P6e8Hu-0cXDkdqp@pXm;MZL;YP}kc!)Z<6Jt8$pSzs5U zIT5eM|1A=?YXarC2UA0|ttx)98zTlF5zjncZ#+jd3`ven@c708s^j#Vn z-)%Pqp1U?lDW)EYU=0V#wWdW^97didUfy>2E`$6DXKxVX+W{013EPFDzw`oT!glp} z6(T8Ieql8naP&@g7vHbP&njB;JUjH#BHQa@-wQJ->*nFw{DS+M5f>Q4HD0${MPe$B zAf`TURHCja+)`@7YV%mZ$tmH t-~KOr9R2Se&Hv{mc)~w%p)}6M>fyh?Mksyx1oj>>H?cM@``z>L{{l_JTQ2|r diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java b/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java index 43a5b40e..4cc94989 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java @@ -66,11 +66,10 @@ public class WebViewOnTouchClickListener implements View.OnTouchListener { new ColorDrawable(android.graphics.Color.TRANSPARENT)); PhotoView photoView = new PhotoView(context); - photoView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - photoView.getLayoutParams().width = screenWidth; - photoView.getLayoutParams().height = screenHeight; + photoView.setLayoutParams(new LayoutParams(screenWidth, screenHeight)); Glide.with(context).load(url).fitCenter().into(photoView); + builder.addContentView(photoView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 4625291a..20950264 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -12,12 +12,12 @@ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 8313c78ae3a1ad0abfabc60ae68a8e166c7f64f0..6d89e003b0bd71c1267c569f89fb0acd09254629 100755 GIT binary patch delta 1401 zcmV-<1%~?M3XBVoB!5#$L_t(|+U=bEPg_+O$2Z&(Um*Ac@hv7K1j5S%3X~QKv{`)wlnpKRiC)bK9=W znb1o$-rIAMC%5f6&-dKt({rA4?rnN^?2ttkS!9t#^JQmoaewhHJsDyO7n~>^fALXa z6EGT$l{q;%{n^>sLwp=$JFPJr^qqS@VhIN%;mCqjF-mI)FN=r*~1;-o;pq&PT;XOSA;sF3aXZ@>msDPq) z2%d`oKo=3K8h=2$7|{6$05ptP)dISpcR;DBsh_C^l#!9)i2y*CBp?Y$0+N6vAPGnU zl7J*22}pZ@jJdh0>hurDXrwZC7u9>tk^QAU@jkfD-uI%YLz_)?kpjqippLp0?@;fb z8`QnJNX5@L1?p^#&r$cvf~Z3qw2e4GwL^mffZu9|K7R<*)x1A&Pu*Z-0m?5crS_>w zWrQrvisO;nlVmiT#dJD+V_X?o%gQK1Tlho_p#4W*rJmnbsdHh5s@^zGJ-@Dydt-%) zn-5Xpvkr2vEm7|u>s0+tzi5ND@QDaOxp{fiGX9+y84V-DlwVpxtv_BD@9RD~L;GK2 zc)zbv`+xK;DyXa!ZBPdv`05@|N!wv^um2)OO=-swF{PZooYQetZ1$S0s=mFuP%vW)$7MZ9onF+7;)^YYe1F?yOLix z*vex^1D~4;3j+{f$T>yM>Oei(3V7@b4c!8A4u6~y$+u(XHd)H|ZK`v;by9)DBdK-b z2Qpi&cfoR7_`nw$x&&k@uu$jR&&s~$!_#EEXLoF|^XS@G7E5~F*`ZClXS9V6e4zm? z-2t-qy`W5!^<^rmasK_f%VZ+wyQerwU%qcWK7%hbp!L51WN|t@wuAL#t9NSEK3yHQyNbU?pptbgK_m&N5n{e@3NU~Q8V{LQP+AMk|+w4e!X z^x^L>lymG_nDKVZPm}A)W%Ypa9914`T`gH_YrNvPMQi%{OJyp2JI1-AMw}2fyyd4MtJ78PG z!LR{>mVZYMLtmQP2Vp7o-xX|~7!U7lQ`Ul}n7Z5t`qCUAv&~8k!=H+su>;9D%y$GG zZ=Mj^=mULeawlynD4@KO66H=|xPN~QVNGbG5Ba;8{NYdnl7J*22}lBxfFvLZNCMIn zAo*VnIfAx5#m?v*P)bUQM>Qa(+Y&6M7dXCHyat1T5)u-65G%jm9qONYA7FbjJw1Kd zFQ_N;O|LbM@o8VIAwOsUPLFc2K?t-Vss}?X9MgJiY-|Z)#0XOR-}wjGo^oO{#K*@U zPfSc4O-f4oCOJ8IjP0t%Yz*g)7!V6$^2PShww~F+_AuKMY)Nc;*q+h2?eWF(INKxP zdWOet%(a-9n7HWZ=*P5dhyk%6rhnxrFgh_=WRXP{O_aX?Wob(}htN9y00000NkvXX Hu0mjfS2d(R delta 1361 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 JPDHLkV1lj^)ZzdD delta 2988 zcmV;d3sdx&7qSsK@=zj7f@)ebzs_=jul27i6f;$ z9;e@Ta?azt_wpcbxmg}}=FiQ$_niOy|9AiGoV#@D)V5n^MSl@KNT0uJw$3#*HC-l5 zn9!B`mUi;!6Lx?_P&s80URzpPTKCbTNB6he?TOeAC8_`W^IRZ2JH)21x_QjuaP))X zr8b-GVbGRQqeh*??~9<%LEnJ>r|27X>>}H!wyW8fJWQVcT4S4U3KW+cj2Sa#AQW5* z+5-hIgG7*Y8Gm5yCQtG<-PiMiv^$G2O@8Fak%ds=4^Ze!Q$Z-_#J*7z+Bta)bkl>J zJZHA$aSyP*wbia0IQRbC{z!RXzVGl*Lg3e$q$OB;W_+gISoJ?&RfVI^iHl#q% z?Vi9ibJaseig%;O@$HnwQ@&Q;AV{R~|93(EHHEek7=K?t8Dn0jOwGyKs^DPX2ei)+ z_C{-gavL&bsHcpr3X&cO{yq%<|5FPUiue*ji*g!3QO3Mh0Z9iw2ryNdaeJ|v+gcOk zy$&j~GlqYm^uapkdex7bYO7Y0{8IY!}l9&QGvS_m^~Cm z;0U8E5&8M~s{(R0J=ue+4gs@kMr{!m0BK#|YS*%}v(rtT{Q?M#wuYhgxLFZm(N4Y6 z>6dE(-SNgeM}#Tegq|WdH+QN(uBHR?p)kl=Eq}^t2-rtk6tK0Kp@YL?rW}?4Y29c= zh(+V?7>f+|dhsr>9&^o#v1rSk+$=(Y^DVVtZh7V^oHR+4%&HNElP8JMHkTvYwegf7b0h+q0jQ z!5VJ%y01lld7B0Z#-ibWtah)W@-ngb=pi=%7Vh8MTXZ9*>jm$Oe$3Ju_UU%xa+`lcTM+F~_86Kj`g}Wk%LmfMThr$RmTHUWZ*4fg^lDJdxx4H~R)F&2Q!&b=cQtNGpY!d_U| zY`aOdOU3-xwu{+++=QxnvNwq6$Nn&cY2m?oIj5Sq=oSb?)2E9E-aGA@Z<&ENpjrz3 z$w#^?_>#XqSBi0Yj&k@dJ9K8>nk}0yb?V(a))OF7&$_c`PRJnm@%ct`qUbNpd-av3 zVh&ey#`-6l0_%lyqJRA1RUvT)@*zL+C4X5fVZ3?UUkO-d>ipox7sR|n^{0VFZ?|W( zRat${?3Xsb#98!$-8&oQ-cPDk6VJLcC)GmOWK1LW-I|S03r%V!AH5nt{v3zn)tx@+ znxgnEKXu--Q&j$Pd4N{J_HQ#XK zi{l2e6rvtl7npASh#2^KxQZqf*{@%}Y&5$wLad4-Pbcf+k`#9e{uMKyK5;{y!p9j!Q6(UH65;ROWeF%<*CvJkTj+&&kQT z1f51xH&qx0z6~BcxCeFvf%J4t<{CQss|dq}4f`6ig(~W#bPIlqjg93BTS8)D;u3)5 z?5HoZzzdx5@$t)`OQO;#WFIN$jA-ANu^aW#cQ}xlD%*R^(cs_$e~&u!>C-31iZ3`s zD1XMOFwI&Fc(px)WP$^?YCtha%Sr9sv>?kmI9ZnVK`;rjhl#($fyPy}v(YYb`saz5Wp8h$hVj^44|AE ztY9olf73&O;xsJA$uSWZmr@4GqGW0}A3KrO)U#(#evKs+ls{m=fccomZG-TiF@GL- zWIDHxn;0KBagjc5wly;pd6GBBz*tvB1JjXV0pB?POzT}~-g*=luhMI78 zoR2Jdydcw^1*QUv&;AYN6MxKpNWmjnDo|;(nSyLnPU8POhI2NyVO!OQeG|w_6|LPn z^k=%70jnFYHfs{N#{jOya4lE?#~`1qC`ldTxj43EA7v@s!U>c+1@;J)X(b|+HAE@u iu8wtW_BL=UZvO`C_Irg4*Fh zaL;&|pIZS`=eEZKV0-ug^4w0S`#25dt(Tzg!xS8Dxqrayj`7C9=Y7gYM&a|l##*gTne@VfWm_us!olLAfQ|eV zNAY?AzkdsB5`Yc2;23)gj`86oHiv=jQ9mnzW6e>Edg27}G_Njq! z6i<1SPwUWn>)r#jx7UA~0oT+7mcy}#exN9x@+hCy5v7UExre|tIR;ht?+V@)gSTDE zb4`x3bwt~Rj`!S-`12s}+0k?ktaolne-B6kBmt6ue@(z&{m)&MN~PxY4Jeh${b2?8 z4}T3%>Gk>M^#r>oaX>BuGMS9ZCtB!9B`Mt#7Z;Z+m&;4U1ainDE<&FEN)cNS xGQ@U~A@gyG{NSCM1#57#m{_f0rNP7a2^7YLH+Ci?u%rM0002ovPDHLkV1gbfxHSL( delta 923 zcmV;M17!TV2f7E4Eq~ohlVKFMtSBdW(QbkoG;M6T=Epv4>Tu>)YJNm6hthK5<}?ty ziNf%@5V|V0q(njpFC?X+u=Qb@Te?uAk3T^wKf3HfPUk#rGG((@3E!uBA2>X`=i_;P zzxO@oyzlnJ#7KkVVYAs{tyb#}F@-Q}2K)A)@G>@pXT{NEGJoyU>-7qw(Rfe{p}h%1 zBy8(~$G|w0PLw&6d68uMx)suj&;?bil-T!4r9p07F zG}ATd$<8$ab3p;rzjy}CpWj1uZx7SiZgsM2(vzKQ0wtF&f@fxmfprIba12wYVf-aD zOpJnOHo)xM5}-VHJRSze!v~P>aYNI`8K~^I22CHP;eTZN6{aWq+WO#zK*9MYy!!zt zy3h(Hiv{Xmd7&}jXGF5g%b1?*cEZD2R@AGIUKk}zIil^ds z`Nt#ggBaYC6W|>6E@ifOgb~PZb}v@<-35E^on@LMNzMI!mfuCKEl|~U16;l_uvC-_ zN(=HMe~P1cT8Gw)v=3ph<9zyd*OIQV@Xw`?A%7zSoY?D~-lx#`&JR`HH^E>s3H#JQ zKk}zIil=pGy)CZ+>h07b8>go*9nNg%1x5Z8*ZgUgts_bioAZuCgYPxi@AV39i{WjT z;#~eQwvK3B$XZ(iS;Z$d^{JdyT+HI7-vbf>iGW1lA0zNr|GBGDsnona0i{xTG%A76 zp??9gJb(ng@pizGl9Dp7P$-m934|Rn?bd3w0~pB7@e*OtXf%U}ZI6&Mve@|e_++ew zA)QXQfRFAwJ-*<)mBRKU42We|CX-S6#0ovBB<F5)$&{a(S7Uf*A4%i;%m&mc%X; x8OmOfMHa-e@q>3N7Rcg;aewv1?8Ivd@Z%@2xVSjj z)r0i(^l$~=d0LfR@Wu#}1irpN7 z4EGqrGk>GGkeQizPFj7Fxzbr!?HabR`yvPX)TK^V^h5W-qNMC>ff;1jy6{0Si|qve|4Gwzs@%IcC*JC8~8JfgV)H$ zMlV1Y33KpW@33S*zg`2Zxw)+Dr9EuRweMMJ^9wA;YGsbr_tj7W@ce}f_%rZ;7czPc zpnpWZ5gQvDp&F2sloU-5e$#6}!J~^7yDzwbep{f9f@$bGGzC59=uyB-@ z_5yXUARh2S2D02((gi+`^8#C$ofVWW`#pi8Ml}ElQGeyTez=xsSX{@Xja{8={(tJn zc}SpSqRJGnb7)>k@InT%&;ec0iG1-e_wdu#ud&*$&KuJ$mIvi#E@aig{TJ4}_YPZo z=m9ZHBUuQPDXb!u$p{)vu`&X-$irJW9^Fly7%PNPItoqzg>$FQE& zm%RWTRi{p9*_k;e3ZD+bdjDOo0!kjFq@+9p7ikHj1?#K%W~7u;Jp@_kD6X#56h4## z%wn-1e1e@{EBOmTSXfvLxu|cVzEV;b+8-JkI@9Hgy|5^hys#Z!5D7COUh0+Ar`>l4 zFphOTq*xS1?P||NJ655Nxqp|iJuEN=xjU5$iHV6Rr%<{x0YYg=w9j`UBO@z-&EpRs z!iWdRU3;WZ^2^bpl(>6=$>Y(YRGQ$Thmw<%j|wBk{cu;ziB0Pmun0^hZ;sdDsyIsO z&x8@<6;8^JC;)#N&9cA}q~`~Y5F!gHYK1Gu>jw_ZC00HG7_^4Yn14x4G&3sn$70y zxVX6O^gi7|q4gJlNPo%hZuL26$WRO40Ugik`l{UjaK)6RAgJ<9YFJwqIMd%0KAR z2=^GnGr==m$e8`{XODY40uYE>5xa_a@c)PV1WgfRX7FIOeHrz4f`0))bf+nHbACbq O0000UvF`~S55yszT(`4lz9WJN$Ih^n7 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 delta 2086 zcmajgc{~#i1IO`gS!B*(ixIgiXU;WYIVWUp!rW0-9*gye=25xtGk1=1w;WAw=J+{t zYauP!9QAXCtW{6Fp69>kkLUZ(`=9UsA2xrJK$;(BE@H~&1ad}>fkYfitM;wtGN2*x!e zBv5X$Y8yzFc+E*k<>`%Mm80eN47n{2bFT?m+(|EHVe1E?KXdHM;O7SNMq-1!M%7_99gw|nov%ZA&GtkK~8jGP>8$77_nc39z5Km>;TmQ#!;25^I;SVBB1 zu}gQ_&1)8m#ZIL6ourCTBdIb}qt-Ba#fbn`1os=oQq^f^0su>)YWFcKGDfHXN!WYgj-glVi1F`AiH%d8GPCLw0qE@mmOP zo%Hl{e#HPI@nUeun);<8m89p6D2Q4B@Dk|6i37Sd1X!GhB>3w>cI-jToE#ja(^-ok zGjMQ`x{s+WMC~3hV0dfi=qQzws04uYfL;RrFFa@B^9aV9E70n&3SNjOX9k=ZFH)J3 znBBc3;HQuppT+L*!0({gy!c62q%%NS0ItAI!3$ov(^9QSW05fAFz|JK3f?GkG8Y^y zAWxuFwat1P-8Q+JsrFp97SAJ}Sru@*Iq;$W`Y1>@?s!|%d^AC;H56a(9cGoiARjpp zg1!GK!3yyejf3?7&C??(Q}Q+0C5igq?eQ%;<>Q;%wPd&EG2u-JLMf_fC_MC4RePwF zbQ9aMT&;VT)W+K09ECqp*K+6=fx{corJ-NII?7T&O#m#TRe%2L~KY4sn?F=oktcmgvn|5ol?s9tBsSfjdv zLgMuH(V{P^>edSnC}y9alqYzAJ%rGrtze#MQ>w}rM#LU`durSkT2RPp39_@MPXE9y z`s!tnY-XK~Q9*nMN~c9Yr|s-!l}ue7756tnbqj96wCZz2qr-nL9&|30lD#>#y$Znh zKo{TE*%{}G@CEI+7PwL-V4LBITCC~IVIxE z{U0g_(K&}208NOc7mWSSC*mdGhZLUl&NdW-ey%a;Ze2K~=&mIk^g-Gd0y)`n)wWTd z7LzKdU>I=sZpArNdyy1$jHxmk_K>SrY+0ibt@r|-6`;J_Y1hATa6)o^ecK}Zk`02^ z*hP&Z7i)lhG6tDFO_-%8X!ptYI7wo%f8{b=R`PnrFA(p+#+v16o=XV$?-7 zm#-DDQ@Ye#;{qooGcY$&utccomOJrt8zZ0IqjRMsO>Gs_!x>RMbrz^tf8~#1b zfiqA|A%LokR3E={6dJO#Hd}4yBLOpf@FS)+Ha1pOwEG-t#py{uADcUKa&i(SByafy zwB<{~dAH+inIceVqlju%JR|qp*Ha8R{onnF&iUd_qASgBg72ho(?2p8BJeY3eilfB zN`>rF&MKpdLOi*PtciD~D=@UE%YpKGpUcpqGTnj!2_+>sbQE;o*oCm*1f zd`ZzVU-IZ>VC@7&nzY@;7hLh%W2k5Ep=B=p0K!;>m9> zvg$RYb%;cwfsRfKfQ5YWROXQ`vIniE3)G3vZb z0Kcg4DMotlyAajEV{H(L92{}uf$X}ymi!ap-!(2TXLH(alV9*7(|rKHhcU4>esRS! F`rpgP;f??R diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index e52998313cdc30da89131006e728519b860af42f..5b82b4147a71c22e90dad817839df0ac334528dd 100644 GIT binary patch literal 4224 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 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index bdc8d5d8142f3abfefade008968053321591ab9a..1110ade8f7cd804eff75376a383e155ecf0c95e8 100755 GIT binary patch literal 3122 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 IdGD`(1KqOOS^xk5 literal 3122 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 F{|S@_(r*9& diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index aa8e1212950b19c9cd7c3228295690d7d7f5893f..418dc97722f24a4fb721fdd954c5b79b759bf17f 100644 GIT binary patch literal 6617 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 Xg4Dc3F7<$400000NkvXXu0mjfqbjr) literal 6635 zcmV=-~C?TRo(6Ub!4fR#Tef*5P1{+8Kf=QDmMW8SsP6P-;4C<5M zvJ+r5g7tZCb93{E#>U2sy1F{Ys8OTb^jSlnBT@Ko{GS8&;9h?q5x|mwvKVMIrbc%W z0MbT}9^Ei<jp@8q`Ktc4_)LhK4>6LIW< zX(3H8h00ANxZSKVbV8=@g+@W?M8W@Y>Go5)`1wvQYCZgaMu0*ecB4<|8=Jplm&VM= z%M5J;0gzx$qPP8a64XZq0u(|PAn6_`?IQrDZPVbskGQWb+801-r2)P?Cl`d4gmnoC z;(&*Mx;2354uZ+@3n~quJo|G1W58HEUlJ+t0Rj%az0EY~57Oj+;~@-RW+Y^a#(Zl3 z{~L@6W0OGYN8o5Du)e;2GEMYLo}lq!Cah9A4Z!pg0qJCK^B}JPc#f7Eka};TNqyEp z+jLtPI7Vj96G+d}OEcDkY)gLR>(Ty0fOHwt8>?2^{bINc|gghPg8eb=W=yA^xB@>kOKVFQvKavswF+ z{ypDlZf(zZXzj zP*YP=L4!Li!4otP9VQS}TN*?{h1S*8mDAsUm*5FHi2gy8p~jNtOrV|@sDC2CV-ARD z{tsKuoC!Cws;Vl9260e=$8-?AN8VYQRb2dVjjO&xf+sXUL=Mc(+}zyQP!Bc^(PYz~ zkl+a&5Rp8T>gwu^8t@DWRnrCVTq&c=p%=Ag5Zw?Kic4h$%coAx_6TrE;e}4H5qwA? zda*F1JTrl24itVih!=oaVu4ysP0i!m6OZ@kx+X$z~D`(eJtyh?I9UP z2Hlhi(?y;5sRWO8K}3!ZOxY#D)TuRR8>IHJU2N!i zjtzwmwDxJy>{XWnut({JTVGsUJbfUwkg9zMtxwBzh5gbT&_d*qZ5j|Q@@;q_j0%h^~b;_D|_9$x(ysa#IcB9gA<}zi}=+XY4r+aWO zp24%I19hQJn~~{L!VC^`@5@rvp=7>pu#5JAwpg`uyK>I^2YQrMyWdpC&z|M?dEA40 zb# zdDJ~R5G@wsWSY&`2l4Uo$$d6s8uQg+7orH>a^~|-dj-ImFFd0(oph2{`us`l%azr8cY1vu zb)yYCm@)RoZU+YX0wAHbq6k25*a1NGjg89U$N$}{@I{$>+bv$}n04cIexFAhXv+@X zSXo)wF2X=;U(A@A_o51l#d*zE_r4}AU2I5xJSL@uK%Kis@v}G zd9;DH(5A(Mie1RilRLi(SipG)z2!fVWCw4ugZUam#CX*%z3aa0xu=vh`*-Wj7yzI( zL*!YVcFmPK00L}hZF*j>g{ZADKFGM0-1*Yd(tCh~-tZui1BoUiZngt}reFF?osba# z1mT^3|Gm2JR=mDN8Qa!&9DtK1D$AaEQg`2yCm&bqKwUbQp4zkt58B2&DB!cGRsNHm zot;XRd~9_S*3{Z+DEzZteu027NjZ7#IeODXnx^gCwa3lZ8S@AvZ|gj+X}`Egtpj!G zv>UaFwymCAt*op(oSdATD{v90`5H>d8>u-i&9Ve~^6FKF+-2rfSE%1NPd!Ch{>qEG z?-x9DzcQ-+$DrVhD=yQM?KfXnfral;mrlb`n`qkxX^o>qq$dU(mFAlw=)u#izI1hT zeZ8{yPmk$^ziq2BZpQRu_szZSR>ONH%$cn;j2owNCC~2{J^rXtKekDI9(Cb&RmMgV%t$|h{;MHd(l+r7%vpa0C*+%1?-Cg&|f zE#m2Y&A9wh!>m2(MjM`Wpf6UOL&%6pf=E!F0Mp<8fCG? zW}2NEpJ!xbRPtFuegPC!P*C8ehrhOB5OMrzGY#`w^X|Dzsc&lXz2sv|qjJW5_w?jV z`*!unaf#re*E*;Tw58);)F<@KiorzEK;L9#WsM3LKu)K#iXJ>-H2}f1%(~%Pz1w}@ z?H?D-2T(`r*(-WH-~Q^$J-n~R2^0L*fwqj&Bj}rzTzbv2j_-4Fa+-h*p8(<@Vl>u( z(BJ=OH2|q3_LWWgyw^+5^~|pOC=KJsD=XgEa-4W?IbPq4%PtKJ$kZ0v)RB1Vn>P|4 z>gkN^?CfU0u^<5;hr>~4MF35`@aOvVJqPzGr+9JQjnf}Jmu?6EL8FYF(iU(%XcKMg zTzcxG1p)L!KmcO(6kS+YSWORpXC(kZb1d2TCqvi0dD_%o)iq)69Ho8h=3@Xt?B|So z?+#dtsYzOD)5xVqAJJEfnXn^l!lE^Ya(V|4d13gGxPMy73u|4`uB?9ht=@0d@wR|| z`B}=6_3M-+8y;8Y-tn8>@3!!=1qgjaUoGZ^eVv(^SsyTfa&vQw>EXXy2|x=Uen2m* zy*rh0GiLNT9DpP#ysEwuU$kwsivxYNSRClH^z`(aKmeq!L`=@k&TDLG`FKogtJ2uo z+J)trW)v*QYG`f_DDP#oDsaJr_Z?euVaiSrY8!npS`8UUehg#B9GEr#s_d!#+Q!Di zBT`dK89;vBc-)k7_O9)JUPEsWy+K`2yJi$j^uj+rq|1DJCPIy(zlgg`UVU~5ENDC1 zFfN5Y`&ui6F=OnQ1GDBIvIhp{t$P%yj4Z~+P~W+*f&!e%ki2^To*ipHco&21^1BmZ zAPadz3m<(*4e}XkAM%WhmSSL+slUKsP_z*B0e#Vh7O2nOygG~(V-92&$v~F1@4wsC zL4BCFe%)Tqg~j;Gg$*hA5kN^RcWr-i?S}`Ijt>rWnhGFxp~uZM<}z*PpKG`b zBxJY*`eKyTN8b~;dTEkpxcIzBwux#r!y%B+X)$8wHjRxZ8)ME*Y3eIzd5_S&7H z0w9z*x8AH%`FOjRZd`8|uxmbbTF3wheK87fqVJws5@W$TJc-h499l%6D0CKrpVA>-b4#!xt5~@unPgc%+@mW3b-2CD(w;lx4$h%qi$b-F# z7za%YQJ>H^BX3cVX^ibGgXlHp0&`+gCjR@ZtgI=(1oPt|{&uCp&yS0ViE-4`)&0ec zRf(!=e$}syUGt9B>i0-&8hzjPleM9HybSft2=o{W#)PpMy8JX3!QLJuWL{QQb|^YJ z8Zn?a4kG&9ojR0n&Zw=e-DK9ndIZ|A_go(w{DaawZJOahPjHO`S#Dw4Qd{bq;qDI_ z3&w=886Eau(xQBIL49dy={Al54GZ*yj&K}nN1v%xRaG~exibR^Ort0+w#w*;He7ej zUae3q=%bF`(O57hqi8zjz|13miPGE$EHEYl`U!+^CQHdBB_+$u%*eN{Y&Z0>j3ycf zB6y1xg;GHu(bqu6gt21|%-WTTWA5_v^Unho7!%=vp3VUxoj|C=x}eX@N~(fXA{!n^ z++yzSw}vEnHX_sLYanC7*aOK04qy`XOTxf-U_o(G*eQJZXc06Dg>r)$ijtOH9w(G9l6OTg`3JVMGhBK9%oE+cV-^~cm$jE>v zmP(b(5G2|RE_BSL_o9W=gQCv2-pQ!wvk~tR+Q$sn-D4GEXI56$;@%QyPac#=rGT{0 zelxWYT-?=~?KM3Qih5pYYPH^Ra_BSq?(Mi?jM+@{Meh6iB>Q5D7>ljAGpu5hd80{Mw%64HS2e z$os-+97Qbq=)V4js_M?O3d^BNFBU4!F29{2i~ekA4jx_unU5GTBBi(PyHQ>Y3_Lw9 zF0Pie&;Qur;Bi^J2M^tD_upb;V;doJJ`?DKe)du|W5b6J$9h-?k?DIyo4YvIIt+%gf7uNKa3n16gzWBH~2Mm)4BM zk_pS8PiI9%#YU-x?5BN@c`qs|!s2-+%R07Sezno#h*vTU0z=P8k@4CQaF|Y&r!Vi#l^)tNrq)C z%fx};K3+YtxVX4X#0<#wn@)E0JDDf5R?31r=_5>>ode~0`O-q_n(3IBm;(ANbvm6_ z!xfYO3VrPZ8Nqbr=jY!7*|7}8n&hOG{stUYTWLKCeS&EW2cu zWl*$_j!^TiMUb$jii(OuGQb$R;Njo?I!sz;0hfP-@CrqP)WxBkXG9=wnqNAf-P>ZAFv*X540)6`Vn-j(&cikgRPaOEHq44RaF(D%}+r#ETeQYO_w)QHiB&`wt`fV zt=%F)6dI`tvI=jIOlnv*IV>yFOqY=s3fJr-bHK(@sdc;EdpJ^klm{eB5QByMlily& zXHZxs4$VHV@KDe`Mtmrl2$~a7YItS@q7NmAOp7%C2gzU@WWh2?4h7!hj}IZDnaV`1 zEHN>$h0NK13J^&l2Ms*`osf_)88RSQ6mz0A}gNC|ybL`FuABvSVZ+)9oUbxB@y;<+u%CGuNNr}H(MMEVorwR@RxHpZ^=oDX;BuX*7>z!D9rX;Y{WVqoSfJ=(9Q_BV#3b zXdg4V?vf@gV3VcpVJEVDC_O#B1K{B~b@Ch!52Zk1e{!NYb|>?Bz*UG-5b@irF=^7( z_u-=B6DEu1>{TMm6ETN0mzA0|&2d)bJb`MWNRCAyk(WmU$C{K%@FIu9ab0JvZnyiJyu7@dFlU%Mei8F{PKVhMJVwDrL_?D}cUD4^Pz5!dl9F;7 z@-}$G1UDM2W=&(RIyG8nJI&D?Hd$4eJD$TNp3?|BnXN!pG{!UGD_}JYAl2pO=3YwN z=&x}1HJ)1cU;q*Wr&~A{m;;)NPjYf{E@v-Gn5+VxyLdBJ6ov|j1i6O#&E4Au2M8)c~F7Jh!@3jmN?Tx z8`YA^o`tn6#E-t$0I5@OBrAhS^q)CSrvMJd>U27vp|Q_4&^nnsSFv{IJH6FL(Hy%- z|JE?B$lz~p=u-~XUUzt0=p~m=0Yp6=ce^u zOaqhvjJ7WVG(y{;@7P+5SeQoRRB=Sv!DCP2xrmZlr+3;Yf>rf!UI>-N9KfwHZM9TJ zB_$;-B(nLtl9H1B*l`Ik3C*Mhlz96Es7{naY3mSR5qw6wD@6mEBj_XgN_}30zH>ZB zm?}4qF^k7MoaZ1yYMuTAlF&#c{I;s<9&a!*(PZM5IvkEWTrSr(x7+#Z;Sx-W)i&8YeM)_K1AU^tok@MH=f0|DSrg9@8b<&pMgph* zffU1&o5br}aykD~?xB?+ppkKLacx;yS?A^F=ig1_bPEadBhmt2L9ozL@OS_$2)s9% zNN62Ai#h~YP&XEHp)IsYZJ$qln8KQ-&O_UjbKi4$EJ;%11P@429JY^V&m@Zpcaa86 zLNgr$6qPZFiHWl^GBVC30bfg|&ov1q^BBF`gs^hkWrV*ei;=X2a-xGK&Q4%=81=3LVNQ72O z(0~cKA?&;?Mf?Q9(`YD9P>o~_Q4itA#Kg3a);J|TKK@kVDKk*;H~tUbF+dt%E;Y|< z!BQ>SnErOaPLnR?>ngh27t5e&Zp;V)o`#P-!)UMq_C;m$n@H z&g1@C4Oq&!jY4iSoBNRB0UA$jBY_j5U>e4Ow?rnVX-rgeSR*)C*iJSr#jG*PxRi4d z|1RZwiujpAt|O1@%;Ywbxy=#W2MHRBf@vrVEt1J;EXP!aGk+4mN@3HI#)LM5!JsV} z{9PK~o1y_qJl7e=ZA5dM5gz7Ag2v*2(t=6=D~bgk!@`ectzlHe_c8oTlm;kTut>lR p5>R=9E8GKU+G2E%XFY@N`hT*otY-F}$?E_B002ovPDHLkV1frj$Nc~R diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 9286a161283d985ae9d92133924f914100874c99..ec360cfaa75d22bb2ce811649f4614591388d39c 100755 GIT binary patch literal 4466 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 aQ4Da4-|jq!Dj{73K;yoSdd0oxLH`8XH5ae| literal 4396 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 is6#D4t^n`F Date: Wed, 27 May 2020 14:07:30 +0300 Subject: [PATCH 35/53] Up version, libs --- app/build.gradle | 10 +++++----- app/src/main/assets/apache_libraries.html | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9eff4099..f7641b8e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,8 +14,8 @@ android { applicationId "gr.thmmy.mthmmy" minSdkVersion 19 targetSdkVersion 29 - versionCode 22 - versionName "1.7.4" + versionCode 23 + versionName "1.8.0" archivesBaseName = "mTHMMY-v$versionName" buildConfigField "String", "CURRENT_BRANCH", "\"" + getCurrentBranch() + "\"" buildConfigField "String", "COMMIT_HASH", "\"" + getCommitHash() + "\"" @@ -84,8 +84,8 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.exifinterface:exifinterface:1.2.0' implementation 'com.google.android.material:material:1.1.0' - implementation 'com.google.firebase:firebase-analytics:17.4.1' - implementation 'com.google.firebase:firebase-messaging:20.1.7' + implementation 'com.google.firebase:firebase-analytics:17.4.2' + implementation 'com.google.firebase:firebase-messaging:20.2.0' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.snatik:storage:2.1.0' implementation 'com.squareup.okhttp3:okhttp:3.12.12' //TODO: Warning: okhttp has dropped support for Android v.19 since okhttp 3.13! @@ -106,7 +106,7 @@ dependencies { implementation 'ru.noties:markwon:2.0.2' implementation 'net.gotev:uploadservice:3.5.2' implementation 'net.gotev:uploadservice-okhttp:3.4.2' //TODO: Warning: v.3.5 depends on okhttp 3.13! - implementation 'com.itkacher.okhttpprofiler:okhttpprofiler:1.0.5' //Plugin: https://plugins.jetbrains.com/plugin/11249-okhttp-profiler + implementation 'com.itkacher.okhttpprofiler:okhttpprofiler:1.0.7' //Plugin: https://plugins.jetbrains.com/plugin/11249-okhttp-profiler implementation 'com.github.bumptech.glide:glide:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' testImplementation 'junit:junit:4.12' diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index e2addec6..0a77a925 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -51,7 +51,7 @@
        android-storage v2.1.0
      • -
        OkHttpProfiler v1.0.5
        +
        OkHttpProfiler v1.0.7
      From 381b5aaf1b5bfa2a96ccd01fde23c25ac1d28e3e Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 27 May 2020 14:39:41 +0300 Subject: [PATCH 36/53] Bug fixes (BoardActivity) --- .../activities/board/BoardActivity.java | 22 ++++++++++--------- .../mthmmy/activities/board/BoardAdapter.java | 4 ++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index b625980a..87e7d27b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -21,6 +21,8 @@ import org.jsoup.select.Elements; import java.util.ArrayList; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.LoginActivity; @@ -158,9 +160,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo @Override public void onLoadMore() { - if (pagesLoaded < numberOfPages && parsedTopics.get(parsedTopics.size() - 1) != null) { + if (pagesLoaded < numberOfPages && !parsedTopics.isEmpty() && parsedTopics.get(parsedTopics.size() - 1) != null) { parsedTopics.add(null); - boardAdapter.notifyItemInserted(parsedSubBoards.size() + parsedTopics.size()); + boardAdapter.notifyItemInserted(parsedSubBoards.size() + parsedTopics.size()); // This gets a warning and should be changed //Load data boardTask = new BoardTask(); @@ -296,15 +298,15 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo pStats = "Replies: " + topicColumns.get(4).text() + ", Views: " + topicColumns.get(5).text(); pLastPost = topicColumns.last().text(); - if (pLastPost.contains("by")) { - pLastPostDateTime = pLastPost.substring(0, pLastPost.indexOf("by") -1); - pLastUser = pLastPost.substring(pLastPost.indexOf("by") + 3); - } else if (pLastPost.contains("από")) { - pLastPostDateTime = pLastPost.substring(0, pLastPost.indexOf("από") - 1); - pLastUser = pLastPost.substring(pLastPost.indexOf("από") + 4); - } else { - Timber.wtf("Board parsing about to fail. pLastPost came with: %s", pLastPost); + Pattern pattern = Pattern.compile("(.+)\\s(by|από)\\s(.+)$"); + Matcher matcher = pattern.matcher(pLastPost); + if (matcher.find()){ + pLastPostDateTime = matcher.group(1); + pLastUser = matcher.group(3); } + else + throw new ParseException("Parsing failed (pLastPost came with: \"" + pLastPost + "\")"); + pLastPostUrl = topicColumns.last().select("a:has(img)").first().attr("href"); tempTopics.add(new Topic(pTopicUrl, pSubject, pStarter, pLastUser, pLastPostDateTime, pLastPostUrl, pStats, pLocked, pSticky, pUnread)); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java index b016c5e4..f9093cf8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java @@ -39,8 +39,8 @@ class BoardAdapter extends RecyclerView.Adapter { private final int VIEW_TYPE_LOADING = 4; private final Context context; - private ArrayList parsedSubBoards = new ArrayList<>(); - private ArrayList parsedTopics = new ArrayList<>(); + private ArrayList parsedSubBoards; + private ArrayList parsedTopics; private final ArrayList boardExpandableVisibility = new ArrayList<>(); private final ArrayList topicExpandableVisibility = new ArrayList<>(); From c94ee97d272300f695f55b8e720ad51fe5cd3fab Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 27 May 2020 15:05:22 +0300 Subject: [PATCH 37/53] Refactoring --- .../activities/create_content/CreateContentActivity.java | 4 ++-- .../thmmy/mthmmy/activities/main/forum/ForumFragment.java | 2 +- .../mthmmy/activities/main/recent/RecentAdapter.java | 2 +- .../mthmmy/activities/main/recent/RecentFragment.java | 2 +- .../mthmmy/activities/main/unread/UnreadAdapter.java | 2 +- .../mthmmy/activities/main/unread/UnreadFragment.java | 2 +- .../thmmy/mthmmy/activities/profile/ProfileActivity.java | 4 ++-- .../profile/latestPosts/LatestPostsAdapter.java | 2 +- .../gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java | 2 +- .../mthmmy/activities/shoutbox/ShoutboxFragment.java | 6 +++--- .../gr/thmmy/mthmmy/activities/topic/TopicActivity.java | 4 ++-- .../gr/thmmy/mthmmy/activities/topic/TopicAdapter.java | 8 ++++---- .../gr/thmmy/mthmmy/activities/upload/UploadActivity.java | 2 +- .../main/java/gr/thmmy/mthmmy/base/BaseApplication.java | 2 +- .../main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java | 4 ++-- app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java | 4 ++-- .../mthmmy/utils/{ => crashreporting}/CrashReporter.java | 2 +- .../utils/{ => crashreporting}/CrashReportingTree.java | 2 +- .../thmmy/mthmmy/utils/{ => ui}/CenterVerticalSpan.java | 2 +- .../gr/thmmy/mthmmy/utils/{ => ui}/CircleTransform.java | 2 +- .../mthmmy/utils/{ => ui}/ScrollAwareFABBehavior.java | 2 +- .../mthmmy/utils/{ => ui}/ScrollAwareLinearBehavior.java | 2 +- .../utils/{ => ui}/WebViewOnTouchClickListener.java | 2 +- .../{utils => views}/AppCompatSpinnerWithoutDefault.java | 2 +- .../{utils => views}/CustomLinearLayoutManager.java | 2 +- .../thmmy/mthmmy/{utils => views}/CustomRecyclerView.java | 2 +- .../mthmmy/{utils => views}/RelativeTimeTextView.java | 2 +- .../mthmmy/{utils => views}/ToggledBackgroundButton.java | 2 +- .../thmmy/mthmmy/{ => views}/editorview/EditorView.java | 2 +- .../mthmmy/{ => views}/editorview/EmojiInputField.java | 2 +- .../mthmmy/{ => views}/editorview/EmojiKeyboard.java | 2 +- .../{ => views}/editorview/EmojiKeyboardAdapter.java | 2 +- .../{ => views}/editorview/FormatButtonsAdapter.java | 2 +- .../mthmmy/{ => views}/editorview/IEmojiKeyboard.java | 2 +- app/src/main/res/layout-v21/activity_profile.xml | 2 +- app/src/main/res/layout/activity_board.xml | 2 +- app/src/main/res/layout/activity_create_content.xml | 4 ++-- app/src/main/res/layout/activity_downloads.xml | 2 +- app/src/main/res/layout/activity_profile.xml | 2 +- app/src/main/res/layout/activity_topic.xml | 6 +++--- app/src/main/res/layout/activity_topic_edit_row.xml | 2 +- .../main/res/layout/activity_topic_quick_reply_row.xml | 2 +- app/src/main/res/layout/activity_upload.xml | 6 +++--- app/src/main/res/layout/fragment_forum.xml | 2 +- app/src/main/res/layout/fragment_recent.xml | 2 +- app/src/main/res/layout/fragment_recent_row.xml | 2 +- app/src/main/res/layout/fragment_shoutbox.xml | 6 +++--- app/src/main/res/layout/fragment_unread.xml | 4 ++-- app/src/main/res/layout/fragment_unread_row.xml | 2 +- build.gradle | 2 +- emojis/build.gradle | 2 +- 51 files changed, 69 insertions(+), 69 deletions(-) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => crashreporting}/CrashReporter.java (98%) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => crashreporting}/CrashReportingTree.java (94%) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => ui}/CenterVerticalSpan.java (96%) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => ui}/CircleTransform.java (97%) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => ui}/ScrollAwareFABBehavior.java (98%) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => ui}/ScrollAwareLinearBehavior.java (99%) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => ui}/WebViewOnTouchClickListener.java (98%) rename app/src/main/java/gr/thmmy/mthmmy/{utils => views}/AppCompatSpinnerWithoutDefault.java (99%) rename app/src/main/java/gr/thmmy/mthmmy/{utils => views}/CustomLinearLayoutManager.java (97%) rename app/src/main/java/gr/thmmy/mthmmy/{utils => views}/CustomRecyclerView.java (98%) rename app/src/main/java/gr/thmmy/mthmmy/{utils => views}/RelativeTimeTextView.java (99%) rename app/src/main/java/gr/thmmy/mthmmy/{utils => views}/ToggledBackgroundButton.java (95%) rename app/src/main/java/gr/thmmy/mthmmy/{ => views}/editorview/EditorView.java (99%) rename app/src/main/java/gr/thmmy/mthmmy/{ => views}/editorview/EmojiInputField.java (81%) rename app/src/main/java/gr/thmmy/mthmmy/{ => views}/editorview/EmojiKeyboard.java (99%) rename app/src/main/java/gr/thmmy/mthmmy/{ => views}/editorview/EmojiKeyboardAdapter.java (98%) rename app/src/main/java/gr/thmmy/mthmmy/{ => views}/editorview/FormatButtonsAdapter.java (98%) rename app/src/main/java/gr/thmmy/mthmmy/{ => views}/editorview/IEmojiKeyboard.java (95%) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index 920a03b9..29b0c699 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -15,9 +15,9 @@ import com.google.android.material.textfield.TextInputLayout; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.settings.SettingsActivity; import gr.thmmy.mthmmy.base.BaseActivity; -import gr.thmmy.mthmmy.editorview.EditorView; -import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.session.SessionManager; +import gr.thmmy.mthmmy.views.editorview.EditorView; +import gr.thmmy.mthmmy.views.editorview.EmojiKeyboard; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java index 86860ec1..061db9d2 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java @@ -30,10 +30,10 @@ import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.Board; import gr.thmmy.mthmmy.model.Category; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.utils.CustomRecyclerView; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; +import gr.thmmy.mthmmy.views.CustomRecyclerView; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java index 4a805f8b..084c3a3a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java @@ -14,7 +14,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; -import gr.thmmy.mthmmy.utils.RelativeTimeTextView; +import gr.thmmy.mthmmy.views.RelativeTimeTextView; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index 673dc32a..5b27c570 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -26,10 +26,10 @@ import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.utils.CustomRecyclerView; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; +import gr.thmmy.mthmmy.views.CustomRecyclerView; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Response; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java index c9568fb7..068f5e61 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java @@ -14,7 +14,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; -import gr.thmmy.mthmmy.utils.RelativeTimeTextView; +import gr.thmmy.mthmmy.views.RelativeTimeTextView; import timber.log.Timber; class UnreadAdapter extends RecyclerView.Adapter { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 8bac71ba..e388dc2e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -31,10 +31,10 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.utils.CustomRecyclerView; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; +import gr.thmmy.mthmmy.views.CustomRecyclerView; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Request; import okhttp3.Response; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java index e3425c3c..301d4b5a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java @@ -46,12 +46,12 @@ import gr.thmmy.mthmmy.activities.topic.TopicActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.model.ThmmyPage; -import gr.thmmy.mthmmy.utils.CenterVerticalSpan; -import gr.thmmy.mthmmy.utils.CircleTransform; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.Parcel; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; +import gr.thmmy.mthmmy.utils.ui.CenterVerticalSpan; +import gr.thmmy.mthmmy.utils.ui.CircleTransform; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Response; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java index 5b401f01..83dfddc2 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java @@ -18,7 +18,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.model.TopicSummary; -import gr.thmmy.mthmmy.utils.WebViewOnTouchClickListener; +import gr.thmmy.mthmmy.utils.ui.WebViewOnTouchClickListener; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java index 9976975e..d2639fe2 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java @@ -23,7 +23,7 @@ import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.activities.topic.TopicActivity; import gr.thmmy.mthmmy.model.Shout; import gr.thmmy.mthmmy.model.ThmmyPage; -import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import gr.thmmy.mthmmy.views.CustomRecyclerView; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java index ad42a414..12d5f5eb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java @@ -19,13 +19,13 @@ import androidx.recyclerview.widget.LinearLayoutManager; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; -import gr.thmmy.mthmmy.editorview.EditorView; -import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.model.Shout; import gr.thmmy.mthmmy.model.Shoutbox; -import gr.thmmy.mthmmy.utils.CustomRecyclerView; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.viewmodel.ShoutboxViewModel; +import gr.thmmy.mthmmy.views.CustomRecyclerView; +import gr.thmmy.mthmmy.views.editorview.EditorView; +import gr.thmmy.mthmmy.views.editorview.EmojiKeyboard; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index 2a9defb9..8e81cdd4 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -49,16 +49,16 @@ import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.base.BaseApplication; -import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; -import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; +import gr.thmmy.mthmmy.views.CustomLinearLayoutManager; +import gr.thmmy.mthmmy.views.editorview.EmojiKeyboard; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index 327fe44d..1a195624 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -65,18 +65,18 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.board.BoardActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; -import gr.thmmy.mthmmy.editorview.EditorView; -import gr.thmmy.mthmmy.editorview.IEmojiKeyboard; import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; -import gr.thmmy.mthmmy.utils.CircleTransform; -import gr.thmmy.mthmmy.utils.WebViewOnTouchClickListener; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.utils.parsing.ThmmyParser; +import gr.thmmy.mthmmy.utils.ui.CircleTransform; +import gr.thmmy.mthmmy.utils.ui.WebViewOnTouchClickListener; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; +import gr.thmmy.mthmmy.views.editorview.EditorView; +import gr.thmmy.mthmmy.views.editorview.IEmojiKeyboard; import timber.log.Timber; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java index 0d9135a4..55f3f16e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java @@ -64,11 +64,11 @@ import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.UploadCategory; import gr.thmmy.mthmmy.model.UploadFile; import gr.thmmy.mthmmy.services.UploadsReceiver; -import gr.thmmy.mthmmy.utils.AppCompatSpinnerWithoutDefault; import gr.thmmy.mthmmy.utils.FileUtils; import gr.thmmy.mthmmy.utils.TakePhoto; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.parsing.ParseTask; +import gr.thmmy.mthmmy.views.AppCompatSpinnerWithoutDefault; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index f19bac9e..8bdadf10 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -40,7 +40,7 @@ import java.util.concurrent.TimeUnit; import gr.thmmy.mthmmy.BuildConfig; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.utils.CrashReportingTree; +import gr.thmmy.mthmmy.utils.crashreporting.CrashReportingTree; import io.fabric.sdk.android.Fabric; import okhttp3.CipherSuite; import okhttp3.ConnectionSpec; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java index 659cde2f..b65fd2f4 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java @@ -8,13 +8,13 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.YEAR_IN_MILLIS; -class DateTimeUtils { +public class DateTimeUtils { private static final long MONTH_IN_MILLIS = 30*DAY_IN_MILLIS; private static final long DECADE_IN_MILLIS = 10*YEAR_IN_MILLIS; @VisibleForTesting - static String getRelativeTimeSpanString(long time) { + public static String getRelativeTimeSpanString(long time) { long now = System.currentTimeMillis(); boolean past = (now >= time); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java index 9ae5a309..a8c42c8b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java @@ -10,6 +10,7 @@ import java.io.IOException; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.utils.crashreporting.CrashReporter; import gr.thmmy.mthmmy.utils.parsing.ParseException; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -17,8 +18,7 @@ import okhttp3.Response; import timber.log.Timber; public abstract class NetworkTask extends ExternalAsyncTask> { - - protected OnNetworkTaskFinishedListener onNetworkTaskFinishedListener; + private OnNetworkTaskFinishedListener onNetworkTaskFinishedListener; public NetworkTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, OnNetworkTaskFinishedListener onNetworkTaskFinishedListener) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CrashReporter.java b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/utils/CrashReporter.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java index 67ba0395..65011440 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CrashReporter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.crashreporting; import com.crashlytics.android.Crashlytics; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CrashReportingTree.java b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java similarity index 94% rename from app/src/main/java/gr/thmmy/mthmmy/utils/CrashReportingTree.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java index 8f85459a..f378000e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CrashReportingTree.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.crashreporting; import android.util.Log; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CenterVerticalSpan.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/CenterVerticalSpan.java similarity index 96% rename from app/src/main/java/gr/thmmy/mthmmy/utils/CenterVerticalSpan.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/ui/CenterVerticalSpan.java index 104dd01e..8d0c3d60 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CenterVerticalSpan.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/CenterVerticalSpan.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.ui; import android.graphics.Canvas; import android.graphics.Paint; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/CircleTransform.java similarity index 97% rename from app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/ui/CircleTransform.java index c6da6010..813463bd 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/CircleTransform.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.ui; import android.graphics.Bitmap; import android.graphics.BitmapShader; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareFABBehavior.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareFABBehavior.java index a77502f3..78c5f196 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareFABBehavior.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.ui; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareLinearBehavior.java similarity index 99% rename from app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareLinearBehavior.java index cc877deb..1a7a75b8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareLinearBehavior.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.ui; import android.animation.Animator; import android.content.Context; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/WebViewOnTouchClickListener.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/ui/WebViewOnTouchClickListener.java index 4cc94989..6239f9d3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/WebViewOnTouchClickListener.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/WebViewOnTouchClickListener.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.ui; import android.annotation.SuppressLint; import android.app.Dialog; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/AppCompatSpinnerWithoutDefault.java b/app/src/main/java/gr/thmmy/mthmmy/views/AppCompatSpinnerWithoutDefault.java similarity index 99% rename from app/src/main/java/gr/thmmy/mthmmy/utils/AppCompatSpinnerWithoutDefault.java rename to app/src/main/java/gr/thmmy/mthmmy/views/AppCompatSpinnerWithoutDefault.java index 77293dfe..e7ba0e4c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/AppCompatSpinnerWithoutDefault.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/AppCompatSpinnerWithoutDefault.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.views; import android.annotation.SuppressLint; import android.content.Context; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CustomLinearLayoutManager.java b/app/src/main/java/gr/thmmy/mthmmy/views/CustomLinearLayoutManager.java similarity index 97% rename from app/src/main/java/gr/thmmy/mthmmy/utils/CustomLinearLayoutManager.java rename to app/src/main/java/gr/thmmy/mthmmy/views/CustomLinearLayoutManager.java index f4dd5042..50621846 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CustomLinearLayoutManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/CustomLinearLayoutManager.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.views; import android.content.Context; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CustomRecyclerView.java b/app/src/main/java/gr/thmmy/mthmmy/views/CustomRecyclerView.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/utils/CustomRecyclerView.java rename to app/src/main/java/gr/thmmy/mthmmy/views/CustomRecyclerView.java index 766e7207..1b605cdd 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CustomRecyclerView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/CustomRecyclerView.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.views; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java b/app/src/main/java/gr/thmmy/mthmmy/views/RelativeTimeTextView.java similarity index 99% rename from app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java rename to app/src/main/java/gr/thmmy/mthmmy/views/RelativeTimeTextView.java index 9b5b5f74..43ea351f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/RelativeTimeTextView.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.views; import android.annotation.SuppressLint; import android.content.Context; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ToggledBackgroundButton.java b/app/src/main/java/gr/thmmy/mthmmy/views/ToggledBackgroundButton.java similarity index 95% rename from app/src/main/java/gr/thmmy/mthmmy/utils/ToggledBackgroundButton.java rename to app/src/main/java/gr/thmmy/mthmmy/views/ToggledBackgroundButton.java index 6c189e87..296ecf77 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ToggledBackgroundButton.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/ToggledBackgroundButton.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.views; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EditorView.java similarity index 99% rename from app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java rename to app/src/main/java/gr/thmmy/mthmmy/views/editorview/EditorView.java index 97f7d42f..051bfdfb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EditorView.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.editorview; +package gr.thmmy.mthmmy.views.editorview; import android.animation.Animator; import android.annotation.SuppressLint; diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiInputField.java similarity index 81% rename from app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java rename to app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiInputField.java index 0cdccd60..88d2e790 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiInputField.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.editorview; +package gr.thmmy.mthmmy.views.editorview; import android.view.inputmethod.InputConnection; diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiKeyboard.java similarity index 99% rename from app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java rename to app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiKeyboard.java index 903ff5fe..dc5b06e5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiKeyboard.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.editorview; +package gr.thmmy.mthmmy.views.editorview; import android.content.Context; import android.os.Handler; diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboardAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiKeyboardAdapter.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboardAdapter.java rename to app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiKeyboardAdapter.java index efcb9519..1f857a16 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboardAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiKeyboardAdapter.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.editorview; +package gr.thmmy.mthmmy.views.editorview; import android.graphics.drawable.AnimationDrawable; import android.view.LayoutInflater; diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/FormatButtonsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/FormatButtonsAdapter.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/editorview/FormatButtonsAdapter.java rename to app/src/main/java/gr/thmmy/mthmmy/views/editorview/FormatButtonsAdapter.java index 732149ae..699bf760 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/FormatButtonsAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/FormatButtonsAdapter.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.editorview; +package gr.thmmy.mthmmy.views.editorview; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/IEmojiKeyboard.java similarity index 95% rename from app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java rename to app/src/main/java/gr/thmmy/mthmmy/views/editorview/IEmojiKeyboard.java index 3ec906f2..07ab89bb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/editorview/IEmojiKeyboard.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.editorview; +package gr.thmmy.mthmmy.views.editorview; public interface IEmojiKeyboard { /** diff --git a/app/src/main/res/layout-v21/activity_profile.xml b/app/src/main/res/layout-v21/activity_profile.xml index c5da47d9..f8f2faff 100644 --- a/app/src/main/res/layout-v21/activity_profile.xml +++ b/app/src/main/res/layout-v21/activity_profile.xml @@ -113,7 +113,7 @@ android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margins" - app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior" + app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior" app:srcCompat="@drawable/ic_pm_fab"/> diff --git a/app/src/main/res/layout/activity_board.xml b/app/src/main/res/layout/activity_board.xml index 0a61658e..f10dd068 100644 --- a/app/src/main/res/layout/activity_board.xml +++ b/app/src/main/res/layout/activity_board.xml @@ -62,6 +62,6 @@ android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margins" - app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior" + app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior" app:srcCompat="@drawable/ic_add_fab" /> diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index 7e6a9b40..5c42f68b 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -46,7 +46,7 @@ android:inputType="text"/> - - diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 8a51cbd9..3a63ad27 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -112,7 +112,7 @@ android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margins" - app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior" + app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior" app:srcCompat="@drawable/ic_pm_fab"/> diff --git a/app/src/main/res/layout/activity_topic.xml b/app/src/main/res/layout/activity_topic.xml index b61c41cf..24793374 100644 --- a/app/src/main/res/layout/activity_topic.xml +++ b/app/src/main/res/layout/activity_topic.xml @@ -51,7 +51,7 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity" /> - + app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareLinearBehavior"> diff --git a/app/src/main/res/layout/activity_topic_edit_row.xml b/app/src/main/res/layout/activity_topic_edit_row.xml index 39b67582..a5875f53 100644 --- a/app/src/main/res/layout/activity_topic_edit_row.xml +++ b/app/src/main/res/layout/activity_topic_edit_row.xml @@ -76,7 +76,7 @@ android:textSize="10sp" tools:ignore="SmallSp" /> - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_forum.xml b/app/src/main/res/layout/fragment_forum.xml index 2f5de239..a428557b 100644 --- a/app/src/main/res/layout/fragment_forum.xml +++ b/app/src/main/res/layout/fragment_forum.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_unread_row.xml b/app/src/main/res/layout/fragment_unread_row.xml index 07041cc5..d9da3ace 100644 --- a/app/src/main/res/layout/fragment_unread_row.xml +++ b/app/src/main/res/layout/fragment_unread_row.xml @@ -32,7 +32,7 @@ android:layout_below="@+id/title" android:layout_toEndOf="@+id/dateTime"/> - Date: Thu, 28 May 2020 20:27:02 +0300 Subject: [PATCH 38/53] UnreadFragment improvements --- .../main/unread/UnreadFragment.java | 227 +++++++++--------- .../thmmy/mthmmy/session/SessionManager.java | 96 ++++++-- .../mthmmy/session/ValidateSessionTask.java | 18 ++ .../utils/parsing/ThmmyDateTimeParser.java | 8 +- app/src/main/res/layout/fragment_unread.xml | 3 +- 5 files changed, 208 insertions(+), 144 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index e388dc2e..7a4dd005 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -1,4 +1,3 @@ - package gr.thmmy.mthmmy.activities.main.unread; import android.os.AsyncTask; @@ -23,20 +22,20 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; +import gr.thmmy.mthmmy.session.ValidateSessionTask; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.views.CustomRecyclerView; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; -import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; @@ -60,12 +59,13 @@ public class UnreadFragment extends BaseFragment { private UnreadAdapter unreadAdapter; private List topicSummaries; - private String markAsReadUrl = ""; + private String markAsReadUrl; private int numberOfPages = 0; private int loadedPages = 0; private UnreadTask unreadTask; private MarkReadTask markReadTask; + private ValidateSessionTask validateSessionTask; // Required empty public constructor public UnreadFragment() {} @@ -89,18 +89,22 @@ public class UnreadFragment extends BaseFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); topicSummaries = new ArrayList<>(); + markAsReadUrl = BaseApplication.getInstance().getSessionManager().getMarkAllAsReadLink(); + if(markAsReadUrl==null){ + Timber.i("MarkAsRead URL is null."); + startValidateSessionTask(); + } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - if (topicSummaries.isEmpty()) { - unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); + if (topicSummaries.isEmpty()){ + unreadTask = new UnreadTask(this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, this::onUnreadTaskFinished); assert SessionManager.unreadUrl != null; unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); } - markReadTask = new MarkReadTask(); - Timber.d("onActivityCreated"); + markReadTask = new MarkReadTask(this::onMarkReadTaskStarted, this::onMarkReadTaskFinished); } @@ -139,15 +143,7 @@ public class UnreadFragment extends BaseFragment { swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.primary); swipeRefreshLayout.setColorSchemeResources(R.color.accent); swipeRefreshLayout.setOnRefreshListener( - () -> { - if (!unreadTask.isRunning()) { - numberOfPages = 0; - loadedPages = 0; - unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); - assert SessionManager.unreadUrl != null; - unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); - } - } + this::startUnreadTask ); } @@ -157,17 +153,18 @@ public class UnreadFragment extends BaseFragment { @Override public void onDestroy() { super.onDestroy(); - if (unreadTask!=null){ + cancelUnreadTaskIfRunning(); + if (markReadTask!=null){ try{ - if(unreadTask.isRunning()) - unreadTask.cancel(true); + if(markReadTask.isRunning()) + markReadTask.cancel(true); } // Yes, it happens even though we checked catch (NullPointerException ignored){ } } - if (markReadTask!=null){ + if (validateSessionTask!=null){ try{ - if(markReadTask.isRunning()) - markReadTask.cancel(true); + if(validateSessionTask.isRunning()) + validateSessionTask.cancel(true); } // Yes, it happens even though we checked catch (NullPointerException ignored){ } } @@ -175,15 +172,42 @@ public class UnreadFragment extends BaseFragment { topicSummaries.clear(); } + private void startUnreadTask(){ + if (unreadTask!=null) { + try{ + if(!unreadTask.isRunning()){ + numberOfPages = 0; + loadedPages = 0; + unreadTask = new UnreadTask(UnreadFragment.this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, UnreadFragment.this::onUnreadTaskFinished); + assert SessionManager.unreadUrl != null; + unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); + } + } + catch (NullPointerException ignored){ } + } + } + + private void startValidateSessionTask(){ + validateSessionTask = new ValidateSessionTask(); + validateSessionTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + private void cancelUnreadTaskIfRunning(){ + if (unreadTask!=null){ + try{ + if(unreadTask.isRunning()) + unreadTask.cancel(true); + } // Yes, it happens even though we checked + catch (NullPointerException ignored){ } + } + } + public interface UnreadFragmentInteractionListener extends FragmentInteractionListener { void onUnreadFragmentInteraction(TopicSummary topicSummary); } private void showMarkAsReadFAB() { - markAsReadFAB.setOnClickListener(v -> { - if (!markReadTask.isRunning() && !unreadTask.isRunning()) - showMarkAsReadConfirmationDialog(); - }); + markAsReadFAB.setOnClickListener(v -> showMarkAsReadConfirmationDialog()); markAsReadFAB.show(); markAsReadFAB.setTag(true); } @@ -199,27 +223,36 @@ public class UnreadFragment extends BaseFragment { builder.setTitle("Mark all as read"); builder.setMessage("Are you sure that you want to mark ALL topics as read?"); builder.setPositiveButton("Yep", (dialogInterface, i) -> { - markReadTask = new MarkReadTask(); - markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markAsReadUrl); + if (!markReadTask.isRunning() && markAsReadUrl!=null){ + markReadTask = new MarkReadTask(this::onMarkReadTaskStarted, this::onMarkReadTaskFinished); + markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markAsReadUrl); + } }); builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); builder.create().show(); } - //---------------------------------------ASYNC TASK----------------------------------- + private void hideProgressUI(){ + progressBar.setVisibility(ProgressBar.INVISIBLE); + swipeRefreshLayout.setRefreshing(false); + } + + //---------------------------------------UNREAD TASK----------------------------------- private void onUnreadTaskStarted() { progressBar.setVisibility(ProgressBar.VISIBLE); } - private void onUnreadTaskFinished(int resultCode, UnreadTaskData unreadTaskData) { + private void onUnreadTaskCancelled() { + swipeRefreshLayout.setRefreshing(false); + } + + private void onUnreadTaskFinished(int resultCode, ArrayList fetchedUnread) { if (resultCode == NetworkResultCodes.SUCCESSFUL) { - ArrayList fetchedUnread = unreadTaskData.getTopicSummaries(); if(!fetchedUnread.isEmpty()){ if(loadedPages==0) topicSummaries.clear(); topicSummaries.addAll(fetchedUnread); - markAsReadUrl = unreadTaskData.getMarkAsReadUrl(); noUnreadTopicsTextView.setVisibility(View.INVISIBLE); showMarkAsReadFAB(); } @@ -231,18 +264,15 @@ public class UnreadFragment extends BaseFragment { unreadAdapter.notifyDataSetChanged(); loadedPages++; if (loadedPages < numberOfPages) { - unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); + unreadTask = new UnreadTask(this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, this::onUnreadTaskFinished); assert SessionManager.unreadUrl != null; unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString() + ";start=" + loadedPages * 20); } - else { - progressBar.setVisibility(ProgressBar.INVISIBLE); - swipeRefreshLayout.setRefreshing(false); - } + else + hideProgressUI(); } else{ - progressBar.setVisibility(ProgressBar.INVISIBLE); - swipeRefreshLayout.setRefreshing(false); + hideProgressUI(); if (resultCode == NetworkResultCodes.NETWORK_ERROR) Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); else @@ -251,16 +281,15 @@ public class UnreadFragment extends BaseFragment { } } - private class UnreadTask extends NewParseTask { - UnreadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { - super(onTaskStartedListener, onParseTaskFinishedListener); + private class UnreadTask extends NewParseTask> { + UnreadTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { + super(onTaskStartedListener, onTaskCancelledListener, onParseTaskFinishedListener); } @Override - protected UnreadTaskData parse(Document document, Response response) throws ParseException { + protected ArrayList parse(Document document, Response response) throws ParseException { Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); ArrayList fetchedTopicSummaries = new ArrayList<>(); - String markAsReadUrl=""; if (!unread.isEmpty()) { for (Element row : unread) { Elements information = row.select("td"); @@ -278,12 +307,9 @@ public class UnreadFragment extends BaseFragment { } Element topBar = document.select("table:not(.bordercolor):not(#bodyarea):has(td.middletext)").first(); - Element pagesElement = null, markRead = null; - if (topBar != null) { + Element pagesElement = null; + if (topBar != null) pagesElement = topBar.select("td.middletext").first(); - markRead = document.select("table:not(.bordercolor):not([width])").select("a") - .first(); - } if (numberOfPages == 0 && pagesElement != null) { Elements pages = pagesElement.select("a"); @@ -293,91 +319,60 @@ public class UnreadFragment extends BaseFragment { numberOfPages = 1; } - if (markRead != null && loadedPages == numberOfPages - 1) - markAsReadUrl = markRead.attr("href"); - - return new UnreadTaskData(fetchedTopicSummaries, markAsReadUrl); + return fetchedTopicSummaries; } - - return new UnreadTaskData(new ArrayList<>(), markAsReadUrl); + return new ArrayList<>(); } @Override - protected int getResultCode(Response response, UnreadTaskData data) { + protected int getResultCode(Response response, ArrayList topicSummaries) { return NetworkResultCodes.SUCCESSFUL; } } - private class UnreadTaskData { - ArrayList topicSummaries; - String markAsReadUrl; - - UnreadTaskData(ArrayList topicSummaries, String markAsReadUrl){ - this.topicSummaries = topicSummaries; - this.markAsReadUrl = markAsReadUrl; - } + //---------------------------------------MARKREAD TASK------------------------------------------ + private void onMarkReadTaskStarted() { + cancelUnreadTaskIfRunning(); + progressBar.setVisibility(ProgressBar.VISIBLE); + } - ArrayList getTopicSummaries() { - return topicSummaries; + private void onMarkReadTaskFinished(int resultCode, Boolean isSessionVerified) { + hideProgressUI(); + if (resultCode == NetworkResultCodes.SUCCESSFUL) { + if (!isSessionVerified){ + Toast.makeText(getContext(), "Session verification failed", Toast.LENGTH_SHORT).show(); + startValidateSessionTask(); + } + else + startUnreadTask(); } - - String getMarkAsReadUrl() { - return markAsReadUrl; + else{ + hideProgressUI(); + if (resultCode == NetworkResultCodes.NETWORK_ERROR) + Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); + else + Toast.makeText(getContext(), "Unexpected error," + + " please contact the developers with the details", Toast.LENGTH_LONG).show(); } } - private class MarkReadTask extends AsyncTask { - private static final int SUCCESS = 0; - private static final int NETWORK_ERROR = 1; - private static final int OTHER_ERROR = 2; - - @Override - protected void onPreExecute() { - progressBar.setVisibility(ProgressBar.VISIBLE); + private class MarkReadTask extends NewParseTask { + MarkReadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected Integer doInBackground(String... strings) { - Request request = new Request.Builder() - .url(strings[0]) - .build(); - try { - client.newCall(request).execute(); - return SUCCESS; - } catch (IOException e) { - Timber.i(e, "IO Exception"); - return NETWORK_ERROR; - } catch (Exception e) { - Timber.e(e, "Exception"); - return OTHER_ERROR; - } + protected Boolean parse(Document document, Response response) throws ParseException { + Elements sessionVerificationFailed = document.select("td:containsOwn(Session " + + "verification failed. Please try logging out and back in again, and then try " + + "again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " + + "αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)"); + return sessionVerificationFailed.isEmpty(); } @Override - protected void onPostExecute(Integer result) { - progressBar.setVisibility(ProgressBar.GONE); - - if (result == NETWORK_ERROR) { - Toast.makeText(getContext() - , "Task was unsuccessful!\n Please check your internet conneciton.", - Toast.LENGTH_LONG).show(); - } else if (result == OTHER_ERROR) { - Toast.makeText(getContext() - , "Fatal error!\n Task aborted...", Toast.LENGTH_LONG).show(); - } else { - if (!unreadTask.isRunning()) { - numberOfPages = 0; - loadedPages = 0; - unreadTask = new UnreadTask(UnreadFragment.this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskFinished); - assert SessionManager.unreadUrl != null; - unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); - } - } - } - - //TODO: Maybe extend this task and use isRunning() from ExternalAsyncTask instead (?) - public boolean isRunning(){ - return getStatus() == AsyncTask.Status.RUNNING; + protected int getResultCode(Response response, Boolean isSessionVerified) { + return NetworkResultCodes.SUCCESSFUL; } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index 36def1de..81dd2f31 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -39,6 +39,8 @@ public class SessionManager { private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); public static final HttpUrl unreadUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=unread;all;start=0;theme=4"); public static final HttpUrl shoutboxUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=tpmod;sa=shoutbox;theme=4"); + private static final String baseLogoutLink = "https://www.thmmy.gr/smf/index.php?action=logout;sesc="; + private static final String baseMarkAllAsReadLink = "https://www.thmmy.gr/smf/index.php?action=markasread;sa=all;sesc="; private static final String guestName = "Guest"; //Response Codes @@ -63,7 +65,9 @@ public class SessionManager { private static final String USER_ID = "UserID"; private static final String AVATAR_LINK = "AvatarLink"; private static final String HAS_AVATAR = "HasAvatar"; + private static final String SESC = "Sesc"; private static final String LOGOUT_LINK = "LogoutLink"; + private static final String MARK_ALL_AS_READ_LINK = "MarkAllAsReadLink"; private static final String LOGGED_IN = "LoggedIn"; private static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault"; @@ -84,7 +88,7 @@ public class SessionManager { * Always call it in a separate thread. */ public int login(String... strings) { - Timber.i("Logging in..."); + Timber.d("Logging in..."); //Build the login request for each case Request request; @@ -114,8 +118,7 @@ public class SessionManager { Response response = client.newCall(request).execute(); Document document = Jsoup.parse(response.body().string()); - if (validateRetrievedCookies()) - { + if (validateRetrievedCookies()) { Timber.i("Login successful!"); setPersistentCookieSession(); //Store cookies @@ -129,7 +132,10 @@ public class SessionManager { if (avatar != null) editor.putString(AVATAR_LINK, avatar); editor.putBoolean(HAS_AVATAR, avatar != null); - editor.putString(LOGOUT_LINK, extractLogoutLink(document)); + String sesc = extractSesc(document); + editor.putString(SESC, sesc); + editor.putString(LOGOUT_LINK, generateLogoutLink(sesc)); + editor.putString(MARK_ALL_AS_READ_LINK, generateMarkAllAsReadLink(sesc)); editor.apply(); return SUCCESS; @@ -181,10 +187,10 @@ public class SessionManager { * Always call it in a separate thread in a way that won't hinder performance (e.g. after * fragments' data are retrieved). */ - public void validateSession() { - Timber.i("Validating session..."); - + void validateSession() { + Timber.e("Validating session..."); if (isLoggedIn()) { + Timber.e("Refreshing session..."); int loginResult = login(); if (loginResult != FAILURE) return; @@ -204,18 +210,15 @@ public class SessionManager { setLoginScreenAsDefault(false); } - /** * Logout function. Always call it in a separate thread. */ public int logout() { Timber.i("Logging out..."); - - Request request = new Request.Builder() - .url(sharedPrefs.getString(LOGOUT_LINK, "LogoutLink")) - .build(); - try { + Request request = new Request.Builder() + .url(getLogoutLink()) + .build(); //Make request & handle response Response response = client.newCall(request).execute(); Document document = Jsoup.parse(response.body().string()); @@ -258,14 +261,31 @@ public class SessionManager { public Cookie getThmmyCookie() { List cookieList = cookieJar.loadForRequest(indexUrl); - for(Cookie cookie: cookieList) - { + for(Cookie cookie: cookieList) { if(cookie.name().equals("THMMYgrC00ki3")) return cookie; } return null; } + public String getMarkAllAsReadLink() { + String markAsReadLink = sharedPrefs.getString(MARK_ALL_AS_READ_LINK, null); + if(markAsReadLink == null){ //For older versions, extract it from logout link (otherwise user would have to login again) + String sesc = extractSescFromLogoutLink(getLogoutLink()); + if(sesc!=null) { + setSesc(sesc); + markAsReadLink = generateMarkAllAsReadLink(sesc); + setMarkAsReadLink(markAsReadLink); + return markAsReadLink; + } + } + return markAsReadLink; // Warning: it can be null + } + + private String getLogoutLink() { + return sharedPrefs.getString(LOGOUT_LINK, null); + } + public boolean hasAvatar() { return sharedPrefs.getBoolean(HAS_AVATAR, false); } @@ -280,6 +300,21 @@ public class SessionManager { //--------------------------------------GETTERS END--------------------------------------------- + //---------------------------------------SETTERS------------------------------------------------ + private void setSesc(String sesc){ + SharedPreferences.Editor editor = sharedPrefs.edit(); + editor.putString(SESC, sesc); + editor.apply(); + } + + private void setMarkAsReadLink(String markAllAsReadLink){ + SharedPreferences.Editor editor = sharedPrefs.edit(); + editor.putString(MARK_ALL_AS_READ_LINK, markAllAsReadLink); + editor.apply(); + } + + //--------------------------------------SETTERS END--------------------------------------------- + //------------------------------------OTHER FUNCTIONS------------------------------------------- private boolean validateRetrievedCookies() { List cookieList = cookieJar.loadForRequest(indexUrl); @@ -353,7 +388,6 @@ public class SessionManager { return "User"; //return a default username } - @NonNull private int extractUserId(@NonNull Document doc) { try{ Elements elements = doc.select("a:containsOwn(Εμφάνιση των μηνυμάτων σας), a:containsOwn(Show own posts)"); @@ -383,17 +417,33 @@ public class SessionManager { return null; } - @NonNull - private String extractLogoutLink(@NonNull Document doc) { + private String extractSesc(@NonNull Document doc) { Elements logoutLink = doc.select("a[href^=https://www.thmmy.gr/smf/index.php?action=logout;sesc=]"); - if (!logoutLink.isEmpty()) { String link = logoutLink.first().attr("href"); - if (link != null && !link.isEmpty()) - return link; + return extractSescFromLogoutLink(link); + } + Timber.e(new ParseException("Parsing failed(extractSesc)"),"ParseException"); + return null; + } + + private String extractSescFromLogoutLink(String logoutLink){ + if (logoutLink != null){ + Pattern pattern = Pattern.compile(".+;sesc=(\\w+)"); + Matcher matcher = pattern.matcher(logoutLink); + if (matcher.find()) + return matcher.group(1); } - Timber.e(new ParseException("Parsing failed(logoutLink extraction)"),"ParseException"); - return "https://www.thmmy.gr/smf/index.php?action=logout"; //return a default link + Timber.e(new ParseException("Parsing failed(extractSescFromLogoutLink)"),"ParseException"); + return null; + } + + private String generateLogoutLink(String sesc){ + return baseLogoutLink + sesc; + } + + private String generateMarkAllAsReadLink(String sesc){ + return baseMarkAllAsReadLink + sesc; } //----------------------------------OTHER FUNCTIONS END----------------------------------------- diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java b/app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java new file mode 100644 index 00000000..b5c1392f --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java @@ -0,0 +1,18 @@ +package gr.thmmy.mthmmy.session; + +import android.os.AsyncTask; + +import gr.thmmy.mthmmy.base.BaseApplication; + + +public class ValidateSessionTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + BaseApplication.getInstance().getSessionManager().validateSession(); + return null; + } + + public boolean isRunning(){ + return getStatus() == AsyncTask.Status.RUNNING; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java index 3c398bd1..6e27ca61 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java @@ -42,7 +42,7 @@ public class ThmmyDateTimeParser { private ThmmyDateTimeParser(){} public static String convertToTimestamp(String thmmyDateTime){ - Timber.d("Will attempt to convert %s to timestamp.", thmmyDateTime); + Timber.v("Will attempt to convert %s to timestamp.", thmmyDateTime); String originalDateTime = thmmyDateTime; DateTimeZone dtz = getDtz(); @@ -67,12 +67,12 @@ public class ThmmyDateTimeParser { dateTime=formatter.withZone(dtz).withLocale(englishLocale).parseDateTime(thmmyDateTime); } catch (IllegalArgumentException e1){ - Timber.d("Parsing DateTime %s using English Locale failed.", thmmyDateTime); + Timber.v("Parsing DateTime %s using English Locale failed.", thmmyDateTime); try{ DateFormatSymbols dfs = DateTimeUtils.getDateFormatSymbols(greekLocale); thmmyDateTime = thmmyDateTime.replace("am",dfs.getAmPmStrings()[0]); thmmyDateTime = thmmyDateTime.replace("pm",dfs.getAmPmStrings()[1]); - Timber.d("Attempting to parse DateTime %s using Greek Locale...", thmmyDateTime); + Timber.v("Attempting to parse DateTime %s using Greek Locale...", thmmyDateTime); dateTime=formatter.withZone(dtz).withLocale(greekLocale).parseDateTime(thmmyDateTime); } catch (IllegalArgumentException e2){ @@ -82,7 +82,7 @@ public class ThmmyDateTimeParser { } } String timestamp = Long.toString(dateTime.getMillis()); - Timber.d("DateTime %s was converted to %s, or %s", originalDateTime, timestamp, dateTime.toString()); + Timber.v("DateTime %s was converted to %s, or %s", originalDateTime, timestamp, dateTime.toString()); return timestamp; } diff --git a/app/src/main/res/layout/fragment_unread.xml b/app/src/main/res/layout/fragment_unread.xml index 363bb734..3a89ebc8 100644 --- a/app/src/main/res/layout/fragment_unread.xml +++ b/app/src/main/res/layout/fragment_unread.xml @@ -37,7 +37,8 @@ android:layout_height="wrap_content" android:visibility="invisible" android:text="@string/no_unread_topics" - android:textColor="@color/primary_text" + android:textColor="@color/accent" + android:textSize="@dimen/medium_text" app:layout_anchor="@+id/relativeLayout" app:layout_anchorGravity="center" /> From 3e28b3a03b4249697dbadf5e23f9b907afdfe75c Mon Sep 17 00:00:00 2001 From: Thodoris Tyrovouzis Date: Fri, 29 May 2020 11:02:45 +0300 Subject: [PATCH 39/53] fix bug where changing the orientation would make EditorView's visibility to GONE --- .../thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java | 5 +++-- app/src/main/res/layout/fragment_shoutbox.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java index 12d5f5eb..a24b9155 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java @@ -107,7 +107,7 @@ public class ShoutboxFragment extends Fragment { shoutAdapter.notifyDataSetChanged(); } }); - shoutboxViewModel.setOnShoutboxTaskStarted(this::onShoutboxTaskSarted); + shoutboxViewModel.setOnShoutboxTaskStarted(this::onShoutboxTaskStarted); shoutboxViewModel.setOnShoutboxTaskFinished(this::onShoutboxTaskFinished); shoutboxViewModel.setOnSendShoutTaskStarted(this::onSendShoutTaskStarted); shoutboxViewModel.setOnSendShoutTaskFinished(this::onSendShoutTaskFinished); @@ -115,9 +115,10 @@ public class ShoutboxFragment extends Fragment { shoutboxViewModel.loadShoutbox(false); } - private void onShoutboxTaskSarted() { + private void onShoutboxTaskStarted() { Timber.i("Starting shoutbox task..."); progressBar.setVisibility(View.VISIBLE); + editorView.setVisibility(View.GONE); } private void onSendShoutTaskStarted() { diff --git a/app/src/main/res/layout/fragment_shoutbox.xml b/app/src/main/res/layout/fragment_shoutbox.xml index ae0e8133..7b2d51e7 100644 --- a/app/src/main/res/layout/fragment_shoutbox.xml +++ b/app/src/main/res/layout/fragment_shoutbox.xml @@ -30,7 +30,7 @@ android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:paddingTop="8dp" - android:visibility="gone"/> + android:visibility="visible"/> Date: Fri, 29 May 2020 13:05:48 +0300 Subject: [PATCH 40/53] Copy links from WebViews on long clicks --- .../latestPosts/LatestPostsAdapter.java | 6 +- .../mthmmy/activities/topic/TopicAdapter.java | 5 +- .../utils/ui/WebViewOnTouchClickListener.java | 78 ------------- .../thmmy/mthmmy/views/ReactiveWebView.java | 105 ++++++++++++++++++ .../layout-v21/activity_topic_post_row.xml | 2 +- .../res/layout/activity_topic_post_row.xml | 2 +- .../res/layout/fragment_latest_posts_row.xml | 2 +- 7 files changed, 112 insertions(+), 88 deletions(-) delete mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/ui/WebViewOnTouchClickListener.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java index 83dfddc2..fbfb9300 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java @@ -6,7 +6,6 @@ import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.webkit.WebView; import android.widget.RelativeLayout; import android.widget.TextView; @@ -18,7 +17,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.model.TopicSummary; -import gr.thmmy.mthmmy.utils.ui.WebViewOnTouchClickListener; +import gr.thmmy.mthmmy.views.ReactiveWebView; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; /** @@ -81,7 +80,6 @@ class LatestPostsAdapter extends RecyclerView.Adapter { latestPostViewHolder.post.setBackgroundColor(Color.argb(1, 255, 255, 255)); latestPostViewHolder.post.loadDataWithBaseURL("file:///android_asset/" , topic.getPost(), "text/html", "UTF-8", null); - latestPostViewHolder.post.setOnTouchListener(new WebViewOnTouchClickListener(context)); latestPostViewHolder.latestPostsRow.setOnClickListener(v -> { if (interactionListener != null) { @@ -106,7 +104,7 @@ class LatestPostsAdapter extends RecyclerView.Adapter { final RelativeLayout latestPostsRow; final TextView postTitle; final TextView postDate; - final WebView post; + final ReactiveWebView post; LatestPostViewHolder(View itemView) { super(itemView); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index 1a195624..bb970644 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -73,8 +73,8 @@ import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.utils.parsing.ThmmyParser; import gr.thmmy.mthmmy.utils.ui.CircleTransform; -import gr.thmmy.mthmmy.utils.ui.WebViewOnTouchClickListener; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; +import gr.thmmy.mthmmy.views.ReactiveWebView; import gr.thmmy.mthmmy.views.editorview.EditorView; import gr.thmmy.mthmmy.views.editorview.IEmojiKeyboard; import timber.log.Timber; @@ -363,7 +363,6 @@ class TopicAdapter extends RecyclerView.Adapter { //Post's WebView parameters holder.post.setClickable(true); holder.post.setWebViewClient(new LinkLauncher()); - holder.post.setOnTouchListener(new WebViewOnTouchClickListener(context)); //noinspection ConstantConditions loadAvatar(currentPost.getThumbnailURL(), holder.thumbnail); @@ -834,7 +833,7 @@ class TopicAdapter extends RecyclerView.Adapter { final LinearLayout cardChildLinear; final TextView postDate, postNum, username, subject; final ImageView thumbnail; - final public WebView post; + final public ReactiveWebView post; final ImageButton quoteToggle, overflowButton; final RelativeLayout header; final LinearLayout userExtraInfo; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/WebViewOnTouchClickListener.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/WebViewOnTouchClickListener.java deleted file mode 100644 index 6239f9d3..00000000 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/WebViewOnTouchClickListener.java +++ /dev/null @@ -1,78 +0,0 @@ -package gr.thmmy.mthmmy.utils.ui; - -import android.annotation.SuppressLint; -import android.app.Dialog; -import android.content.Context; -import android.graphics.drawable.ColorDrawable; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.Window; -import android.webkit.WebView; - -import com.bumptech.glide.Glide; -import com.github.chrisbanes.photoview.PhotoView; - -import gr.thmmy.mthmmy.base.BaseApplication; - -/** - * Workaround for WebView's inability to send onClick events (sends only onLongClickEvents) - * If an image is find when clicking it will be inflated as a zoomed/zoomable/pinchable PhotoView - */ -public class WebViewOnTouchClickListener implements View.OnTouchListener { - private final static int screenWidth = BaseApplication.getInstance().getWidthInPixels(); - private final static int screenHeight = BaseApplication.getInstance().getHeightInPixels(); - - private final static long MAX_TOUCH_DURATION = 100; - private final Context context; - private long downTime; - - public WebViewOnTouchClickListener(Context context){ - this.context = context; - } - - @SuppressLint("ClickableViewAccessibility") - @Override - public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - downTime = event.getEventTime(); - break; - case MotionEvent.ACTION_UP: - if(event.getEventTime() - downTime <= MAX_TOUCH_DURATION) - onClick((WebView) v); - break; - default: - break; - } - return false; - } - - private void onClick(WebView webView){ - WebView.HitTestResult result = webView.getHitTestResult(); - if(result.getType() == WebView.HitTestResult.IMAGE_TYPE){ - String imageURL = result.getExtra(); - showImage(imageURL); - } - webView.performClick(); - } - - private void showImage(String url) { - Dialog builder = new Dialog(context); - builder.requestWindowFeature(Window.FEATURE_NO_TITLE); - builder.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - builder.getWindow().setBackgroundDrawable( - new ColorDrawable(android.graphics.Color.TRANSPARENT)); - - PhotoView photoView = new PhotoView(context); - photoView.setLayoutParams(new LayoutParams(screenWidth, screenHeight)); - - Glide.with(context).load(url).fitCenter().into(photoView); - - builder.addContentView(photoView, new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - builder.show(); - } -} diff --git a/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java new file mode 100644 index 00000000..1d41bda7 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java @@ -0,0 +1,105 @@ +package gr.thmmy.mthmmy.views; + +import android.app.Dialog; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.view.Window; +import android.webkit.WebView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.github.chrisbanes.photoview.PhotoView; + +import gr.thmmy.mthmmy.base.BaseApplication; + +import static android.content.Context.CLIPBOARD_SERVICE; + +public class ReactiveWebView extends WebView { + private final static int screenWidth = BaseApplication.getInstance().getWidthInPixels(); + private final static int screenHeight = BaseApplication.getInstance().getHeightInPixels(); + + private final static long MAX_TOUCH_DURATION = 100; + private final Context context; + private long downTime; + + + public ReactiveWebView(Context context) { + super(context); + this.context = context; + setOnLongClickListener(); + } + + public ReactiveWebView(Context context, AttributeSet attrs) { + super(context, attrs); + this.context = context; + setOnLongClickListener(); + } + + public ReactiveWebView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.context = context; + setOnLongClickListener(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + downTime = event.getEventTime(); + break; + case MotionEvent.ACTION_UP: + if(event.getEventTime() - downTime <= MAX_TOUCH_DURATION) + performClick(); + break; + default: + break; + } + return super.onTouchEvent(event); + } + + @Override + public boolean performClick() { + WebView.HitTestResult result = this.getHitTestResult(); + if(result.getType() == WebView.HitTestResult.IMAGE_TYPE){ + String imageURL = result.getExtra(); + showImage(imageURL); + } + return super.performClick(); + } + + private void showImage(String url) { + Dialog builder = new Dialog(context); + builder.requestWindowFeature(Window.FEATURE_NO_TITLE); + builder.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + builder.getWindow().setBackgroundDrawable( + new ColorDrawable(android.graphics.Color.TRANSPARENT)); + + PhotoView photoView = new PhotoView(context); + photoView.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight)); + + Glide.with(context).load(url).fitCenter().into(photoView); + + builder.addContentView(photoView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + builder.show(); + } + + private void setOnLongClickListener(){ + this.setOnLongClickListener(v -> { + HitTestResult result = ReactiveWebView.this.getHitTestResult(); + if(result.getType() == HitTestResult.SRC_ANCHOR_TYPE){ + ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", result.getExtra()); + clipboard.setPrimaryClip(clip); + Toast.makeText(BaseApplication.getInstance().getApplicationContext(),"Link copied",Toast.LENGTH_SHORT).show(); + } + return false; + }); + } +} diff --git a/app/src/main/res/layout-v21/activity_topic_post_row.xml b/app/src/main/res/layout-v21/activity_topic_post_row.xml index d1464a61..e51a2887 100644 --- a/app/src/main/res/layout-v21/activity_topic_post_row.xml +++ b/app/src/main/res/layout-v21/activity_topic_post_row.xml @@ -225,7 +225,7 @@ android:layout_height="match_parent" android:layout_marginBottom="16dp"> - - - Date: Fri, 29 May 2020 13:29:09 +0300 Subject: [PATCH 41/53] shoutbox bug fix (#69) * fix bug where changing the orientation while guest would make EditorView visible * +8dp shoutbox EditorView margin bottom --- .../gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java | 1 + .../java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java | 2 +- app/src/main/res/layout/fragment_shoutbox.xml | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java index a24b9155..0049fa6b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java @@ -105,6 +105,7 @@ public class ShoutboxFragment extends Fragment { Timber.i("Shoutbox loaded successfully"); shoutAdapter.setShouts(shoutbox.getShouts()); shoutAdapter.notifyDataSetChanged(); + editorView.setVisibility(shoutbox.getShoutSend() == null ? View.GONE : View.VISIBLE); } }); shoutboxViewModel.setOnShoutboxTaskStarted(this::onShoutboxTaskStarted); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java index 59797774..8a1d3768 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java @@ -45,7 +45,7 @@ public class ShoutboxTask extends NewParseTask { String formUrl = shoutboxForm.attr("action"); String sc = shoutboxForm.select("input[name=sc]").first().attr("value"); String shoutName = shoutboxForm.select("input[name=tp-shout-name]").first().attr("value"); - // TODO: make shout send nullable and disable shouting + Element shoutSendInput = shoutboxForm.select("input[name=shout_send]").first(); String shoutSend = null; if (shoutSendInput != null) diff --git a/app/src/main/res/layout/fragment_shoutbox.xml b/app/src/main/res/layout/fragment_shoutbox.xml index 7b2d51e7..69a2649c 100644 --- a/app/src/main/res/layout/fragment_shoutbox.xml +++ b/app/src/main/res/layout/fragment_shoutbox.xml @@ -29,8 +29,9 @@ android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" + android:layout_marginBottom="8dp" android:paddingTop="8dp" - android:visibility="visible"/> + android:visibility="gone"/> Date: Fri, 29 May 2020 13:40:16 +0300 Subject: [PATCH 42/53] migrate to ReactiveWebView in shoutbox --- .../java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java | 3 ++- app/src/main/res/layout/fragment_shoutbox_shout_row.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java index d2639fe2..f2c7d192 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java @@ -24,6 +24,7 @@ import gr.thmmy.mthmmy.activities.topic.TopicActivity; import gr.thmmy.mthmmy.model.Shout; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.views.CustomRecyclerView; +import gr.thmmy.mthmmy.views.ReactiveWebView; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE; @@ -85,7 +86,7 @@ public class ShoutAdapter extends CustomRecyclerView.Adapter - Date: Fri, 29 May 2020 15:09:48 +0300 Subject: [PATCH 43/53] Animated avatars --- .../activities/profile/ProfileActivity.java | 44 +++++++------------ .../mthmmy/activities/topic/TopicAdapter.java | 29 ++++++------ 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java index 301d4b5a..49637709 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java @@ -25,9 +25,9 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; +import com.bumptech.glide.Glide; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.tabs.TabLayout; -import com.squareup.picasso.Picasso; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -51,7 +51,6 @@ import gr.thmmy.mthmmy.utils.Parcel; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.ui.CenterVerticalSpan; -import gr.thmmy.mthmmy.utils.ui.CircleTransform; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Response; import timber.log.Timber; @@ -130,9 +129,9 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment avatarView = findViewById(R.id.user_thumbnail); if (!Objects.equals(avatarUrl, "")) //noinspection ConstantConditions - loadAvatar(); + loadAvatar(false); else - loadDefaultAvatar(); + loadAvatar(true); usernameView = findViewById(R.id.profile_activity_username); usernameView.setTypeface(Typeface.createFromAsset(this.getAssets() , "fonts/fontawesome-webfont.ttf")); @@ -213,29 +212,18 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(false); } - private void loadAvatar(){ - Picasso.with(this) - .load(avatarUrl) - .fit() - .centerCrop() - .error(Objects.requireNonNull(ResourcesCompat.getDrawable(this.getResources() - , R.drawable.ic_default_user_avatar, null))) - .placeholder(Objects.requireNonNull(ResourcesCompat.getDrawable(this.getResources() - , R.drawable.ic_default_user_avatar, null))) - .transform(new CircleTransform()) - .into(avatarView); - } + private void loadAvatar(Boolean loadDefault){ + String avatarUri; + if(loadDefault) + avatarUri = "R.drawable.ic_default_user_avatar"; + else + avatarUri = avatarUrl; - private void loadDefaultAvatar(){ - Picasso.with(this) - .load(R.drawable.ic_default_user_avatar) - .fit() - .centerCrop() - .error(Objects.requireNonNull(ResourcesCompat.getDrawable(this.getResources() - , R.drawable.ic_default_user_avatar, null))) - .placeholder(Objects.requireNonNull(ResourcesCompat.getDrawable(this.getResources() - , R.drawable.ic_default_user_avatar, null))) - .transform(new CircleTransform()) + Glide.with(this) + .load(avatarUri) + .circleCrop() + .error(R.drawable.ic_default_user_avatar) + .placeholder(R.drawable.ic_default_user_avatar) .into(avatarView); } @@ -319,9 +307,9 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment } else if (usernameView.getText() != username) usernameView.setText(username); if (avatarUrl != null && !Objects.equals(avatarUrl, "")) //noinspection ConstantConditions - loadAvatar(); + loadAvatar(false); else - loadDefaultAvatar(); + loadAvatar(true); if (personalText != null) { personalTextView.setText(personalText); personalTextView.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index bb970644..d457db1d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -47,13 +47,15 @@ import androidx.core.content.res.ResourcesCompat; import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; +import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.github.mikephil.charting.charts.HorizontalBarChart; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; -import com.squareup.picasso.Picasso; import java.text.DecimalFormat; import java.util.ArrayList; @@ -65,6 +67,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.board.BoardActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; @@ -72,7 +75,6 @@ import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.utils.parsing.ThmmyParser; -import gr.thmmy.mthmmy.utils.ui.CircleTransform; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import gr.thmmy.mthmmy.views.ReactiveWebView; import gr.thmmy.mthmmy.views.editorview.EditorView; @@ -365,7 +367,7 @@ class TopicAdapter extends RecyclerView.Adapter { holder.post.setWebViewClient(new LinkLauncher()); //noinspection ConstantConditions - loadAvatar(currentPost.getThumbnailURL(), holder.thumbnail); + loadAvatar(currentPost.getThumbnailURL(), holder.thumbnail, holder.itemView.getContext()); //Sets username,submit date, index number, subject, post's and attached files texts holder.username.setText(currentPost.getAuthor()); @@ -646,7 +648,7 @@ class TopicAdapter extends RecyclerView.Adapter { Post reply = (Post) topicItems.get(position); //noinspection ConstantConditions - loadAvatar(getSessionManager().getAvatarLink(), holder.thumbnail); + loadAvatar(getSessionManager().getAvatarLink(), holder.thumbnail, holder.itemView.getContext()); holder.username.setText(getSessionManager().getUsername()); holder.itemView.setAlpha(1f); @@ -738,7 +740,7 @@ class TopicAdapter extends RecyclerView.Adapter { final EditMessageViewHolder holder = (EditMessageViewHolder) currentHolder; //noinspection ConstantConditions - loadAvatar(getSessionManager().getAvatarLink(), holder.thumbnail); + loadAvatar(getSessionManager().getAvatarLink(), holder.thumbnail, holder.itemView.getContext()); holder.username.setText(getSessionManager().getUsername()); holder.editSubject.setText(currentPost.getSubject()); @@ -808,16 +810,15 @@ class TopicAdapter extends RecyclerView.Adapter { } } - private void loadAvatar(String imageUrl, ImageView imageView) { - Picasso.with(context) + private void loadAvatar(String imageUrl, ImageView imageView, Context context) { + if(imageUrl!=null) + imageUrl = imageUrl.trim(); + + Glide.with(context) .load(imageUrl) - .fit() - .centerCrop() - .error(Objects.requireNonNull(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_avatar_darker, null))) - .placeholder(Objects.requireNonNull(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_avatar_darker, null))) - .transform(new CircleTransform()) + .circleCrop() + .error(R.drawable.ic_default_user_avatar_darker) + .placeholder(R.drawable.ic_default_user_avatar_darker) .into(imageView); } From 5f7c996db22022f24fb6d135417ce5343450bb64 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 29 May 2020 18:40:31 +0300 Subject: [PATCH 44/53] WebView-RecyclerView improvements --- .../thmmy/mthmmy/activities/profile/ProfileActivity.java | 1 - .../gr/thmmy/mthmmy/activities/topic/TopicActivity.java | 8 +++++--- .../gr/thmmy/mthmmy/activities/topic/TopicAdapter.java | 4 ---- .../main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java | 9 +++++++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java index 49637709..0cb1edeb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java @@ -19,7 +19,6 @@ import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatDelegate; -import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index 8e81cdd4..629b2f60 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -187,6 +187,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo recyclerView.setLayoutManager(layoutManager); topicAdapter = new TopicAdapter(this, emojiKeyboard, topicItems); recyclerView.setAdapter(topicAdapter); + recyclerView.setItemViewCacheSize(15); //Every page has maximum 15 posts replyFAB = findViewById(R.id.topic_fab); replyFAB.hide(); @@ -661,11 +662,11 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo Toast.makeText(this, "Failed to remove vote", Toast.LENGTH_LONG).show(); } }); - // observe the chages in data + // observe the changes in data viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> { if (pageIndicatorIndex == null) return; - pageIndicator.setText(String.valueOf(pageIndicatorIndex) + "/" + - String.valueOf(viewModel.getPageCount())); + pageIndicator.setText(pageIndicatorIndex + "/" + + viewModel.getPageCount()); }); viewModel.getTopicTitle().observe(this, newTopicTitle -> { if (newTopicTitle == null) return; @@ -692,6 +693,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo viewModel.getTopicItems().observe(this, postList -> { if (postList == null) progressBar.setVisibility(ProgressBar.VISIBLE); recyclerView.getRecycledViewPool().clear(); //Avoid inconsistency detected bug + recyclerView.scrollToPosition(0); topicItems.clear(); topicItems.addAll(postList); topicAdapter.notifyDataSetChanged(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index d457db1d..50b1f157 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -43,13 +43,10 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.AppCompatButton; -import androidx.core.content.res.ResourcesCompat; import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; -import com.bumptech.glide.RequestBuilder; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.github.mikephil.charting.charts.HorizontalBarChart; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; @@ -67,7 +64,6 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.board.BoardActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; -import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; diff --git a/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java index 1d41bda7..35fe87b7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java @@ -31,19 +31,24 @@ public class ReactiveWebView extends WebView { public ReactiveWebView(Context context) { super(context); this.context = context; - setOnLongClickListener(); + init(); } public ReactiveWebView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; - setOnLongClickListener(); + init(); } public ReactiveWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; + init(); + } + + private void init(){ setOnLongClickListener(); + this.setVerticalScrollBarEnabled(false); } @Override From 104b5684671424b77287e55814784a76f8c9c570 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 29 May 2020 19:17:47 +0300 Subject: [PATCH 45/53] Refresh sesc/markAsReadUrl if needed --- .../main/unread/UnreadFragment.java | 15 +++++++++-- .../mthmmy/activities/topic/TopicAdapter.java | 4 +-- .../thmmy/mthmmy/session/SessionManager.java | 25 +++++++++++++++---- .../mthmmy/viewmodel/TopicViewModel.java | 2 +- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 7a4dd005..c3088094 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -307,9 +307,12 @@ public class UnreadFragment extends BaseFragment { } Element topBar = document.select("table:not(.bordercolor):not(#bodyarea):has(td.middletext)").first(); - Element pagesElement = null; - if (topBar != null) + Element pagesElement = null, markRead = null; + if (topBar != null) { pagesElement = topBar.select("td.middletext").first(); + markRead = document.select("table:not(.bordercolor):not([width])").select("a") + .first(); + } if (numberOfPages == 0 && pagesElement != null) { Elements pages = pagesElement.select("a"); @@ -319,6 +322,14 @@ public class UnreadFragment extends BaseFragment { numberOfPages = 1; } + if (markRead != null && loadedPages == numberOfPages - 1){ + String retrievedMarkAsReadUrl = markRead.attr("href"); + if(!retrievedMarkAsReadUrl.equals(markAsReadUrl)) { + markAsReadUrl = retrievedMarkAsReadUrl; + BaseApplication.getInstance().getSessionManager().refreshSescFromUrl(retrievedMarkAsReadUrl); + } + } + return fetchedTopicSummaries; } return new ArrayList<>(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index 50b1f157..213de341 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -967,7 +967,7 @@ class TopicAdapter extends RecyclerView.Adapter { if (viewModel.getCurrentPageIndex() == viewModel.getPageCount()) { //same page postFocusListener.onPostFocusChange(getItemCount() - 1); - Timber.e("new"); + Timber.d("new"); return true; } } @@ -979,7 +979,7 @@ class TopicAdapter extends RecyclerView.Adapter { for (int i = 0; i < topicItems.size(); i++) { if (topicItems.get(i) instanceof Post && ((Post) topicItems.get(i)).getPostIndex() == testAgainst) { //same page - Timber.e(Integer.toString(i)); + Timber.d(Integer.toString(i)); postFocusListener.onPostFocusChange(i); return true; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index 81dd2f31..2dab5489 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -244,6 +244,15 @@ public class SessionManager { guestLogin(); } } + + public void refreshSescFromUrl(String url){ + String sesc = extractSescFromLink(url); + if(sesc!=null){ + setSesc(sesc); + setLogoutLink(generateLogoutLink(sesc)); + setMarkAsReadLink(sesc); + } + } //--------------------------------------AUTH ENDS----------------------------------------------- //---------------------------------------GETTERS------------------------------------------------ @@ -271,7 +280,7 @@ public class SessionManager { public String getMarkAllAsReadLink() { String markAsReadLink = sharedPrefs.getString(MARK_ALL_AS_READ_LINK, null); if(markAsReadLink == null){ //For older versions, extract it from logout link (otherwise user would have to login again) - String sesc = extractSescFromLogoutLink(getLogoutLink()); + String sesc = extractSescFromLink(getLogoutLink()); if(sesc!=null) { setSesc(sesc); markAsReadLink = generateMarkAllAsReadLink(sesc); @@ -313,6 +322,12 @@ public class SessionManager { editor.apply(); } + private void setLogoutLink(String logoutLink){ + SharedPreferences.Editor editor = sharedPrefs.edit(); + editor.putString(LOGOUT_LINK, logoutLink); + editor.apply(); + } + //--------------------------------------SETTERS END--------------------------------------------- //------------------------------------OTHER FUNCTIONS------------------------------------------- @@ -421,16 +436,16 @@ public class SessionManager { Elements logoutLink = doc.select("a[href^=https://www.thmmy.gr/smf/index.php?action=logout;sesc=]"); if (!logoutLink.isEmpty()) { String link = logoutLink.first().attr("href"); - return extractSescFromLogoutLink(link); + return extractSescFromLink(link); } Timber.e(new ParseException("Parsing failed(extractSesc)"),"ParseException"); return null; } - private String extractSescFromLogoutLink(String logoutLink){ - if (logoutLink != null){ + private String extractSescFromLink(String link){ + if (link != null){ Pattern pattern = Pattern.compile(".+;sesc=(\\w+)"); - Matcher matcher = pattern.matcher(logoutLink); + Matcher matcher = pattern.matcher(link); if (matcher.find()) return matcher.group(1); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index bac3952a..8f8f4c3a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -132,7 +132,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa int pageRequested = pageIndicatorIndex.getValue() - 1; if (pageRequested != currentPageIndex - 1) { Timber.i("Changing to page " + pageRequested + 1); - loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + String.valueOf(pageRequested * 15)); + loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + pageRequested * 15); pageIndicatorIndex.setValue(pageRequested + 1); } else { stopLoading(); From c889fc2d18232d63d2719593e5cff2bd9febe48c Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 29 May 2020 19:31:22 +0300 Subject: [PATCH 46/53] Display zoomed/zoomable Profile pictures on click --- .../activities/profile/ProfileActivity.java | 9 +++-- .../thmmy/mthmmy/utils/ui/PhotoViewUtils.java | 35 +++++++++++++++++++ .../thmmy/mthmmy/views/ReactiveWebView.java | 31 ++-------------- 3 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java index 0cb1edeb..380a827b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java @@ -57,6 +57,7 @@ import timber.log.Timber; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; import static gr.thmmy.mthmmy.utils.parsing.ParseHelpers.emojiTagToHtml; +import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage; /** * Activity for user profile. When creating an Intent of this activity you need to bundle a String @@ -127,8 +128,8 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment avatarView = findViewById(R.id.user_thumbnail); if (!Objects.equals(avatarUrl, "")) - //noinspection ConstantConditions loadAvatar(false); + else loadAvatar(true); usernameView = findViewById(R.id.profile_activity_username); @@ -215,8 +216,11 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment String avatarUri; if(loadDefault) avatarUri = "R.drawable.ic_default_user_avatar"; - else + else { avatarUri = avatarUrl; + if(avatarUrl!=null) + avatarView.setOnClickListener(v -> displayPhotoViewImage(ProfileActivity.this, avatarUrl)); + } Glide.with(this) .load(avatarUri) @@ -305,7 +309,6 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment usernameView.setText(usernameSpan); } else if (usernameView.getText() != username) usernameView.setText(username); if (avatarUrl != null && !Objects.equals(avatarUrl, "")) - //noinspection ConstantConditions loadAvatar(false); else loadAvatar(true); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java new file mode 100644 index 00000000..cb357324 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java @@ -0,0 +1,35 @@ +package gr.thmmy.mthmmy.utils.ui; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.view.ViewGroup; +import android.view.Window; + +import com.bumptech.glide.Glide; +import com.github.chrisbanes.photoview.PhotoView; + +import gr.thmmy.mthmmy.base.BaseApplication; + +public class PhotoViewUtils { + private final static int screenWidth = BaseApplication.getInstance().getWidthInPixels(); + private final static int screenHeight = BaseApplication.getInstance().getHeightInPixels(); + + public static void displayPhotoViewImage(Context context, String url) { + Dialog builder = new Dialog(context); + builder.requestWindowFeature(Window.FEATURE_NO_TITLE); + builder.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + builder.getWindow().setBackgroundDrawable( + new ColorDrawable(android.graphics.Color.TRANSPARENT)); + + PhotoView photoView = new PhotoView(context); + photoView.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight)); + + Glide.with(context).load(url).fitCenter().into(photoView); + + builder.addContentView(photoView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + builder.show(); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java index 35fe87b7..294c6451 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java @@ -1,28 +1,19 @@ package gr.thmmy.mthmmy.views; -import android.app.Dialog; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.graphics.drawable.ColorDrawable; import android.util.AttributeSet; import android.view.MotionEvent; -import android.view.ViewGroup; -import android.view.Window; import android.webkit.WebView; import android.widget.Toast; -import com.bumptech.glide.Glide; -import com.github.chrisbanes.photoview.PhotoView; - import gr.thmmy.mthmmy.base.BaseApplication; import static android.content.Context.CLIPBOARD_SERVICE; +import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage; public class ReactiveWebView extends WebView { - private final static int screenWidth = BaseApplication.getInstance().getWidthInPixels(); - private final static int screenHeight = BaseApplication.getInstance().getHeightInPixels(); - private final static long MAX_TOUCH_DURATION = 100; private final Context context; private long downTime; @@ -72,29 +63,11 @@ public class ReactiveWebView extends WebView { WebView.HitTestResult result = this.getHitTestResult(); if(result.getType() == WebView.HitTestResult.IMAGE_TYPE){ String imageURL = result.getExtra(); - showImage(imageURL); + displayPhotoViewImage(context, imageURL); } return super.performClick(); } - private void showImage(String url) { - Dialog builder = new Dialog(context); - builder.requestWindowFeature(Window.FEATURE_NO_TITLE); - builder.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - builder.getWindow().setBackgroundDrawable( - new ColorDrawable(android.graphics.Color.TRANSPARENT)); - - PhotoView photoView = new PhotoView(context); - photoView.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight)); - - Glide.with(context).load(url).fitCenter().into(photoView); - - builder.addContentView(photoView, new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - builder.show(); - } - private void setOnLongClickListener(){ this.setOnLongClickListener(v -> { HitTestResult result = ReactiveWebView.this.getHitTestResult(); From 2fa356d16e7ba52e272825b4f1c744f22eb3d742 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 30 May 2020 14:46:09 +0300 Subject: [PATCH 47/53] Add ability to download images/ copy their links --- .../downloads/DownloadsAdapter.java | 59 +++++++---------- .../activities/topic/TopicActivity.java | 4 +- .../gr/thmmy/mthmmy/base/BaseActivity.java | 11 +--- .../java/gr/thmmy/mthmmy/model/ThmmyFile.java | 21 ++++-- .../thmmy/mthmmy/services/DownloadHelper.java | 7 +- .../thmmy/mthmmy/utils/parsing/ParseTask.java | 2 +- .../utils/ui/ImageDownloadDialogBuilder.java | 66 +++++++++++++++++++ .../thmmy/mthmmy/utils/ui/PhotoViewUtils.java | 13 +++- .../thmmy/mthmmy/views/ReactiveWebView.java | 20 ++++-- app/src/main/res/values/strings.xml | 2 +- 10 files changed, 144 insertions(+), 61 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java index d5ca46ad..63a2c8a8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java @@ -34,7 +34,7 @@ class DownloadsAdapter extends RecyclerView.Adapter { private final int VIEW_TYPE_LOADING = 1; private final Context context; - private ArrayList parsedDownloads = new ArrayList<>(); + private ArrayList parsedDownloads; private final ArrayList downloadExpandableVisibility = new ArrayList<>(); DownloadsAdapter(Context context, ArrayList parsedDownloads) { @@ -77,17 +77,14 @@ class DownloadsAdapter extends RecyclerView.Adapter { } if (download.getType() == Download.DownloadItemType.DOWNLOADS_CATEGORY) { - downloadViewHolder.downloadRow.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(context, DownloadsActivity.class); - Bundle extras = new Bundle(); - extras.putString(BUNDLE_DOWNLOADS_URL, download.getUrl()); - extras.putString(BUNDLE_DOWNLOADS_TITLE, download.getTitle()); - intent.putExtras(extras); - intent.setFlags(FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } + downloadViewHolder.downloadRow.setOnClickListener(view -> { + Intent intent = new Intent(context, DownloadsActivity.class); + Bundle extras = new Bundle(); + extras.putString(BUNDLE_DOWNLOADS_URL, download.getUrl()); + extras.putString(BUNDLE_DOWNLOADS_TITLE, download.getTitle()); + intent.putExtras(extras); + intent.setFlags(FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); }); if (downloadExpandableVisibility.get(downloadViewHolder.getAdapterPosition())) { @@ -97,20 +94,17 @@ class DownloadsAdapter extends RecyclerView.Adapter { downloadViewHolder.informationExpandable.setVisibility(View.GONE); downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); } - downloadViewHolder.informationExpandableBtn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - final boolean visible = downloadExpandableVisibility.get(downloadViewHolder. - getAdapterPosition()); - if (visible) { - downloadViewHolder.informationExpandable.setVisibility(View.GONE); - downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); - } else { - downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE); - downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp); - } - downloadExpandableVisibility.set(downloadViewHolder.getAdapterPosition(), !visible); + downloadViewHolder.informationExpandableBtn.setOnClickListener(view -> { + final boolean visible = downloadExpandableVisibility.get(downloadViewHolder. + getAdapterPosition()); + if (visible) { + downloadViewHolder.informationExpandable.setVisibility(View.GONE); + downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); + } else { + downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE); + downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp); } + downloadExpandableVisibility.set(downloadViewHolder.getAdapterPosition(), !visible); }); downloadViewHolder.title.setTypeface(Typeface.createFromAsset(context.getAssets() , "fonts/fontawesome-webfont.ttf")); @@ -124,15 +118,12 @@ class DownloadsAdapter extends RecyclerView.Adapter { downloadViewHolder.title.setText(tmp); } } else { - downloadViewHolder.downloadRow.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - try { - ((BaseActivity) context).downloadFile(new ThmmyFile( - new URL(download.getUrl()), download.getFileName(), null)); - } catch (MalformedURLException e) { - e.printStackTrace(); - } + downloadViewHolder.downloadRow.setOnClickListener(view -> { + try { + ((BaseActivity) context).downloadFile(new ThmmyFile( + new URL(download.getUrl()), download.getFileName(), null)); + } catch (MalformedURLException e) { + e.printStackTrace(); } }); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index 629b2f60..4bff495a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -187,7 +187,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo recyclerView.setLayoutManager(layoutManager); topicAdapter = new TopicAdapter(this, emojiKeyboard, topicItems); recyclerView.setAdapter(topicAdapter); - recyclerView.setItemViewCacheSize(15); //Every page has maximum 15 posts + recyclerView.setItemViewCacheSize(17); //Every page has maximum 15 posts + Poll + EditorView replyFAB = findViewById(R.id.topic_fab); replyFAB.hide(); @@ -814,7 +814,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo //Make a toast to inform the user that the url was copied Toast.makeText( TopicActivity.this, - TopicActivity.this.getString(R.string.url_copied_msg), + TopicActivity.this.getString(R.string.link_copied_msg), Toast.LENGTH_SHORT).show(); } //Something happened. Probably the device does not support this (report to Firebase) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 6068304a..37f88876 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -735,7 +735,6 @@ public abstract class BaseActivity extends AppCompatActivity { } } - @Override public void onRequestPermissionsResult(int permsRequestCode, @NonNull String[] permissions , @NonNull int[] grantResults) { @@ -760,13 +759,7 @@ public abstract class BaseActivity extends AppCompatActivity { } } - //Uses temp file - called after permission grant - private void downloadFile() { - if (checkPerms()) - prepareDownload(tempThmmyFile); - } - - private void prepareDownload(ThmmyFile thmmyFile) { + private void prepareDownload(@NonNull ThmmyFile thmmyFile) { String fileName = thmmyFile.getFilename(); if (FileUtils.fileNameExists(fileName)) openDownloadPrompt(thmmyFile); @@ -774,7 +767,7 @@ public abstract class BaseActivity extends AppCompatActivity { DownloadHelper.enqueueDownload(thmmyFile); } - private void openDownloadPrompt(final ThmmyFile thmmyFile) { + private void openDownloadPrompt(@NonNull final ThmmyFile thmmyFile) { View view = getLayoutInflater().inflate(R.layout.download_prompt_dialog, null); final BottomSheetDialog dialog = new BottomSheetDialog(this); dialog.setContentView(view); diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java index e071a6a2..91f7a5d7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java @@ -1,5 +1,7 @@ package gr.thmmy.mthmmy.model; +import android.webkit.URLUtil; + import java.net.URL; public class ThmmyFile { @@ -8,27 +10,36 @@ public class ThmmyFile { */ private static final String TAG = "ThmmyFile"; private final URL fileUrl; - private final String filename, fileInfo; + private final String fileName, fileInfo; /** * This constructor only creates a ThmmyFile object and does not download the file. * * @param fileUrl {@link URL} object with file's url - * @param filename {@link String} with desired file name + * @param fileName {@link String} with desired file name * @param fileInfo {@link String} with any extra information (like number of downloads) */ - public ThmmyFile(URL fileUrl, String filename, String fileInfo) { + public ThmmyFile(URL fileUrl, String fileName, String fileInfo) { this.fileUrl = fileUrl; - this.filename = filename; + if(fileName!=null) + this.fileName = fileName; + else + this.fileName = URLUtil.guessFileName(fileUrl.toString(), null, null); this.fileInfo = fileInfo; } + public ThmmyFile(URL fileUrl) { + this.fileUrl = fileUrl; + this.fileName = URLUtil.guessFileName(fileUrl.toString(), null, null); + this.fileInfo = null; + } + public URL getFileUrl() { return fileUrl; } public String getFilename() { - return filename; + return fileName; } public String getFileInfo() { diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/DownloadHelper.java b/app/src/main/java/gr/thmmy/mthmmy/services/DownloadHelper.java index 65b5a426..9ba05eef 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/services/DownloadHelper.java +++ b/app/src/main/java/gr/thmmy/mthmmy/services/DownloadHelper.java @@ -6,6 +6,8 @@ import android.net.Uri; import android.os.Environment; import android.widget.Toast; +import androidx.annotation.NonNull; + import java.io.File; import gr.thmmy.mthmmy.base.BaseApplication; @@ -34,7 +36,8 @@ public class DownloadHelper { DownloadManager.Request request = new DownloadManager.Request(downloadURI); Cookie thmmyCookie = BaseApplication.getInstance().getSessionManager().getThmmyCookie(); - request.addRequestHeader("Cookie", thmmyCookie.name() + "=" + thmmyCookie.value()); + if(thmmyCookie!=null) + request.addRequestHeader("Cookie", thmmyCookie.name() + "=" + thmmyCookie.value()); request.setTitle(fileName); request.setMimeType(getMimeType(fileName)); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); @@ -49,6 +52,7 @@ public class DownloadHelper { } } + @NonNull private static String renameFileIfExists(String originalFileName) { final String dirPath = SAVE_DIR.getAbsolutePath(); File file = new File(dirPath, originalFileName); @@ -68,7 +72,6 @@ public class DownloadHelper { file = new File(dirPath, String.format(nameFormat, i)); } - return file.getName(); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseTask.java index 4f335025..9ead4364 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseTask.java @@ -21,7 +21,7 @@ import timber.log.Timber; */ public abstract class ParseTask extends AsyncTask { protected String url; - protected enum ResultCode { + public enum ResultCode { SUCCESS, PARSING_ERROR, NETWORK_ERROR, OTHER_ERROR } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java new file mode 100644 index 00000000..fe5dc54c --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java @@ -0,0 +1,66 @@ +package gr.thmmy.mthmmy.utils.ui; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.ContextWrapper; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; + +import java.net.MalformedURLException; +import java.net.URL; + +import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.model.ThmmyFile; +import timber.log.Timber; + +import static android.content.Context.CLIPBOARD_SERVICE; + +public class ImageDownloadDialogBuilder extends AlertDialog.Builder{ + private static final String[] colors = {"Copy image location", "Save Image"}; + + private Context context; + private String imageURL; + + public ImageDownloadDialogBuilder(@NonNull Context context, String imageURL) { + super(context); + this.context = context; + this.imageURL = imageURL; + + setItems(colors, (dialog, which) -> { + if(which == 0) + copyUrlToClipboard(); + else { + try { + getBaseActivity().downloadFile(new ThmmyFile(new URL(imageURL))); + } catch (MalformedURLException e) { + Timber.e(e, "Exception downloading image (MalformedURLException)"); + } catch (NullPointerException e) { + Timber.e(e, "Exception downloading image (NullPointerException)"); + } + } + }); + } + + private void copyUrlToClipboard(){ + ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", imageURL); + clipboard.setPrimaryClip(clip); + Toast.makeText(BaseApplication.getInstance().getApplicationContext(),context.getString(R.string.link_copied_msg),Toast.LENGTH_SHORT).show(); + } + + private BaseActivity getBaseActivity() { + Context baseActivityContext = context; + while (baseActivityContext instanceof ContextWrapper) { + if (context instanceof BaseActivity) { + return (BaseActivity) context; + } + baseActivityContext = ((ContextWrapper)context).getBaseContext(); + } + return null; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java index cb357324..b361c68d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java @@ -15,7 +15,7 @@ public class PhotoViewUtils { private final static int screenWidth = BaseApplication.getInstance().getWidthInPixels(); private final static int screenHeight = BaseApplication.getInstance().getHeightInPixels(); - public static void displayPhotoViewImage(Context context, String url) { + public static void displayPhotoViewImage(Context context, String imageURL) { Dialog builder = new Dialog(context); builder.requestWindowFeature(Window.FEATURE_NO_TITLE); builder.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); @@ -25,11 +25,20 @@ public class PhotoViewUtils { PhotoView photoView = new PhotoView(context); photoView.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight)); - Glide.with(context).load(url).fitCenter().into(photoView); + Glide.with(context) + .load(imageURL) + .fitCenter() + .into(photoView); builder.addContentView(photoView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); builder.show(); + + photoView.setOnLongClickListener(v -> { + ImageDownloadDialogBuilder imageDownloadDialogBuilder = new ImageDownloadDialogBuilder(context, imageURL); + imageDownloadDialogBuilder.show(); + return false; + }); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java index 294c6451..7c9efdb8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java @@ -8,7 +8,9 @@ import android.view.MotionEvent; import android.webkit.WebView; import android.widget.Toast; +import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.utils.ui.ImageDownloadDialogBuilder; import static android.content.Context.CLIPBOARD_SERVICE; import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage; @@ -71,13 +73,21 @@ public class ReactiveWebView extends WebView { private void setOnLongClickListener(){ this.setOnLongClickListener(v -> { HitTestResult result = ReactiveWebView.this.getHitTestResult(); - if(result.getType() == HitTestResult.SRC_ANCHOR_TYPE){ - ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", result.getExtra()); - clipboard.setPrimaryClip(clip); - Toast.makeText(BaseApplication.getInstance().getApplicationContext(),"Link copied",Toast.LENGTH_SHORT).show(); + if(result.getType() == HitTestResult.SRC_ANCHOR_TYPE) + copyUrlToClipboard(result.getExtra()); + else if(result.getType() == WebView.HitTestResult.IMAGE_TYPE) { + String imageURL = result.getExtra(); + ImageDownloadDialogBuilder builder = new ImageDownloadDialogBuilder(context,imageURL); + builder.show(); } return false; }); } + + private void copyUrlToClipboard(String urlToCopy){ + ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", urlToCopy); + clipboard.setPrimaryClip(clip); + Toast.makeText(BaseApplication.getInstance().getApplicationContext(),context.getString(R.string.link_copied_msg),Toast.LENGTH_SHORT).show(); + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0cae84b..88e8899f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -233,5 +233,5 @@ New topic Create topic - URL copied + Link copied From d1191d6006b842b65ab5978b2ca9e42e19f5780b Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 30 May 2020 16:48:23 +0300 Subject: [PATCH 48/53] Glide error handling for FileNotFoundException --- .../utils/ui/ImageDownloadDialogBuilder.java | 3 +- .../thmmy/mthmmy/utils/ui/PhotoViewUtils.java | 33 +++++++++++++++---- .../main/res/drawable/ic_file_not_found.xml | 5 +++ 3 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 app/src/main/res/drawable/ic_file_not_found.xml diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java index fe5dc54c..33b63d79 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java @@ -56,9 +56,8 @@ public class ImageDownloadDialogBuilder extends AlertDialog.Builder{ private BaseActivity getBaseActivity() { Context baseActivityContext = context; while (baseActivityContext instanceof ContextWrapper) { - if (context instanceof BaseActivity) { + if (context instanceof BaseActivity) return (BaseActivity) context; - } baseActivityContext = ((ContextWrapper)context).getBaseContext(); } return null; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java index b361c68d..1d5dc485 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/PhotoViewUtils.java @@ -3,12 +3,20 @@ package gr.thmmy.mthmmy.utils.ui; import android.app.Dialog; import android.content.Context; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.view.ViewGroup; import android.view.Window; +import androidx.annotation.Nullable; + import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; import com.github.chrisbanes.photoview.PhotoView; +import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; public class PhotoViewUtils { @@ -24,21 +32,32 @@ public class PhotoViewUtils { PhotoView photoView = new PhotoView(context); photoView.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight)); - Glide.with(context) .load(imageURL) .fitCenter() + .error(R.drawable.ic_file_not_found) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + photoView.setZoomable(false); + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + photoView.setOnLongClickListener(v -> { + ImageDownloadDialogBuilder imageDownloadDialogBuilder = new ImageDownloadDialogBuilder(context, imageURL); + imageDownloadDialogBuilder.show(); + return false; + }); + return false; + } + }) .into(photoView); builder.addContentView(photoView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); builder.show(); - - photoView.setOnLongClickListener(v -> { - ImageDownloadDialogBuilder imageDownloadDialogBuilder = new ImageDownloadDialogBuilder(context, imageURL); - imageDownloadDialogBuilder.show(); - return false; - }); } } diff --git a/app/src/main/res/drawable/ic_file_not_found.xml b/app/src/main/res/drawable/ic_file_not_found.xml new file mode 100644 index 00000000..78615445 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_not_found.xml @@ -0,0 +1,5 @@ + + + From d8b6e3a640ee9ebc368b34b9927722754893fdad Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 30 May 2020 17:05:17 +0300 Subject: [PATCH 49/53] Animated avatars in drawer, dropped Picasso in favor of Glide --- app/build.gradle | 2 - app/proguard-rules.pro | 3 -- app/src/main/assets/apache_libraries.html | 3 -- .../gr/thmmy/mthmmy/base/BaseApplication.java | 12 ++--- .../mthmmy/utils/ui/CircleTransform.java | 47 ------------------- 5 files changed, 3 insertions(+), 64 deletions(-) delete mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/ui/CircleTransform.java diff --git a/app/build.gradle b/app/build.gradle index f7641b8e..5e0f435c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -89,8 +89,6 @@ dependencies { implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.snatik:storage:2.1.0' implementation 'com.squareup.okhttp3:okhttp:3.12.12' //TODO: Warning: okhttp has dropped support for Android v.19 since okhttp 3.13! - implementation 'com.squareup.picasso:picasso:2.5.2' - implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' implementation 'org.jsoup:jsoup:1.10.3' //TODO: Warning: upgrading from 1.10.3 will break stuff! implementation 'joda-time:joda-time:2.10.4' implementation 'com.github.franmontiel:PersistentCookieJar:1.0.1' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e7c4ece2..d78e3cec 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -29,9 +29,6 @@ # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. -dontwarn org.codehaus.mojo.animal_sniffer.* -# Picasso --dontwarn com.squareup.okhttp.** - #Glide -keep public class * implements com.bumptech.glide.module.GlideModule -keep public class * extends com.bumptech.glide.module.AppGlideModule diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index 0a77a925..ef777771 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -8,9 +8,6 @@
    • OkHttp v3.12.12 (Copyright ©2019 Square, Inc.)
    • -
    • -
      Picasso v2.5.2 (Copyright ©2013 Square, Inc.)
      -
    • PersistentCookieJar v1.0.1 (Copyright ©2016 Francisco José Montiel Navarro)
    • diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index 8bdadf10..da6fb9cc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -13,6 +13,7 @@ import android.widget.ImageView; import androidx.core.content.ContextCompat; import androidx.preference.PreferenceManager; +import com.bumptech.glide.Glide; import com.crashlytics.android.Crashlytics; import com.crashlytics.android.core.CrashlyticsCore; import com.franmontiel.persistentcookiejar.PersistentCookieJar; @@ -21,12 +22,10 @@ import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersisto import com.google.firebase.FirebaseApp; import com.google.firebase.analytics.FirebaseAnalytics; import com.itkacher.okhttpprofiler.OkHttpProfilerInterceptor; -import com.jakewharton.picasso.OkHttp3Downloader; import com.mikepenz.fontawesome_typeface_library.FontAwesome; import com.mikepenz.iconics.IconicsDrawable; import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader; import com.mikepenz.materialdrawer.util.DrawerImageLoader; -import com.squareup.picasso.Picasso; import net.gotev.uploadservice.UploadService; import net.gotev.uploadservice.okhttp.OkHttpStack; @@ -142,11 +141,6 @@ public class BaseApplication extends Application { client = builder.build(); sessionManager = new SessionManager(client, cookieJar, sharedPrefsCookiePersistor, sharedPrefs, draftsPrefs); - Picasso picasso = new Picasso.Builder(getApplicationContext()) - .downloader(new OkHttp3Downloader(client)) - .build(); - - Picasso.setSingletonInstance(picasso); //All following Picasso (with Picasso.with(Context context) requests will use this Picasso object //Sets up upload service UploadService.NAMESPACE = BuildConfig.APPLICATION_ID; @@ -156,12 +150,12 @@ public class BaseApplication extends Application { DrawerImageLoader.init(new AbstractDrawerImageLoader() { @Override public void set(ImageView imageView, Uri uri, Drawable placeholder, String tag) { - Picasso.with(imageView.getContext()).load(uri).placeholder(placeholder).into(imageView); + Glide.with(imageView.getContext()).load(uri).circleCrop().error(placeholder).placeholder(placeholder).into(imageView); } @Override public void cancel(ImageView imageView) { - Picasso.with(imageView.getContext()).cancelRequest(imageView); + Glide.with(imageView.getContext()).clear(imageView); } @Override diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/CircleTransform.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/CircleTransform.java deleted file mode 100644 index 813463bd..00000000 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/CircleTransform.java +++ /dev/null @@ -1,47 +0,0 @@ -package gr.thmmy.mthmmy.utils.ui; - -import android.graphics.Bitmap; -import android.graphics.BitmapShader; -import android.graphics.Canvas; -import android.graphics.Paint; - -import com.squareup.picasso.Transformation; - -/** - * Used as parameter for PICASSO library's {@link com.squareup.picasso.RequestCreator#transform(Transformation) transform} method. - * @see com.squareup.picasso.Picasso Picasso - */ -public class CircleTransform implements Transformation { - @Override - public Bitmap transform(Bitmap source) { - int size = Math.min(source.getWidth(), source.getHeight()); - - int x = (source.getWidth() - size) / 2; - int y = (source.getHeight() - size) / 2; - - Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); - if (squaredBitmap != source) - source.recycle(); - - // For GIF images - Bitmap.Config config = source.getConfig() != null ? source.getConfig() : Bitmap.Config.ARGB_8888; - Bitmap bitmap = Bitmap.createBitmap(size, size, config); - - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); - paint.setShader(shader); - paint.setAntiAlias(true); - - float r = size / 2f; - canvas.drawCircle(r, r, r, paint); - - squaredBitmap.recycle(); - return bitmap; - } - - @Override - public String key() { - return "circle"; - } -} \ No newline at end of file From 8f355097d29b03ff1f6a7c9d31ec6ec859925446 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 30 May 2020 17:54:05 +0300 Subject: [PATCH 50/53] Minor BookmarksFragment improvement --- .../bookmarks/BookmarksFragment.java | 38 ++++++++----------- .../thmmy/mthmmy/session/SessionManager.java | 4 +- .../main/res/layout/fragment_bookmarks.xml | 15 +++++++- app/src/main/res/layout/fragment_unread.xml | 1 + app/src/main/res/values/strings.xml | 3 +- 5 files changed, 32 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java index 67de4c2e..23562e0d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java @@ -1,7 +1,6 @@ package gr.thmmy.mthmmy.activities.bookmarks; import android.app.Activity; -import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; @@ -34,6 +33,8 @@ public class BookmarksFragment extends Fragment { static final String INTERACTION_TOGGLE_BOARD_NOTIFICATION = "TOGGLE_BOARD_NOTIFICATION"; static final String INTERACTION_REMOVE_BOARD_BOOKMARK= "REMOVE_BOARD_BOOKMARK"; + private TextView nothingBookmarkedTextView; + private ArrayList bookmarks = null; private Type type; private String interactionClick, interactionToggle, interactionRemove; @@ -100,8 +101,10 @@ public class BookmarksFragment extends Fragment { final View rootView = layoutInflater.inflate(R.layout.fragment_bookmarks, container, false); //bookmarks container final LinearLayout bookmarksLinearView = rootView.findViewById(R.id.bookmarks_container); + nothingBookmarkedTextView = rootView.findViewById(R.id.nothing_bookmarked); if(this.bookmarks != null && !this.bookmarks.isEmpty()) { + hideNothingBookmarked(); for (final Bookmark bookmark : bookmarks) { if (bookmark != null && bookmark.getTitle() != null) { final LinearLayout row = (LinearLayout) layoutInflater.inflate( @@ -137,38 +140,27 @@ public class BookmarksFragment extends Fragment { row.setVisibility(View.GONE); if (bookmarks.isEmpty()){ - bookmarksLinearView.addView(bookmarksListEmptyMessage()); + showNothingBookmarked(); } }); bookmarksLinearView.addView(row); } } } else - bookmarksLinearView.addView(bookmarksListEmptyMessage()); + showNothingBookmarked(); return rootView; } - private TextView bookmarksListEmptyMessage() { - TextView emptyBookmarksCategory = new TextView(this.getContext()); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - params.setMargins(0, 12, 0, 0); - emptyBookmarksCategory.setLayoutParams(params); - if(type==Type.TOPIC) - emptyBookmarksCategory.setText(getString(R.string.empty_topic_bookmarks)); - else if(type==Type.BOARD) - emptyBookmarksCategory.setText(getString(R.string.empty_board_bookmarks)); - - emptyBookmarksCategory.setTypeface(emptyBookmarksCategory.getTypeface(), Typeface.BOLD); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - emptyBookmarksCategory.setTextColor(this.getContext().getColor(R.color.primary_text)); - else { - //noinspection deprecation - emptyBookmarksCategory.setTextColor(this.getContext().getResources().getColor(R.color.primary_text)); - } - emptyBookmarksCategory.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); - return emptyBookmarksCategory; + + private void showNothingBookmarked() { + if(nothingBookmarkedTextView!=null) + nothingBookmarkedTextView.setVisibility(View.VISIBLE); + } + + private void hideNothingBookmarked(){ + if(nothingBookmarkedTextView!=null) + nothingBookmarkedTextView.setVisibility(View.INVISIBLE); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index 2dab5489..36490d56 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -188,9 +188,9 @@ public class SessionManager { * fragments' data are retrieved). */ void validateSession() { - Timber.e("Validating session..."); + Timber.i("Validating session..."); if (isLoggedIn()) { - Timber.e("Refreshing session..."); + Timber.i("Refreshing session..."); int loginResult = login(); if (loginResult != FAILURE) return; diff --git a/app/src/main/res/layout/fragment_bookmarks.xml b/app/src/main/res/layout/fragment_bookmarks.xml index 9e4c7ca2..8d1372c0 100644 --- a/app/src/main/res/layout/fragment_bookmarks.xml +++ b/app/src/main/res/layout/fragment_bookmarks.xml @@ -1,5 +1,5 @@ - @@ -22,4 +22,15 @@ android:divider="?android:listDivider" android:dividerPadding="16dp"/> - \ No newline at end of file + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_unread.xml b/app/src/main/res/layout/fragment_unread.xml index 3a89ebc8..4d1d5506 100644 --- a/app/src/main/res/layout/fragment_unread.xml +++ b/app/src/main/res/layout/fragment_unread.xml @@ -39,6 +39,7 @@ android:text="@string/no_unread_topics" android:textColor="@color/accent" android:textSize="@dimen/medium_text" + android:textIsSelectable="false" app:layout_anchor="@+id/relativeLayout" app:layout_anchorGravity="center" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 88e8899f..d1c69acb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -105,8 +105,7 @@ Remove - You have no bookmarked boards - You have no bookmarked topics + Nothing bookmarked here! Toggle Notification From 1601380175166ca1642c309096b5b0c60b1fff0d Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 30 May 2020 18:44:20 +0300 Subject: [PATCH 51/53] Tiny download optimization --- .../thmmy/mthmmy/activities/downloads/DownloadsActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java index 95e0334c..2bb96af2 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java @@ -159,7 +159,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter. public void onLoadMore() { if (pagesLoaded < numberOfPages) { parsedDownloads.add(null); - downloadsAdapter.notifyItemInserted(parsedDownloads.size()); + downloadsAdapter.notifyItemInserted(parsedDownloads.size()); //This gets a warning - change it! //Load data parseDownloadPageTask = new ParseDownloadPageTask(); @@ -287,7 +287,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter. OkHttpClient client = BaseApplication.getInstance().getClient(); String fileName = null; try { - Response response = client.newCall(new Request.Builder().url(download.getUrl()).build()).execute(); + Response response = client.newCall(new Request.Builder().url(download.getUrl()).head().build()).execute(); String contentDisposition = response.headers("Content-Disposition").toString(); //check if link provides an attachment if (contentDisposition.contains("attachment")) fileName = contentDisposition.split("\"")[1]; From acd1de776969ac7a1275ee15c06a288a97149f9b Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sun, 31 May 2020 12:53:08 +0300 Subject: [PATCH 52/53] Avoid autoscrolling downwards when changing from/to some topic pages --- .../mthmmy/activities/topic/TopicActivity.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index 4bff495a..f9145be5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -83,6 +83,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo public static final String BUNDLE_TOPIC_TITLE = "TOPIC_TITLE"; private MaterialProgressBar progressBar; private TextView toolbarTitle; + private CustomLinearLayoutManager layoutManager; private RecyclerView recyclerView; //Posts related private TopicAdapter topicAdapter; @@ -181,7 +182,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo recyclerView = findViewById(R.id.topic_recycler_view); recyclerView.setHasFixedSize(true); //LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); - CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager( + layoutManager = new CustomLinearLayoutManager( getApplicationContext(), topicPageUrl); recyclerView.setLayoutManager(layoutManager); @@ -691,12 +692,19 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } }); viewModel.getTopicItems().observe(this, postList -> { - if (postList == null) progressBar.setVisibility(ProgressBar.VISIBLE); + if (postList == null) + progressBar.setVisibility(ProgressBar.VISIBLE); recyclerView.getRecycledViewPool().clear(); //Avoid inconsistency detected bug - recyclerView.scrollToPosition(0); topicItems.clear(); - topicItems.addAll(postList); - topicAdapter.notifyDataSetChanged(); + + /* A workaround to avoid automatic scrolling when a new page + page is loaded (it happens sometimes only)*/ + recyclerView.setAdapter(topicAdapter); + + if (postList != null) { + topicItems.addAll(postList); + topicAdapter.notifyDataSetChanged(); + } }); /*viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> { if (focusedPostIndex == null) return; From f20b9140f19d306f7866d6ab0863d225520719b7 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sun, 31 May 2020 13:15:28 +0300 Subject: [PATCH 53/53] Pad and center personal text in ProfileActivity --- .../thmmy/mthmmy/activities/profile/ProfileActivity.java | 2 +- app/src/main/res/layout-v21/activity_profile.xml | 7 ++++++- app/src/main/res/layout/activity_profile.xml | 7 ++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java index 380a827b..81f70fae 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java @@ -312,7 +312,7 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment loadAvatar(false); else loadAvatar(true); - if (personalText != null) { + if (personalText != null && !personalText.isEmpty()) { personalTextView.setText(personalText); personalTextView.setVisibility(View.VISIBLE); } diff --git a/app/src/main/res/layout-v21/activity_profile.xml b/app/src/main/res/layout-v21/activity_profile.xml index f8f2faff..34064eaf 100644 --- a/app/src/main/res/layout-v21/activity_profile.xml +++ b/app/src/main/res/layout-v21/activity_profile.xml @@ -37,7 +37,7 @@ android:id="@+id/user_thumbnail" android:layout_width="@dimen/profile_activity_avatar_size" android:layout_height="@dimen/profile_activity_avatar_size" - android:layout_marginBottom="5dp" + android:layout_marginBottom="6dp" android:layout_gravity="center" android:adjustViewBounds="true" android:contentDescription="@string/post_thumbnail" @@ -50,6 +50,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:paddingTop="6dp" + android:paddingBottom="4dp" + android:textAlignment="center" android:textColor="@color/primary_text" android:visibility="gone"/> diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 3a63ad27..097805a6 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -37,7 +37,7 @@ android:id="@+id/user_thumbnail" android:layout_width="@dimen/profile_activity_avatar_size" android:layout_height="@dimen/profile_activity_avatar_size" - android:layout_marginBottom="5dp" + android:layout_marginBottom="6dp" android:layout_gravity="center" android:adjustViewBounds="true" android:contentDescription="@string/post_thumbnail" @@ -49,6 +49,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:paddingTop="6dp" + android:paddingBottom="4dp" + android:textAlignment="center" android:textColor="@color/primary_text" android:visibility="gone"/>