From b7718500dfd004116e41bb5932324ad8c698b72c Mon Sep 17 00:00:00 2001 From: Apostolof Date: Mon, 26 Dec 2016 01:41:13 +0200 Subject: [PATCH] More code cleanup and (javadoc style) commenting --- .../activities/profile/ProfileActivity.java | 66 +++++-- .../activities/profile/ProfileParser.java | 82 ++++++-- .../mthmmy/activities/topic/TopicAdapter.java | 3 +- .../mthmmy/activities/topic/TopicParser.java | 183 ++++++++++++------ .../thmmy/mthmmy/utils/CircleTransform.java | 19 +- .../mthmmy/utils/ScrollAwareFABBehavior.java | 4 + 6 files changed, 241 insertions(+), 116 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 8ce5d4fc..00db479d 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 @@ -37,16 +37,19 @@ import mthmmy.utils.Report; import okhttp3.Request; import okhttp3.Response; -import static gr.thmmy.mthmmy.activities.profile.ProfileParser.NAME_INDEX; import static gr.thmmy.mthmmy.activities.profile.ProfileParser.PERSONAL_TEXT_INDEX; -import static gr.thmmy.mthmmy.activities.profile.ProfileParser.THUMBNAIL_URL; -import static gr.thmmy.mthmmy.activities.profile.ProfileParser.parseProfile; +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; import static gr.thmmy.mthmmy.session.SessionManager.LOGIN_STATUS; +/** + * 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}. + */ public class ProfileActivity extends BaseActivity { - - //Graphic elements + //Graphic element variables private ImageView userThumbnail; private TextView userName; private TextView personalText; @@ -55,10 +58,20 @@ public class ProfileActivity extends BaseActivity { private FloatingActionButton replyFAB; //Other variables - private ArrayList parsedProfileData; + /** + * 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"; + /** + * {@link ArrayList} of Strings used to hold profile's information. Data are added in {@link ProfileTask}. + */ + private ArrayList parsedProfileData; private static final int THUMBNAIL_SIZE = 200; @Override @@ -67,10 +80,9 @@ public class ProfileActivity extends BaseActivity { setContentView(R.layout.activity_profile); PACKAGE_NAME = getApplicationContext().getPackageName(); - Bundle extras = getIntent().getExtras(); - //Initialize toolbar, drawer and ProgressBar + //Initialize graphic elements toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle(null); setSupportActionBar(toolbar); @@ -78,9 +90,7 @@ public class ProfileActivity extends BaseActivity { getSupportActionBar().setDisplayShowTitleEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } - createDrawer(); - progressBar = (ProgressBar) findViewById(R.id.progressBar); userThumbnail = (ImageView) findViewById(R.id.user_thumbnail); @@ -136,22 +146,32 @@ public class ProfileActivity extends BaseActivity { } }); - new ProfileTask().execute(extras.getString("PROFILE_URL")); //Attempt data parsing + new ProfileTask().execute(extras.getString(EXTRAS_PROFILE_URL)); //Attempt data parsing } + /** + * 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 ProfileTask's {@link AsyncTask#execute execute} method needs to have 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 - //Show a progress bar until done protected void onPreExecute() { progressBar.setVisibility(ProgressBar.VISIBLE); replyFAB.setEnabled(false); } - protected Boolean doInBackground(String... strings) { + protected Boolean doInBackground(String... profileUrl) { Document document; - String pageUrl = strings[0] + ";wap"; //Profile's page wap url + String pageUrl = profileUrl[0] + ";wap"; //Profile's page wap url Request request = new Request.Builder() .url(pageUrl) @@ -160,7 +180,7 @@ public class ProfileActivity extends BaseActivity { Response response = client.newCall(request).execute(); document = Jsoup.parse(response.body().string()); //long parseStartTime = System.nanoTime(); - parsedProfileData = parseProfile(document); //Parse data + parsedProfileData = parseProfileSummary(document); //long parseEndTime = System.nanoTime(); return true; } catch (SSLHandshakeException e) { @@ -173,22 +193,26 @@ public class ProfileActivity extends BaseActivity { protected void onPostExecute(Boolean result) { if (!result) { //Parse failed! - //Should never happen Toast.makeText(getBaseContext() , "Fatal error!\n Aborting...", Toast.LENGTH_LONG).show(); finish(); } //Parse was successful - progressBar.setVisibility(ProgressBar.INVISIBLE); //Hide progress bar - populateLayout(); //Show parsed data + progressBar.setVisibility(ProgressBar.INVISIBLE); + populateLayout(); } } + /** + * 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}

+ */ private void populateLayout() { - if (parsedProfileData.get(THUMBNAIL_URL) != null) + if (parsedProfileData.get(THUMBNAIL_URL_INDEX) != null) //noinspection ConstantConditions Picasso.with(this) - .load(parsedProfileData.get(THUMBNAIL_URL)) + .load(parsedProfileData.get(THUMBNAIL_URL_INDEX)) .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) .centerCrop() .error(ResourcesCompat.getDrawable(this.getResources() @@ -198,7 +222,7 @@ public class ProfileActivity extends BaseActivity { .transform(new CircleTransform()) .into(userThumbnail); - userName.setText(parsedProfileData.get(NAME_INDEX)); + userName.setText(parsedProfileData.get(USERNAME_INDEX)); if (parsedProfileData.get(PERSONAL_TEXT_INDEX) != null) { personalText.setVisibility(View.VISIBLE); 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 index adffccc8..fab4e120 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileParser.java @@ -9,51 +9,94 @@ 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 { - //Other variables + /** + * Debug Tag for logging debug output to LogCat + */ @SuppressWarnings("unused") private static final String TAG = "ProfileParser"; - static final int THUMBNAIL_URL = 0; - static final int NAME_INDEX = 1; + /** + * 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; - static ArrayList parseProfile(Document doc) { + /** + * 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 returnArray = new ArrayList<>(); + ArrayList parsedInformation = new ArrayList<>(); //Contains all summary's rows - Elements summaryRows = doc.select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) tr"); + Elements summaryRows = profile.select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) tr"); - { //Find thumbnail url - Element tmpEl = doc.select(".bordercolor img.avatar").first(); + { //Finds thumbnail's url + Element tmpEl = profile.select(".bordercolor img.avatar").first(); if (tmpEl != null) - returnArray.add(THUMBNAIL_URL, tmpEl.attr("abs:src")); + parsedInformation.add(THUMBNAIL_URL_INDEX, tmpEl.attr("abs:src")); else //User doesn't have an avatar - returnArray.add(THUMBNAIL_URL, null); + parsedInformation.add(THUMBNAIL_URL_INDEX, null); } - { //Find username + { //Finds username Element tmpEl = summaryRows.first(); if (tmpEl != null) { - returnArray.add(NAME_INDEX, tmpEl.select("td").get(1).text()); + parsedInformation.add(USERNAME_INDEX, tmpEl.select("td").get(1).text()); } else { //Should never get here! //Something is wrong. - Report.e(TAG, "An error occurred while trying to find profile's username."); + Report.e(PACKAGE_NAME + "." + TAG, "An error occurred while trying to find profile's username."); + parsedInformation.add(USERNAME_INDEX, null); } } - { //Find personal text - String tmpPersonalText = doc.select("td.windowbg:nth-child(2)").first().text().trim(); - returnArray.add(PERSONAL_TEXT_INDEX, tmpPersonalText); + { //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<>(); @@ -86,14 +129,15 @@ class ProfileParser { //Add stuff to make it work in WebView //style.css pHtml = ("" + pHtml); - } else if (!rowText.contains("Name") && !rowText.contains("Όνομα")) { + } else if (!rowText.contains("Name") && !rowText.contains("Όνομα")) { //Don't add username twice if (Objects.equals(row.select("td").get(1).text(), "")) continue; + //Style parsed information with html pHtml = "" + row.select("td").first().text() + " " + row.select("td").get(1).text(); } - returnArray.add(pHtml); + parsedInformation.add(pHtml); } - return returnArray; + return parsedInformation; } } 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 7e973ff3..111788bb 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 @@ -42,6 +42,7 @@ import gr.thmmy.mthmmy.utils.CircleTransform; import mthmmy.utils.Report; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.EXTRAS_PROFILE_URL; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.NO_POST_FOCUS; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.base_url; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.downloadFileAsync; @@ -296,7 +297,7 @@ class TopicAdapter extends RecyclerView.Adapter { Intent intent = new Intent(context, ProfileActivity.class); Bundle b = new Bundle(); - b.putString("PROFILE_URL", currentPost.getProfileURL()); //Profile url + b.putString(EXTRAS_PROFILE_URL, currentPost.getProfileURL()); //Profile url intent.putExtras(b); //Put url to next Intent intent.setFlags(FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); 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 7a74acfc..0bae59a5 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 @@ -14,12 +14,27 @@ import java.util.Objects; import gr.thmmy.mthmmy.data.Post; +/** + * Singleton used for parsing a topic. + *

Class contains the methods:

  • {@link #parseUsersViewingThisTopic(Document, String)}
  • + *
  • {@link #parseCurrentPageIndex(Document, String)}
  • + *
  • {@link #parseTopicNumberOfPages(Document, int, String)}
  • + *
  • {@link #parseTopic(Document, String)}
  • + *
  • {@link #defineLanguage(Document)}
  • + *
  • (private) {@link #colorPicker(String)}

+ */ class TopicParser { //Languages supported + /** + * String constant containing one of the supported forum languages + */ private static final String LANGUAGE_GREEK = "Greek"; + /** + * String constant containing one of the supported forum languages + */ private static final String LANGUAGE_ENGLISH = "English"; - //User colors variables + //User colors private static final int USER_COLOR_BLACK = Color.parseColor("#000000"); private static final int USER_COLOR_RED = Color.parseColor("#F44336"); private static final int USER_COLOR_GREEN = Color.parseColor("#4CAF50"); @@ -27,64 +42,91 @@ class TopicParser { private static final int USER_COLOR_PINK = Color.parseColor("#FF4081"); private static final int USER_COLOR_YELLOW = Color.parseColor("#FFEB3B"); + /** + * Debug Tag for logging debug output to LogCat + */ @SuppressWarnings("unused") private static final String TAG = "TopicParser"; - static String parseUsersViewingThisTopic(Document doc, String language) { + /** + * Returns users currently viewing this topic. + * + * @param topic {@link Document} object containing this topic's source code + * @param language a String containing this topic's language set, this is returned by + * {@link #defineLanguage(Document)} + * @return String containing html with the usernames of users + * @see org.jsoup.Jsoup Jsoup + */ + static String parseUsersViewingThisTopic(Document topic, String language) { if (Objects.equals(language, LANGUAGE_GREEK)) - return doc.select("td:containsOwn(διαβάζουν αυτό το θέμα)").first().html(); - return doc.select("td:containsOwn(are viewing this topic)").first().html(); + return topic.select("td:containsOwn(διαβάζουν αυτό το θέμα)").first().html(); + return topic.select("td:containsOwn(are viewing this topic)").first().html(); } - static int parseCurrentPageIndex(Document doc, String language) { - int returnPage = 1; + /** + * Returns current topic's page index. + * + * @param topic {@link Document} object containing this topic's source code + * @param language a String containing this topic's language set, this is returned by + * {@link #defineLanguage(Document)} + * @return int containing parsed topic's current page + * @see org.jsoup.Jsoup Jsoup + */ + static int parseCurrentPageIndex(Document topic, String language) { + int parsedPage = 1; if (Objects.equals(language, LANGUAGE_GREEK)) { - //Contains pages - Elements findCurrentPage = doc.select("td:contains(Σελίδες:)>b"); + Elements findCurrentPage = topic.select("td:contains(Σελίδες:)>b"); for (Element item : findCurrentPage) { - if (!item.text().contains("...") //It's not "..." - && !item.text().contains("Σελίδες:")) { //Nor "Σελίδες:" - returnPage = Integer.parseInt(item.text()); + if (!item.text().contains("...") + && !item.text().contains("Σελίδες:")) { + parsedPage = Integer.parseInt(item.text()); break; } } } else { - Elements findCurrentPage = doc.select("td:contains(Pages:)>b"); + Elements findCurrentPage = topic.select("td:contains(Pages:)>b"); for (Element item : findCurrentPage) { if (!item.text().contains("...") && !item.text().contains("Pages:")) { - returnPage = Integer.parseInt(item.text()); + parsedPage = Integer.parseInt(item.text()); break; } } } - return returnPage; + return parsedPage; } - static int parseTopicNumberOfPages(Document doc, int thisPage, String language) { - //Method's variables + /** + * Returns the number of this topic's pages. + * + * @param topic {@link Document} object containing this topic's source code + * @param currentPage an int containing current page of this topic + * @param language a String containing this topic's language set, this is returned by + * {@link #defineLanguage(Document)} + * @return int containing the number of pages + * @see org.jsoup.Jsoup Jsoup + */ + static int parseTopicNumberOfPages(Document topic, int currentPage, String language) { int returnPages = 1; if (Objects.equals(language, LANGUAGE_GREEK)) { - //Contains all pages - Elements pages = doc.select("td:contains(Σελίδες:)>a.navPages"); + Elements pages = topic.select("td:contains(Σελίδες:)>a.navPages"); if (pages.size() != 0) { - returnPages = thisPage; //Initialize the number - for (Element item : pages) { //Just a max + returnPages = currentPage; + for (Element item : pages) { if (Integer.parseInt(item.text()) > returnPages) returnPages = Integer.parseInt(item.text()); } } } else { - //Contains all pages - Elements pages = doc.select("td:contains(Pages:)>a.navPages"); + Elements pages = topic.select("td:contains(Pages:)>a.navPages"); if (pages.size() != 0) { - returnPages = thisPage; + returnPages = currentPage; for (Element item : pages) { if (Integer.parseInt(item.text()) > returnPages) returnPages = Integer.parseInt(item.text()); @@ -95,20 +137,30 @@ class TopicParser { return returnPages; } - static ArrayList parseTopic(Document doc, String language) { + /** + * This method parses all the information of a topic and it's posts. + * + * @param topic {@link Document} object containing this topic's source code + * @param language a String containing this topic's language set, this is returned by + * {@link #defineLanguage(Document)} + * @return {@link ArrayList} of {@link Post}s + * @see org.jsoup.Jsoup Jsoup + */ + static ArrayList parseTopic(Document topic, String language) { //Method's variables final int NO_INDEX = -1; - ArrayList returnList = new ArrayList<>(); - Elements rows; + ArrayList parsedPostsList = new ArrayList<>(); + Elements postRows; + //Each row is a post if (Objects.equals(language, LANGUAGE_GREEK)) - rows = doc.select("form[id=quickModForm]>table>tbody>tr:matches(στις)"); + postRows = topic.select("form[id=quickModForm]>table>tbody>tr:matches(στις)"); else { - rows = doc.select("form[id=quickModForm]>table>tbody>tr:matches(on)"); + postRows = topic.select("form[id=quickModForm]>table>tbody>tr:matches(on)"); } - for (Element item : rows) { //For every post - //Variables to pass + for (Element item : postRows) { + //Variables for Post constructor String p_userName, p_thumbnailUrl, p_subject, p_post, p_postDate, p_profileURL, p_rank, p_specialRank, p_gender, p_personalText, p_numberOfPosts; int p_postNum, p_postIndex, p_numberOfStars, p_userColor; @@ -127,20 +179,20 @@ class TopicParser { p_attachedFiles = new ArrayList<>(); //Language independent parsing - //Find thumbnail url + //Finds thumbnail url Element thumbnailUrl = item.select("img.avatar").first(); p_thumbnailUrl = null; //In case user doesn't have an avatar if (thumbnailUrl != null) { p_thumbnailUrl = thumbnailUrl.attr("abs:src"); } - //Find subject + //Finds subject p_subject = item.select("div[id^=subject_]").first().select("a").first().text(); - //Find post's text + //Finds post's text p_post = item.select("div").select(".post").first().outerHtml(); - { //Fix embedded videos + { //Fixes embedded videos Elements noembedTag = item.select("div").select(".post").first().select("noembed"); ArrayList embededVideosUrls = new ArrayList<>(); @@ -172,6 +224,8 @@ class TopicParser { p_post = ("" + p_post); //Find post's index + //This is an int assigned by the forum used for post focusing and quotes, it is not + //the same as reply index. Element postIndex = item.select("a[name^=msg]").first(); if (postIndex == null) p_postIndex = NO_INDEX; @@ -183,7 +237,7 @@ class TopicParser { //Language dependent parsing Element userName; if (Objects.equals(language, LANGUAGE_GREEK)) { - //Find username + //Finds username and profile's url userName = item.select("a[title^=Εμφάνιση προφίλ του μέλους]").first(); if (userName == null) { //Deleted profile p_isDeleted = true; @@ -197,13 +251,13 @@ class TopicParser { p_profileURL = userName.attr("href"); } - //Find post's submit date + //Finds post's submit date Element postDate = item.select("div.smalltext:matches(στις:)").first(); p_postDate = postDate.text(); p_postDate = p_postDate.substring(p_postDate.indexOf("στις:") + 6 , p_postDate.indexOf(" »")); - //Find post's number + //Finds post's reply index number Element postNum = item.select("div.smalltext:matches(Απάντηση #)").first(); if (postNum == null) { //Topic starter p_postNum = 0; @@ -213,7 +267,7 @@ class TopicParser { } - //Find attached file's urls, names and info, if present + //Finds attached file's urls, names and info, if present Elements postAttachments = item.select("div:containsOwn(έγινε λήψη):containsOwn(φορές.)"); if (postAttachments != null) { Elements attachedFiles = postAttachments.select("a"); @@ -222,12 +276,12 @@ class TopicParser { for (int i = 0; i < attachedFiles.size(); ++i) { String[] attachedArray = new String[3]; - //Get file's url and filename + //Gets file's url and filename Element tmpAttachedFileUrlAndName = attachedFiles.get(i); attachedArray[0] = tmpAttachedFileUrlAndName.attr("href"); attachedArray[1] = tmpAttachedFileUrlAndName.text().substring(1); - //Get file's info (size and download count) + //Gets file's info (size and download count) String postAttachmentsTextSbstr = postAttachmentsText.substring( postAttachmentsText.indexOf(attachedArray[1])); @@ -238,7 +292,7 @@ class TopicParser { } } } else { - //Find username + //Finds username userName = item.select("a[title^=View the profile of]").first(); if (userName == null) { //Deleted profile p_isDeleted = true; @@ -252,13 +306,13 @@ class TopicParser { p_profileURL = userName.attr("href"); } - //Find post's submit date + //Finds post's submit date Element postDate = item.select("div.smalltext:matches(on:)").first(); p_postDate = postDate.text(); p_postDate = p_postDate.substring(p_postDate.indexOf("on:") + 4 , p_postDate.indexOf(" »")); - //Find post's number + //Finds post's reply index number Element postNum = item.select("div.smalltext:matches(Reply #)").first(); if (postNum == null) { //Topic starter p_postNum = 0; @@ -268,7 +322,7 @@ class TopicParser { } - //Find attached file's urls, names and info, if present + //Finds attached file's urls, names and info, if present Elements postAttachments = item.select("div:containsOwn(downloaded):containsOwn(times.)"); if (postAttachments != null) { Elements attachedFiles = postAttachments.select("a"); @@ -277,12 +331,12 @@ class TopicParser { for (int i = 0; i < attachedFiles.size(); ++i) { String[] attachedArray = new String[3]; - //Get file's url and filename + //Gets file's url and filename Element tmpAttachedFileUrlAndName = attachedFiles.get(i); attachedArray[0] = tmpAttachedFileUrlAndName.attr("href"); attachedArray[1] = tmpAttachedFileUrlAndName.text().substring(1); - //Get file's info (size and download count) + //Gets file's info (size and download count) String postAttachmentsTextSbstr = postAttachmentsText.substring( postAttachmentsText.indexOf(attachedArray[1])); @@ -295,12 +349,12 @@ class TopicParser { } if (!p_isDeleted) { //Active user - //Get extra info + //Gets extra info int postsLineIndex = -1; int starsLineIndex = -1; - Element info = userName.parent().nextElementSibling(); //Get sibling "div" - List infoList = Arrays.asList(info.html().split("
")); + Element usersExtraInfo = userName.parent().nextElementSibling(); //Get sibling "div" + List infoList = Arrays.asList(usersExtraInfo.html().split("
")); if (Objects.equals(language, LANGUAGE_GREEK)) { for (String line : infoList) { @@ -349,7 +403,6 @@ class TopicParser { //If this member has no stars yet ==> New member, //or is just a member if (starsLineIndex == -1 || starsLineIndex == 1) { - //In this case: p_rank = infoList.get(0).trim(); //First line has the rank p_specialRank = null; //They don't have a special rank } else if (starsLineIndex == 2) { //This member has a special rank @@ -357,43 +410,53 @@ class TopicParser { p_rank = infoList.get(1).trim(); //Second line has the rank } for (int i = postsLineIndex + 1; i < infoList.size() - 1; ++i) { - //Search under "Posts:" + //Searches under "Posts:" //and above "Personal Message", "View Profile" etc buttons - String thisLine = infoList.get(i); - //If this line isn't empty and doesn't contain user's avatar if (!Objects.equals(thisLine, "") && thisLine != null && !Objects.equals(thisLine, " \n") && !thisLine.contains("avatar") && !thisLine.contains("Forum supports:
  • {@link #LANGUAGE_ENGLISH}
  • + *
  • {@link #LANGUAGE_GREEK}

+ * @param topic {@link Document} object containing this topic's source code + * @return String containing the language of a topic + * @see org.jsoup.Jsoup Jsoup + */ + static String defineLanguage(Document topic) { + if (topic.select("h3").text().contains("Καλώς ορίσατε")) { return LANGUAGE_GREEK; } else { //Default is english (eg. guest's language) return LANGUAGE_ENGLISH; } } + /** + * Returns the color of a user according to user's rank on forum. + * @param starsUrl String containing the URL of a user's stars + * @return an int corresponding to the right color + */ private static int colorPicker(String starsUrl) { if (starsUrl.contains("/star.gif")) return USER_COLOR_YELLOW; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java b/app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java index 874e07d4..2294b83e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java @@ -1,19 +1,4 @@ package gr.thmmy.mthmmy.utils; -/* - * Copyright 2014 Julian Shen - * - * 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. - */ import android.graphics.Bitmap; import android.graphics.BitmapShader; @@ -22,6 +7,10 @@ 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) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java index e910ecbd..45e40871 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java @@ -7,6 +7,10 @@ import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.View; +/** + * Extends FloatingActionButton's behavior so the button will hide when scrolling down and show + * otherwise. + */ public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior { public ScrollAwareFABBehavior(Context context, AttributeSet attrs) { super();