From 85eef4f8c106bd4074ec1001151ae327470cc2ee Mon Sep 17 00:00:00 2001 From: Apostolof Date: Wed, 22 Feb 2017 22:24:17 +0200 Subject: [PATCH] Topic reply init. --- .../activities/topic/TopicActivity.java | 134 +++- .../mthmmy/activities/topic/TopicAdapter.java | 666 ++++++++++-------- .../res/layout/activity_topic_post_row.xml | 17 +- .../layout/activity_topic_quick_reply_row.xml | 53 ++ app/src/main/res/values/strings.xml | 2 + 5 files changed, 530 insertions(+), 342 deletions(-) create mode 100644 app/src/main/res/layout/activity_topic_quick_reply_row.xml 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 8ca6f707..92cc5317 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 @@ -14,14 +14,19 @@ import android.util.SparseArray; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; +import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Selector; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.Objects; @@ -33,7 +38,9 @@ import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.utils.ParseHelpers; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import mthmmy.utils.Report; +import okhttp3.MultipartBody; import okhttp3.Request; +import okhttp3.RequestBody; import okhttp3.Response; /** @@ -62,10 +69,11 @@ public class TopicActivity extends BaseActivity { private TopicAdapter topicAdapter; private ArrayList postsList; private static final int NO_POST_FOCUS = -1; - private static int postFocus = NO_POST_FOCUS; + private int postFocus = NO_POST_FOCUS; private static int postFocusPosition = 0; - //Quotes - public static final ArrayList toQuoteList = new ArrayList<>(); + //Reply + private FloatingActionButton replyFAB; + private String replyPageUrl = null; //Topic's pages private int thisPage = 1; private int numberOfPages = 1; @@ -85,7 +93,6 @@ public class TopicActivity extends BaseActivity { private ImageButton nextPage; private ImageButton lastPage; //Other variables - private FloatingActionButton replyFAB; private MaterialProgressBar progressBar; private static String base_url = ""; private String topicTitle; @@ -132,42 +139,27 @@ public class TopicActivity extends BaseActivity { recyclerView.setHasFixedSize(true); LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(layoutManager); - topicAdapter = new TopicAdapter(this, postsList, - topicTask); + topicAdapter = new TopicAdapter(this, postsList, topicTask); recyclerView.setAdapter(topicAdapter); replyFAB = (FloatingActionButton) findViewById(R.id.topic_fab); replyFAB.setEnabled(false); - replyFAB.hide(); - /*if (!sessionManager.isLoggedIn()) replyFAB.hide(); + final LinearLayout bottomNavBar = (LinearLayout) findViewById(R.id.bottom_navigation_bar); + if (!sessionManager.isLoggedIn()) replyFAB.hide(); else { replyFAB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (sessionManager.isLoggedIn()) { - //TODO Reply - } else { - new AlertDialog.Builder(TopicActivity.this) - .setMessage("You need to be logged in to reply!") - .setPositiveButton("Login", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Intent intent = new Intent(TopicActivity.this, LoginActivity.class); - startActivity(intent); - finish(); - overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out); - } - }) - .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - } - }) - .show(); + postsList.add(null); + topicAdapter.prepareForReply(new ReplyTask()); + replyFAB.hide(); + bottomNavBar.setVisibility(View.GONE); + topicAdapter.notifyItemInserted(postsList.size()); } } }); - }*/ + } //Sets bottom navigation bar firstPage = (ImageButton) findViewById(R.id.page_first_button); @@ -488,6 +480,7 @@ public class TopicActivity extends BaseActivity { progressBar.setVisibility(ProgressBar.INVISIBLE); topicAdapter.customNotifyDataSetChanged(new TopicTask()); + if (replyPageUrl == null) replyFAB.setVisibility(View.GONE); if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(true); //Set current page @@ -528,6 +521,12 @@ public class TopicActivity extends BaseActivity { private void parse(Document topic) { ParseHelpers.Language language = ParseHelpers.Language.getLanguage(topic); + //Find reply page url + { + Element replyButton = topic.select("a:has(img[alt=Reply])").first(); + if (replyButton != null) replyPageUrl = replyButton.attr("href"); + } + //Finds topic title if missing if (topicTitle == null || Objects.equals(topicTitle, "")) { parsedTitle = topic.select("td[id=top_subject]").first().text(); @@ -555,7 +554,84 @@ public class TopicActivity extends BaseActivity { postsList.clear(); postsList.addAll(TopicParser.parseTopic(topic, language)); - //postsList = TopicParser.parseTopic(topic, language); + } + } + + class ReplyTask extends AsyncTask { + + @Override + protected void onPreExecute() { + progressBar.setVisibility(ProgressBar.VISIBLE); + paginationEnabled(false); + replyFAB.setEnabled(false); + } + + @Override + protected Boolean doInBackground(String... message) { + Document document; + String numReplies, seqnum, sc, subject, topic; + + Request request = new Request.Builder() + .url(replyPageUrl + ";wap2") + .build(); + try { + Response response = client.newCall(request).execute(); + document = Jsoup.parse(response.body().string()); + + //https://www.thmmy.gr/smf/index.php?action=post;topic=67565.15;num_replies=27 + numReplies = replyPageUrl.substring(replyPageUrl.indexOf("num_replies=") + 12); + seqnum = document.select("input[name=seqnum]").first().attr("value"); + sc = document.select("input[name=sc]").first().attr("value"); + subject = document.select("input[name=subject]").first().attr("value"); + topic = document.select("input[name=topic]").first().attr("value"); + Log.d(TAG, "numReplies " + numReplies + "\n" + + "seqnum " + seqnum + "\n" + + "sc " + sc + "\n" + + "subject " + subject + "\n" + + "topic " + topic + "\n"); + } catch (IOException e) { + Report.i(TAG, "Post failed.", e); + return false; + } catch (Selector.SelectorParseException e) { + Report.e(TAG, "Post failed.", e); + return false; + } + + Log.d(TAG, message[0]); + RequestBody postBody = null; + try { + postBody = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("message", URLEncoder.encode(message[0], "UTF-8")) + .addFormDataPart("num_replies", numReplies) + .addFormDataPart("seqnum", seqnum) + .addFormDataPart("sc", sc) + .addFormDataPart("subject", subject) + .addFormDataPart("topic", topic) + .addFormDataPart("goback", "1") + .build(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + Request post = new Request.Builder() + .url("https://www.thmmy.gr/smf/index.php?action=post2") + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") + .post(postBody) + .build(); + + try { + client.newCall(post).execute(); + return true; + } catch (IOException e) { + Report.i(TAG, "Post failed.", e); + return false; + } + } + + @Override + protected void onPostExecute(Boolean result) { + progressBar.setVisibility(ProgressBar.GONE); } } } \ 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 index 2ea65fb9..d989f608 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -11,9 +11,11 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.content.res.ResourcesCompat; +import android.support.v7.widget.AppCompatImageButton; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; +import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -21,6 +23,7 @@ import android.view.ViewGroup; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; @@ -31,6 +34,7 @@ import android.widget.TextView; import com.squareup.picasso.Picasso; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Objects; @@ -50,12 +54,11 @@ 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.TopicActivity.toQuoteList; /** * Custom {@link android.support.v7.widget.RecyclerView.Adapter} used for topics. */ -class TopicAdapter extends RecyclerView.Adapter { +class TopicAdapter extends RecyclerView.Adapter { /** * Debug Tag for logging debug output to LogCat */ @@ -65,6 +68,7 @@ class TopicAdapter extends RecyclerView.Adapter { */ private static int THUMBNAIL_SIZE; private final Context context; + private ArrayList toQuoteList = new ArrayList<>(); private final List postsList; /** * Used to hold the state of visibility and other attributes for views that are animated or @@ -87,69 +91,16 @@ class TopicAdapter extends RecyclerView.Adapter { */ private static final int isQuoteButtonChecked = 2; private TopicActivity.TopicTask topicTask; - - /** - * Custom {@link RecyclerView.ViewHolder} implementation - */ - class MyViewHolder extends RecyclerView.ViewHolder { - final CardView cardView; - final LinearLayout cardChildLinear; - final FrameLayout postDateAndNumberExp; - final TextView postDate, postNum, username, subject; - final ImageView thumbnail; - final public WebView post; - final ImageButton quoteToggle; - final RelativeLayout header; - final LinearLayout userExtraInfo; - final View bodyFooterDivider; - final LinearLayout postFooter; - - final TextView specialRank, rank, gender, numberOfPosts, personalText, stars; - - MyViewHolder(View view) { - super(view); - //Initializes layout's graphic elements - //Standard stuff - cardView = (CardView) view.findViewById(R.id.card_view); - cardChildLinear = (LinearLayout) view.findViewById(R.id.card_child_linear); - 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 = (ImageView) 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); - post.setBackgroundColor(Color.argb(1, 255, 255, 255)); - quoteToggle = (ImageButton) view.findViewById(R.id.toggle_quote_button); - bodyFooterDivider = view.findViewById(R.id.body_footer_divider); - postFooter = (LinearLayout) view.findViewById(R.id.post_footer); - - //User's extra info - 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 = (TextView) view.findViewById(R.id.stars); - } - - /** - * Cancels all pending Picasso requests - */ - void cleanup() { - Picasso.with(context).cancelRequest(thumbnail); - thumbnail.setImageDrawable(null); - } - } + private TopicActivity.ReplyTask replyTask; + private final int VIEW_TYPE_POST = 0; + private final int VIEW_TYPE_QUICK_REPLY = 1; + private boolean firstTime = false; /** * @param context the context of the {@link RecyclerView} * @param postsList List of {@link Post} objects to use */ - TopicAdapter(Context context, List postsList, - TopicActivity.TopicTask topicTask) { + TopicAdapter(Context context, List postsList, TopicActivity.TopicTask topicTask) { this.context = context; this.postsList = postsList; @@ -161,280 +112,322 @@ class TopicAdapter extends RecyclerView.Adapter { this.topicTask = topicTask; } + void prepareForReply(TopicActivity.ReplyTask replyTask) { + this.replyTask = replyTask; + firstTime = true; + } + @Override - public void onViewRecycled(final MyViewHolder holder) { - holder.cleanup(); + public int getItemViewType(int position) { + return postsList.get(position) == null ? VIEW_TYPE_QUICK_REPLY : VIEW_TYPE_POST; } @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); + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == VIEW_TYPE_POST) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.activity_topic_post_row, parent, false); + return new PostViewHolder(itemView); + } else if (viewType == VIEW_TYPE_QUICK_REPLY) { + View view = LayoutInflater.from(parent.getContext()). + inflate(R.layout.activity_topic_quick_reply_row, parent, false); + return new QuickReplyViewHolder(view); + } + return null; } @SuppressLint("SetJavaScriptEnabled") @Override - public void onBindViewHolder(final MyViewHolder holder, final int position) { - final Post currentPost = postsList.get(position); - - //Post's WebView parameters - holder.post.setClickable(true); - holder.post.setWebViewClient(new LinkLauncher()); - - //Avoids errors about layout having 0 width/height - holder.thumbnail.setMinimumWidth(1); - holder.thumbnail.setMinimumHeight(1); - //Sets thumbnail size - holder.thumbnail.setMaxWidth(THUMBNAIL_SIZE); - holder.thumbnail.setMaxHeight(THUMBNAIL_SIZE); - - //noinspection ConstantConditions - Picasso.with(context) - .load(currentPost.getThumbnailUrl()) - .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) - .centerCrop() - .error(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail, null)) - .placeholder(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail, null)) - .transform(new CircleTransform()) - .into(holder.thumbnail); - - //Sets username,submit date, index number, subject, post's and attached files texts - holder.username.setText(currentPost.getAuthor()); - holder.postDate.setText(currentPost.getPostDate()); - if (currentPost.getPostNumber() != 0) - holder.postNum.setText(context.getString( - R.string.user_number_of_posts, currentPost.getPostNumber())); - else - holder.postNum.setText(""); - holder.subject.setText(currentPost.getSubject()); - holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null); - if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { - 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(); - for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) { - final TextView attached = new TextView(context); - attached.setTextSize(10f); - attached.setClickable(true); - attached.setTypeface(Typeface.createFromAsset(context.getAssets() + public void onBindViewHolder(final RecyclerView.ViewHolder currentHolder, final int position) { + if (currentHolder instanceof PostViewHolder) { + final Post currentPost = postsList.get(position); + final PostViewHolder holder = (PostViewHolder) currentHolder; + + //Post's WebView parameters + holder.post.setClickable(true); + holder.post.setWebViewClient(new LinkLauncher()); + + //Avoids errors about layout having 0 width/height + holder.thumbnail.setMinimumWidth(1); + holder.thumbnail.setMinimumHeight(1); + //Sets thumbnail size + holder.thumbnail.setMaxWidth(THUMBNAIL_SIZE); + holder.thumbnail.setMaxHeight(THUMBNAIL_SIZE); + + //noinspection ConstantConditions + Picasso.with(context) + .load(currentPost.getThumbnailUrl()) + .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) + .centerCrop() + .error(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail, null)) + .placeholder(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail, null)) + .transform(new CircleTransform()) + .into(holder.thumbnail); + + //Sets username,submit date, index number, subject, post's and attached files texts + holder.username.setText(currentPost.getAuthor()); + holder.postDate.setText(currentPost.getPostDate()); + if (currentPost.getPostNumber() != 0) + holder.postNum.setText(context.getString( + R.string.user_number_of_posts, currentPost.getPostNumber())); + else + holder.postNum.setText(""); + holder.subject.setText(currentPost.getSubject()); + holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null); + if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { + 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(); + 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); + } + } else { + holder.bodyFooterDivider.setVisibility(View.GONE); + holder.postFooter.removeAllViews(); + } + + String mSpecialRank, mRank, mGender, mNumberOfPosts, mPersonalText; + int mNumberOfStars, mUserColor; + + if (!currentPost.isDeleted()) { //Sets user's extra info + mSpecialRank = currentPost.getSpecialRank(); + mRank = currentPost.getRank(); + mGender = currentPost.getGender(); + mNumberOfPosts = currentPost.getNumberOfPosts(); + mPersonalText = currentPost.getPersonalText(); + mNumberOfStars = currentPost.getNumberOfStars(); + mUserColor = currentPost.getUserColor(); + } else { + mSpecialRank = null; + mRank = null; + mGender = null; + mNumberOfPosts = null; + mPersonalText = null; + mNumberOfStars = 0; + mUserColor = 0; + } + + if (!Objects.equals(mSpecialRank, "") && mSpecialRank != null) { + holder.specialRank.setText(mSpecialRank); + holder.specialRank.setVisibility(View.VISIBLE); + } else + holder.specialRank.setVisibility(View.GONE); + if (!Objects.equals(mRank, "") && mRank != null) { + holder.rank.setText(mRank); + holder.rank.setVisibility(View.VISIBLE); + } else + holder.rank.setVisibility(View.GONE); + if (!Objects.equals(mGender, "") && mGender != null) { + holder.gender.setText(mGender); + holder.gender.setVisibility(View.VISIBLE); + } else + holder.gender.setVisibility(View.GONE); + if (!Objects.equals(mNumberOfPosts, "") && mNumberOfPosts != null) { + holder.numberOfPosts.setText(mNumberOfPosts); + holder.numberOfPosts.setVisibility(View.VISIBLE); + } else + holder.numberOfPosts.setVisibility(View.GONE); + if (!Objects.equals(mPersonalText, "") && mPersonalText != null) { + holder.personalText.setText("\"" + mPersonalText + "\""); + holder.personalText.setVisibility(View.VISIBLE); + } else + holder.personalText.setVisibility(View.GONE); + if (mNumberOfStars > 0) { + holder.stars.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() { + String aStar = context.getResources().getString(R.string.fa_icon_star); + String usersStars = ""; + for (int i = 0; i < mNumberOfStars; ++i) { + usersStars += aStar; + } + holder.stars.setText(usersStars); + holder.stars.setTextColor(mUserColor); + holder.stars.setVisibility(View.VISIBLE); + } else + holder.stars.setVisibility(View.GONE); + //Special card for special member of the month! + if (mUserColor == TopicParser.USER_COLOR_PINK) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + holder.cardChildLinear.setBackground(context.getResources(). + getDrawable(R.drawable.member_of_the_month_card, null)); + } else //noinspection deprecation + holder.cardChildLinear.setBackground(context.getResources(). + getDrawable(R.drawable.member_of_the_month_card)); + } else holder.cardChildLinear.setBackground(null); + + //Avoid's view's visibility recycling + if (!currentPost.isDeleted() && viewProperties.get(position)[isUserExtraInfoVisibile]) { + holder.userExtraInfo.setVisibility(View.VISIBLE); + holder.userExtraInfo.setAlpha(1.0f); + } else { + holder.userExtraInfo.setVisibility(View.GONE); + holder.userExtraInfo.setAlpha(0.0f); + } + if (!currentPost.isDeleted()) { + //Sets graphics behavior + holder.header.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View view) { - ((BaseActivity) context).launchDownloadService(attachedFile); + public void onClick(View v) { + //Clicking an expanded header starts profile activity + 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()); + tmp[isUserExtraInfoVisibile] = !tmp[isUserExtraInfoVisibile]; + viewProperties.set(holder.getAdapterPosition(), tmp); + TopicAnimations.animateUserExtraInfoVisibility(holder.userExtraInfo); } }); + //Clicking the expanded part of a header (the extra info) makes it collapse + holder.userExtraInfo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); + tmp[1] = false; + viewProperties.set(holder.getAdapterPosition(), tmp); - holder.postFooter.addView(attached); + TopicAnimations.animateUserExtraInfoVisibility(v); + } + }); + } else { + holder.header.setOnClickListener(null); + holder.userExtraInfo.setOnClickListener(null); } - } else { - holder.bodyFooterDivider.setVisibility(View.GONE); - holder.postFooter.removeAllViews(); - } - - String mSpecialRank, mRank, mGender, mNumberOfPosts, mPersonalText; - int mNumberOfStars, mUserColor; - - if (!currentPost.isDeleted()) { //Sets user's extra info - mSpecialRank = currentPost.getSpecialRank(); - mRank = currentPost.getRank(); - mGender = currentPost.getGender(); - mNumberOfPosts = currentPost.getNumberOfPosts(); - mPersonalText = currentPost.getPersonalText(); - mNumberOfStars = currentPost.getNumberOfStars(); - mUserColor = currentPost.getUserColor(); - } else { - mSpecialRank = null; - mRank = null; - mGender = null; - mNumberOfPosts = null; - mPersonalText = null; - mNumberOfStars = 0; - mUserColor = 0; - } - if (!Objects.equals(mSpecialRank, "") && mSpecialRank != null) { - holder.specialRank.setText(mSpecialRank); - holder.specialRank.setVisibility(View.VISIBLE); - } else - holder.specialRank.setVisibility(View.GONE); - if (!Objects.equals(mRank, "") && mRank != null) { - holder.rank.setText(mRank); - holder.rank.setVisibility(View.VISIBLE); - } else - holder.rank.setVisibility(View.GONE); - if (!Objects.equals(mGender, "") && mGender != null) { - holder.gender.setText(mGender); - holder.gender.setVisibility(View.VISIBLE); - } else - holder.gender.setVisibility(View.GONE); - if (!Objects.equals(mNumberOfPosts, "") && mNumberOfPosts != null) { - holder.numberOfPosts.setText(mNumberOfPosts); - holder.numberOfPosts.setVisibility(View.VISIBLE); - } else - holder.numberOfPosts.setVisibility(View.GONE); - if (!Objects.equals(mPersonalText, "") && mPersonalText != null) { - holder.personalText.setText("\"" + mPersonalText + "\""); - holder.personalText.setVisibility(View.VISIBLE); - } else - holder.personalText.setVisibility(View.GONE); - if (mNumberOfStars > 0) { - holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets() - , "fonts/fontawesome-webfont.ttf")); - - String aStar = context.getResources().getString(R.string.fa_icon_star); - String usersStars = ""; - for (int i = 0; i < mNumberOfStars; ++i) { - usersStars += aStar; + //Avoid's view's visibility recycling + if (viewProperties.get(position)[isPostDateAndNumberVisibile]) { //Expanded + holder.postDateAndNumberExp.setVisibility(View.VISIBLE); + holder.postDateAndNumberExp.setAlpha(1.0f); + holder.postDateAndNumberExp.setTranslationY(0); + + holder.username.setMaxLines(Integer.MAX_VALUE); + holder.username.setEllipsize(null); + + holder.subject.setTextColor(Color.parseColor("#FFFFFF")); + holder.subject.setMaxLines(Integer.MAX_VALUE); + holder.subject.setEllipsize(null); + } else { //Collapsed + holder.postDateAndNumberExp.setVisibility(View.GONE); + holder.postDateAndNumberExp.setAlpha(0.0f); + holder.postDateAndNumberExp.setTranslationY(holder.postDateAndNumberExp.getHeight()); + + holder.username.setMaxLines(1); + holder.username.setEllipsize(TextUtils.TruncateAt.END); + + holder.subject.setTextColor(Color.parseColor("#757575")); + holder.subject.setMaxLines(1); + holder.subject.setEllipsize(TextUtils.TruncateAt.END); } - holder.stars.setText(usersStars); - holder.stars.setTextColor(mUserColor); - holder.stars.setVisibility(View.VISIBLE); - } else - holder.stars.setVisibility(View.GONE); - //Special card for special member of the month! - if (mUserColor == TopicParser.USER_COLOR_PINK) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - holder.cardChildLinear.setBackground(context.getResources(). - getDrawable(R.drawable.member_of_the_month_card, null)); - } else //noinspection deprecation - holder.cardChildLinear.setBackground(context.getResources(). - getDrawable(R.drawable.member_of_the_month_card)); - } else holder.cardChildLinear.setBackground(null); - - //Avoid's view's visibility recycling - if (!currentPost.isDeleted() && viewProperties.get(position)[isUserExtraInfoVisibile]) { - holder.userExtraInfo.setVisibility(View.VISIBLE); - holder.userExtraInfo.setAlpha(1.0f); - } else { - holder.userExtraInfo.setVisibility(View.GONE); - holder.userExtraInfo.setAlpha(0.0f); - } - if (!currentPost.isDeleted()) { - //Sets graphics behavior - holder.header.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - //Clicking an expanded header starts profile activity - 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); + //noinspection PointlessBooleanExpression,ConstantConditions + if (!BaseActivity.getSessionManager().isLoggedIn() || true) //Hide it until reply is implemented + holder.quoteToggle.setVisibility(View.GONE); + else { + if (viewProperties.get(position)[isQuoteButtonChecked]) + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked); + else + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked); + //Sets graphics behavior + holder.quoteToggle.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); + if (tmp[isQuoteButtonChecked]) { + if (toQuoteList.contains(currentPost.getPostNumber())) { + toQuoteList.remove(toQuoteList.indexOf(currentPost.getPostNumber())); + } else + Report.i(TAG, "An error occurred while trying to exclude post from" + + "toQuoteList, post wasn't there!"); + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked); + } else { + toQuoteList.add(currentPost.getPostNumber()); + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked); + } + tmp[isQuoteButtonChecked] = !tmp[isQuoteButtonChecked]; + viewProperties.set(holder.getAdapterPosition(), tmp); } - - boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); - tmp[isUserExtraInfoVisibile] = !tmp[isUserExtraInfoVisibile]; - viewProperties.set(holder.getAdapterPosition(), tmp); - TopicAnimations.animateUserExtraInfoVisibility(holder.userExtraInfo); - } - }); - //Clicking the expanded part of a header (the extra info) makes it collapse - holder.userExtraInfo.setOnClickListener(new View.OnClickListener() { + }); + } + //Card expand/collapse when card is touched + holder.cardView.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { + public void onClick(View view) { + //Change post's viewProperties accordingly boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); - tmp[1] = false; + tmp[isPostDateAndNumberVisibile] = !tmp[isPostDateAndNumberVisibile]; viewProperties.set(holder.getAdapterPosition(), tmp); - TopicAnimations.animateUserExtraInfoVisibility(v); + TopicAnimations.animatePostExtraInfoVisibility(holder.postDateAndNumberExp + , holder.username, holder.subject + , Color.parseColor("#FFFFFF") + , Color.parseColor("#757575")); } }); - } else { - holder.header.setOnClickListener(null); - holder.userExtraInfo.setOnClickListener(null); - } - - //Avoid's view's visibility recycling - if (viewProperties.get(position)[isPostDateAndNumberVisibile]) { //Expanded - holder.postDateAndNumberExp.setVisibility(View.VISIBLE); - holder.postDateAndNumberExp.setAlpha(1.0f); - holder.postDateAndNumberExp.setTranslationY(0); - - holder.username.setMaxLines(Integer.MAX_VALUE); - holder.username.setEllipsize(null); - - holder.subject.setTextColor(Color.parseColor("#FFFFFF")); - holder.subject.setMaxLines(Integer.MAX_VALUE); - holder.subject.setEllipsize(null); - } else { //Collapsed - holder.postDateAndNumberExp.setVisibility(View.GONE); - holder.postDateAndNumberExp.setAlpha(0.0f); - holder.postDateAndNumberExp.setTranslationY(holder.postDateAndNumberExp.getHeight()); - - holder.username.setMaxLines(1); - holder.username.setEllipsize(TextUtils.TruncateAt.END); - - holder.subject.setTextColor(Color.parseColor("#757575")); - holder.subject.setMaxLines(1); - holder.subject.setEllipsize(TextUtils.TruncateAt.END); - } - //noinspection PointlessBooleanExpression,ConstantConditions - if (!BaseActivity.getSessionManager().isLoggedIn() || true) //Hide it until reply is implemented - holder.quoteToggle.setVisibility(View.GONE); - else { - if (viewProperties.get(position)[isQuoteButtonChecked]) - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked); - else - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked); - //Sets graphics behavior - holder.quoteToggle.setOnClickListener(new View.OnClickListener() { + //Also when post is clicked + holder.post.setOnTouchListener(new CustomTouchListener(holder.post, holder.cardView)); + } else if (currentHolder instanceof QuickReplyViewHolder) { + final QuickReplyViewHolder holder = (QuickReplyViewHolder) currentHolder; + if (firstTime) { + //Build quotes + String quotes = ""; + for (int quotePosition : toQuoteList) { + //Date postDate = new Date(); + Log.d(TAG, postsList.get(quotePosition).getPostDate()); + if (postsList.get(quotePosition).getPostIndex() != 0) { + quotes += "[quote author=" + postsList.get(quotePosition).getAuthor() + + " link=topic=68525.msg" + postsList.get(quotePosition).getPostIndex() + + "#msg" + postsList.get(quotePosition).getPostIndex() + + " date=" + "1000" + + "\n" + postsList.get(quotePosition).getContent() + + "\n" + "[/quote]" + "\n"; + } + } + holder.quickReply.setText(quotes); + } + holder.submitButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); - if (tmp[isQuoteButtonChecked]) { - if (toQuoteList.contains(currentPost.getPostNumber())) { - toQuoteList.remove(toQuoteList.indexOf(currentPost.getPostNumber())); - } else - Report.i(TAG, "An error occurred while trying to exclude post from" + - "toQuoteList, post wasn't there!"); - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked); - } else { - toQuoteList.add(currentPost.getPostNumber()); - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked); - } - tmp[isQuoteButtonChecked] = !tmp[isQuoteButtonChecked]; - viewProperties.set(holder.getAdapterPosition(), tmp); + if (holder.quickReply.getText().toString().isEmpty()) return; + holder.submitButton.setEnabled(false); + replyTask.execute(holder.quickReply.getText().toString()); } }); } - //Card expand/collapse when card is touched - holder.cardView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - //Change post's viewProperties accordingly - boolean[] tmp = viewProperties.get(holder.getAdapterPosition()); - tmp[isPostDateAndNumberVisibile] = !tmp[isPostDateAndNumberVisibile]; - viewProperties.set(holder.getAdapterPosition(), tmp); - - TopicAnimations.animatePostExtraInfoVisibility(holder.postDateAndNumberExp - , holder.username, holder.subject - , Color.parseColor("#FFFFFF") - , Color.parseColor("#757575")); - } - }); - //Also when post is clicked - holder.post.setOnTouchListener(new CustomTouchListener(holder.post, holder.cardView)); } void customNotifyDataSetChanged(TopicActivity.TopicTask topicTask) { @@ -452,6 +445,68 @@ class TopicAdapter extends RecyclerView.Adapter { return postsList.size(); } + /** + * Custom {@link RecyclerView.ViewHolder} implementation + */ + private class PostViewHolder extends RecyclerView.ViewHolder { + final CardView cardView; + final LinearLayout cardChildLinear; + final FrameLayout postDateAndNumberExp; + final TextView postDate, postNum, username, subject; + final ImageView thumbnail; + final public WebView post; + final ImageButton quoteToggle; + final RelativeLayout header; + final LinearLayout userExtraInfo; + final View bodyFooterDivider; + final LinearLayout postFooter; + + final TextView specialRank, rank, gender, numberOfPosts, personalText, stars; + + PostViewHolder(View view) { + super(view); + //Initializes layout's graphic elements + //Standard stuff + cardView = (CardView) view.findViewById(R.id.card_view); + cardChildLinear = (LinearLayout) view.findViewById(R.id.card_child_linear); + 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 = (ImageView) 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); + post.setBackgroundColor(Color.argb(1, 255, 255, 255)); + quoteToggle = (ImageButton) view.findViewById(R.id.toggle_quote_button); + bodyFooterDivider = view.findViewById(R.id.body_footer_divider); + postFooter = (LinearLayout) view.findViewById(R.id.post_footer); + + //User's extra info + 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 = (TextView) view.findViewById(R.id.stars); + } + } + + /** + * Custom {@link RecyclerView.ViewHolder} implementation + */ + private static class QuickReplyViewHolder extends RecyclerView.ViewHolder { + final EditText quickReply; + final AppCompatImageButton submitButton; + + QuickReplyViewHolder(View quickReply) { + super(quickReply); + this.quickReply = (EditText) quickReply.findViewById(R.id.quick_reply_text); + submitButton = (AppCompatImageButton) quickReply.findViewById(R.id.quick_reply_submit); + } + } + /** * This class is a gesture detector for WebViews. It handles post's clicks, long clicks and * touch and drag. @@ -592,6 +647,7 @@ class TopicAdapter extends RecyclerView.Adapter { //Method always returns true as no url should be loaded in the WebViews return true; } + } /** diff --git a/app/src/main/res/layout/activity_topic_post_row.xml b/app/src/main/res/layout/activity_topic_post_row.xml index 6c56547e..13e53227 100644 --- a/app/src/main/res/layout/activity_topic_post_row.xml +++ b/app/src/main/res/layout/activity_topic_post_row.xml @@ -1,12 +1,13 @@ - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dffad4fe..b1d04389 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,6 +44,8 @@ Page next last + Quick reply… + Submit Username