Browse Source

Color change and functionality of links at topic's extra info dialog. Post's last edit date, profile action to only the thumbnail. Ability to install to external memory.

pull/24/head
Apostolos Fanakis 8 years ago
parent
commit
cc9c1e85ac
  1. 3
      app/src/main/AndroidManifest.xml
  2. 37
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  3. 104
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  4. 15
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
  5. 20
      app/src/main/java/gr/thmmy/mthmmy/model/Post.java
  6. 3
      app/src/main/res/values/colors.xml

3
app/src/main/AndroidManifest.xml

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="gr.thmmy.mthmmy"> package="gr.thmmy.mthmmy"
android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

37
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java

@ -1,5 +1,6 @@
package gr.thmmy.mthmmy.activities.topic; package gr.thmmy.mthmmy.activities.topic;
import android.content.Intent;
import android.graphics.Rect; import android.graphics.Rect;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
@ -11,7 +12,6 @@ import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.text.Html; import android.text.Html;
import android.text.SpannableString;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.text.method.ScrollingMovementMethod; import android.text.method.ScrollingMovementMethod;
@ -39,6 +39,8 @@ import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import gr.thmmy.mthmmy.R; 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.BaseActivity;
import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Bookmark;
import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.Post;
@ -51,6 +53,12 @@ import okhttp3.Request;
import okhttp3.RequestBody; import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.ReplyParser.replyStatus; import static gr.thmmy.mthmmy.activities.topic.ReplyParser.replyStatus;
/** /**
@ -621,14 +629,33 @@ public class TopicActivity extends BaseActivity {
postsList.addAll(TopicParser.parseTopic(topic, language)); postsList.addAll(TopicParser.parseTopic(topic, language));
} }
private void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span) private void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span) {
{
int start = strBuilder.getSpanStart(span); int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span); int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span); int flags = strBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() { ClickableSpan clickable = new ClickableSpan() {
@Override
public void onClick(View view) { public void onClick(View view) {
//TODO ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(span.getURL()));
if (target.is(ThmmyPage.PageCategory.BOARD)) {
Intent intent = new Intent(getApplicationContext(), BoardActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_BOARD_URL, span.getURL());
extras.putString(BUNDLE_BOARD_TITLE, "");
intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
} else if (target.is(ThmmyPage.PageCategory.PROFILE)) {
Intent intent = new Intent(getApplicationContext(), ProfileActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, span.getURL());
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
extras.putString(BUNDLE_PROFILE_USERNAME, "");
intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
} else if (target.is(ThmmyPage.PageCategory.INDEX))
finish();
} }
}; };
strBuilder.setSpan(clickable, start, end, flags); strBuilder.setSpan(clickable, start, end, flags);
@ -639,7 +666,7 @@ public class TopicActivity extends BaseActivity {
CharSequence sequence = Html.fromHtml(html); CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence); SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class); URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for(URLSpan span : urls) { for (URLSpan span : urls) {
makeLinkClickable(strBuilder, span); makeLinkClickable(strBuilder, span);
} }
return strBuilder; return strBuilder;

104
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java

@ -18,6 +18,7 @@ import android.support.v7.widget.RecyclerView;
import android.text.Editable; import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
@ -198,34 +199,52 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.postNum.setText(""); holder.postNum.setText("");
holder.subject.setText(currentPost.getSubject()); holder.subject.setText(currentPost.getSubject());
holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null); holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null);
if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { if ((currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0)
|| (currentPost.getLastEdit() != null)) {
holder.bodyFooterDivider.setVisibility(View.VISIBLE); holder.bodyFooterDivider.setVisibility(View.VISIBLE);
int filesTextColor;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
filesTextColor = context.getResources().getColor(R.color.accent, null);
} else //noinspection deprecation
filesTextColor = context.getResources().getColor(R.color.accent);
holder.postFooter.removeAllViews(); holder.postFooter.removeAllViews();
for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) {
final TextView attached = new TextView(context);
attached.setTextSize(10f);
attached.setClickable(true);
attached.setTypeface(Typeface.createFromAsset(context.getAssets()
, "fonts/fontawesome-webfont.ttf"));
attached.setText(faIconFromFilename(attachedFile.getFilename()) + " "
+ attachedFile.getFilename() + attachedFile.getFileInfo());
attached.setTextColor(filesTextColor);
attached.setPadding(0, 3, 0, 3);
attached.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
((BaseActivity) context).launchDownloadService(attachedFile);
}
});
holder.postFooter.addView(attached); if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) {
int filesTextColor;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
filesTextColor = context.getResources().getColor(R.color.accent, null);
} else //noinspection deprecation
filesTextColor = context.getResources().getColor(R.color.accent);
for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) {
final TextView attached = new TextView(context);
attached.setTextSize(10f);
attached.setClickable(true);
attached.setTypeface(Typeface.createFromAsset(context.getAssets()
, "fonts/fontawesome-webfont.ttf"));
attached.setText(faIconFromFilename(attachedFile.getFilename()) + " "
+ attachedFile.getFilename() + attachedFile.getFileInfo());
attached.setTextColor(filesTextColor);
attached.setPadding(0, 3, 0, 3);
attached.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
((BaseActivity) context).launchDownloadService(attachedFile);
}
});
holder.postFooter.addView(attached);
}
}
if (currentPost.getLastEdit() != null && currentPost.getLastEdit().length() > 0) {
int lastEditTextColor;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
lastEditTextColor = context.getResources().getColor(R.color.white, null);
} else //noinspection deprecation
lastEditTextColor = context.getResources().getColor(R.color.white);
final TextView lastEdit = new TextView(context);
lastEdit.setTextSize(12f);
lastEdit.setText(currentPost.getLastEdit());
lastEdit.setTextColor(lastEditTextColor);
lastEdit.setPadding(0, 3, 0, 3);
holder.postFooter.addView(lastEdit);
} }
} else { } else {
holder.bodyFooterDivider.setVisibility(View.GONE); holder.bodyFooterDivider.setVisibility(View.GONE);
@ -312,24 +331,27 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
} }
if (!currentPost.isDeleted()) { if (!currentPost.isDeleted()) {
//Sets graphics behavior //Sets graphics behavior
holder.thumbnail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Clicking the thumbnail opens user's profile
Intent intent = new Intent(context, ProfileActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, currentPost.getProfileURL());
if (currentPost.getThumbnailUrl() == null)
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
else
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, currentPost.getThumbnailUrl());
extras.putString(BUNDLE_PROFILE_USERNAME, currentPost.getAuthor());
intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
holder.header.setOnClickListener(new View.OnClickListener() { holder.header.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
//Clicking an expanded header starts profile activity //Clicking the header makes it expand/collapse
if (viewProperties.get(holder.getAdapterPosition())[isUserExtraInfoVisibile]) {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, currentPost.getProfileURL());
if (currentPost.getThumbnailUrl() == null)
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
else
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, currentPost.getThumbnailUrl());
extras.putString(BUNDLE_PROFILE_USERNAME, currentPost.getAuthor());
intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); boolean[] tmp = viewProperties.get(holder.getAdapterPosition());
tmp[isUserExtraInfoVisibile] = !tmp[isUserExtraInfoVisibile]; tmp[isUserExtraInfoVisibile] = !tmp[isUserExtraInfoVisibile];
viewProperties.set(holder.getAdapterPosition(), tmp); viewProperties.set(holder.getAdapterPosition(), tmp);
@ -341,7 +363,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); boolean[] tmp = viewProperties.get(holder.getAdapterPosition());
tmp[1] = false; tmp[isUserExtraInfoVisibile] = false;
viewProperties.set(holder.getAdapterPosition(), tmp); viewProperties.set(holder.getAdapterPosition(), tmp);
TopicAnimations.animateUserExtraInfoVisibility(v); TopicAnimations.animateUserExtraInfoVisibility(v);

15
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java

@ -160,7 +160,7 @@ class TopicParser {
for (Element thisRow : postRows) { for (Element thisRow : postRows) {
//Variables for Post constructor //Variables for Post constructor
String p_userName, p_thumbnailUrl, p_subject, p_post, p_postDate, p_profileURL, p_rank, String p_userName, p_thumbnailUrl, p_subject, p_post, p_postDate, p_profileURL, p_rank,
p_specialRank, p_gender, p_personalText, p_numberOfPosts; p_specialRank, p_gender, p_personalText, p_numberOfPosts, p_postLastEditDate;
int p_postNum, p_postIndex, p_numberOfStars, p_userColor; int p_postNum, p_postIndex, p_numberOfStars, p_userColor;
boolean p_isDeleted = false; boolean p_isDeleted = false;
ArrayList<ThmmyFile> p_attachedFiles; ArrayList<ThmmyFile> p_attachedFiles;
@ -175,6 +175,7 @@ class TopicParser {
p_numberOfStars = 0; p_numberOfStars = 0;
p_userColor = USER_COLOR_YELLOW; p_userColor = USER_COLOR_YELLOW;
p_attachedFiles = new ArrayList<>(); p_attachedFiles = new ArrayList<>();
p_postLastEditDate = null;
//Language independent parsing //Language independent parsing
//Finds thumbnail url //Finds thumbnail url
@ -190,11 +191,11 @@ class TopicParser {
//Finds post's text //Finds post's text
p_post = ParseHelpers.youtubeEmbeddedFix(thisRow.select("div").select(".post").first()); p_post = ParseHelpers.youtubeEmbeddedFix(thisRow.select("div").select(".post").first());
//Add stuff to make it work in WebView //Adds stuff to make it work in WebView
//style.css //style.css
p_post = ("<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />" + p_post); p_post = ("<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />" + p_post);
//Find post's index //Finds post's index
//This is an int assigned by the forum used for post focusing and quotes, it is not //This is an int assigned by the forum used for post focusing and quotes, it is not
//the same as reply index. //the same as reply index.
Element postIndex = thisRow.select("a[name^=msg]").first(); Element postIndex = thisRow.select("a[name^=msg]").first();
@ -205,6 +206,10 @@ class TopicParser {
p_postIndex = Integer.parseInt(tmp.substring(tmp.indexOf("msg") + 3)); p_postIndex = Integer.parseInt(tmp.substring(tmp.indexOf("msg") + 3));
} }
Element postLastEditDate = thisRow.select("td.smalltext[id^=modified_]").first();
if (postLastEditDate != null && !Objects.equals(postLastEditDate.text(), ""))
p_postLastEditDate = postLastEditDate.text();
//Language dependent parsing //Language dependent parsing
Element userName; Element userName;
if (language.is(ParseHelpers.Language.GREEK)) { if (language.is(ParseHelpers.Language.GREEK)) {
@ -406,12 +411,12 @@ class TopicParser {
parsedPostsList.add(new Post(p_thumbnailUrl, p_userName, p_subject, p_post, p_postIndex parsedPostsList.add(new Post(p_thumbnailUrl, p_userName, p_subject, p_post, p_postIndex
, p_postNum, p_postDate, p_profileURL, p_rank, p_specialRank, p_gender , p_postNum, p_postDate, p_profileURL, p_rank, p_specialRank, p_gender
, p_numberOfPosts, p_personalText, p_numberOfStars, p_userColor , p_numberOfPosts, p_personalText, p_numberOfStars, p_userColor
, p_attachedFiles)); , p_attachedFiles, p_postLastEditDate));
} else { //Deleted user } else { //Deleted user
//Add new post in postsList, only standard information needed //Add new post in postsList, only standard information needed
parsedPostsList.add(new Post(p_thumbnailUrl, p_userName, p_subject, p_post, p_postIndex parsedPostsList.add(new Post(p_thumbnailUrl, p_userName, p_subject, p_post, p_postIndex
, p_postNum, p_postDate, p_userColor, p_attachedFiles)); , p_postNum, p_postDate, p_userColor, p_attachedFiles, p_postLastEditDate));
} }
} }
return parsedPostsList; return parsedPostsList;

20
app/src/main/java/gr/thmmy/mthmmy/model/Post.java

@ -27,6 +27,7 @@ public class Post {
private final boolean isDeleted; private final boolean isDeleted;
private final int userColor; private final int userColor;
private final ArrayList<ThmmyFile> attachedFiles; private final ArrayList<ThmmyFile> attachedFiles;
private final String lastEdit;
//Extra info //Extra info
private final String profileURL; private final String profileURL;
@ -57,6 +58,7 @@ public class Post {
personalText = ""; personalText = "";
numberOfStars = 0; numberOfStars = 0;
attachedFiles = null; attachedFiles = null;
lastEdit = null;
} }
/** /**
@ -80,12 +82,13 @@ public class Post {
* @param numberOfStars author's number of stars * @param numberOfStars author's number of stars
* @param userColor author's user color * @param userColor author's user color
* @param attachedFiles post's attached files * @param attachedFiles post's attached files
* @param lastEdit post's last edit date
*/ */
public Post(@Nullable String thumbnailUrl, String author, String subject, String content public Post(@Nullable String thumbnailUrl, String author, String subject, String content
, int postIndex, int postNumber, String postDate, String profileURl, @Nullable String rank , int postIndex, int postNumber, String postDate, String profileURl, @Nullable String rank
, @Nullable String special_rank, @Nullable String gender, @Nullable String numberOfPosts , @Nullable String special_rank, @Nullable String gender, @Nullable String numberOfPosts
, @Nullable String personalText, int numberOfStars, int userColor , @Nullable String personalText, int numberOfStars, int userColor
, @Nullable ArrayList<ThmmyFile> attachedFiles) { , @Nullable ArrayList<ThmmyFile> attachedFiles, @Nullable String lastEdit) {
if (Objects.equals(thumbnailUrl, "")) this.thumbnailUrl = null; if (Objects.equals(thumbnailUrl, "")) this.thumbnailUrl = null;
else this.thumbnailUrl = thumbnailUrl; else this.thumbnailUrl = thumbnailUrl;
this.author = author; this.author = author;
@ -97,6 +100,7 @@ public class Post {
this.isDeleted = false; this.isDeleted = false;
this.userColor = userColor; this.userColor = userColor;
this.attachedFiles = attachedFiles; this.attachedFiles = attachedFiles;
this.lastEdit = lastEdit;
this.profileURL = profileURl; this.profileURL = profileURl;
this.rank = rank; this.rank = rank;
this.specialRank = special_rank; this.specialRank = special_rank;
@ -120,10 +124,11 @@ public class Post {
* @param postDate date of submission * @param postDate date of submission
* @param userColor author's user color * @param userColor author's user color
* @param attachedFiles post's attached files * @param attachedFiles post's attached files
* @param lastEdit post's last edit date
*/ */
public Post(@Nullable String thumbnailUrl, String author, String subject, String content public Post(@Nullable String thumbnailUrl, String author, String subject, String content
, int postIndex, int postNumber, String postDate, int userColor , int postIndex, int postNumber, String postDate, int userColor
, @Nullable ArrayList<ThmmyFile> attachedFiles) { , @Nullable ArrayList<ThmmyFile> attachedFiles, @Nullable String lastEdit) {
if (Objects.equals(thumbnailUrl, "")) this.thumbnailUrl = null; if (Objects.equals(thumbnailUrl, "")) this.thumbnailUrl = null;
else this.thumbnailUrl = thumbnailUrl; else this.thumbnailUrl = thumbnailUrl;
this.author = author; this.author = author;
@ -135,6 +140,7 @@ public class Post {
this.isDeleted = true; this.isDeleted = true;
this.userColor = userColor; this.userColor = userColor;
this.attachedFiles = attachedFiles; this.attachedFiles = attachedFiles;
this.lastEdit = lastEdit;
profileURL = null; profileURL = null;
rank = "Rank"; rank = "Rank";
specialRank = "Special rank"; specialRank = "Special rank";
@ -310,4 +316,14 @@ public class Post {
public ArrayList<ThmmyFile> getAttachedFiles() { public ArrayList<ThmmyFile> getAttachedFiles() {
return attachedFiles; return attachedFiles;
} }
/**
* Gets this post's last edit date or null if post hasn't been edited.
*
* @return date of last edit or null
*/
@Nullable
public String getLastEdit() {
return lastEdit;
}
} }

3
app/src/main/res/values/colors.xml

@ -16,7 +16,8 @@
<color name="background">#323232</color> <color name="background">#323232</color>
<color name="card_background">#3C3F41</color> <color name="card_background">#3C3F41</color>
<color name="divider">#8B8B8B</color> <color name="divider">#8B8B8B</color>
<color name="link_color">#4B0082</color> <!--<color name="link_color">#FFC107</color>-->
<color name="link_color">#FF9800</color>
<color name="white">#FFFFFF</color> <color name="white">#FFFFFF</color>
<color name="iron">#CCCCCC</color> <color name="iron">#CCCCCC</color>

Loading…
Cancel
Save