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 1b9062b2..f286fdee 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 @@ -67,7 +67,7 @@ import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage; * this user's avatar url using the key {@link #BUNDLE_PROFILE_THUMBNAIL_URL} and a String containing * the username using the key {@link #BUNDLE_PROFILE_USERNAME}. */ -public class ProfileActivity extends BaseActivity implements LatestPostsFragment.LatestPostsFragmentInteractionListener { +public class ProfileActivity extends BaseActivity implements LatestPostsFragment.LatestPostsFragmentInteractionListener, LatestPostsFragment.OnLoadingListener, StatsFragment.OnLoadingListener{ /** * The key to use when putting profile's url String to {@link ProfileActivity}'s Bundle. */ @@ -209,6 +209,24 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment startActivity(i); } + @Override + public void onLoadingLatestPosts(boolean loading) { + setBarVisibility(loading); + } + + @Override + public void onLoadingStats(boolean loading) { + setBarVisibility(loading); + } + + private void setBarVisibility (boolean visible){ + if(visible) + progressBar.setVisibility(ProgressBar.VISIBLE); + else + progressBar.setVisibility(ProgressBar.INVISIBLE); + + } + public void onProfileTaskStarted() { progressBar.setVisibility(ProgressBar.VISIBLE); if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(false); @@ -233,7 +251,7 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment .into(avatarView); } else - Timber.d("Will not load Glide image (invalid context)"); + Timber.i("Will not load Glide image (invalid context)"); } /** @@ -336,7 +354,6 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment , Toast.LENGTH_LONG).show(); finish(); } else { - Timber.d("Parse failed!"); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Fatal error!\n Aborting..." , Toast.LENGTH_LONG).show(); finish(); @@ -358,8 +375,12 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment private void setupViewPager(ViewPager viewPager, Document profilePage) { ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFrag(SummaryFragment.newInstance(profilePage), "SUMMARY"); - adapter.addFrag(LatestPostsFragment.newInstance(profileUrl), "LATEST POSTS"); - adapter.addFrag(StatsFragment.newInstance(profileUrl), "STATS"); + LatestPostsFragment latestPostsFragment = LatestPostsFragment.newInstance(profileUrl); + latestPostsFragment.setOnLoadingListener(this); + adapter.addFrag(latestPostsFragment, "LATEST POSTS"); + StatsFragment statsFragment = StatsFragment.newInstance(profileUrl); + statsFragment.setOnLoadingListener(this); + adapter.addFrag(statsFragment, "STATS"); viewPager.setAdapter(adapter); } 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 09c3c1e0..4bd9ee1f 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 @@ -19,7 +19,6 @@ import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.views.ReactiveWebView; -import me.zhanghai.android.materialprogressbar.MaterialProgressBar; /** * {@link RecyclerView.Adapter} that can display a {@link TopicSummary} and makes a call to the @@ -28,7 +27,6 @@ import me.zhanghai.android.materialprogressbar.MaterialProgressBar; 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; @@ -40,14 +38,10 @@ class LatestPostsAdapter extends RecyclerView.Adapter { this.parsedTopicSummaries = parsedTopicSummaries; } - interface OnLoadMoreListener { - void onLoadMore(); - } - @Override public int getItemViewType(int position) { if (parsedTopicSummaries.get(position) == null && position == 0) return VIEW_TYPE_EMPTY; - return parsedTopicSummaries.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM; + return VIEW_TYPE_ITEM; } @NonNull @@ -57,10 +51,6 @@ class LatestPostsAdapter extends RecyclerView.Adapter { View view = LayoutInflater.from(parent.getContext()). inflate(R.layout.fragment_profile_latest_posts_row, parent, false); return new LatestPostViewHolder(view); - } else if (viewType == VIEW_TYPE_LOADING) { - View view = LayoutInflater.from(parent.getContext()). - inflate(R.layout.recycler_loading_item, parent, false); - return new LoadingViewHolder(view); } else { // viewType == VIEW_TYPE_EMPTY View view = LayoutInflater.from(parent.getContext()). inflate(R.layout.fragment_profile_latest_posts_empty_message, parent, false); @@ -71,28 +61,22 @@ class LatestPostsAdapter extends RecyclerView.Adapter { @SuppressLint("ClickableViewAccessibility") @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { - if (holder instanceof LatestPostViewHolder) { - PostSummary topic = parsedTopicSummaries.get(position); - final LatestPostViewHolder latestPostViewHolder = (LatestPostViewHolder) holder; - - latestPostViewHolder.postTitle.setText(topic.getSubject()); - latestPostViewHolder.postDate.setText(topic.getDateTime()); - latestPostViewHolder.post.setBackgroundColor(Color.argb(1, 255, 255, 255)); - latestPostViewHolder.post.loadDataWithBaseURL("file:///android_asset/" - , topic.getPost(), "text/html", "UTF-8", null); - - latestPostViewHolder.latestPostsRow.setOnClickListener(v -> { - if (interactionListener != null) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that a post has been selected. - interactionListener.onLatestPostsFragmentInteraction( - parsedTopicSummaries.get(holder.getAdapterPosition())); - } - }); - } else if (holder instanceof LoadingViewHolder) { - LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder; - loadingViewHolder.progressBar.setIndeterminate(true); - } + PostSummary topic = parsedTopicSummaries.get(position); + final LatestPostViewHolder latestPostViewHolder = (LatestPostViewHolder) holder; + latestPostViewHolder.postTitle.setText(topic.getSubject()); + latestPostViewHolder.postDate.setText(topic.getDateTime()); + latestPostViewHolder.post.setBackgroundColor(Color.argb(1, 255, 255, 255)); + latestPostViewHolder.post.loadDataWithBaseURL("file:///android_asset/" + , topic.getPost(), "text/html", "UTF-8", null); + + latestPostViewHolder.latestPostsRow.setOnClickListener(v -> { + if (interactionListener != null) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that a post has been selected. + interactionListener.onLatestPostsFragmentInteraction( + parsedTopicSummaries.get(holder.getAdapterPosition())); + } + }); } @Override @@ -114,13 +98,4 @@ class LatestPostsAdapter extends RecyclerView.Adapter { post = itemView.findViewById(R.id.post); } } - - private static class LoadingViewHolder extends RecyclerView.ViewHolder { - final MaterialProgressBar progressBar; - - LoadingViewHolder(View itemView) { - super(itemView); - progressBar = itemView.findViewById(R.id.recycler_progress_bar); - } - } } \ No newline at end of file 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 dd00d425..cbe2f3f0 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 @@ -5,7 +5,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; import androidx.annotation.NonNull; import androidx.recyclerview.widget.DividerItemDecoration; @@ -27,7 +26,6 @@ import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; -import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; @@ -35,7 +33,7 @@ import timber.log.Timber; /** * Use the {@link LatestPostsFragment#newInstance} factory method to create an instance of this fragment. */ -public class LatestPostsFragment extends BaseFragment implements LatestPostsAdapter.OnLoadMoreListener { +public class LatestPostsFragment extends BaseFragment { /** * The key to use when putting profile's url String to {@link LatestPostsFragment}'s Bundle. */ @@ -50,12 +48,13 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap private int pagesLoaded = 0; private String profileUrl; private LatestPostsTask profileLatestPostsTask; - private MaterialProgressBar progressBar; private boolean isLoadingMore; private boolean userHasPosts = true; private static final int visibleThreshold = 5; private int lastVisibleItem, totalItemCount; + private OnLoadingListener onLoadingListener; + public LatestPostsFragment() { // Required empty public constructor } @@ -87,16 +86,16 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap Bundle savedInstanceState) { final View rootView = inflater.inflate(R.layout.fragment_profile_latest_posts, container, false); latestPostsAdapter = new LatestPostsAdapter(this.getContext(), fragmentInteractionListener, parsedTopicSummaries); - RecyclerView mainContent = rootView.findViewById(R.id.profile_latest_posts_recycler); - mainContent.setAdapter(latestPostsAdapter); + RecyclerView recyclerView = rootView.findViewById(R.id.profile_latest_posts_recycler); + recyclerView.setAdapter(latestPostsAdapter); final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); - mainContent.setLayoutManager(layoutManager); - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mainContent.getContext(), + recyclerView.setLayoutManager(layoutManager); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), layoutManager.getOrientation()); - mainContent.addItemDecoration(dividerItemDecoration); + recyclerView.addItemDecoration(dividerItemDecoration); + recyclerView.setItemViewCacheSize(15); - //latestPostsAdapter.setOnLoadMoreListener(); - mainContent.addOnScrollListener(new RecyclerView.OnScrollListener() { + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); @@ -110,20 +109,15 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap } } }); - progressBar = rootView.findViewById(R.id.progressBar); return rootView; } - @Override public void onLoadMore() { if (pagesLoaded < numberOfPages) { - parsedTopicSummaries.add(null); - latestPostsAdapter.notifyItemInserted(parsedTopicSummaries.size() - 1); - //Load data profileLatestPostsTask = new LatestPostsTask(); profileLatestPostsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileUrl + ";sa=showPosts;start=" + pagesLoaded * 15); - ++pagesLoaded; + pagesLoaded++; } } @@ -148,6 +142,14 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap void onLatestPostsFragmentInteraction(PostSummary postSummary); } + public interface OnLoadingListener { + void onLoadingLatestPosts(boolean loading); + } + + public void setOnLoadingListener(OnLoadingListener onLoadingListener) { + this.onLoadingListener = onLoadingListener; + } + /** * An {@link AsyncTask} that handles asynchronous fetching of a profile page and parsing this * user's latest posts. @@ -155,8 +157,16 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap * parameter!

*/ private class LatestPostsTask extends AsyncTask { + private ArrayList fetchedParsedTopicSummaries; + + @Override protected void onPreExecute() { - if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE); + onLoadingListener.onLoadingLatestPosts(true); + } + + public LatestPostsTask() { + super(); + fetchedParsedTopicSummaries = new ArrayList<>(); } protected Boolean doInBackground(String... profileUrl) { @@ -177,10 +187,12 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap protected void onPostExecute(Boolean result) { if (Boolean.FALSE.equals(result)) Timber.e(new ParseException("Parsing failed (latest posts)"),"ParseException"); //TODO: This is inaccurate (e.g. can also have an I/O cause) - - progressBar.setVisibility(ProgressBar.INVISIBLE); + int prevSize = parsedTopicSummaries.size(); + parsedTopicSummaries.addAll(fetchedParsedTopicSummaries); + latestPostsAdapter.notifyItemRangeInserted(prevSize, parsedTopicSummaries.size() - prevSize); latestPostsAdapter.notifyDataSetChanged(); isLoadingMore = false; + onLoadingListener.onLoadingLatestPosts(false); } //TODO: better parse error handling (ParseException etc.) @@ -192,14 +204,10 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap latestPostsRows = latestPostsPage. select("td:has(table:Contains(Εμφάνιση μηνυμάτων)):not([style]) > table"); - //Removes loading item - if (isLoadingMore) - parsedTopicSummaries.remove(parsedTopicSummaries.size() - 1); - if (!latestPostsRows.select("td:contains(Sorry, no matches were found)").isEmpty() || !latestPostsRows.select("td:contains(Δυστυχώς δεν βρέθηκε τίποτα)").isEmpty()){ userHasPosts = false; - parsedTopicSummaries.add(null); + fetchedParsedTopicSummaries.add(null); return true; } @@ -228,7 +236,7 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap //style.css pPost = ("" + pPost); - parsedTopicSummaries.add(new PostSummary(pTopicUrl, pTopicTitle, pDateTime, pPost)); + fetchedParsedTopicSummaries.add(new PostSummary(pTopicUrl, pTopicTitle, pDateTime, pPost)); } } return true; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java index aee0401e..33a892f4 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java @@ -8,7 +8,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; -import android.widget.ProgressBar; import android.widget.TextView; import androidx.fragment.app.Fragment; @@ -43,7 +42,6 @@ import javax.net.ssl.SSLHandshakeException; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.utils.parsing.ParseException; -import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; @@ -56,7 +54,6 @@ public class StatsFragment extends Fragment { private String profileUrl; private ProfileStatsTask profileStatsTask; private LinearLayout mainContent; - private MaterialProgressBar progressBar; private boolean userHasPosts = true; private String generalStatisticsTitle = "", generalStatistics = "", postingActivityByTimeTitle = "", mostPopularBoardsByPostsTitle = "", mostPopularBoardsByActivityTitle = ""; @@ -64,6 +61,8 @@ public class StatsFragment extends Fragment { private final List mostPopularBoardsByPosts = new ArrayList<>(), mostPopularBoardsByActivity = new ArrayList<>(); private final ArrayList mostPopularBoardsByPostsLabels = new ArrayList<>(), mostPopularBoardsByActivityLabels = new ArrayList<>(); + private OnLoadingListener onLoadingListener; + public StatsFragment() { // Required empty public constructor } @@ -94,7 +93,6 @@ public class StatsFragment extends Fragment { Bundle savedInstanceState) { final View rootView = inflater.inflate(R.layout.fragment_profile_stats, container, false); mainContent = rootView.findViewById(R.id.main_content); - progressBar = rootView.findViewById(R.id.progressBar); if (profileStatsTask!=null && profileStatsTask.getStatus() == AsyncTask.Status.FINISHED) populateLayout(); return rootView; @@ -117,6 +115,14 @@ public class StatsFragment extends Fragment { profileStatsTask.cancel(true); } + public interface OnLoadingListener { + void onLoadingStats(boolean loading); + } + + public void setOnLoadingListener(OnLoadingListener onLoadingListener) { + this.onLoadingListener = onLoadingListener; + } + /** * An {@link AsyncTask} that handles asynchronous parsing of a profile page's data. * {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link #()} @@ -129,7 +135,7 @@ public class StatsFragment extends Fragment { @Override protected void onPreExecute() { - progressBar.setVisibility(ProgressBar.VISIBLE); + onLoadingListener.onLoadingStats(true); } @Override @@ -150,7 +156,7 @@ public class StatsFragment extends Fragment { @Override protected void onPostExecute(Boolean result) { - progressBar.setVisibility(ProgressBar.INVISIBLE); + onLoadingListener.onLoadingStats(false); if (!result) Timber.e(new ParseException("Parsing failed (user stats)"),"ParseException"); //TODO: This is inaccurate (e.g. can also have an I/O cause) else @@ -221,7 +227,7 @@ public class StatsFragment extends Fragment { } private void populateLayout() { - progressBar.setVisibility(ProgressBar.VISIBLE); + onLoadingListener.onLoadingStats(true);; ((TextView) mainContent.findViewById(R.id.general_statistics_title)) .setText(generalStatisticsTitle); ((TextView) mainContent.findViewById(R.id.general_statistics)) @@ -229,6 +235,7 @@ public class StatsFragment extends Fragment { if (!userHasPosts) { mainContent.removeViews(2, mainContent.getChildCount() - 2); + onLoadingListener.onLoadingStats(false); return; } @@ -346,7 +353,7 @@ public class StatsFragment extends Fragment { mostPopularBoardsByActivityData.setValueTextColor(Color.WHITE); mostPopularBoardsByActivityChart.setData(mostPopularBoardsByActivityData); mostPopularBoardsByActivityChart.invalidate(); - progressBar.setVisibility(ProgressBar.INVISIBLE); + onLoadingListener.onLoadingStats(false); } private class MyXAxisValueFormatter implements IAxisValueFormatter { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java index cf41e751..21513a4b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java @@ -25,7 +25,6 @@ import java.util.Objects; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.views.ReactiveWebView; -import timber.log.Timber; /** * Use the {@link SummaryFragment#newInstance} factory method to create an instance of this fragment. @@ -69,7 +68,7 @@ public class SummaryFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - profileSummaryDocument = Jsoup.parse(getArguments().getString(PROFILE_DOCUMENT)); + profileSummaryDocument = Jsoup.parse(requireArguments().getString(PROFILE_DOCUMENT)); parsedProfileSummaryData = new ArrayList<>(); } @@ -90,7 +89,6 @@ public class SummaryFragment extends Fragment { summaryTask = new SummaryTask(); summaryTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileSummaryDocument); } - Timber.d("onActivityCreated"); } @Override @@ -189,13 +187,11 @@ public class SummaryFragment extends Fragment { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) entry.setTextColor(getResources().getColor(R.color.primary_text, null)); else - //noinspection deprecation entry.setTextColor(getResources().getColor(R.color.primary_text)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { entry.setText(Html.fromHtml(profileSummaryRow, Html.FROM_HTML_MODE_LEGACY)); } else { - //noinspection deprecation entry.setText(Html.fromHtml(profileSummaryRow)); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java index c2c1a578..0fd18e5c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java @@ -28,13 +28,11 @@ public abstract class BaseFragment extends Fragment { @Override public void onAttach(Context context) { super.onAttach(context); - if (context instanceof FragmentInteractionListener) { + if (context instanceof FragmentInteractionListener) fragmentInteractionListener = (FragmentInteractionListener) context; - - } else { + else throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); - } } @Override diff --git a/app/src/main/res/layout/fragment_profile_latest_posts.xml b/app/src/main/res/layout/fragment_profile_latest_posts.xml index c44fee77..5802869a 100644 --- a/app/src/main/res/layout/fragment_profile_latest_posts.xml +++ b/app/src/main/res/layout/fragment_profile_latest_posts.xml @@ -1,26 +1,14 @@ + android:layout_height="match_parent" + android:background="@color/background_light"> - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_profile_stats.xml b/app/src/main/res/layout/fragment_profile_stats.xml index be4ddde2..54e7bbbd 100644 --- a/app/src/main/res/layout/fragment_profile_stats.xml +++ b/app/src/main/res/layout/fragment_profile_stats.xml @@ -1,7 +1,6 @@ @@ -87,15 +86,4 @@ android:layout_marginBottom="14dp"/> - - \ No newline at end of file