Browse Source

Changed topic activity's NestedScrollView to RecyclerView. Embedded videos fixes.

pull/24/head
Apostolos Fanakis 8 years ago
parent
commit
03c78f49cb
  1. 455
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  2. 421
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  3. 11
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
  4. 0
      app/src/main/res/drawable/progress_bar_bg.xml
  5. 2
      app/src/main/res/layout/activity_login.xml
  6. 17
      app/src/main/res/layout/activity_topic.xml
  7. 1
      app/src/main/res/layout/activity_topic_post_row.xml

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

@ -1,41 +1,27 @@
package gr.thmmy.mthmmy.activities.topic; package gr.thmmy.mthmmy.activities.topic;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityOptionsCompat; import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.Pair; import android.support.v4.util.Pair;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.CardView; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.android.volley.toolbox.ImageLoader;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
@ -49,7 +35,6 @@ import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.BaseActivity; import gr.thmmy.mthmmy.activities.BaseActivity;
import gr.thmmy.mthmmy.activities.LoginActivity; import gr.thmmy.mthmmy.activities.LoginActivity;
import gr.thmmy.mthmmy.data.Post; import gr.thmmy.mthmmy.data.Post;
import gr.thmmy.mthmmy.utils.CircularNetworkImageView;
import gr.thmmy.mthmmy.utils.ImageController; import gr.thmmy.mthmmy.utils.ImageController;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
@ -64,14 +49,13 @@ public class TopicActivity extends BaseActivity {
/* --Posts-- */ /* --Posts-- */
private List<Post> postsList; private List<Post> postsList;
private LinearLayout postsLinearLayout;
private static final int NO_POST_FOCUS = -1; private static final int NO_POST_FOCUS = -1;
private int postFocus = NO_POST_FOCUS; private int postFocus = NO_POST_FOCUS;
//Quote //Quote
private final ArrayList<Integer> toQuoteList = new ArrayList<>(); public static final ArrayList<Integer> toQuoteList = new ArrayList<>();
/* --Topic's pages-- */ /* --Topic's pages-- */
private int thisPage = 1; private int thisPage = 1;
private String base_url = ""; public static String base_url = "";
private int numberOfPages = 1; private int numberOfPages = 1;
private final SparseArray<String> pagesUrls = new SparseArray<>(); private final SparseArray<String> pagesUrls = new SparseArray<>();
//Page select //Page select
@ -83,21 +67,18 @@ public class TopicActivity extends BaseActivity {
private static final int SMALL_STEP = 1; private static final int SMALL_STEP = 1;
private static final int LARGE_STEP = 10; private static final int LARGE_STEP = 10;
private Integer pageRequestValue; private Integer pageRequestValue;
private ImageButton firstPage;
private ImageButton previousPage;
private ImageButton nextPage;
private ImageButton lastPage;
/* --Thumbnail-- */ ImageButton firstPage;
private static final int THUMBNAIL_SIZE = 80; ImageButton previousPage;
private ImageLoader imageLoader = ImageController.getInstance().getImageLoader(); ImageButton nextPage;
ImageButton lastPage;
//Other variables //Other variables
private ProgressBar progressBar; private ProgressBar progressBar;
private static final String TAG = "TopicActivity"; private static final String TAG = "TopicActivity";
private String topicTitle; private String topicTitle;
private String parsedTitle;
private FloatingActionButton replyFAB; private FloatingActionButton replyFAB;
private String parsedTitle;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -107,7 +88,7 @@ public class TopicActivity extends BaseActivity {
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
topicTitle = getIntent().getExtras().getString("TOPIC_TITLE"); topicTitle = getIntent().getExtras().getString("TOPIC_TITLE");
//Initialize toolbar //Initialize toolbar, drawer and ProgressBar
toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(topicTitle); toolbar.setTitle(topicTitle);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
@ -116,14 +97,8 @@ public class TopicActivity extends BaseActivity {
createDrawer(); createDrawer();
//Variables initialization
postsLinearLayout = (LinearLayout) findViewById(R.id.posts_list);
progressBar = (ProgressBar) findViewById(R.id.progressBar); progressBar = (ProgressBar) findViewById(R.id.progressBar);
if (imageLoader == null)
imageLoader = ImageController.getInstance().getImageLoader();
postsList = new ArrayList<>(); postsList = new ArrayList<>();
@ -137,6 +112,7 @@ public class TopicActivity extends BaseActivity {
initDecrementButton(previousPage, SMALL_STEP); initDecrementButton(previousPage, SMALL_STEP);
initIncrementButton(nextPage, SMALL_STEP); initIncrementButton(nextPage, SMALL_STEP);
initIncrementButton(lastPage, LARGE_STEP); initIncrementButton(lastPage, LARGE_STEP);
firstPage.setEnabled(false); firstPage.setEnabled(false);
previousPage.setEnabled(false); previousPage.setEnabled(false);
nextPage.setEnabled(false); nextPage.setEnabled(false);
@ -215,7 +191,7 @@ public class TopicActivity extends BaseActivity {
} }
//--------------------------------------BOTTOM NAV BAR METHODS-------------------------------------- //--------------------------------------BOTTOM NAV BAR METHODS--------------------------------------
private void initIncrementButton(ImageButton increment, final int step) { private void initIncrementButton(ImageButton increment, final int step) {
// Increment once for a click // Increment once for a click
increment.setOnClickListener(new View.OnClickListener() { increment.setOnClickListener(new View.OnClickListener() {
@ -318,8 +294,8 @@ public class TopicActivity extends BaseActivity {
private void changePage(int pageRequested) { private void changePage(int pageRequested) {
if (pageRequested != thisPage - 1) { if (pageRequested != thisPage - 1) {
//Restart activity with new page //Restart activity with new page
Pair<View, String> p1 = Pair.create((View)replyFAB, "fab"); Pair<View, String> p1 = Pair.create((View) replyFAB, "fab");
Pair<View, String> p2 = Pair.create((View)toolbar, "toolbar"); Pair<View, String> p2 = Pair.create((View) toolbar, "toolbar");
ActivityOptionsCompat options = ActivityOptionsCompat. ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(this, p1, p2); makeSceneTransitionAnimation(this, p1, p2);
@ -332,7 +308,7 @@ public class TopicActivity extends BaseActivity {
} }
//------------------------------------BOTTOM NAV BAR METHODS END------------------------------------ //------------------------------------BOTTOM NAV BAR METHODS END------------------------------------
//---------------------------------------TOPIC ASYNC TASK------------------------------------------- //---------------------------------------TOPIC ASYNC TASK-------------------------------------------
public class TopicTask extends AsyncTask<String, Void, Boolean> { public class TopicTask extends AsyncTask<String, Void, Boolean> {
//Class variables //Class variables
private static final String TAG = "TopicTask"; //Separate tag for AsyncTask private static final String TAG = "TopicTask"; //Separate tag for AsyncTask
@ -389,6 +365,14 @@ public class TopicActivity extends BaseActivity {
pageRequestValue = thisPage; pageRequestValue = thisPage;
if (numberOfPages >= 1000) if (numberOfPages >= 1000)
pageIndicator.setTextSize(16); pageIndicator.setTextSize(16);
firstPage.setEnabled(true);
previousPage.setEnabled(true);
nextPage.setEnabled(true);
lastPage.setEnabled(true);
if (topicTitle == null || Objects.equals(topicTitle, ""))
toolbar.setTitle(parsedTitle);
} }
/* Parse method */ /* Parse method */
@ -396,11 +380,10 @@ public class TopicActivity extends BaseActivity {
//Find topic title if missing //Find topic title if missing
if (topicTitle == null || Objects.equals(topicTitle, "")) { if (topicTitle == null || Objects.equals(topicTitle, "")) {
parsedTitle = document.select("td[id=top_subject]").first().text(); parsedTitle = document.select("td[id=top_subject]").first().text();
if(parsedTitle.contains("Topic:")) { if (parsedTitle.contains("Topic:")) {
parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Topic:") + 7 parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Topic:") + 7
, parsedTitle.indexOf("(Read") - 2); , parsedTitle.indexOf("(Read") - 2);
} } else {
else{
parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Θέμα:") + 6 parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Θέμα:") + 6
, parsedTitle.indexOf("(Αναγνώστηκε") - 2); , parsedTitle.indexOf("(Αναγνώστηκε") - 2);
Log.d(TAG, parsedTitle); Log.d(TAG, parsedTitle);
@ -432,298 +415,26 @@ public class TopicActivity extends BaseActivity {
* adds a card for each post to the ScrollView. * adds a card for each post to the ScrollView.
*/ */
private void populateLayout() { private void populateLayout() {
//Enable reply button RecyclerView recyclerView = (RecyclerView)findViewById(R.id.topic_recycler_view);
replyFAB.setEnabled(true); recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
//Set topic title if not already present recyclerView.setLayoutManager(layoutManager);
if (topicTitle == null || Objects.equals(topicTitle, "")) {
topicTitle = parsedTitle; TopicAdapter adapter = new TopicAdapter(getApplicationContext(), postsList);
if (toolbar != null) { recyclerView.setAdapter(adapter);
toolbar.setTitle(topicTitle);
} //Set post focus
} if (postFocus != NO_POST_FOCUS) {
for (int i = 0; i < postsList.size(); ++i) {
//Now that parsing is complete and we have the url for every page enable page nav buttons Post currentPost = postsList.get(i);
firstPage.setEnabled(true);
previousPage.setEnabled(true);
nextPage.setEnabled(true);
lastPage.setEnabled(true);
//Initialize an inflater
LayoutInflater inflater = (LayoutInflater) getApplicationContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//Create a card for each post
for (final Post currentPost : postsList) {
//Inflate a topic post row layout
View convertView = inflater.inflate(R.layout.activity_topic_post_row
, postsLinearLayout, false);
//Get an ImageLoader instance
if (imageLoader == null)
imageLoader = ImageController.getInstance().getImageLoader();
//Initialize layout's graphic elements
//Basic stuff
final CardView cardView = (CardView) convertView.findViewById(R.id.card_view);
final FrameLayout postDateAndNumberExp = (FrameLayout) convertView.findViewById(R.id.post_date_and_number_exp);
TextView postDate = (TextView) convertView.findViewById(R.id.post_date);
TextView postNum = (TextView) convertView.findViewById(R.id.post_number);
CircularNetworkImageView thumbnail = (CircularNetworkImageView) convertView.findViewById(R.id.thumbnail);
final TextView username = (TextView) convertView.findViewById(R.id.username);
final TextView subject = (TextView) convertView.findViewById(R.id.subject);
final WebView post = (WebView) convertView.findViewById(R.id.post);
final ImageButton quoteToggle = (ImageButton) convertView.findViewById(R.id.toggle_quote_button);
//User's extra
RelativeLayout header = (RelativeLayout) convertView.findViewById(R.id.header);
final LinearLayout userExtraInfo = (LinearLayout) convertView.findViewById(R.id.user_extra_info);
//Post's WebView parameters set
post.setClickable(true);
post.setWebViewClient(new LinkLauncher());
post.getSettings().setJavaScriptEnabled(true);
//TODO
post.getSettings().setPluginState(WebSettings.PluginState.ON_DEMAND);
//Avoiding errors about layout having 0 width/height
thumbnail.setMinimumWidth(1);
thumbnail.setMinimumHeight(1);
//Set thumbnail size
thumbnail.setMaxWidth(THUMBNAIL_SIZE);
thumbnail.setMaxHeight(THUMBNAIL_SIZE);
//Thumbnail image set
if (currentPost.getThumbnailUrl() != null
&& !Objects.equals(currentPost.getThumbnailUrl(), "")) {
thumbnail.setImageUrl(currentPost.getThumbnailUrl(), imageLoader);
}
//Username set
username.setText(currentPost.getAuthor());
//Post's submit date set
postDate.setText(currentPost.getPostDate());
//Post's index number set
if (currentPost.getPostNumber() != 0)
postNum.setText(getString(R.string.user_number_of_posts, currentPost.getPostNumber()));
//postNum.setText("#" + currentPost.getPostNumber());
else
postNum.setText("");
//Post's subject set
subject.setText(currentPost.getSubject());
//Post's text set
post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null);
quoteToggle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (view.isSelected()) {
if (toQuoteList.contains(currentPost.getPostNumber())) {
toQuoteList.remove(toQuoteList.indexOf(currentPost.getPostNumber()));
view.setSelected(false);
} else
Log.i(TAG, "An error occurred while trying to exclude post from" +
"toQuoteList, post wasn't there!");
} else {
toQuoteList.add(currentPost.getPostNumber());
view.setSelected(true);
}
}
});
//If user is not deleted then we have more to do
if (!currentPost.isDeleted()) { //Set extra info
//Variables for Graphics
TextView g_specialRank, g_rank, g_gender, g_numberOfPosts, g_personalText;
LinearLayout g_stars_holder = (LinearLayout) convertView.findViewById(R.id.stars);
//Variables for content
String c_specialRank = currentPost.getSpecialRank(), c_rank = currentPost.getRank(), c_gender = currentPost.getGender(), c_numberOfPosts = currentPost.getNumberOfPosts(), c_personalText = currentPost.getPersonalText(), c_urlOfStars = currentPost.getUrlOfStars();
int c_numberOfStars = currentPost.getNumberOfStars();
if (!Objects.equals(c_specialRank, "") && c_specialRank != null) {
g_specialRank = (TextView) convertView.findViewById(R.id.special_rank);
g_specialRank.setText(c_specialRank);
g_specialRank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_rank, "") && c_rank != null) {
g_rank = (TextView) convertView.findViewById(R.id.rank);
g_rank.setText(c_rank);
g_rank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_gender, "") && c_gender != null) {
g_gender = (TextView) convertView.findViewById(R.id.gender);
g_gender.setText(c_gender);
g_gender.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_numberOfPosts, "") && c_numberOfPosts != null) {
g_numberOfPosts = (TextView) convertView.findViewById(R.id.number_of_posts);
g_numberOfPosts.setText(c_numberOfPosts);
g_numberOfPosts.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_personalText, "") && c_personalText != null) {
g_personalText = (TextView) convertView.findViewById(R.id.personal_text);
g_personalText.setText("\"" + c_personalText + "\"");
g_personalText.setVisibility(View.VISIBLE);
}
for (int i = 0; i < c_numberOfStars; ++i) {
CircularNetworkImageView star = new CircularNetworkImageView(this);
star.setImageUrl(c_urlOfStars, imageLoader);
//Remove spacing between stars...
//Don't know why this is happening in the first place
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins((int) getResources().getDimension(R.dimen.stars_margin)
, 0
, (int) getResources().getDimension(R.dimen.stars_margin)
, 0);
star.setLayoutParams(params);
g_stars_holder.addView(star, 0);
g_stars_holder.setVisibility(View.VISIBLE);
}
/* --Header expand/collapse functionality-- */
header.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(userExtraInfo);
}
});
//Clicking the expanded part of a header should collapse the extra info
userExtraInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(v);
}
});
/* --Header expand/collapse functionality end-- */
}
/* --Card expand/collapse functionality-- */
//Should expand/collapse when card is touched
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animatePostExtraInfoVisibility(postDateAndNumberExp
, username, subject
,ContextCompat.getColor(getApplicationContext(), R.color.black)
,ContextCompat.getColor(getApplicationContext(), R.color.secondary_text));
}
});
//Also when post is clicked
post.setOnTouchListener(new CustomTouchListener(post,cardView, quoteToggle));
/* --Card expand/collapse-like functionality end-- */
//Add view to the linear layout that holds all posts
postsLinearLayout.addView(convertView);
//Set post focus
if (postFocus != NO_POST_FOCUS) {
if (currentPost.getPostIndex() == postFocus) { if (currentPost.getPostIndex() == postFocus) {
//TODO //TODO
} }
} }
} }
} }
//--------------------------------------POPULATE UI METHOD END--------------------------------------
//--------------------------------------CUSTOM WEBVIEW CLIENT--------------------------------------- //--------------------------------------POPULATE UI METHOD END--------------------------------------
/**
* This class is used to handle link clicks in WebViews.
* When link url is one that the app can handle internally, it does.
* Otherwise user is prompt to open the link in a browser.
*/
@SuppressWarnings("unchecked")
private class LinkLauncher extends WebViewClient { //Used to handle link clicks
//Older versions
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
final Uri uri = Uri.parse(url);
return handleUri(uri);
}
//Newest versions
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
final Uri uri = request.getUrl();
return handleUri(uri);
}
//Handle url clicks
private boolean handleUri(final Uri uri) {
//Method always returns true as we don't want any url to be loaded in WebViews
Log.i(TAG, "Uri = " + uri);
final String host = uri.getHost(); //Get requested url's host
final String uriString = uri.toString();
//Determine if you are going to pass the url to a
//host's application activity or load it in a browser.
if (Objects.equals(host, "www.thmmy.gr")) {
//This is my web site, so figure out what Activity should launch
if (uriString.contains("topic=")) { //This url points to a topic
//Is the link pointing to current topic?
if (Objects.equals(
uriString.substring(0, uriString.lastIndexOf(".")), base_url)) {
//Get uri's targeted message's index number
String msgIndexReq = uriString.substring(uriString.indexOf("msg") + 3);
if (msgIndexReq.contains("#"))
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf("#"));
else
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf(";"));
//Is this post already shown now? (is it in current page?)
for (Post post : postsList) {
if (post.getPostIndex() == Integer.parseInt(msgIndexReq)) {
//Don't restart Activity
//Just change post focus
//TODO
return true;
}
}
}
//Restart activity with new data
Pair<View, String> p1 = Pair.create((View) replyFAB, "fab");
Pair<View, String> p2 = Pair.create((View) toolbar, "toolbar");
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(TopicActivity.this, p1, p2);
Intent intent = getIntent();
intent.putExtra("TOPIC_URL", uri.toString());
intent.putExtra("TOPIC_TITLE", "");
startActivity(intent, options.toBundle());
finish();
}
return true;
}
//Otherwise, the link is not for a page on my site, so launch
//another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
return true;
}
}
//------------------------------------CUSTOM WEBVIEW CLIENT END-------------------------------------
//----------------------------------------REPETITIVE UPDATER---------------------------------------- //----------------------------------------REPETITIVE UPDATER----------------------------------------
@ -750,94 +461,4 @@ public class TopicActivity extends BaseActivity {
} }
} }
//--------------------------------------REPETITIVE UPDATER END-------------------------------------- //--------------------------------------REPETITIVE UPDATER END--------------------------------------
//--------------------------------------CUSTOM TOUCH LISTENER---------------------------------------
/**
* This class is a gesture detector for WebViews.
* It handles post's clicks, long clicks and touch and drag.
*/
private class CustomTouchListener implements View.OnTouchListener {
//Long press handling
private final int LONG_PRESS_DURATION = 650;
private final Handler webViewLongClickHandler = new Handler();
private boolean wasLongClick = false;
private float downCoordinateX;
private float downCoordinateY;
private final float SCROLL_THRESHOLD = 7;
final private WebView post;
final private CardView cardView;
final private ImageButton quoteToggle;
//Other variables
final static int FINGER_RELEASED = 0;
final static int FINGER_TOUCHED = 1;
final static int FINGER_DRAGGING = 2;
final static int FINGER_UNDEFINED = 3;
private int fingerState = FINGER_RELEASED;
CustomTouchListener(WebView pPost, CardView pCard, ImageButton pQuoteToggle){
post = pPost;
cardView = pCard;
quoteToggle = pQuoteToggle;
}
final Runnable WebViewLongClick = new Runnable() {
public void run() {
wasLongClick = true;
quoteToggle.performClick();
}
};
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
downCoordinateX = motionEvent.getX();
downCoordinateY = motionEvent.getY();
if (fingerState == FINGER_RELEASED)
fingerState = FINGER_TOUCHED;
else
fingerState = FINGER_UNDEFINED;
//Start long click runnable
webViewLongClickHandler.postDelayed(WebViewLongClick
, LONG_PRESS_DURATION);
break;
case MotionEvent.ACTION_UP:
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
if (!wasLongClick && fingerState != FINGER_DRAGGING) {
//If this was a link don't expand the card
WebView.HitTestResult htResult = post.getHitTestResult();
if (htResult.getExtra() != null
&& htResult.getExtra() != null)
return false;
//Else expand/collapse card
cardView.performClick();
} else
wasLongClick = false;
fingerState = FINGER_RELEASED;
break;
case MotionEvent.ACTION_MOVE:
//If finger moved too much, cancel long click
if (((Math.abs(downCoordinateX - motionEvent.getX()) > SCROLL_THRESHOLD ||
Math.abs(downCoordinateY - motionEvent.getY()) > SCROLL_THRESHOLD))) {
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
fingerState = FINGER_DRAGGING;
} else fingerState = FINGER_UNDEFINED;
break;
default:
fingerState = FINGER_UNDEFINED;
}
return false;
}
}
//------------------------------------CUSTOM TOUCH LISTENER END-------------------------------------
} }

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

@ -0,0 +1,421 @@
package gr.thmmy.mthmmy.activities.topic;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.volley.toolbox.ImageLoader;
import java.util.List;
import java.util.Objects;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.data.Post;
import gr.thmmy.mthmmy.utils.CircularNetworkImageView;
import gr.thmmy.mthmmy.utils.ImageController;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.base_url;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.toQuoteList;
class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
private static final String TAG = "TopicAdapter";
private static final int THUMBNAIL_SIZE = 80;
private ImageLoader imageLoader = ImageController.getInstance().getImageLoader();
private Context context;
private List<Post> postsList;
class MyViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
FrameLayout postDateAndNumberExp;
TextView postDate, postNum, username, subject;
CircularNetworkImageView thumbnail;
public WebView post;
ImageButton quoteToggle;
RelativeLayout header;
LinearLayout userExtraInfo;
TextView specialRank, rank, gender, numberOfPosts, personalText;
LinearLayout stars_holder;
MyViewHolder(View view) {
super(view);
//Initialize layout's graphic elements
//Basic stuff
cardView = (CardView) view.findViewById(R.id.card_view);
postDateAndNumberExp = (FrameLayout) view.findViewById(R.id.post_date_and_number_exp);
postDate = (TextView) view.findViewById(R.id.post_date);
postNum = (TextView) view.findViewById(R.id.post_number);
thumbnail = (CircularNetworkImageView) view.findViewById(R.id.thumbnail);
username = (TextView) view.findViewById(R.id.username);
subject = (TextView) view.findViewById(R.id.subject);
post = (WebView) view.findViewById(R.id.post);
quoteToggle = (ImageButton) view.findViewById(R.id.toggle_quote_button);
//User's extra
header = (RelativeLayout) view.findViewById(R.id.header);
userExtraInfo = (LinearLayout) view.findViewById(R.id.user_extra_info);
specialRank = (TextView) view.findViewById(R.id.special_rank);
rank = (TextView) view.findViewById(R.id.rank);
gender = (TextView) view.findViewById(R.id.gender);
numberOfPosts = (TextView) view.findViewById(R.id.number_of_posts);
personalText = (TextView) view.findViewById(R.id.personal_text);
stars_holder = (LinearLayout) view.findViewById(R.id.stars);
}
}
TopicAdapter(Context context, List<Post> postsList) {
this.context = context;
this.postsList = postsList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_topic_post_row, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final Post currentPost = postsList.get(position);
//Post's WebView parameters set
holder.post.setClickable(true);
holder.post.setWebViewClient(new LinkLauncher());
holder.post.getSettings().setJavaScriptEnabled(true);
holder.post.getSettings().setPluginState(WebSettings.PluginState.ON_DEMAND);
//Avoiding errors about layout having 0 width/height
holder.thumbnail.setMinimumWidth(1);
holder.thumbnail.setMinimumHeight(1);
//Set thumbnail size
holder.thumbnail.setMaxWidth(THUMBNAIL_SIZE);
holder.thumbnail.setMaxHeight(THUMBNAIL_SIZE);
//Thumbnail image set
if (currentPost.getThumbnailUrl() != null
&& !Objects.equals(currentPost.getThumbnailUrl(), "")) {
holder.thumbnail.setImageUrl(currentPost.getThumbnailUrl(), imageLoader);
}
//Username set
holder.username.setText(currentPost.getAuthor());
//Post's submit date set
holder.postDate.setText(currentPost.getPostDate());
//Post's index number set
if (currentPost.getPostNumber() != 0)
holder.postNum.setText(context.getString(
R.string.user_number_of_posts, currentPost.getPostNumber()));
else
holder.postNum.setText("");
//Post's subject set
holder.subject.setText(currentPost.getSubject());
//Post's text set
holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null);
holder.quoteToggle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (view.isSelected()) {
if (toQuoteList.contains(currentPost.getPostNumber())) {
toQuoteList.remove(toQuoteList.indexOf(currentPost.getPostNumber()));
view.setSelected(false);
} else
Log.i(TAG, "An error occurred while trying to exclude post from" +
"toQuoteList, post wasn't there!");
} else {
toQuoteList.add(currentPost.getPostNumber());
view.setSelected(true);
}
}
});
//If user is not deleted then we have more to do
if (!currentPost.isDeleted()) { //Set extra info
//Variables for content
String c_specialRank = currentPost.getSpecialRank()
, c_rank = currentPost.getRank()
, c_gender = currentPost.getGender()
, c_numberOfPosts = currentPost.getNumberOfPosts()
, c_personalText = currentPost.getPersonalText()
, c_urlOfStars = currentPost.getUrlOfStars();
int c_numberOfStars = currentPost.getNumberOfStars();
if (!Objects.equals(c_specialRank, "") && c_specialRank != null) {
holder.specialRank.setText(c_specialRank);
holder.specialRank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_rank, "") && c_rank != null) {
holder.rank.setText(c_rank);
holder.rank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_gender, "") && c_gender != null) {
holder.gender.setText(c_gender);
holder.gender.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_numberOfPosts, "") && c_numberOfPosts != null) {
holder.numberOfPosts.setText(c_numberOfPosts);
holder.numberOfPosts.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_personalText, "") && c_personalText != null) {
holder.personalText.setText("\"" + c_personalText + "\"");
holder.personalText.setVisibility(View.VISIBLE);
}
for (int i = 0; i < c_numberOfStars; ++i) {
CircularNetworkImageView star = new CircularNetworkImageView(context);
star.setImageUrl(c_urlOfStars, imageLoader);
//Remove spacing between stars...
//Don't know why this is happening in the first place
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins((int) context.getResources().getDimension(R.dimen.stars_margin)
, 0
, (int) context.getResources().getDimension(R.dimen.stars_margin)
, 0);
star.setLayoutParams(params);
holder.stars_holder.addView(star, 0);
holder.stars_holder.setVisibility(View.VISIBLE);
}
/* --Header expand/collapse functionality-- */
holder.header.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(holder.userExtraInfo);
}
});
//Clicking the expanded part of a header should collapse the extra info
holder.userExtraInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(v);
}
});
/* --Header expand/collapse functionality end-- */
}
/* --Card expand/collapse functionality-- */
//Should expand/collapse when card is touched
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animatePostExtraInfoVisibility(holder.postDateAndNumberExp
, holder.username, holder.subject
, Color.parseColor("#000000")
, Color.parseColor("#757575"));
}
});
//Also when post is clicked
holder.post.setOnTouchListener(new CustomTouchListener(holder.post, holder.cardView, holder.quoteToggle));
}
@Override
public int getItemCount() {
return postsList.size();
}
//--------------------------------------CUSTOM TOUCH LISTENER---------------------------------------
/**
* This class is a gesture detector for WebViews.
* It handles post's clicks, long clicks and touch and drag.
*/
private class CustomTouchListener implements View.OnTouchListener {
//Long press handling
private final int LONG_PRESS_DURATION = 650;
private final Handler webViewLongClickHandler = new Handler();
private boolean wasLongClick = false;
private float downCoordinateX;
private float downCoordinateY;
private final float SCROLL_THRESHOLD = 7;
final private WebView post;
final private CardView cardView;
final private ImageButton quoteToggle;
//Other variables
final static int FINGER_RELEASED = 0;
final static int FINGER_TOUCHED = 1;
final static int FINGER_DRAGGING = 2;
final static int FINGER_UNDEFINED = 3;
private int fingerState = FINGER_RELEASED;
CustomTouchListener(WebView pPost, CardView pCard, ImageButton pQuoteToggle) {
post = pPost;
cardView = pCard;
quoteToggle = pQuoteToggle;
}
final Runnable WebViewLongClick = new Runnable() {
public void run() {
wasLongClick = true;
quoteToggle.performClick();
}
};
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
downCoordinateX = motionEvent.getX();
downCoordinateY = motionEvent.getY();
if (fingerState == FINGER_RELEASED)
fingerState = FINGER_TOUCHED;
else
fingerState = FINGER_UNDEFINED;
//Start long click runnable
webViewLongClickHandler.postDelayed(WebViewLongClick
, LONG_PRESS_DURATION);
break;
case MotionEvent.ACTION_UP:
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
if (!wasLongClick && fingerState != FINGER_DRAGGING) {
//If this was a link don't expand the card
WebView.HitTestResult htResult = post.getHitTestResult();
if (htResult.getExtra() != null
&& htResult.getExtra() != null)
return false;
//Else expand/collapse card
cardView.performClick();
} else
wasLongClick = false;
fingerState = FINGER_RELEASED;
break;
case MotionEvent.ACTION_MOVE:
//If finger moved too much, cancel long click
if (((Math.abs(downCoordinateX - motionEvent.getX()) > SCROLL_THRESHOLD ||
Math.abs(downCoordinateY - motionEvent.getY()) > SCROLL_THRESHOLD))) {
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
fingerState = FINGER_DRAGGING;
} else fingerState = FINGER_UNDEFINED;
break;
default:
fingerState = FINGER_UNDEFINED;
}
return false;
}
}
//------------------------------------CUSTOM TOUCH LISTENER END-------------------------------------
//--------------------------------------CUSTOM WEBVIEW CLIENT---------------------------------------
/**
* This class is used to handle link clicks in WebViews.
* When link url is one that the app can handle internally, it does.
* Otherwise user is prompt to open the link in a browser.
*/
@SuppressWarnings("unchecked")
private class LinkLauncher extends WebViewClient { //Used to handle link clicks
//Older versions
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
final Uri uri = Uri.parse(url);
return handleUri(uri);
}
//Newest versions
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
final Uri uri = request.getUrl();
return handleUri(uri);
}
//Handle url clicks
private boolean handleUri(final Uri uri) {
//Method always returns true as we don't want any url to be loaded in WebViews
Log.i(TAG, "Uri = " + uri);
final String host = uri.getHost(); //Get requested url's host
final String uriString = uri.toString();
//Determine if you are going to pass the url to a
//host's application activity or load it in a browser.
if (Objects.equals(host, "www.thmmy.gr")) {
//This is my web site, so figure out what Activity should launch
if (uriString.contains("topic=")) { //This url points to a topic
//Is the link pointing to current topic?
if (Objects.equals(
uriString.substring(0, uriString.lastIndexOf(".")), base_url)) {
//Get uri's targeted message's index number
String msgIndexReq = uriString.substring(uriString.indexOf("msg") + 3);
if (msgIndexReq.contains("#"))
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf("#"));
else
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf(";"));
//Is this post already shown now? (is it in current page?)
for (Post post : postsList) {
if (post.getPostIndex() == Integer.parseInt(msgIndexReq)) {
//Don't restart Activity
//Just change post focus
//TODO
return true;
}
}
}
//Restart activity with new data
//TODO
}
return true;
}
//Otherwise, the link is not for a page on my site, so launch
//another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
return true;
}
}
//------------------------------------CUSTOM WEBVIEW CLIENT END-------------------------------------
}

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

@ -1,7 +1,5 @@
package gr.thmmy.mthmmy.activities.topic; package gr.thmmy.mthmmy.activities.topic;
import android.util.Log;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
@ -123,15 +121,18 @@ class TopicParser {
for (Element _noembed : noembedTag) { for (Element _noembed : noembedTag) {
embededVideosUrls.add(_noembed.text().substring(_noembed.text() embededVideosUrls.add(_noembed.text().substring(_noembed.text()
.indexOf("href=\"https://www.youtube.com/watch?") + 6 .indexOf("href=\"https://www.youtube.com/watch?") + 38
, _noembed.text().indexOf("target") - 6)); , _noembed.text().indexOf("target") - 2));
} }
int tmp_counter = 0; int tmp_counter = 0;
while (p_post.contains("<embed")) { while (p_post.contains("<embed")) {
if (tmp_counter > embededVideosUrls.size())
break;
p_post = p_post.replace( p_post = p_post.replace(
p_post.substring(p_post.indexOf("<embed"), p_post.indexOf("/noembed>") + 9) p_post.substring(p_post.indexOf("<embed"), p_post.indexOf("/noembed>") + 9)
, "<iframe width=\"200\" height=\"315\" src=\"" , "<iframe width=\"100%\" height=\"auto\" src=\""
+ "https://www.youtube.com/embed/"
+ embededVideosUrls.get(tmp_counter) + embededVideosUrls.get(tmp_counter)
+ "\" frameborder=\"0\" allowfullscreen></iframe>" + "\" frameborder=\"0\" allowfullscreen></iframe>"
); );

0
app/src/main/res/drawable/login_progress_bar_bg.xml → app/src/main/res/drawable/progress_bar_bg.xml

2
app/src/main/res/layout/activity_login.xml

@ -114,7 +114,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:background="@drawable/login_progress_bar_bg"/> android:background="@drawable/progress_bar_bg"/>
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"

17
app/src/main/res/layout/activity_topic.xml

@ -27,7 +27,8 @@
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView <android.support.v7.widget.RecyclerView
android:id="@+id/topic_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="top|start" android:layout_gravity="top|start"
@ -36,18 +37,7 @@
android:background="@color/background" android:background="@color/background"
android:scrollbars="none" android:scrollbars="none"
tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity"> tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity">
</android.support.v7.widget.RecyclerView>
<LinearLayout
android:id="@+id/posts_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingBottom="4dp"
android:paddingTop="4dp">
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<LinearLayout <LinearLayout
android:id="@+id/bottom_navigation_bar" android:id="@+id/bottom_navigation_bar"
@ -110,6 +100,7 @@
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_gravity="center" android:layout_gravity="center"
android:background="@drawable/progress_bar_bg"
android:visibility="invisible"/> android:visibility="invisible"/>
<android.support.design.widget.FloatingActionButton <android.support.design.widget.FloatingActionButton

1
app/src/main/res/layout/activity_topic_post_row.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"

Loading…
Cancel
Save