From 03c78f49cbc29efd24d966ed949a19e4bfeb174f Mon Sep 17 00:00:00 2001 From: Apostolof Date: Tue, 6 Dec 2016 20:32:47 +0200 Subject: [PATCH] Changed topic activity's NestedScrollView to RecyclerView. Embedded videos fixes. --- .../activities/topic/TopicActivity.java | 455 ++---------------- .../mthmmy/activities/topic/TopicAdapter.java | 421 ++++++++++++++++ .../mthmmy/activities/topic/TopicParser.java | 11 +- ...rogress_bar_bg.xml => progress_bar_bg.xml} | 0 app/src/main/res/layout/activity_login.xml | 2 +- app/src/main/res/layout/activity_topic.xml | 17 +- .../res/layout/activity_topic_post_row.xml | 1 - 7 files changed, 470 insertions(+), 437 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java rename app/src/main/res/drawable/{login_progress_bar_bg.xml => progress_bar_bg.xml} (100%) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index f1f9c0b5..d5a86c37 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -1,41 +1,27 @@ package gr.thmmy.mthmmy.activities.topic; -import android.annotation.TargetApi; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; -import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.content.ContextCompat; import android.support.v4.util.Pair; 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.util.Log; import android.util.SparseArray; -import android.view.LayoutInflater; import android.view.MotionEvent; 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.LinearLayout; import android.widget.ProgressBar; -import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; -import com.android.volley.toolbox.ImageLoader; - import org.jsoup.Jsoup; 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.LoginActivity; import gr.thmmy.mthmmy.data.Post; -import gr.thmmy.mthmmy.utils.CircularNetworkImageView; import gr.thmmy.mthmmy.utils.ImageController; import okhttp3.Request; import okhttp3.Response; @@ -64,14 +49,13 @@ public class TopicActivity extends BaseActivity { /* --Posts-- */ private List postsList; - private LinearLayout postsLinearLayout; private static final int NO_POST_FOCUS = -1; private int postFocus = NO_POST_FOCUS; //Quote - private final ArrayList toQuoteList = new ArrayList<>(); + public static final ArrayList toQuoteList = new ArrayList<>(); /* --Topic's pages-- */ private int thisPage = 1; - private String base_url = ""; + public static String base_url = ""; private int numberOfPages = 1; private final SparseArray pagesUrls = new SparseArray<>(); //Page select @@ -83,21 +67,18 @@ public class TopicActivity extends BaseActivity { private static final int SMALL_STEP = 1; private static final int LARGE_STEP = 10; private Integer pageRequestValue; - private ImageButton firstPage; - private ImageButton previousPage; - private ImageButton nextPage; - private ImageButton lastPage; - /* --Thumbnail-- */ - private static final int THUMBNAIL_SIZE = 80; - private ImageLoader imageLoader = ImageController.getInstance().getImageLoader(); + ImageButton firstPage; + ImageButton previousPage; + ImageButton nextPage; + ImageButton lastPage; //Other variables private ProgressBar progressBar; private static final String TAG = "TopicActivity"; private String topicTitle; - private String parsedTitle; private FloatingActionButton replyFAB; + private String parsedTitle; @Override protected void onCreate(Bundle savedInstanceState) { @@ -107,7 +88,7 @@ public class TopicActivity extends BaseActivity { Bundle extras = getIntent().getExtras(); topicTitle = getIntent().getExtras().getString("TOPIC_TITLE"); - //Initialize toolbar + //Initialize toolbar, drawer and ProgressBar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle(topicTitle); setSupportActionBar(toolbar); @@ -116,14 +97,8 @@ public class TopicActivity extends BaseActivity { createDrawer(); - //Variables initialization - postsLinearLayout = (LinearLayout) findViewById(R.id.posts_list); - progressBar = (ProgressBar) findViewById(R.id.progressBar); - if (imageLoader == null) - imageLoader = ImageController.getInstance().getImageLoader(); - postsList = new ArrayList<>(); @@ -137,6 +112,7 @@ public class TopicActivity extends BaseActivity { initDecrementButton(previousPage, SMALL_STEP); initIncrementButton(nextPage, SMALL_STEP); initIncrementButton(lastPage, LARGE_STEP); + firstPage.setEnabled(false); previousPage.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) { // Increment once for a click increment.setOnClickListener(new View.OnClickListener() { @@ -318,8 +294,8 @@ public class TopicActivity extends BaseActivity { private void changePage(int pageRequested) { if (pageRequested != thisPage - 1) { //Restart activity with new page - Pair p1 = Pair.create((View)replyFAB, "fab"); - Pair p2 = Pair.create((View)toolbar, "toolbar"); + Pair p1 = Pair.create((View) replyFAB, "fab"); + Pair p2 = Pair.create((View) toolbar, "toolbar"); ActivityOptionsCompat options = ActivityOptionsCompat. makeSceneTransitionAnimation(this, p1, p2); @@ -332,7 +308,7 @@ public class TopicActivity extends BaseActivity { } //------------------------------------BOTTOM NAV BAR METHODS END------------------------------------ -//---------------------------------------TOPIC ASYNC TASK------------------------------------------- + //---------------------------------------TOPIC ASYNC TASK------------------------------------------- public class TopicTask extends AsyncTask { //Class variables private static final String TAG = "TopicTask"; //Separate tag for AsyncTask @@ -389,6 +365,14 @@ public class TopicActivity extends BaseActivity { pageRequestValue = thisPage; if (numberOfPages >= 1000) 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 */ @@ -396,11 +380,10 @@ public class TopicActivity extends BaseActivity { //Find topic title if missing if (topicTitle == null || Objects.equals(topicTitle, "")) { 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.indexOf("(Read") - 2); - } - else{ + } else { parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Θέμα:") + 6 , parsedTitle.indexOf("(Αναγνώστηκε") - 2); Log.d(TAG, parsedTitle); @@ -432,298 +415,26 @@ public class TopicActivity extends BaseActivity { * adds a card for each post to the ScrollView. */ private void populateLayout() { - //Enable reply button - replyFAB.setEnabled(true); - - //Set topic title if not already present - if (topicTitle == null || Objects.equals(topicTitle, "")) { - topicTitle = parsedTitle; - if (toolbar != null) { - toolbar.setTitle(topicTitle); - } - } - - //Now that parsing is complete and we have the url for every page enable page nav buttons - 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) { + RecyclerView recyclerView = (RecyclerView)findViewById(R.id.topic_recycler_view); + recyclerView.setHasFixedSize(true); + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); + recyclerView.setLayoutManager(layoutManager); + + TopicAdapter adapter = new TopicAdapter(getApplicationContext(), postsList); + recyclerView.setAdapter(adapter); + + //Set post focus + if (postFocus != NO_POST_FOCUS) { + for (int i = 0; i < postsList.size(); ++i) { + Post currentPost = postsList.get(i); if (currentPost.getPostIndex() == postFocus) { //TODO } } } } -//--------------------------------------POPULATE UI METHOD 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 - Pair p1 = Pair.create((View) replyFAB, "fab"); - Pair 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------------------------------------- +//--------------------------------------POPULATE UI METHOD END-------------------------------------- //----------------------------------------REPETITIVE UPDATER---------------------------------------- @@ -750,94 +461,4 @@ public class TopicActivity extends BaseActivity { } } //--------------------------------------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------------------------------------- } \ No newline at end of file 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 new file mode 100644 index 00000000..472995ff --- /dev/null +++ b/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 { + private static final String TAG = "TopicAdapter"; + + private static final int THUMBNAIL_SIZE = 80; + private ImageLoader imageLoader = ImageController.getInstance().getImageLoader(); + private Context context; + private List 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 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------------------------------------- + +} \ No newline at end of file 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 771b86ca..e27c80f8 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 @@ -1,7 +1,5 @@ package gr.thmmy.mthmmy.activities.topic; -import android.util.Log; - import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -123,15 +121,18 @@ class TopicParser { for (Element _noembed : noembedTag) { embededVideosUrls.add(_noembed.text().substring(_noembed.text() - .indexOf("href=\"https://www.youtube.com/watch?") + 6 - , _noembed.text().indexOf("target") - 6)); + .indexOf("href=\"https://www.youtube.com/watch?") + 38 + , _noembed.text().indexOf("target") - 2)); } int tmp_counter = 0; while (p_post.contains(" embededVideosUrls.size()) + break; p_post = p_post.replace( p_post.substring(p_post.indexOf("") + 9) - , "" ); diff --git a/app/src/main/res/drawable/login_progress_bar_bg.xml b/app/src/main/res/drawable/progress_bar_bg.xml similarity index 100% rename from app/src/main/res/drawable/login_progress_bar_bg.xml rename to app/src/main/res/drawable/progress_bar_bg.xml diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index d3db5790..5228f8a0 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -114,7 +114,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:background="@drawable/login_progress_bar_bg"/> + android:background="@drawable/progress_bar_bg"/> - - - - - - +