From cfd19618d73c8cc226c44bf1f7d8038a5bf30c68 Mon Sep 17 00:00:00 2001
From: Apostolof
Date: Mon, 2 Jan 2017 16:05:13 +0200
Subject: [PATCH] Work in progress: summary tab completed
---
.../activities/profile/ProfileActivity.java | 172 +++++++++++-------
.../activities/profile/ProfileParser.java | 143 ---------------
.../profile/summary/SummaryFragment.java | 59 +++---
.../mthmmy/activities/topic/TopicAdapter.java | 15 +-
.../main/res/layout-v21/activity_profile.xml | 2 +-
app/src/main/res/layout/activity_profile.xml | 2 +-
.../profile_fragment_latest_posts_row.xml | 7 +
.../res/layout/profile_fragment_summary.xml | 43 ++---
8 files changed, 165 insertions(+), 278 deletions(-)
delete mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileParser.java
create mode 100644 app/src/main/res/layout/profile_fragment_latest_posts_row.xml
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 0c73e611..c85795d0 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
@@ -2,21 +2,19 @@ package gr.thmmy.mthmmy.activities.profile;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
+import android.support.design.widget.TabLayout;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
-import android.text.Html;
-import android.util.Log;
import android.view.View;
-import android.webkit.WebView;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -25,64 +23,65 @@ import com.squareup.picasso.Picasso;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
import java.util.ArrayList;
+import java.util.List;
import javax.net.ssl.SSLHandshakeException;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.LoginActivity;
import gr.thmmy.mthmmy.activities.base.BaseActivity;
+import gr.thmmy.mthmmy.activities.profile.summary.SummaryFragment;
import gr.thmmy.mthmmy.utils.CircleTransform;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report;
import okhttp3.Request;
import okhttp3.Response;
-import static gr.thmmy.mthmmy.activities.profile.ProfileParser.PERSONAL_TEXT_INDEX;
-import static gr.thmmy.mthmmy.activities.profile.ProfileParser.THUMBNAIL_URL_INDEX;
-import static gr.thmmy.mthmmy.activities.profile.ProfileParser.USERNAME_INDEX;
-import static gr.thmmy.mthmmy.activities.profile.ProfileParser.parseProfileSummary;
-import static gr.thmmy.mthmmy.session.SessionManager.LOGGED_IN;
-
/**
- * Activity for user's profile. When creating an Intent of this activity you need to bundle a String
- * containing this user's profile url using the key {@link #EXTRAS_PROFILE_URL}.
+ * Activity for user profile. When creating an Intent of this activity you need to bundle a String
+ * containing this user's profile url using the key {@link #BUNDLE_PROFILE_URL}, a String containing
+ * this user's avatar url and a String containing the username.
*/
public class ProfileActivity extends BaseActivity {
- //Graphic element variables
- private ImageView userThumbnail;
- private TextView userName;
- private TextView personalText;
+ //Graphics
+ private TextView personalTextView;
private MaterialProgressBar progressBar;
private FloatingActionButton replyFAB;
private ViewPager viewPager;
-
- //Other variables
+ //Other variables and constants
/**
* Debug Tag for logging debug output to LogCat
*/
@SuppressWarnings("unused")
private static final String TAG = "ProfileActivity";
- static String PACKAGE_NAME;
/**
* The key to use when putting profile's url String to {@link ProfileActivity}'s Bundle.
*/
- public static final String EXTRAS_PROFILE_URL = "PROFILE_URL";
+ public static final String BUNDLE_PROFILE_URL = "PROFILE_URL";
/**
- * {@link ArrayList} of Strings used to hold profile's information. Data are added in {@link ProfileTask}.
+ * The key to use when putting user's thumbnail url String to {@link ProfileActivity}'s Bundle.
+ * If user doesn't have a thumbnail put an empty string.
*/
- private ArrayList parsedProfileData;
- private ProfileTask profileTask;
+ public static final String BUNDLE_THUMBNAIL_URL = "THUMBNAIL_URL";
+ /**
+ * The key to use when putting username String to {@link ProfileActivity}'s Bundle.
+ */
+ public static final String BUNDLE_USERNAME = "USERNAME";
private static final int THUMBNAIL_SIZE = 200;
+ private ProfileTask profileTask;
+ private String personalText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
- PACKAGE_NAME = getApplicationContext().getPackageName();
Bundle extras = getIntent().getExtras();
+ String thumbnailUrl = extras.getString(BUNDLE_THUMBNAIL_URL);
+ String username = extras.getString(BUNDLE_USERNAME);
//Initializes graphic elements
toolbar = (Toolbar) findViewById(R.id.toolbar);
@@ -97,9 +96,24 @@ public class ProfileActivity extends BaseActivity {
progressBar = (MaterialProgressBar) findViewById(R.id.progressBar);
- userThumbnail = (ImageView) findViewById(R.id.user_thumbnail);
- userName = (TextView) findViewById(R.id.profile_activity_username);
- personalText = (TextView) findViewById(R.id.profile_activity_personal_text);
+ ImageView thumbnailView = (ImageView) findViewById(R.id.user_thumbnail);
+ if (thumbnailUrl != null)
+ //noinspection ConstantConditions
+ Picasso.with(this)
+ .load(thumbnailUrl)
+ .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)
+ .centerCrop()
+ .error(ResourcesCompat.getDrawable(this.getResources()
+ , R.drawable.ic_default_user_thumbnail, null))
+ .placeholder(ResourcesCompat.getDrawable(this.getResources()
+ , R.drawable.ic_default_user_thumbnail, null))
+ .transform(new CircleTransform())
+ .into(thumbnailView);
+ TextView usernameView = (TextView) findViewById(R.id.profile_activity_username);
+ usernameView.setText(username);
+ personalTextView = (TextView) findViewById(R.id.profile_activity_personal_text);
+
+ viewPager = (ViewPager) findViewById(R.id.profile_tab_container);
replyFAB = (FloatingActionButton) findViewById(R.id.profile_fab); //TODO hide fab while logged out
replyFAB.setEnabled(false);
@@ -131,10 +145,8 @@ public class ProfileActivity extends BaseActivity {
}
});
- //Gets info
- parsedProfileData = new ArrayList<>();
profileTask = new ProfileTask();
- profileTask.execute(extras.getString(EXTRAS_PROFILE_URL)); //Attempt data parsing
+ profileTask.execute(extras.getString(BUNDLE_PROFILE_URL)); //Attempt data parsing
}
@Override
@@ -145,19 +157,19 @@ public class ProfileActivity extends BaseActivity {
}
/**
- * An {@link AsyncTask} that handles asynchronous fetching of a profile page and parsing it's
- * data. {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link #populateLayout()}
- * to build graphics.
- *
- *
Calling ProfileSummaryTask's {@link AsyncTask#execute execute} method needs to have profile's url
- * as String parameter!
+ * An {@link AsyncTask} that handles asynchronous fetching of a profile page and parsing this
+ * user's personal text.
+ *
ProfileTask's {@link AsyncTask#execute execute} method needs a profile's url as String
+ * parameter!
*/
public class ProfileTask extends AsyncTask {
//Class variables
/**
* Debug Tag for logging debug output to LogCat
*/
- private static final String TAG = "TopicTask"; //Separate tag for AsyncTask
+ @SuppressWarnings("unused")
+ private static final String TAG = "ProfileTask"; //Separate tag for AsyncTask
+ Document profilePage;
protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE);
@@ -165,7 +177,6 @@ public class ProfileActivity extends BaseActivity {
}
protected Boolean doInBackground(String... profileUrl) {
- Document document;
String pageUrl = profileUrl[0] + ";wap"; //Profile's page wap url
Request request = new Request.Builder()
@@ -173,10 +184,18 @@ public class ProfileActivity extends BaseActivity {
.build();
try {
Response response = client.newCall(request).execute();
- document = Jsoup.parse(response.body().string());
- //long parseStartTime = System.nanoTime();
- parsedProfileData = parseProfileSummary(document);
- //long parseEndTime = System.nanoTime();
+ profilePage = Jsoup.parse(response.body().string());
+ { //Finds personal text
+ Element tmpEl = profilePage.select("td.windowbg:nth-child(2)").first();
+ if (tmpEl != null) {
+ personalText = tmpEl.text().trim();
+ } else {
+ //Should never get here!
+ //Something is wrong.
+ Report.e(TAG, "An error occurred while trying to find profile's personal text.");
+ personalText = null;
+ }
+ }
return true;
} catch (SSLHandshakeException e) {
Report.w(TAG, "Certificate problem (please switch to unsafe connection).");
@@ -194,36 +213,55 @@ public class ProfileActivity extends BaseActivity {
}
//Parse was successful
progressBar.setVisibility(ProgressBar.INVISIBLE);
- populateLayout();
+
+ if (personalText != null) {
+ personalTextView.setVisibility(View.VISIBLE);
+ personalTextView.setText(personalText);
+ } else {
+ personalTextView.setVisibility(View.GONE);
+ }
+
+ setupViewPager(viewPager, profilePage);
+ TabLayout tabLayout = (TabLayout) findViewById(R.id.profile_tabs);
+ tabLayout.setupWithViewPager(viewPager);
}
}
/**
- * Simple method that builds the UI of a {@link ProfileActivity}.
- *
Use this method only after parsing profile's data with {@link ProfileTask} as it
- * reads from {@link #parsedProfileData}
+ * Simple method that sets up the {@link ViewPager} of a {@link ProfileActivity}
+ * @param viewPager the ViewPager to be setup
+ * @param profilePage this profile's parsed page
*/
- private void populateLayout() {
- if (parsedProfileData.get(THUMBNAIL_URL_INDEX) != null)
- //noinspection ConstantConditions
- Picasso.with(this)
- .load(parsedProfileData.get(THUMBNAIL_URL_INDEX))
- .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)
- .centerCrop()
- .error(ResourcesCompat.getDrawable(this.getResources()
- , R.drawable.ic_default_user_thumbnail, null))
- .placeholder(ResourcesCompat.getDrawable(this.getResources()
- , R.drawable.ic_default_user_thumbnail, null))
- .transform(new CircleTransform())
- .into(userThumbnail);
+ private void setupViewPager(ViewPager viewPager, Document profilePage) {
+ ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
+ adapter.addFrag(SummaryFragment.newInstance(profilePage), "SUMMARY");
+ //adapter.addFrag(new );
+ //adapter.addFrag(new );
+ viewPager.setAdapter(adapter);
+ }
- userName.setText(parsedProfileData.get(USERNAME_INDEX));
+ class ViewPagerAdapter extends FragmentPagerAdapter {
+ private final List mFragmentList = new ArrayList<>();
+ private final List mFragmentTitleList = new ArrayList<>();
- if (parsedProfileData.get(PERSONAL_TEXT_INDEX) != null) {
- personalText.setVisibility(View.VISIBLE);
- personalText.setText(parsedProfileData.get(PERSONAL_TEXT_INDEX));
- } else {
- personalText.setVisibility(View.GONE);
+ ViewPagerAdapter(FragmentManager manager) {
+ super(manager);
+ }
+ @Override
+ public Fragment getItem(int position) {
+ return mFragmentList.get(position);
+ }
+ @Override
+ public int getCount() {
+ return mFragmentList.size();
+ }
+ void addFrag(Fragment fragment, String title) {
+ mFragmentList.add(fragment);
+ mFragmentTitleList.add(title);
+ }
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return mFragmentTitleList.get(position);
}
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileParser.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileParser.java
deleted file mode 100644
index fab4e120..00000000
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileParser.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package gr.thmmy.mthmmy.activities.profile;
-
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import java.util.ArrayList;
-import java.util.Objects;
-
-import mthmmy.utils.Report;
-
-import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.PACKAGE_NAME;
-
-/**
- * Singleton used for parsing user's profile.
- *
Class contains the methods:
{@link #parseProfileSummary(Document)}
- *
- */
-class ProfileParser {
- /**
- * Debug Tag for logging debug output to LogCat
- */
- @SuppressWarnings("unused")
- private static final String TAG = "ProfileParser";
- /**
- * Index of user's thumbnail url in parsed information ArrayList
- *
Not the url itself!
- */
- static final int THUMBNAIL_URL_INDEX = 0;
- /**
- * Index of user's username in parsed information ArrayList
- *
Not the username itself!
- */
- static final int USERNAME_INDEX = 1;
- /**
- * Index of user's personal text in parsed information ArrayList
- *
Not the text itself!
- */
- static final int PERSONAL_TEXT_INDEX = 2;
-
- /**
- * Returns an {@link ArrayList} of {@link String}s. This method is used to parse all available
- * information in a user profile.
- *
- * User's thumbnail image url, username and personal text are placed at Array's indexes defined
- * by public constants THUMBNAIL_URL_INDEX, USERNAME_INDEX and PERSONAL_TEXT_INDEX respectively.
- *
- * @param profile {@link Document} object containing this profile's source code
- * @return ArrayList containing this profile's parsed information
- * @see org.jsoup.Jsoup Jsoup
- */
- static ArrayList parseProfileSummary(Document profile) {
- //Method's variables
- ArrayList parsedInformation = new ArrayList<>();
-
- //Contains all summary's rows
- Elements summaryRows = profile.select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) tr");
-
- { //Finds thumbnail's url
- Element tmpEl = profile.select(".bordercolor img.avatar").first();
- if (tmpEl != null)
- parsedInformation.add(THUMBNAIL_URL_INDEX, tmpEl.attr("abs:src"));
- else //User doesn't have an avatar
- parsedInformation.add(THUMBNAIL_URL_INDEX, null);
- }
-
- { //Finds username
- Element tmpEl = summaryRows.first();
- if (tmpEl != null) {
- parsedInformation.add(USERNAME_INDEX, tmpEl.select("td").get(1).text());
- } else {
- //Should never get here!
- //Something is wrong.
- Report.e(PACKAGE_NAME + "." + TAG, "An error occurred while trying to find profile's username.");
- parsedInformation.add(USERNAME_INDEX, null);
- }
- }
-
- { //Finds personal text
- Element tmpEl = profile.select("td.windowbg:nth-child(2)").first();
- if (tmpEl != null) {
- String tmpPersonalText = tmpEl.text().trim();
- parsedInformation.add(PERSONAL_TEXT_INDEX, tmpPersonalText);
- } else {
- //Should never get here!
- //Something is wrong.
- Report.e(PACKAGE_NAME + "." + TAG, "An error occurred while trying to find profile's personal text.");
- parsedInformation.add(PERSONAL_TEXT_INDEX, null);
- }
- }
-
- for (Element row : summaryRows) {
- String rowText = row.text(), pHtml = "";
-
- //Horizontal rule rows
- if (row.select("td").size() == 1)
- pHtml = "";
- else if (rowText.contains("Signature") || rowText.contains("Υπογραφή")) {
- //This needs special handling since it may have css
- { //Fix embedded videos
- Elements noembedTag = row.select("noembed");
- ArrayList embededVideosUrls = new ArrayList<>();
-
- for (Element _noembed : noembedTag) {
- embededVideosUrls.add(_noembed.text().substring(_noembed.text()
- .indexOf("href=\"https://www.youtube.com/watch?") + 38
- , _noembed.text().indexOf("target") - 2));
- }
-
- pHtml = row.html();
-
- int tmp_counter = 0;
- while (pHtml.contains("