From ee8d0383489a76fac7fafac0c2bfca56af9f7e25 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 16 Sep 2018 12:56:35 +0300 Subject: [PATCH 01/16] create poll in model --- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 85 +++++++++++++++++++ .../main/java/gr/thmmy/mthmmy/model/Post.java | 2 +- .../java/gr/thmmy/mthmmy/model/TopicItem.java | 4 + 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/model/Poll.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java new file mode 100644 index 00000000..49fbba8b --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -0,0 +1,85 @@ +package gr.thmmy.mthmmy.model; + +import java.text.DecimalFormat; + +public class Poll { + private final String question; + private Entry[] entries; + private int availableVoteCount; + private String pollFormUrl, sc; + + public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc) { + this.question = question; + this.entries = entries; + this.availableVoteCount = availableVoteCount; + this.pollFormUrl = pollFormUrl; + this.sc = sc; + } + + public String getQuestion() { + return question; + } + + public Entry[] getEntries() { + return entries; + } + + public int getAvailableVoteCount() { + return availableVoteCount; + } + + public String getPollFormUrl() { + return pollFormUrl; + } + + public String getSc() { + return sc; + } + + public int totalVotes() { + int sum = 0; + for (Entry entry : entries) { + sum += entry.votes; + } + return sum; + } + + public String getVotePercentage(int index) { + DecimalFormat format = new DecimalFormat(".#"); + double percentage = 100 * ((double) entries[index].votes / (double) totalVotes()); + return format.format(percentage); + } + + static class Entry { + private final String entryName; + private int votes; + + public Entry(String entryName, int votes) { + this.entryName = entryName; + this.votes = votes; + } + + /** + * Constructor for entry with unknown number of votes + * + * @param entryName + * The name of the entry + */ + public Entry(String entryName) { + this.entryName = entryName; + votes = -1; + } + + public String getEntryName() { + return entryName; + } + + public int getVotes() { + return votes; + } + + public void setVotes(int votes) { + this.votes = votes; + } + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Post.java b/app/src/main/java/gr/thmmy/mthmmy/model/Post.java index 078386dc..1113ffbc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Post.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Post.java @@ -15,7 +15,7 @@ import java.util.Objects; * gender, number of posts, personal text and number of start to be described in addition to * previous fields.

*/ -public class Post { +public class Post extends TopicItem { public static final int TYPE_POST = 0; public static final int TYPE_QUICK_REPLY = 1; public static final int TYPE_EDIT = 2; diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java new file mode 100644 index 00000000..9d38a85e --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java @@ -0,0 +1,4 @@ +package gr.thmmy.mthmmy.model; + +public class TopicItem { +} From 290daf8eab592a6a1b68ca18dbfa9545b47b27f2 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 16 Sep 2018 13:02:45 +0300 Subject: [PATCH 02/16] add remove vote url --- app/src/main/java/gr/thmmy/mthmmy/model/Poll.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 49fbba8b..1b8e07a7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -6,14 +6,16 @@ public class Poll { private final String question; private Entry[] entries; private int availableVoteCount; - private String pollFormUrl, sc; + private String pollFormUrl, sc, removeVoteUrl; - public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc) { + public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc, + String removeVoteUrl) { this.question = question; this.entries = entries; this.availableVoteCount = availableVoteCount; this.pollFormUrl = pollFormUrl; this.sc = sc; + this.removeVoteUrl = removeVoteUrl; } public String getQuestion() { @@ -36,6 +38,10 @@ public class Poll { return sc; } + public String getRemoveVoteUrl() { + return removeVoteUrl; + } + public int totalVotes() { int sum = 0; for (Entry entry : entries) { From 7db9c43fd855d83b24a325c261581e77dac1edc8 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 18 Sep 2018 22:41:35 +0300 Subject: [PATCH 03/16] generify posts list to topic items --- .../activities/topic/TopicActivity.java | 38 +- .../mthmmy/activities/topic/TopicAdapter.java | 779 +++++++++--------- .../mthmmy/activities/topic/TopicParser.java | 5 +- .../activities/topic/tasks/TopicTask.java | 5 +- .../topic/tasks/TopicTaskResult.java | 7 +- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 4 +- .../java/gr/thmmy/mthmmy/model/TopicItem.java | 3 +- .../mthmmy/viewmodel/TopicViewModel.java | 13 +- 8 files changed, 434 insertions(+), 420 deletions(-) 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 953f7ad8..92154320 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 @@ -12,7 +12,6 @@ import android.os.Bundle; import android.os.Handler; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; -import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatDelegate; @@ -50,6 +49,7 @@ import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; @@ -85,7 +85,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo /** * Holds a list of this topic's posts */ - private ArrayList postsList; + private ArrayList topicItems; //Reply related private FloatingActionButton replyFAB; //Topic's pages related @@ -170,7 +170,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo progressBar = findViewById(R.id.progressBar); emojiKeyboard = findViewById(R.id.emoji_keyboard); - postsList = new ArrayList<>(); + topicItems = new ArrayList<>(); recyclerView = findViewById(R.id.topic_recycler_view); recyclerView.setHasFixedSize(true); @@ -179,7 +179,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo getApplicationContext(), topicPageUrl); recyclerView.setLayoutManager(layoutManager); - topicAdapter = new TopicAdapter(this, postsList); + topicAdapter = new TopicAdapter(this, topicItems); recyclerView.setAdapter(topicAdapter); replyFAB = findViewById(R.id.topic_fab); @@ -280,15 +280,15 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } return; } else if (viewModel.isWritingReply()) { - postsList.remove(postsList.size() - 1); - topicAdapter.notifyItemRemoved(postsList.size()); + topicItems.remove(topicItems.size() - 1); + topicAdapter.notifyItemRemoved(topicItems.size()); topicAdapter.setBackButtonHidden(); viewModel.setWritingReply(false); replyFAB.show(); bottomNavBar.setVisibility(View.VISIBLE); return; } else if (viewModel.isEditingPost()) { - postsList.get(viewModel.getPostBeingEditedPosition()).setPostType(Post.TYPE_POST); + ((Post) topicItems.get(viewModel.getPostBeingEditedPosition())).setPostType(Post.TYPE_POST); topicAdapter.notifyItemChanged(viewModel.getPostBeingEditedPosition()); topicAdapter.setBackButtonHidden(); viewModel.setEditingPost(false); @@ -538,7 +538,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo replyFAB.show(); bottomNavBar.setVisibility(View.VISIBLE); viewModel.setWritingReply(false); - if ((postsList.get(postsList.size() - 1).getPostNumber() + 1) % 15 == 0) { + if ((((Post) topicItems.get(topicItems.size() - 1)).getPostNumber() + 1) % 15 == 0) { Timber.i("Reply was posted in new page. Switching to last page."); viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + "." + 2147483647); } else { @@ -547,8 +547,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } else { Timber.w("Post reply unsuccessful"); Toast.makeText(getBaseContext(), "Post failed!", Toast.LENGTH_SHORT).show(); - recyclerView.getChildAt(postsList.size() - 1).setAlpha(1); - recyclerView.getChildAt(postsList.size() - 1).setEnabled(true); + recyclerView.getChildAt(topicItems.size() - 1).setAlpha(1); + recyclerView.getChildAt(topicItems.size() - 1).setEnabled(true); } } }); @@ -581,7 +581,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo if (result) { Timber.i("Post edit successful"); - postsList.get(position).setPostType(Post.TYPE_POST); + ((Post) topicItems.get(position)).setPostType(Post.TYPE_POST); topicAdapter.notifyItemChanged(position); replyFAB.show(); bottomNavBar.setVisibility(View.VISIBLE); @@ -631,11 +631,11 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo else replyFAB.show(); }); - viewModel.getPostsList().observe(this, postList -> { + viewModel.getTopicItems().observe(this, postList -> { if (postList == null) progressBar.setVisibility(ProgressBar.VISIBLE); recyclerView.getRecycledViewPool().clear(); //Avoid inconsistency detected bug - postsList.clear(); - postsList.addAll(postList); + topicItems.clear(); + topicItems.addAll(postList); topicAdapter.notifyDataSetChanged(); }); /*viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> { @@ -652,7 +652,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo break; case NETWORK_ERROR: Timber.w("Network error on loaded page"); - if (viewModel.getPostsList().getValue() == null) { + if (viewModel.getTopicItems().getValue() == null) { // no page has been loaded yet. Give user the ability to refresh recyclerView.setVisibility(View.GONE); TextView errorTextview = findViewById(R.id.error_textview); @@ -710,9 +710,9 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo Timber.i("Prepare for reply successful"); //prepare for a reply viewModel.setWritingReply(true); - postsList.add(Post.newQuickReply()); - topicAdapter.notifyItemInserted(postsList.size()); - recyclerView.scrollToPosition(postsList.size() - 1); + topicItems.add(Post.newQuickReply()); + topicAdapter.notifyItemInserted(topicItems.size()); + recyclerView.scrollToPosition(topicItems.size() - 1); replyFAB.hide(); bottomNavBar.setVisibility(View.GONE); } else { @@ -725,7 +725,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo if (result != null && result.isSuccessful()) { Timber.i("Prepare for edit successful"); viewModel.setEditingPost(true); - postsList.get(result.getPosition()).setPostType(Post.TYPE_EDIT); + ((Post) topicItems.get(result.getPosition())).setPostType(Post.TYPE_EDIT); topicAdapter.notifyItemChanged(result.getPosition()); recyclerView.scrollToPosition(result.getPosition()); replyFAB.hide(); 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 bf9f3b52..509c13c1 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 @@ -46,9 +46,11 @@ import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.editorview.EditorView; import gr.thmmy.mthmmy.editorview.EmojiKeyboard; +import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyPage; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CircleTransform; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; @@ -76,16 +78,16 @@ class TopicAdapter extends RecyclerView.Adapter { private final Context context; private final OnPostFocusChangeListener postFocusListener; private final EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner; - private final List postsList; + private final List topicItems; private TopicViewModel viewModel; /** * @param context the context of the {@link RecyclerView} - * @param postsList List of {@link Post} objects to use + * @param topicItems List of {@link Post} objects to use */ - TopicAdapter(TopicActivity context, List postsList) { + TopicAdapter(TopicActivity context, List topicItems) { this.context = context; - this.postsList = postsList; + this.topicItems = topicItems; this.postFocusListener = context; this.emojiKeyboardOwner = context; @@ -96,7 +98,8 @@ class TopicAdapter extends RecyclerView.Adapter { @Override public int getItemViewType(int position) { - return postsList.get(position).getPostType(); + if (topicItems.get(position) instanceof Poll) return Poll.TYPE_POLL; + return ((Post) topicItems.get(position)).getPostType(); } @NonNull @@ -141,414 +144,418 @@ class TopicAdapter extends RecyclerView.Adapter { @Override public void onBindViewHolder(@NonNull 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_white_24dp, null)) - .placeholder(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, 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) - || (currentPost.getLastEdit() != null)) { - holder.bodyFooterDivider.setVisibility(View.VISIBLE); - holder.postFooter.removeAllViews(); - - if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { - int filesTextColor; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - filesTextColor = context.getResources().getColor(R.color.accent, null); - } else //noinspection deprecation - filesTextColor = context.getResources().getColor(R.color.accent); - - for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) { - final TextView attached = new TextView(context); - attached.setTextSize(10f); - attached.setClickable(true); - attached.setTypeface(Typeface.createFromAsset(context.getAssets() - , "fonts/fontawesome-webfont.ttf")); - attached.setText(faIconFromFilename(attachedFile.getFilename()) + " " - + attachedFile.getFilename() + attachedFile.getFileInfo()); - attached.setTextColor(filesTextColor); - attached.setPadding(0, 3, 0, 3); - - attached.setOnClickListener(view -> ((BaseActivity) context).downloadFile(attachedFile)); - - holder.postFooter.addView(attached); + if (currentHolder.getItemViewType() == Poll.TYPE_POLL) { + + } else { + Post currentPost = (Post) topicItems.get(position); + if (currentHolder instanceof PostViewHolder) { + 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_white_24dp, null)) + .placeholder(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, 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) + || (currentPost.getLastEdit() != null)) { + holder.bodyFooterDivider.setVisibility(View.VISIBLE); + holder.postFooter.removeAllViews(); + + if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { + int filesTextColor; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + filesTextColor = context.getResources().getColor(R.color.accent, null); + } else //noinspection deprecation + filesTextColor = context.getResources().getColor(R.color.accent); + + for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) { + final TextView attached = new TextView(context); + attached.setTextSize(10f); + attached.setClickable(true); + attached.setTypeface(Typeface.createFromAsset(context.getAssets() + , "fonts/fontawesome-webfont.ttf")); + attached.setText(faIconFromFilename(attachedFile.getFilename()) + " " + + attachedFile.getFilename() + attachedFile.getFileInfo()); + attached.setTextColor(filesTextColor); + attached.setPadding(0, 3, 0, 3); + + attached.setOnClickListener(view -> ((BaseActivity) context).downloadFile(attachedFile)); + + holder.postFooter.addView(attached); + } } + if (currentPost.getLastEdit() != null && currentPost.getLastEdit().length() > 0) { + int lastEditTextColor; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + lastEditTextColor = context.getResources().getColor(R.color.white, null); + } else //noinspection deprecation + lastEditTextColor = context.getResources().getColor(R.color.white); + + final TextView lastEdit = new TextView(context); + lastEdit.setTextSize(12f); + lastEdit.setText(currentPost.getLastEdit()); + lastEdit.setTextColor(lastEditTextColor); + lastEdit.setPadding(0, 3, 0, 3); + holder.postFooter.addView(lastEdit); + } + } else { + holder.bodyFooterDivider.setVisibility(View.GONE); + holder.postFooter.removeAllViews(); } - if (currentPost.getLastEdit() != null && currentPost.getLastEdit().length() > 0) { - int lastEditTextColor; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - lastEditTextColor = context.getResources().getColor(R.color.white, null); - } else //noinspection deprecation - lastEditTextColor = context.getResources().getColor(R.color.white); - - final TextView lastEdit = new TextView(context); - lastEdit.setTextSize(12f); - lastEdit.setText(currentPost.getLastEdit()); - lastEdit.setTextColor(lastEditTextColor); - lastEdit.setPadding(0, 3, 0, 3); - holder.postFooter.addView(lastEdit); - } - } else { - 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(); - } else { - mSpecialRank = null; - mRank = null; - mGender = null; - mNumberOfPosts = null; - mPersonalText = null; - mNumberOfStars = 0; - } - mUserColor = currentPost.getUserColor(); - - 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 (mUserColor != USER_COLOR_YELLOW) { - holder.username.setTextColor(mUserColor); - } else { - holder.username.setTextColor(USER_COLOR_WHITE); - } - if (mNumberOfStars > 0) { - holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets() - , "fonts/fontawesome-webfont.ttf")); - - String aStar = context.getResources().getString(R.string.fa_icon_star); - StringBuilder usersStars = new StringBuilder(); - for (int i = 0; i < mNumberOfStars; ++i) { - usersStars.append(aStar); - } - holder.stars.setText(usersStars.toString()); - holder.stars.setTextColor(mUserColor); - holder.stars.setVisibility(View.VISIBLE); - } else - holder.stars.setVisibility(View.GONE); - - if (currentPost.isUserMentionedInPost()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - holder.cardChildLinear.setBackground(context.getResources(). - getDrawable(R.drawable.mention_card, null)); - } else //noinspection deprecation - holder.cardChildLinear.setBackground(context.getResources(). - getDrawable(R.drawable.mention_card)); - } else if (mUserColor == TopicParser.USER_COLOR_PINK) { - //Special card for special member of the month! - 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() && viewModel.isUserExtraInfoVisible(holder.getAdapterPosition())) { - holder.userExtraInfo.setVisibility(View.VISIBLE); - holder.userExtraInfo.setAlpha(1.0f); - - 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 { - holder.userExtraInfo.setVisibility(View.GONE); - holder.userExtraInfo.setAlpha(0.0f); - - 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); - } - if (!currentPost.isDeleted()) { - //Sets graphics behavior - holder.thumbnail.setOnClickListener(view -> { - //Clicking the thumbnail opens user's profile - Intent intent = new Intent(context, ProfileActivity.class); - Bundle extras = new Bundle(); - extras.putString(BUNDLE_PROFILE_URL, currentPost.getProfileURL()); - if (currentPost.getThumbnailURL() == null) - extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); - else - extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, currentPost.getThumbnailURL()); - extras.putString(BUNDLE_PROFILE_USERNAME, currentPost.getAuthor()); - intent.putExtras(extras); - intent.setFlags(FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - }); - holder.header.setOnClickListener(v -> { - //Clicking the header makes it expand/collapse - viewModel.toggleUserInfo(holder.getAdapterPosition()); - TopicAnimations.animateUserExtraInfoVisibility(holder.username, - holder.subject, Color.parseColor("#FFFFFF"), - Color.parseColor("#757575"), holder.userExtraInfo); - }); - //Clicking the expanded part of a header (the extra info) makes it collapse - holder.userExtraInfo.setOnClickListener(v -> { - viewModel.hideUserInfo(holder.getAdapterPosition()); - TopicAnimations.animateUserExtraInfoVisibility(holder.username, - holder.subject, Color.parseColor("#FFFFFF"), - Color.parseColor("#757575"), (LinearLayout) v); - }); - } else { - holder.header.setOnClickListener(null); - holder.userExtraInfo.setOnClickListener(null); - } + String mSpecialRank, mRank, mGender, mNumberOfPosts, mPersonalText; + int mNumberOfStars, mUserColor; - holder.overflowButton.setOnClickListener(view -> { - //Inflates the popup menu content - LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - if (layoutInflater == null) { - return; + 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(); + } else { + mSpecialRank = null; + mRank = null; + mGender = null; + mNumberOfPosts = null; + mPersonalText = null; + mNumberOfStars = 0; } - View popUpContent = layoutInflater.inflate(R.layout.activity_topic_overflow_menu, null); - - //Creates the PopupWindow - final PopupWindow popUp = new PopupWindow(holder.overflowButton.getContext()); - popUp.setContentView(popUpContent); - popUp.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT); - popUp.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT); - popUp.setFocusable(true); - - TextView shareButton = popUpContent.findViewById(R.id.post_share_button); - Drawable shareStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_share_white_24dp); - shareButton.setCompoundDrawablesRelativeWithIntrinsicBounds(shareStartDrawable, null, null, null); - shareButton.setOnClickListener(v -> { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.setType("text/plain"); - sendIntent.putExtra(Intent.EXTRA_TEXT, currentPost.getPostURL()); - context.startActivity(Intent.createChooser(sendIntent, "Share via")); - popUp.dismiss(); - }); + mUserColor = currentPost.getUserColor(); + + 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 (mUserColor != USER_COLOR_YELLOW) { + holder.username.setTextColor(mUserColor); + } else { + holder.username.setTextColor(USER_COLOR_WHITE); + } + if (mNumberOfStars > 0) { + holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets() + , "fonts/fontawesome-webfont.ttf")); + + String aStar = context.getResources().getString(R.string.fa_icon_star); + StringBuilder usersStars = new StringBuilder(); + for (int i = 0; i < mNumberOfStars; ++i) { + usersStars.append(aStar); + } + holder.stars.setText(usersStars.toString()); + holder.stars.setTextColor(mUserColor); + holder.stars.setVisibility(View.VISIBLE); + } else + holder.stars.setVisibility(View.GONE); + + if (currentPost.isUserMentionedInPost()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + holder.cardChildLinear.setBackground(context.getResources(). + getDrawable(R.drawable.mention_card, null)); + } else //noinspection deprecation + holder.cardChildLinear.setBackground(context.getResources(). + getDrawable(R.drawable.mention_card)); + } else if (mUserColor == TopicParser.USER_COLOR_PINK) { + //Special card for special member of the month! + 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); - final TextView editPostButton = popUpContent.findViewById(R.id.edit_post); - Drawable editStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_edit_white_24dp); - editPostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(editStartDrawable, null, null, null); + //Avoid's view's visibility recycling + if (!currentPost.isDeleted() && viewModel.isUserExtraInfoVisible(holder.getAdapterPosition())) { + holder.userExtraInfo.setVisibility(View.VISIBLE); + holder.userExtraInfo.setAlpha(1.0f); - if (viewModel.isEditingPost() || currentPost.getPostEditURL() == null || currentPost.getPostEditURL().equals("")) { - editPostButton.setVisibility(View.GONE); + 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 { - editPostButton.setOnClickListener(v -> { - viewModel.prepareForEdit(position, postsList.get(position).getPostEditURL()); - popUp.dismiss(); - }); - } + holder.userExtraInfo.setVisibility(View.GONE); + holder.userExtraInfo.setAlpha(0.0f); - TextView deletePostButton = popUpContent.findViewById(R.id.delete_post); + holder.username.setMaxLines(1); + holder.username.setEllipsize(TextUtils.TruncateAt.END); - if (currentPost.getPostDeleteURL() == null || currentPost.getPostDeleteURL().equals("")) { - deletePostButton.setVisibility(View.GONE); + holder.subject.setTextColor(Color.parseColor("#757575")); + holder.subject.setMaxLines(1); + holder.subject.setEllipsize(TextUtils.TruncateAt.END); + } + if (!currentPost.isDeleted()) { + //Sets graphics behavior + holder.thumbnail.setOnClickListener(view -> { + //Clicking the thumbnail opens user's profile + Intent intent = new Intent(context, ProfileActivity.class); + Bundle extras = new Bundle(); + extras.putString(BUNDLE_PROFILE_URL, currentPost.getProfileURL()); + if (currentPost.getThumbnailURL() == null) + extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); + else + extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, currentPost.getThumbnailURL()); + extras.putString(BUNDLE_PROFILE_USERNAME, currentPost.getAuthor()); + intent.putExtras(extras); + intent.setFlags(FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + }); + holder.header.setOnClickListener(v -> { + //Clicking the header makes it expand/collapse + viewModel.toggleUserInfo(holder.getAdapterPosition()); + TopicAnimations.animateUserExtraInfoVisibility(holder.username, + holder.subject, Color.parseColor("#FFFFFF"), + Color.parseColor("#757575"), holder.userExtraInfo); + }); + //Clicking the expanded part of a header (the extra info) makes it collapse + holder.userExtraInfo.setOnClickListener(v -> { + viewModel.hideUserInfo(holder.getAdapterPosition()); + TopicAnimations.animateUserExtraInfoVisibility(holder.username, + holder.subject, Color.parseColor("#FFFFFF"), + Color.parseColor("#757575"), (LinearLayout) v); + }); } else { - Drawable deleteStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_delete_white_24dp); - deletePostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(deleteStartDrawable, null, null, null); - popUpContent.findViewById(R.id.delete_post).setOnClickListener(v -> { - new AlertDialog.Builder(holder.overflowButton.getContext()) - .setTitle("Delete post") - .setMessage("Do you really want to delete this post?") - .setIcon(android.R.drawable.ic_dialog_alert) - .setPositiveButton(android.R.string.yes, (dialog, whichButton) -> viewModel.deletePost(currentPost.getPostDeleteURL())) - .setNegativeButton(android.R.string.no, null).show(); + holder.header.setOnClickListener(null); + holder.userExtraInfo.setOnClickListener(null); + } + + holder.overflowButton.setOnClickListener(view -> { + //Inflates the popup menu content + LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + if (layoutInflater == null) { + return; + } + View popUpContent = layoutInflater.inflate(R.layout.activity_topic_overflow_menu, null); + + //Creates the PopupWindow + final PopupWindow popUp = new PopupWindow(holder.overflowButton.getContext()); + popUp.setContentView(popUpContent); + popUp.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT); + popUp.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT); + popUp.setFocusable(true); + + TextView shareButton = popUpContent.findViewById(R.id.post_share_button); + Drawable shareStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_share_white_24dp); + shareButton.setCompoundDrawablesRelativeWithIntrinsicBounds(shareStartDrawable, null, null, null); + shareButton.setOnClickListener(v -> { + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.setType("text/plain"); + sendIntent.putExtra(Intent.EXTRA_TEXT, currentPost.getPostURL()); + context.startActivity(Intent.createChooser(sendIntent, "Share via")); popUp.dismiss(); }); - } - //Displays the popup - popUp.showAsDropDown(holder.overflowButton); - }); + final TextView editPostButton = popUpContent.findViewById(R.id.edit_post); + Drawable editStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_edit_white_24dp); + editPostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(editStartDrawable, null, null, null); + + if (viewModel.isEditingPost() || currentPost.getPostEditURL() == null || currentPost.getPostEditURL().equals("")) { + editPostButton.setVisibility(View.GONE); + } else { + editPostButton.setOnClickListener(v -> { + viewModel.prepareForEdit(position, currentPost.getPostEditURL()); + popUp.dismiss(); + }); + } - //noinspection PointlessBooleanExpression,ConstantConditions - if (!BaseActivity.getSessionManager().isLoggedIn() || !viewModel.canReply()) { - holder.quoteToggle.setVisibility(View.GONE); - } else { - if (viewModel.getToQuoteList().contains(currentPost.getPostIndex())) - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked_accent_24dp); - else - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp); - //Sets graphics behavior - holder.quoteToggle.setOnClickListener(view -> { - viewModel.postIndexToggle(currentPost.getPostIndex()); + TextView deletePostButton = popUpContent.findViewById(R.id.delete_post); + + if (currentPost.getPostDeleteURL() == null || currentPost.getPostDeleteURL().equals("")) { + deletePostButton.setVisibility(View.GONE); + } else { + Drawable deleteStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_delete_white_24dp); + deletePostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(deleteStartDrawable, null, null, null); + popUpContent.findViewById(R.id.delete_post).setOnClickListener(v -> { + new AlertDialog.Builder(holder.overflowButton.getContext()) + .setTitle("Delete post") + .setMessage("Do you really want to delete this post?") + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(android.R.string.yes, (dialog, whichButton) -> viewModel.deletePost(currentPost.getPostDeleteURL())) + .setNegativeButton(android.R.string.no, null).show(); + popUp.dismiss(); + }); + } + + //Displays the popup + popUp.showAsDropDown(holder.overflowButton); + }); + + //noinspection PointlessBooleanExpression,ConstantConditions + if (!BaseActivity.getSessionManager().isLoggedIn() || !viewModel.canReply()) { + holder.quoteToggle.setVisibility(View.GONE); + } else { if (viewModel.getToQuoteList().contains(currentPost.getPostIndex())) holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked_accent_24dp); else holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp); - }); - } - } else if (currentHolder instanceof QuickReplyViewHolder) { - final QuickReplyViewHolder holder = (QuickReplyViewHolder) currentHolder; - - //noinspection ConstantConditions - Picasso.with(context) - .load(getSessionManager().getAvatarLink()) - .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) - .centerCrop() - .error(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .placeholder(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .transform(new CircleTransform()) - .into(holder.thumbnail); - holder.username.setText(getSessionManager().getUsername()); - holder.quickReplySubject.setText("Re: " + viewModel.getTopicTitle().getValue()); - holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); - holder.quickReplySubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - - holder.replyEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.replyEditor.updateEmojiKeyboardVisibility(); - holder.replyEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - InputConnection ic12 = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic12); - holder.replyEditor.updateEmojiKeyboardVisibility(); - }); - - holder.replyEditor.setText(viewModel.getBuildedQuotes()); - holder.replyEditor.setOnSubmitListener(view -> { - if (holder.quickReplySubject.getText().toString().isEmpty()) return; - if (holder.replyEditor.getText().toString().isEmpty()) { - holder.replyEditor.setError("Required"); - return; - } - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - holder.itemView.setAlpha(0.5f); - holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); - - viewModel.postReply(context, holder.quickReplySubject.getText().toString(), - holder.replyEditor.getText().toString()); - }); - holder.replyEditor.setOnClickListener(view -> holder.replyEditor.setError(null)); - - if (backPressHidden) { - holder.replyEditor.requestFocus(); - backPressHidden = false; - } - } else if (currentHolder instanceof EditMessageViewHolder) { - final EditMessageViewHolder holder = (EditMessageViewHolder) currentHolder; - - //noinspection ConstantConditions - Picasso.with(context) - .load(getSessionManager().getAvatarLink()) - .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) - .centerCrop() - .error(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .placeholder(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .transform(new CircleTransform()) - .into(holder.thumbnail); - holder.username.setText(getSessionManager().getUsername()); - holder.editSubject.setText(postsList.get(position).getSubject()); - holder.editSubject.setRawInputType(InputType.TYPE_CLASS_TEXT); - holder.editSubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - - holder.editEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.editEditor.updateEmojiKeyboardVisibility(); - holder.editEditor.setText(viewModel.getPostBeingEditedText()); - holder.editEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - if (hasFocus) { - InputConnection ic1 = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic1); - holder.editEditor.updateEmojiKeyboardVisibility(); + //Sets graphics behavior + holder.quoteToggle.setOnClickListener(view -> { + viewModel.postIndexToggle(currentPost.getPostIndex()); + if (viewModel.getToQuoteList().contains(currentPost.getPostIndex())) + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked_accent_24dp); + else + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp); + }); } - }); - holder.editEditor.setOnSubmitListener(view -> { - if (holder.editSubject.getText().toString().isEmpty()) return; - if (holder.editEditor.getText().toString().isEmpty()) { - holder.editEditor.setError("Required"); - return; + } else if (currentHolder instanceof QuickReplyViewHolder) { + final QuickReplyViewHolder holder = (QuickReplyViewHolder) currentHolder; + + //noinspection ConstantConditions + Picasso.with(context) + .load(getSessionManager().getAvatarLink()) + .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) + .centerCrop() + .error(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .placeholder(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .transform(new CircleTransform()) + .into(holder.thumbnail); + holder.username.setText(getSessionManager().getUsername()); + holder.quickReplySubject.setText("Re: " + viewModel.getTopicTitle().getValue()); + holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); + holder.quickReplySubject.setImeOptions(EditorInfo.IME_ACTION_DONE); + + holder.replyEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); + InputConnection ic = holder.replyEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); + holder.replyEditor.updateEmojiKeyboardVisibility(); + holder.replyEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { + InputConnection ic12 = holder.replyEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic12); + holder.replyEditor.updateEmojiKeyboardVisibility(); + }); + + holder.replyEditor.setText(viewModel.getBuildedQuotes()); + holder.replyEditor.setOnSubmitListener(view -> { + if (holder.quickReplySubject.getText().toString().isEmpty()) return; + if (holder.replyEditor.getText().toString().isEmpty()) { + holder.replyEditor.setError("Required"); + return; + } + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + holder.itemView.setAlpha(0.5f); + holder.itemView.setEnabled(false); + emojiKeyboardOwner.setEmojiKeyboardVisible(false); + + viewModel.postReply(context, holder.quickReplySubject.getText().toString(), + holder.replyEditor.getText().toString()); + }); + holder.replyEditor.setOnClickListener(view -> holder.replyEditor.setError(null)); + + if (backPressHidden) { + holder.replyEditor.requestFocus(); + backPressHidden = false; } - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - holder.itemView.setAlpha(0.5f); - holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); + } else if (currentHolder instanceof EditMessageViewHolder) { + final EditMessageViewHolder holder = (EditMessageViewHolder) currentHolder; + + //noinspection ConstantConditions + Picasso.with(context) + .load(getSessionManager().getAvatarLink()) + .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) + .centerCrop() + .error(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .placeholder(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .transform(new CircleTransform()) + .into(holder.thumbnail); + holder.username.setText(getSessionManager().getUsername()); + holder.editSubject.setText(currentPost.getSubject()); + holder.editSubject.setRawInputType(InputType.TYPE_CLASS_TEXT); + holder.editSubject.setImeOptions(EditorInfo.IME_ACTION_DONE); + + holder.editEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); + InputConnection ic = holder.editEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); + holder.editEditor.updateEmojiKeyboardVisibility(); + holder.editEditor.setText(viewModel.getPostBeingEditedText()); + holder.editEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { + if (hasFocus) { + InputConnection ic1 = holder.editEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic1); + holder.editEditor.updateEmojiKeyboardVisibility(); + } + }); + holder.editEditor.setOnSubmitListener(view -> { + if (holder.editSubject.getText().toString().isEmpty()) return; + if (holder.editEditor.getText().toString().isEmpty()) { + holder.editEditor.setError("Required"); + return; + } + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + holder.itemView.setAlpha(0.5f); + holder.itemView.setEnabled(false); + emojiKeyboardOwner.setEmojiKeyboardVisible(false); - viewModel.editPost(position, holder.editSubject.getText().toString(), holder.editEditor.getText().toString()); - }); + viewModel.editPost(position, holder.editSubject.getText().toString(), holder.editEditor.getText().toString()); + }); - if (backPressHidden) { - holder.editEditor.requestFocus(); - backPressHidden = false; + if (backPressHidden) { + holder.editEditor.requestFocus(); + backPressHidden = false; + } } } } @Override public int getItemCount() { - return postsList.size(); + return topicItems.size(); } /** @@ -680,8 +687,8 @@ class TopicAdapter extends RecyclerView.Adapter { if (tmpUrlSbstr.contains("msg")) tmpUrlSbstr = tmpUrlSbstr.substring(0, tmpUrlSbstr.indexOf("msg") - 1); int testAgainst = Integer.parseInt(tmpUrlSbstr); - for (int i = 0; i < postsList.size(); i++) { - if (postsList.get(i).getPostIndex() == testAgainst) { + for (int i = 0; i < topicItems.size(); i++) { + if (topicItems.get(i) instanceof Post && ((Post) topicItems.get(i)).getPostIndex() == testAgainst) { //same page Timber.e(Integer.toString(i)); postFocusListener.onPostFocusChange(i); 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 b0132a14..30878617 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 @@ -18,6 +18,7 @@ import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -146,10 +147,10 @@ public class TopicParser { * @return {@link ArrayList} of {@link Post}s * @see org.jsoup.Jsoup Jsoup */ - public static ArrayList parseTopic(Document topic, ParseHelpers.Language language) { + public static ArrayList parseTopic(Document topic, ParseHelpers.Language language) { //Method's variables final int NO_INDEX = -1; - ArrayList parsedPostsList = new ArrayList<>(); + ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; //Each row is a post diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java index 7c5e5d1f..fa4f9d2d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java @@ -13,6 +13,7 @@ import gr.thmmy.mthmmy.activities.topic.TopicParser; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import okhttp3.Request; import okhttp3.Response; @@ -92,14 +93,14 @@ public class TopicTask extends AsyncTask { //Finds number of pages int pageCount = TopicParser.parseTopicNumberOfPages(topic, currentPageIndex, language); - ArrayList newPostsList = TopicParser.parseTopic(topic, language); + ArrayList newPostsList = TopicParser.parseTopic(topic, language); int loadedPageTopicId = Integer.parseInt(ThmmyPage.getTopicId(newPageUrl)); //Finds the position of the focused message if present int focusedPostIndex = 0; for (int i = 0; i < newPostsList.size(); ++i) { - if (newPostsList.get(i).getPostIndex() == postFocus) { + if (newPostsList.get(i) instanceof Post && ((Post) newPostsList.get(i)).getPostIndex() == postFocus) { focusedPostIndex = i; break; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java index c713da1f..3a4080fb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java @@ -3,6 +3,7 @@ package gr.thmmy.mthmmy.activities.topic.tasks; import java.util.ArrayList; import gr.thmmy.mthmmy.model.Post; +import gr.thmmy.mthmmy.model.TopicItem; public class TopicTaskResult { private final TopicTask.ResultCode resultCode; @@ -16,7 +17,7 @@ public class TopicTaskResult { * This topic's reply url */ private final String replyPageUrl; - private final ArrayList newPostsList; + private final ArrayList newPostsList; /** * The topicId of the loaded page */ @@ -38,7 +39,7 @@ public class TopicTaskResult { private final String topicViewers; public TopicTaskResult(TopicTask.ResultCode resultCode, String topicTitle, - String replyPageUrl, ArrayList newPostsList, int loadedPageTopicId, + String replyPageUrl, ArrayList newPostsList, int loadedPageTopicId, int currentPageIndex, int pageCount, int focusedPostIndex, String topicTreeAndMods, String topicViewers) { this.resultCode = resultCode; @@ -65,7 +66,7 @@ public class TopicTaskResult { return replyPageUrl; } - public ArrayList getNewPostsList() { + public ArrayList getNewPostsList() { return newPostsList; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 1b8e07a7..85fa4c49 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -2,7 +2,9 @@ package gr.thmmy.mthmmy.model; import java.text.DecimalFormat; -public class Poll { +public class Poll extends TopicItem { + public static int TYPE_POLL = 3; + private final String question; private Entry[] entries; private int availableVoteCount; diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java index 9d38a85e..17a8c6ef 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java @@ -1,4 +1,5 @@ package gr.thmmy.mthmmy.model; -public class TopicItem { +public abstract class TopicItem { + } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 96cecf4a..66a80407 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -20,6 +20,7 @@ import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTaskResult; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.Post; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -65,7 +66,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa private MutableLiveData replyPageUrl = new MutableLiveData<>(); private MutableLiveData pageTopicId = new MutableLiveData<>(); private MutableLiveData topicTitle = new MutableLiveData<>(); - private MutableLiveData> postsList = new MutableLiveData<>(); + private MutableLiveData> topicItems = new MutableLiveData<>(); private MutableLiveData focusedPostIndex = new MutableLiveData<>(); private MutableLiveData topicTaskResultCode = new MutableLiveData<>(); private MutableLiveData topicTreeAndMods = new MutableLiveData<>(); @@ -193,7 +194,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa replyPageUrl.setValue(result.getReplyPageUrl()); topicTitle.setValue(result.getTopicTitle()); pageIndicatorIndex.setValue(result.getCurrentPageIndex()); - postsList.setValue(result.getNewPostsList()); + topicItems.setValue(result.getNewPostsList()); focusedPostIndex.setValue(result.getFocusedPostIndex()); isUserExtraInfoVisibile.clear(); for (int i = 0; i < result.getNewPostsList().size(); i++) { @@ -262,8 +263,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa return focusedPostIndex; } - public MutableLiveData> getPostsList() { - return postsList; + public MutableLiveData> getTopicItems() { + return topicItems; } public MutableLiveData getReplyPageUrl() { @@ -388,8 +389,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } public int postCount() { - if (postsList.getValue() == null) + if (topicItems.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); - return postsList.getValue().size(); + return topicItems.getValue().size(); } } From 8ec74335a67fdf5f38bef367d5130791d5b11685 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 19 Sep 2018 00:18:42 +0300 Subject: [PATCH 04/16] cover multiple selection poll --- .../mthmmy/activities/topic/TopicAdapter.java | 38 ++++++++++++++- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 37 ++++++++------- .../mthmmy/viewmodel/TopicViewModel.java | 12 +++++ .../main/res/layout/activity_topic_poll.xml | 46 +++++++++++++++++++ app/src/main/res/values/strings.xml | 3 ++ 5 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/layout/activity_topic_poll.xml 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 509c13c1..32ef244b 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 @@ -15,6 +15,7 @@ import android.support.annotation.NonNull; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.AlertDialog; import android.support.v7.content.res.AppCompatResources; +import android.support.v7.widget.AppCompatButton; import android.support.v7.widget.RecyclerView; import android.text.InputType; import android.text.TextUtils; @@ -27,6 +28,8 @@ import android.view.inputmethod.InputMethodManager; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; @@ -38,6 +41,7 @@ import android.widget.TextView; import com.squareup.picasso.Picasso; import java.util.List; +import java.util.Map; import java.util.Objects; import gr.thmmy.mthmmy.R; @@ -135,6 +139,10 @@ class TopicAdapter extends RecyclerView.Adapter { editPostEdittext.requestFocus(); return new EditMessageViewHolder(view); + } else if (viewType == Poll.TYPE_POLL) { + View view = LayoutInflater.from(parent.getContext()). + inflate(R.layout.activity_topic_edit_row, parent, false); + return new PollViewHolder(view); } else { throw new IllegalArgumentException("Unknown view type"); } @@ -145,7 +153,18 @@ class TopicAdapter extends RecyclerView.Adapter { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder currentHolder, final int position) { if (currentHolder.getItemViewType() == Poll.TYPE_POLL) { - + Poll poll = (Poll) topicItems.get(position); + Poll.Entry[] entries = poll.getEntries(); + PollViewHolder holder = (PollViewHolder) currentHolder; + holder.question.setText(poll.getQuestion()); + if (poll.getAvailableVoteCount() > 1) { + for (int i = 0; i < entries.length; i++) { + CheckBox checkBox = new CheckBox(context); + checkBox.setText(entries[i].getEntryName()); + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> + viewModel.onVoteCheckboxClicked(holder.optionsLayout.indexOfChild(buttonView), isChecked)); + } + } } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { @@ -644,6 +663,23 @@ class TopicAdapter extends RecyclerView.Adapter { } } + static class PollViewHolder extends RecyclerView.ViewHolder { + final TextView question, errorTooManySelected; + final LinearLayout optionsLayout; + final AppCompatButton submitButton; + final AppCompatButton removeVotesButton; + + public PollViewHolder(View itemView) { + super(itemView); + + question = itemView.findViewById(R.id.question_textview); + optionsLayout = itemView.findViewById(R.id.options_layout); + submitButton = itemView.findViewById(R.id.submit_button); + removeVotesButton = itemView.findViewById(R.id.remove_vote_button); + errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); + } + } + /** * 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. diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 85fa4c49..1d1b54bc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -3,21 +3,36 @@ package gr.thmmy.mthmmy.model; import java.text.DecimalFormat; public class Poll extends TopicItem { - public static int TYPE_POLL = 3; + public static final int TYPE_POLL = 3; private final String question; private Entry[] entries; private int availableVoteCount; - private String pollFormUrl, sc, removeVoteUrl; + private String pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl; public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc, - String removeVoteUrl) { + String removeVoteUrl, String showVoteResultsUrl) { this.question = question; this.entries = entries; this.availableVoteCount = availableVoteCount; this.pollFormUrl = pollFormUrl; this.sc = sc; this.removeVoteUrl = removeVoteUrl; + this.showVoteResultsUrl = showVoteResultsUrl; + } + + public int totalVotes() { + int sum = 0; + for (Entry entry : entries) { + sum += entry.votes; + } + return sum; + } + + public String getVotePercentage(int index) { + DecimalFormat format = new DecimalFormat(".#"); + double percentage = 100 * ((double) entries[index].votes / (double) totalVotes()); + return format.format(percentage); } public String getQuestion() { @@ -44,21 +59,11 @@ public class Poll extends TopicItem { return removeVoteUrl; } - public int totalVotes() { - int sum = 0; - for (Entry entry : entries) { - sum += entry.votes; - } - return sum; - } - - public String getVotePercentage(int index) { - DecimalFormat format = new DecimalFormat(".#"); - double percentage = 100 * ((double) entries[index].votes / (double) totalVotes()); - return format.format(percentage); + public String getShowVoteResultsUrl() { + return showVoteResultsUrl; } - static class Entry { + public static class Entry { private final String entryName; private int votes; diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 66a80407..1a4c5adc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -5,6 +5,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; +import android.view.View; +import android.widget.CheckBox; import java.util.ArrayList; @@ -44,6 +46,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa * holds the adapter position of the post being edited */ private int postBeingEditedPosition; + private ArrayList selectedVoteIndices; private TopicTask currentTopicTask; private PrepareForEditTask currentPrepareForEditTask; @@ -245,6 +248,15 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) performPageChange(); } + public void onVoteCheckboxClicked(int index, boolean checked) { + if (checked) { + selectedVoteIndices.add(index); + } else { + selectedVoteIndices.remove(index); + } + + } + // <-------------Just getters, setters and helper methods below here----------------> public MutableLiveData getTopicViewers() { diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml new file mode 100644 index 00000000..3c68a7db --- /dev/null +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + \ 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 c52cf546..d502d343 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,6 +59,9 @@ Network error retry This topic is either missing or off limits to you + Remove vote + Show results + You may only select %d options Username From a381bc8e3965117c6ebfad79d6cb942eb107edab Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 19 Sep 2018 10:06:11 +0300 Subject: [PATCH 05/16] cover single choice poll --- .../mthmmy/activities/topic/TopicAdapter.java | 27 +++++++++++++++---- .../mthmmy/viewmodel/TopicViewModel.java | 15 +++++------ .../main/res/layout/activity_topic_poll.xml | 7 +---- 3 files changed, 30 insertions(+), 19 deletions(-) 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 32ef244b..45df3c58 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 @@ -35,6 +35,8 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; +import android.widget.RadioButton; +import android.widget.RadioGroup; import android.widget.RelativeLayout; import android.widget.TextView; @@ -158,12 +160,27 @@ class TopicAdapter extends RecyclerView.Adapter { PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); if (poll.getAvailableVoteCount() > 1) { - for (int i = 0; i < entries.length; i++) { + LinearLayout optionsLayout = new LinearLayout(context); + optionsLayout.setOrientation(LinearLayout.HORIZONTAL); + for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); - checkBox.setText(entries[i].getEntryName()); + checkBox.setText(entry.getEntryName()); checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> - viewModel.onVoteCheckboxClicked(holder.optionsLayout.indexOfChild(buttonView), isChecked)); + viewModel.onVoteCheckboxClicked(optionsLayout.indexOfChild(buttonView), isChecked)); + optionsLayout.addView(checkBox); + } + holder.rootLayout.addView(optionsLayout, 1); + } else if (poll.getAvailableVoteCount() == 1) { + RadioGroup radioGroup = new RadioGroup(context); + for (int i = 0; i < entries.length; i++) { + RadioButton radioButton = new RadioButton(context); + radioButton.setText(entries[i].getEntryName()); + radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); + radioGroup.addView(radioButton); } + holder.rootLayout.addView(radioGroup, 1); + } else { + //Showing results } } else { Post currentPost = (Post) topicItems.get(position); @@ -665,7 +682,7 @@ class TopicAdapter extends RecyclerView.Adapter { static class PollViewHolder extends RecyclerView.ViewHolder { final TextView question, errorTooManySelected; - final LinearLayout optionsLayout; + final LinearLayout rootLayout; final AppCompatButton submitButton; final AppCompatButton removeVotesButton; @@ -673,7 +690,7 @@ class TopicAdapter extends RecyclerView.Adapter { super(itemView); question = itemView.findViewById(R.id.question_textview); - optionsLayout = itemView.findViewById(R.id.options_layout); + rootLayout = (LinearLayout) itemView; submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 1a4c5adc..18ae0ab5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -5,8 +5,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; -import android.view.View; -import android.widget.CheckBox; import java.util.ArrayList; @@ -46,7 +44,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa * holds the adapter position of the post being edited */ private int postBeingEditedPosition; - private ArrayList selectedVoteIndices; + private ArrayList selectedVoteIndices = new ArrayList<>(); private TopicTask currentTopicTask; private PrepareForEditTask currentPrepareForEditTask; @@ -249,12 +247,13 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } public void onVoteCheckboxClicked(int index, boolean checked) { - if (checked) { - selectedVoteIndices.add(index); - } else { - selectedVoteIndices.remove(index); - } + if (checked) selectedVoteIndices.add(index); + else selectedVoteIndices.remove(index); + } + public void onRadioButtonCLicked(int index) { + selectedVoteIndices.clear(); + selectedVoteIndices.add(index); } // <-------------Just getters, setters and helper methods below here----------------> diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 3c68a7db..96c55c96 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -1,5 +1,6 @@ - - Date: Wed, 19 Sep 2018 12:58:36 +0300 Subject: [PATCH 06/16] finish vote chart viewing --- .../mthmmy/activities/topic/TopicAdapter.java | 28 ++++++++++++++++--- .../main/res/layout/activity_topic_poll.xml | 5 ++++ 2 files changed, 29 insertions(+), 4 deletions(-) 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 45df3c58..9c0f73ea 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 @@ -29,7 +29,6 @@ import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.CheckBox; -import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; @@ -40,10 +39,18 @@ import android.widget.RadioGroup; import android.widget.RelativeLayout; import android.widget.TextView; +import com.github.mikephil.charting.charts.HorizontalBarChart; +import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.formatter.IAxisValueFormatter; +import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import com.squareup.picasso.Picasso; +import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Objects; import gr.thmmy.mthmmy.R; @@ -172,15 +179,26 @@ class TopicAdapter extends RecyclerView.Adapter { holder.rootLayout.addView(optionsLayout, 1); } else if (poll.getAvailableVoteCount() == 1) { RadioGroup radioGroup = new RadioGroup(context); - for (int i = 0; i < entries.length; i++) { + for (Poll.Entry entry : entries) { RadioButton radioButton = new RadioButton(context); - radioButton.setText(entries[i].getEntryName()); + radioButton.setText(entry.getEntryName()); radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); radioGroup.addView(radioButton); } holder.rootLayout.addView(radioGroup, 1); } else { //Showing results + ArrayList valuesToCompare = new ArrayList<>(); + for (int i = 0; i < entries.length; i++) { + valuesToCompare.add(new BarEntry(entries[i].getVotes(), i)); + } + BarDataSet data = new BarDataSet(valuesToCompare, "Vote Results"); + + YAxis yAxisLeft = holder.voteChart.getAxisLeft(); + yAxisLeft.setValueFormatter((value, axis) -> entries[(int) value].getEntryName()); + + BarData barData = new BarData(data); + holder.voteChart.setData(barData); } } else { Post currentPost = (Post) topicItems.get(position); @@ -685,6 +703,7 @@ class TopicAdapter extends RecyclerView.Adapter { final LinearLayout rootLayout; final AppCompatButton submitButton; final AppCompatButton removeVotesButton; + final HorizontalBarChart voteChart; public PollViewHolder(View itemView) { super(itemView); @@ -694,6 +713,7 @@ class TopicAdapter extends RecyclerView.Adapter { submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); + voteChart = itemView.findViewById(R.id.vote_chart); } } diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 96c55c96..2803d653 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -11,6 +11,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" /> + + Date: Wed, 19 Sep 2018 13:16:01 +0300 Subject: [PATCH 07/16] poll parsing init --- .../mthmmy/activities/topic/TopicParser.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 30878617..336e4613 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 @@ -16,6 +16,7 @@ import java.util.Objects; import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.TopicItem; @@ -150,6 +151,9 @@ public class TopicParser { public static ArrayList parseTopic(Document topic, ParseHelpers.Language language) { //Method's variables final int NO_INDEX = -1; + + Poll poll = findPoll(topic, language); + ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; @@ -469,6 +473,20 @@ public class TopicParser { return parsedPostsList; } + private static Poll findPoll(Document topic, ParseHelpers.Language language) { + Elements tables = topic.select("table"); + for (int i = 0; i < tables.size(); i++) { + try { + Element image = tables.get(i).child(0).child(0).child(0); + if (image.html().contains("Poll")) { + return new Poll(); + } else if (image.html().contains("Ψηφοφορία")) { + return new Poll(); + } + } catch (Exception ignored) { } + } + } + /** * Returns the color of a user according to user's rank on forum. * From 4f7d8ba017826548141b6199614ac2d90d1e7567 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Thu, 20 Sep 2018 13:29:57 +0300 Subject: [PATCH 08/16] finish poll parsing --- .../mthmmy/activities/topic/TopicParser.java | 73 +++++++++++++++++-- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 9 ++- 2 files changed, 73 insertions(+), 9 deletions(-) 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 336e4613..a23825c3 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 @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.regex.Matcher; import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; @@ -152,7 +153,7 @@ public class TopicParser { //Method's variables final int NO_INDEX = -1; - Poll poll = findPoll(topic, language); + Poll poll = findPoll(topic); ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; @@ -473,18 +474,76 @@ public class TopicParser { return parsedPostsList; } - private static Poll findPoll(Document topic, ParseHelpers.Language language) { + private static Poll findPoll(Document topic) { + Pattern integerPattern = Pattern.compile("[0-9]+"); Elements tables = topic.select("table"); for (int i = 0; i < tables.size(); i++) { try { Element image = tables.get(i).child(0).child(0).child(0); - if (image.html().contains("Poll")) { - return new Poll(); - } else if (image.html().contains("Ψηφοφορία")) { - return new Poll(); + if (image.html().contains("Poll") || image.html().contains("Ψηφοφορία")) { + // has poll in english + String question; + ArrayList entries = new ArrayList<>(); + int availableVoteCount = 0; + String pollFormUrl = null, sc = null, removeVoteUrl = null, showVoteResultsUrl = null, + showOptionsUrl = null; + + Element secondRow = tables.get(i).select("tr[class=windowbg]").first(); + Element secondColumn = secondRow.child(1); + String columnString = secondColumn.outerHtml(); + question = columnString.substring(columnString.indexOf('>'), columnString.indexOf('<', 2)).trim(); + + Element form = secondColumn.select("form").first(); + if (form != null) { + // english poll in vote mode + pollFormUrl = form.attr("action"); + + Elements formInputs = form.select("input"); + for (int j = 0; j < formInputs.size(); j++) { + if (formInputs.get(i).attr("name").equals("options[]")) { + entries.add(new Poll.Entry(formInputs.get(i).text())); + } else if (formInputs.get(i).attr("name").equals("sc")) { + sc = formInputs.get(i).attr("value"); + } + } + + Element promptColumn = form.child(0).child(0).child(0); + String prompt = promptColumn.text(); + Matcher integerMatcher = integerPattern.matcher(prompt); + availableVoteCount = Integer.parseInt(prompt.substring(integerMatcher.start(), integerMatcher.end())); + + Elements links = form.select("a"); + if (links != null && links.size() > 0) { + showVoteResultsUrl = links.first().attr("href"); + } + } else { + // english poll in results mode + Elements optionRows = secondColumn.child(0).select("table").first().children(); + for (int j = 0; j < optionRows.size(); j++) { + String optionName = optionRows.get(i).child(0).text(); + String voteCountDescription = optionRows.get(i).child(1).text(); + Matcher integerMatcher = integerPattern.matcher(voteCountDescription); + int voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), + integerMatcher.end())); + entries.add(new Poll.Entry(optionName, voteCount)); + } + + Elements links = secondColumn.select("a"); + if (links != null && links.size() > 0) { + if (links.first().text().equals("Remove Vote") || links.first().text().equals("Αφαίρεση ψήφου")) + removeVoteUrl = links.first().attr("href"); + else if (links.first().text().equals("Voting options") || links.first().text().equals("Επιλογές ψηφοφορίας")) + showOptionsUrl = links.first().attr("href"); + } + } + return new Poll(question, entries.toArray(new Poll.Entry[0]), availableVoteCount, + pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl, showOptionsUrl); } - } catch (Exception ignored) { } + } catch (Exception e) { + Timber.v(e, "Could not parse a poll"); + } } + return null; } /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 1d1b54bc..66c28a57 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -8,10 +8,10 @@ public class Poll extends TopicItem { private final String question; private Entry[] entries; private int availableVoteCount; - private String pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl; + private String pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl, showOptionsUrl; public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc, - String removeVoteUrl, String showVoteResultsUrl) { + String removeVoteUrl, String showVoteResultsUrl, String showOptionsUrl) { this.question = question; this.entries = entries; this.availableVoteCount = availableVoteCount; @@ -19,6 +19,7 @@ public class Poll extends TopicItem { this.sc = sc; this.removeVoteUrl = removeVoteUrl; this.showVoteResultsUrl = showVoteResultsUrl; + this.showOptionsUrl = showOptionsUrl; } public int totalVotes() { @@ -63,6 +64,10 @@ public class Poll extends TopicItem { return showVoteResultsUrl; } + public String getShowOptionsUrl() { + return showOptionsUrl; + } + public static class Entry { private final String entryName; private int votes; From cd6d4e07c8dcd2bfaefae365c9c40d5e4a0931bd Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Thu, 20 Sep 2018 13:57:57 +0300 Subject: [PATCH 09/16] fix parse mistakes in results mode --- .../mthmmy/activities/topic/TopicAdapter.java | 2 +- .../thmmy/mthmmy/activities/topic/TopicParser.java | 14 +++++++++----- app/src/main/res/layout/activity_topic_poll.xml | 6 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) 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 9c0f73ea..ad8ecb28 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 @@ -150,7 +150,7 @@ class TopicAdapter extends RecyclerView.Adapter { return new EditMessageViewHolder(view); } else if (viewType == Poll.TYPE_POLL) { View view = LayoutInflater.from(parent.getContext()). - inflate(R.layout.activity_topic_edit_row, parent, false); + inflate(R.layout.activity_topic_poll, parent, false); return new PollViewHolder(view); } else { throw new IllegalArgumentException("Unknown view type"); 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 a23825c3..ecef6034 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 @@ -153,9 +153,12 @@ public class TopicParser { //Method's variables final int NO_INDEX = -1; + ArrayList parsedPostsList = new ArrayList<>(); + Poll poll = findPoll(topic); + if (poll != null) + parsedPostsList.add(poll); - ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; //Each row is a post @@ -491,7 +494,7 @@ public class TopicParser { Element secondRow = tables.get(i).select("tr[class=windowbg]").first(); Element secondColumn = secondRow.child(1); String columnString = secondColumn.outerHtml(); - question = columnString.substring(columnString.indexOf('>'), columnString.indexOf('<', 2)).trim(); + question = columnString.substring(columnString.indexOf('>') + 1, columnString.indexOf('<', 2)).trim(); Element form = secondColumn.select("form").first(); if (form != null) { @@ -518,11 +521,12 @@ public class TopicParser { } } else { // english poll in results mode - Elements optionRows = secondColumn.child(0).select("table").first().children(); + Elements optionRows = secondColumn.child(0).child(0).select("table").first().child(0).children(); for (int j = 0; j < optionRows.size(); j++) { - String optionName = optionRows.get(i).child(0).text(); - String voteCountDescription = optionRows.get(i).child(1).text(); + String optionName = optionRows.get(j).child(0).text(); + String voteCountDescription = optionRows.get(j).child(1).text(); Matcher integerMatcher = integerPattern.matcher(voteCountDescription); + integerMatcher.find(); int voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), integerMatcher.end())); entries.add(new Poll.Entry(optionName, voteCount)); diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 2803d653..9953846f 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -4,7 +4,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content"> + android:layout_width="match_parent" + android:layout_height="250dp" /> Date: Fri, 21 Sep 2018 14:19:29 +0300 Subject: [PATCH 10/16] configure bar chart --- .../mthmmy/activities/topic/TopicAdapter.java | 32 +++++++-- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 5 ++ .../main/res/layout/activity_topic_poll.xml | 70 ++++++++++++------- 3 files changed, 75 insertions(+), 32 deletions(-) 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 ad8ecb28..ff766e62 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 @@ -40,13 +40,11 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.github.mikephil.charting.charts.HorizontalBarChart; -import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; -import com.github.mikephil.charting.formatter.IAxisValueFormatter; -import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import com.squareup.picasso.Picasso; import java.util.ArrayList; @@ -188,18 +186,36 @@ class TopicAdapter extends RecyclerView.Adapter { holder.rootLayout.addView(radioGroup, 1); } else { //Showing results - ArrayList valuesToCompare = new ArrayList<>(); + List valuesToCompare = new ArrayList<>(); for (int i = 0; i < entries.length; i++) { - valuesToCompare.add(new BarEntry(entries[i].getVotes(), i)); + valuesToCompare.add(new BarEntry(i, entries[i].getVotes())); } BarDataSet data = new BarDataSet(valuesToCompare, "Vote Results"); YAxis yAxisLeft = holder.voteChart.getAxisLeft(); - yAxisLeft.setValueFormatter((value, axis) -> entries[(int) value].getEntryName()); + yAxisLeft.setGranularity(1f); + YAxis yAxisRight = holder.voteChart.getAxisRight(); + yAxisRight.setEnabled(false); + + XAxis xAxis = holder.voteChart.getXAxis(); + xAxis.setValueFormatter((value, axis) -> entries[(int) value].getEntryName()); + xAxis.setTextColor(context.getResources().getColor(R.color.primary_text)); + xAxis.setGranularity(1f); + xAxis.setDrawGridLines(false); + xAxis.setDrawAxisLine(false); + xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); BarData barData = new BarData(data); + barData.setValueTextColor(context.getResources().getColor(R.color.accent)); holder.voteChart.setData(barData); + holder.voteChart.getLegend().setEnabled(false); + holder.voteChart.getDescription().setEnabled(false); + holder.voteChart.invalidate(); } + if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); + if (poll.getShowVoteResultsUrl() != null) holder.showPollResultsButton.setVisibility(View.VISIBLE); + if (poll.getShowOptionsUrl() != null) holder.showPollOptionsButton.setVisibility(View.VISIBLE); + if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { @@ -702,7 +718,7 @@ class TopicAdapter extends RecyclerView.Adapter { final TextView question, errorTooManySelected; final LinearLayout rootLayout; final AppCompatButton submitButton; - final AppCompatButton removeVotesButton; + final AppCompatButton removeVotesButton, showPollResultsButton, showPollOptionsButton; final HorizontalBarChart voteChart; public PollViewHolder(View itemView) { @@ -712,6 +728,8 @@ class TopicAdapter extends RecyclerView.Adapter { rootLayout = (LinearLayout) itemView; submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); + showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); + showPollOptionsButton = itemView.findViewById(R.id.show_poll_options_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); voteChart = itemView.findViewById(R.id.vote_chart); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 66c28a57..071557e9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -99,5 +99,10 @@ public class Poll extends TopicItem { public void setVotes(int votes) { this.votes = votes; } + + @Override + public String toString() { + return "Vote label:" + entryName + ", num votes:" + votes; + } } } diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 9953846f..5a63eb03 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -1,20 +1,21 @@ - + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:orientation="vertical"> + android:layout_height="wrap_content" + android:textColor="@color/primary_text" /> + android:layout_height="200dp" /> + android:visibility="gone" /> - + + - - - + + + + + + + + + + \ No newline at end of file From 3189cc93650064fa48ee305fdb8d8dbfbd7419a2 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sat, 22 Sep 2018 18:15:06 +0300 Subject: [PATCH 11/16] fix vote mode parsing in polls --- .../mthmmy/activities/topic/TopicAdapter.java | 5 +++- .../mthmmy/activities/topic/TopicParser.java | 26 +++++++++++++------ .../main/res/layout/activity_topic_poll.xml | 10 +++++-- 3 files changed, 30 insertions(+), 11 deletions(-) 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 ff766e62..43f019da 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 @@ -48,6 +48,7 @@ import com.github.mikephil.charting.data.BarEntry; import com.squareup.picasso.Picasso; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -166,10 +167,11 @@ class TopicAdapter extends RecyclerView.Adapter { holder.question.setText(poll.getQuestion()); if (poll.getAvailableVoteCount() > 1) { LinearLayout optionsLayout = new LinearLayout(context); - optionsLayout.setOrientation(LinearLayout.HORIZONTAL); + optionsLayout.setOrientation(LinearLayout.VERTICAL); for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); checkBox.setText(entry.getEntryName()); + checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> viewModel.onVoteCheckboxClicked(optionsLayout.indexOfChild(buttonView), isChecked)); optionsLayout.addView(checkBox); @@ -211,6 +213,7 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.getLegend().setEnabled(false); holder.voteChart.getDescription().setEnabled(false); holder.voteChart.invalidate(); + holder.voteChart.setVisibility(View.VISIBLE); } if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); if (poll.getShowVoteResultsUrl() != null) holder.showPollResultsButton.setVisibility(View.VISIBLE); 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 ecef6034..9c987964 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,6 +1,7 @@ package gr.thmmy.mthmmy.activities.topic; import android.graphics.Color; +import android.util.Log; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -500,20 +501,29 @@ public class TopicParser { if (form != null) { // english poll in vote mode pollFormUrl = form.attr("action"); - - Elements formInputs = form.select("input"); - for (int j = 0; j < formInputs.size(); j++) { - if (formInputs.get(i).attr("name").equals("options[]")) { - entries.add(new Poll.Entry(formInputs.get(i).text())); - } else if (formInputs.get(i).attr("name").equals("sc")) { - sc = formInputs.get(i).attr("value"); + sc = form.select("input[name=sc]").first().attr("value"); + + int rowIndex = -1; + Elements possibleEntriesRows = form.child(0).child(0).children(); + for (int j = 0; j < possibleEntriesRows.size(); j++) { + if (possibleEntriesRows.get(j).select("input").size() > 0) { + rowIndex = j; + break; } } + String entriesRaw = form.child(0).child(0).child(rowIndex).child(0).html(); + Matcher entryMatcher = Pattern.compile(">[^<]+ 0) { diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 5a63eb03..5c779274 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -15,7 +15,8 @@ + android:layout_height="200dp" + android:visibility="gone"/> + android:visibility="gone" + android:layout_marginEnd="16dp"/> @@ -53,6 +56,7 @@ android:id="@+id/show_poll_options_button" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="16dp" android:text="@string/show_vote_results_button" android:visibility="gone" /> @@ -60,7 +64,9 @@ android:id="@+id/submit_button" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="16dp" android:text="@string/submit" + android:textColor="@color/accent" android:visibility="gone"/> \ No newline at end of file From 4f8af3d539fd9035effcd25406eea916806338c5 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sat, 22 Sep 2018 22:15:02 +0300 Subject: [PATCH 12/16] style vote bar chart a lil bit --- .../gr/thmmy/mthmmy/activities/topic/TopicAdapter.java | 7 +++++++ app/src/main/res/layout/activity_topic_poll.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) 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 43f019da..987528cf 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 @@ -5,6 +5,7 @@ import android.annotation.TargetApi; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -19,6 +20,7 @@ import android.support.v7.widget.AppCompatButton; import android.support.v7.widget.RecyclerView; import android.text.InputType; import android.text.TextUtils; +import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -193,9 +195,11 @@ class TopicAdapter extends RecyclerView.Adapter { valuesToCompare.add(new BarEntry(i, entries[i].getVotes())); } BarDataSet data = new BarDataSet(valuesToCompare, "Vote Results"); + data.setColor(context.getResources().getColor(R.color.accent)); YAxis yAxisLeft = holder.voteChart.getAxisLeft(); yAxisLeft.setGranularity(1f); + yAxisLeft.setTextColor(context.getResources().getColor(R.color.primary_text)); YAxis yAxisRight = holder.voteChart.getAxisRight(); yAxisRight.setEnabled(false); @@ -212,6 +216,9 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.setData(barData); holder.voteChart.getLegend().setEnabled(false); holder.voteChart.getDescription().setEnabled(false); + int chartHeightdp = 10 + 30 * entries.length; + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + holder.voteChart.setMinimumHeight((int) (chartHeightdp * (metrics.densityDpi / 160f))); holder.voteChart.invalidate(); holder.voteChart.setVisibility(View.VISIBLE); } diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 5c779274..e23b57cf 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -15,7 +15,7 @@ Date: Sat, 22 Sep 2018 23:19:34 +0300 Subject: [PATCH 13/16] add functionality to show/ hide results --- .../mthmmy/activities/topic/TopicAdapter.java | 30 +++++++++++++++---- .../java/gr/thmmy/mthmmy/model/ThmmyPage.java | 10 ++++--- .../mthmmy/utils/parsing/ParseHelpers.java | 12 ++++---- .../mthmmy/viewmodel/TopicViewModel.java | 12 ++++++++ .../main/res/layout/activity_topic_poll.xml | 2 +- app/src/main/res/values/strings.xml | 3 +- 6 files changed, 51 insertions(+), 18 deletions(-) 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 987528cf..c6c7ae53 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 @@ -5,7 +5,6 @@ import android.annotation.TargetApi; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -50,7 +49,6 @@ import com.github.mikephil.charting.data.BarEntry; import com.squareup.picasso.Picasso; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -223,9 +221,29 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.setVisibility(View.VISIBLE); } if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); - if (poll.getShowVoteResultsUrl() != null) holder.showPollResultsButton.setVisibility(View.VISIBLE); - if (poll.getShowOptionsUrl() != null) holder.showPollOptionsButton.setVisibility(View.VISIBLE); + else holder.removeVotesButton.setVisibility(View.GONE); + if (poll.getShowVoteResultsUrl() != null) { + holder.showPollResultsButton.setOnClickListener(v -> { + if (holder.voteChart.getData() != null) { + // Chart has been already created, just make it visible + holder.voteChart.setVisibility(View.VISIBLE); + holder.showPollResultsButton.setVisibility(View.GONE); + holder.hidePollResultsButton.setVisibility(View.VISIBLE); + } else viewModel.viewVoteResults(); + }); + holder.showPollResultsButton.setVisibility(View.VISIBLE); + } else holder.showPollResultsButton.setVisibility(View.GONE); + + if (poll.getShowOptionsUrl() != null) { + holder.hidePollResultsButton.setOnClickListener(v -> { + holder.voteChart.setVisibility(View.GONE); + holder.hidePollResultsButton.setVisibility(View.GONE); + holder.showPollResultsButton.setVisibility(View.VISIBLE); + }); + holder.hidePollResultsButton.setVisibility(View.VISIBLE); + } else holder.hidePollResultsButton.setVisibility(View.GONE); if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); + else holder.submitButton.setVisibility(View.GONE); } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { @@ -728,7 +746,7 @@ class TopicAdapter extends RecyclerView.Adapter { final TextView question, errorTooManySelected; final LinearLayout rootLayout; final AppCompatButton submitButton; - final AppCompatButton removeVotesButton, showPollResultsButton, showPollOptionsButton; + final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton; final HorizontalBarChart voteChart; public PollViewHolder(View itemView) { @@ -739,7 +757,7 @@ class TopicAdapter extends RecyclerView.Adapter { submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); - showPollOptionsButton = itemView.findViewById(R.id.show_poll_options_button); + hidePollResultsButton = itemView.findViewById(R.id.show_poll_options_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); voteChart = itemView.findViewById(R.id.vote_chart); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java index bc451fd1..c500c50a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java @@ -3,6 +3,8 @@ package gr.thmmy.mthmmy.model; import android.net.Uri; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import timber.log.Timber; @@ -180,10 +182,10 @@ public class ThmmyPage { public static String getTopicId(String topicUrl) { if (resolvePageCategory(Uri.parse(topicUrl)) == PageCategory.TOPIC) { - String returnString = topicUrl.substring(topicUrl.indexOf("topic=") + 6); - if (returnString.contains(".")) - returnString = returnString.substring(0, returnString.indexOf(".")); - return returnString; + Matcher topicIdMatcher = Pattern.compile("topic=[0-9]+").matcher(topicUrl); + if (topicIdMatcher.find()) { + return topicUrl.substring(topicIdMatcher.start() + 6, topicIdMatcher.end()); + } else return null; } return null; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java index 0034ffc4..804c9e85 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java @@ -5,6 +5,8 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import timber.log.Timber; @@ -179,11 +181,9 @@ public class ParseHelpers { * @return the base URL of the given topic */ public static String getBaseURL(String topicURL) { - if (topicURL.substring(0, topicURL.lastIndexOf(".")).contains("topic=")) - return topicURL.substring(0, topicURL.lastIndexOf(".")); - else { - Timber.wtf(new ParseException("Could not parse base URL of topic")); - return ""; - } + Matcher baseUrlMatcher = Pattern.compile(".+topic=[0-9]+").matcher(topicURL); + if (baseUrlMatcher.find()) + return topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end()); + else return ""; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index a625f311..5bc1f894 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -106,6 +106,18 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } } + public void viewVoteResults() { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Viewing poll results"); + loadUrl(ParseHelpers.getBaseURL(topicUrl) + ";viewResults"); + } + + public void loadBaseUrl() { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Viewing poll results"); + loadUrl(ParseHelpers.getBaseURL(topicUrl)); + } + public void prepareForReply() { if (replyPageUrl.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index e23b57cf..fd4f1f5f 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -57,7 +57,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" - android:text="@string/show_vote_results_button" + android:text="@string/show_vote_options_button" android:visibility="gone" /> retry This topic is either missing or off limits to you Remove vote - Show results + show results You may only select %d options + hide results Username From 87e4e54f3c45499784cdb76e5297207d29df4994 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 23 Sep 2018 00:58:51 +0300 Subject: [PATCH 14/16] fix behaviour of show/hide results --- .../mthmmy/activities/topic/TopicAdapter.java | 34 +++++++------------ .../main/res/layout/activity_topic_poll.xml | 10 ++++-- 2 files changed, 20 insertions(+), 24 deletions(-) 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 c6c7ae53..d0682f1e 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 @@ -166,17 +166,14 @@ class TopicAdapter extends RecyclerView.Adapter { PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); if (poll.getAvailableVoteCount() > 1) { - LinearLayout optionsLayout = new LinearLayout(context); - optionsLayout.setOrientation(LinearLayout.VERTICAL); for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); checkBox.setText(entry.getEntryName()); checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); - checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> - viewModel.onVoteCheckboxClicked(optionsLayout.indexOfChild(buttonView), isChecked)); - optionsLayout.addView(checkBox); + holder.optionsLayout.addView(checkBox); } - holder.rootLayout.addView(optionsLayout, 1); + holder.voteChart.setVisibility(View.GONE); + holder.optionsLayout.setVisibility(View.VISIBLE); } else if (poll.getAvailableVoteCount() == 1) { RadioGroup radioGroup = new RadioGroup(context); for (Poll.Entry entry : entries) { @@ -185,9 +182,13 @@ class TopicAdapter extends RecyclerView.Adapter { radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); radioGroup.addView(radioButton); } - holder.rootLayout.addView(radioGroup, 1); + holder.optionsLayout.addView(radioGroup); + holder.voteChart.setVisibility(View.GONE); + holder.optionsLayout.setVisibility(View.VISIBLE); } else { //Showing results + holder.optionsLayout.removeAllViews(); + holder.optionsLayout.setVisibility(View.GONE); List valuesToCompare = new ArrayList<>(); for (int i = 0; i < entries.length; i++) { valuesToCompare.add(new BarEntry(i, entries[i].getVotes())); @@ -223,23 +224,12 @@ class TopicAdapter extends RecyclerView.Adapter { if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); else holder.removeVotesButton.setVisibility(View.GONE); if (poll.getShowVoteResultsUrl() != null) { - holder.showPollResultsButton.setOnClickListener(v -> { - if (holder.voteChart.getData() != null) { - // Chart has been already created, just make it visible - holder.voteChart.setVisibility(View.VISIBLE); - holder.showPollResultsButton.setVisibility(View.GONE); - holder.hidePollResultsButton.setVisibility(View.VISIBLE); - } else viewModel.viewVoteResults(); - }); + holder.showPollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowVoteResultsUrl())); holder.showPollResultsButton.setVisibility(View.VISIBLE); } else holder.showPollResultsButton.setVisibility(View.GONE); if (poll.getShowOptionsUrl() != null) { - holder.hidePollResultsButton.setOnClickListener(v -> { - holder.voteChart.setVisibility(View.GONE); - holder.hidePollResultsButton.setVisibility(View.GONE); - holder.showPollResultsButton.setVisibility(View.VISIBLE); - }); + holder.hidePollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowOptionsUrl())); holder.hidePollResultsButton.setVisibility(View.VISIBLE); } else holder.hidePollResultsButton.setVisibility(View.GONE); if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); @@ -744,7 +734,7 @@ class TopicAdapter extends RecyclerView.Adapter { static class PollViewHolder extends RecyclerView.ViewHolder { final TextView question, errorTooManySelected; - final LinearLayout rootLayout; + final LinearLayout optionsLayout; final AppCompatButton submitButton; final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton; final HorizontalBarChart voteChart; @@ -753,7 +743,7 @@ class TopicAdapter extends RecyclerView.Adapter { super(itemView); question = itemView.findViewById(R.id.question_textview); - rootLayout = (LinearLayout) itemView; + optionsLayout = itemView.findViewById(R.id.options_layout); submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index fd4f1f5f..84a7e275 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -1,6 +1,6 @@ - + + Date: Sun, 23 Sep 2018 14:45:09 +0300 Subject: [PATCH 15/16] finish submit/remove vote functionality --- .../activities/main/forum/ForumFragment.java | 8 +-- .../main/recent/RecentFragment.java | 8 +-- .../main/unread/UnreadFragment.java | 6 +- .../activities/topic/TopicActivity.java | 11 ++++ .../mthmmy/activities/topic/TopicAdapter.java | 24 ++++--- .../activities/topic/tasks/DeleteTask.java | 6 +- .../topic/tasks/SubmitVoteTask.java | 52 +++++++++++++++ .../thmmy/mthmmy/utils/ExternalAsyncTask.java | 62 +++++++++--------- .../gr/thmmy/mthmmy/utils/NetworkTask.java | 32 +++++----- .../mthmmy/utils/parsing/NewParseTask.java | 17 ++--- .../mthmmy/utils/parsing/ParseHelpers.java | 5 +- .../mthmmy/viewmodel/TopicViewModel.java | 63 ++++++++++++------- 12 files changed, 192 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java index ceb41e13..a85eca23 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java @@ -187,13 +187,13 @@ public class ForumFragment extends BaseFragment { private class ForumTask extends NewParseTask> { private HttpUrl forumUrl = SessionManager.forumUrl; //may change upon collapse/expand - public ForumTask(OnParseTaskStartedListener onParseTaskStartedListener, - OnParseTaskFinishedListener> onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public ForumTask(OnTaskStartedListener onTaskStartedListener, + OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected ArrayList parse(Document document) throws ParseException { + protected ArrayList parse(Document document, Response response) throws ParseException { Elements categoryBlocks = document.select(".tborder:not([style])>table[cellpadding=5]"); if (categoryBlocks.size() != 0) { ArrayList fetchedCategories = new ArrayList<>(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index 98ad7f69..65b0d315 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -157,13 +157,13 @@ public class RecentFragment extends BaseFragment { //---------------------------------------ASYNC TASK----------------------------------- private class RecentTask extends NewParseTask> { - public RecentTask(OnParseTaskStartedListener onParseTaskStartedListener, - OnParseTaskFinishedListener> onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public RecentTask(OnTaskStartedListener onTaskStartedListener, + OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected ArrayList parse(Document document) throws ParseException { + protected ArrayList parse(Document document, Response response) throws ParseException { ArrayList fetchedRecent = new ArrayList<>(); Elements recent = document.select("#block8 :first-child div"); if (!recent.isEmpty()) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 0681c4af..0747b4bf 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -185,12 +185,12 @@ public class UnreadFragment extends BaseFragment { private class UnreadTask extends NewParseTask { - UnreadTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + UnreadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected Void parse(Document document) throws ParseException { + protected Void parse(Document document, Response response) throws ParseException { Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); if (!unread.isEmpty()) { //topicSummaries.clear(); 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 b6201e9c..4a997e49 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 @@ -50,8 +50,10 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; +import gr.thmmy.mthmmy.utils.ExternalAsyncTask; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; @@ -598,6 +600,15 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo progressBar.setVisibility(ProgressBar.GONE); } }); + viewModel.setVoteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); + viewModel.setVoteTaskFinishedListener((resultCode, data) -> { + if (resultCode == NetworkResultCodes.SUCCESSFUL) + Toast.makeText(this, "success", Toast.LENGTH_LONG).show(); + else + Toast.makeText(this, "fail", Toast.LENGTH_LONG).show(); + progressBar.setVisibility(View.GONE); + viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); + }); // observe the chages in data viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> { if (pageIndicatorIndex == null) return; 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 d0682f1e..b7e1ccef 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 @@ -165,6 +165,7 @@ class TopicAdapter extends RecyclerView.Adapter { Poll.Entry[] entries = poll.getEntries(); PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); + holder.optionsLayout.removeAllViews(); if (poll.getAvailableVoteCount() > 1) { for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); @@ -176,10 +177,11 @@ class TopicAdapter extends RecyclerView.Adapter { holder.optionsLayout.setVisibility(View.VISIBLE); } else if (poll.getAvailableVoteCount() == 1) { RadioGroup radioGroup = new RadioGroup(context); - for (Poll.Entry entry : entries) { + for (int i = 0; i < entries.length; i++) { RadioButton radioButton = new RadioButton(context); - radioButton.setText(entry.getEntryName()); - radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); + radioButton.setId(i); + radioButton.setText(entries[i].getEntryName()); + radioButton.setTextColor(context.getResources().getColor(R.color.primary_text)); radioGroup.addView(radioButton); } holder.optionsLayout.addView(radioGroup); @@ -187,7 +189,6 @@ class TopicAdapter extends RecyclerView.Adapter { holder.optionsLayout.setVisibility(View.VISIBLE); } else { //Showing results - holder.optionsLayout.removeAllViews(); holder.optionsLayout.setVisibility(View.GONE); List valuesToCompare = new ArrayList<>(); for (int i = 0; i < entries.length; i++) { @@ -221,8 +222,13 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.invalidate(); holder.voteChart.setVisibility(View.VISIBLE); } - if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); - else holder.removeVotesButton.setVisibility(View.GONE); + if (poll.getRemoveVoteUrl() != null) { + holder.removeVotesButton.setOnClickListener(v -> { + viewModel.loadUrl(poll.getRemoveVoteUrl()); + viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); + }); + holder.removeVotesButton.setVisibility(View.VISIBLE); + } else holder.removeVotesButton.setVisibility(View.GONE); if (poll.getShowVoteResultsUrl() != null) { holder.showPollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowVoteResultsUrl())); holder.showPollResultsButton.setVisibility(View.VISIBLE); @@ -232,8 +238,10 @@ class TopicAdapter extends RecyclerView.Adapter { holder.hidePollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowOptionsUrl())); holder.hidePollResultsButton.setVisibility(View.VISIBLE); } else holder.hidePollResultsButton.setVisibility(View.GONE); - if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); - else holder.submitButton.setVisibility(View.GONE); + if (poll.getPollFormUrl() != null) { + holder.submitButton.setOnClickListener(v -> viewModel.submitVote(holder.optionsLayout)); + holder.submitButton.setVisibility(View.VISIBLE); + } else holder.submitButton.setVisibility(View.GONE); } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java index 41563ae5..b277d2bd 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java @@ -12,8 +12,8 @@ import okhttp3.Response; public class DeleteTask extends NetworkTask { - public DeleteTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public DeleteTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override @@ -28,7 +28,7 @@ public class DeleteTask extends NetworkTask { } @Override - protected Void performTask(Document document) { + protected Void performTask(Document document, Response response) { return null; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java new file mode 100644 index 00000000..886264d6 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java @@ -0,0 +1,52 @@ +package gr.thmmy.mthmmy.activities.topic.tasks; + +import org.jsoup.nodes.Document; + +import java.io.IOException; +import java.util.Arrays; + +import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import timber.log.Timber; + +public class SubmitVoteTask extends NetworkTask { + + private int[] votes; + + public SubmitVoteTask(int... votes) { + this.votes = votes; + } + + @Override + protected Response sendRequest(OkHttpClient client, String... input) throws IOException { + MultipartBody.Builder postBodyBuilder = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("sc", input[1]); + for (int vote : votes) { + postBodyBuilder.addFormDataPart("options[]", Integer.toString(vote)); + } + Timber.d("response" + Arrays.toString(votes)); + + Request voteRequest = new Request.Builder() + .url(input[0]) + .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(postBodyBuilder.build()) + .build(); + return client.newCall(voteRequest).execute(); + } + + @Override + protected Void performTask(Document document, Response response) { + return null; + } + + @Override + protected int getResultCode(Response response, Void data) { + Timber.d("response" + response); + return NetworkResultCodes.SUCCESSFUL; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java index 82b535b6..d20d29dc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java @@ -4,77 +4,77 @@ import android.os.AsyncTask; public abstract class ExternalAsyncTask extends AsyncTask { - protected OnParseTaskStartedListener onParseTaskStartedListener; - protected OnParseTaskCancelledListener onParseTaskCancelledListener; - protected OnParseTaskFinishedListener onParseTaskFinishedListener; + protected OnTaskStartedListener onTaskStartedListener; + protected OnTaskCancelledListener onTaskCancelledListener; + protected OnTaskFinishedListener onTaskFinishedListener; @Override protected void onPreExecute() { - if (onParseTaskStartedListener != null) - onParseTaskStartedListener.onParseStart(); + if (onTaskStartedListener != null) + onTaskStartedListener.onTaskStarted(); else super.onPreExecute(); } @Override protected void onCancelled() { - if (onParseTaskCancelledListener != null) - onParseTaskCancelledListener.onParseCancel(); + if (onTaskCancelledListener != null) + onTaskCancelledListener.onTaskCanceled(); else super.onCancelled(); } @Override protected void onCancelled(V v) { - if (onParseTaskCancelledListener != null) - onParseTaskCancelledListener.onParseCancel(); + if (onTaskCancelledListener != null) + onTaskCancelledListener.onTaskCanceled(); else super.onCancelled(); } @Override protected void onPostExecute(V v) { - if (onParseTaskFinishedListener != null) - onParseTaskFinishedListener.onParseFinish(v); + if (onTaskFinishedListener != null) + onTaskFinishedListener.onTaskFinished(v); else super.onPostExecute(v); } - public ExternalAsyncTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; - this.onParseTaskCancelledListener = onParseTaskCancelledListener; - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public ExternalAsyncTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, + OnTaskFinishedListener onTaskFinishedListener) { + this.onTaskStartedListener = onTaskStartedListener; + this.onTaskCancelledListener = onTaskCancelledListener; + this.onTaskFinishedListener = onTaskFinishedListener; } - public ExternalAsyncTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public ExternalAsyncTask(OnTaskStartedListener onTaskStartedListener, OnTaskFinishedListener onTaskFinishedListener) { + this.onTaskStartedListener = onTaskStartedListener; + this.onTaskFinishedListener = onTaskFinishedListener; } public ExternalAsyncTask() { } - public void setOnParseTaskStartedListener(OnParseTaskStartedListener onParseTaskStartedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; + public void setOnTaskStartedListener(OnTaskStartedListener onTaskStartedListener) { + this.onTaskStartedListener = onTaskStartedListener; } - public void setOnParseTaskCancelledListener(OnParseTaskCancelledListener onParseTaskCancelledListener) { - this.onParseTaskCancelledListener = onParseTaskCancelledListener; + public void setOnTaskCancelledListener(OnTaskCancelledListener onTaskCancelledListener) { + this.onTaskCancelledListener = onTaskCancelledListener; } - public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public void setOnTaskFinishedListener(OnTaskFinishedListener onTaskFinishedListener) { + this.onTaskFinishedListener = onTaskFinishedListener; } - public interface OnParseTaskStartedListener { - void onParseStart(); + public interface OnTaskStartedListener { + void onTaskStarted(); } - public interface OnParseTaskCancelledListener { - void onParseCancel(); + public interface OnTaskCancelledListener { + void onTaskCanceled(); } - public interface OnParseTaskFinishedListener { - void onParseFinish(V result); + public interface OnTaskFinishedListener { + void onTaskFinished(V result); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java index 6793120a..cb613f26 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java @@ -14,17 +14,17 @@ import timber.log.Timber; public abstract class NetworkTask extends ExternalAsyncTask> { - protected OnParseTaskFinishedListener onParseTaskFinishedListener; + protected OnNetworkTaskFinishedListener onNetworkTaskFinishedListener; - public NetworkTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskCancelledListener, null); - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public NetworkTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, + OnNetworkTaskFinishedListener onNetworkTaskFinishedListener) { + super(onTaskStartedListener, onTaskCancelledListener, null); + this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener; } - public NetworkTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, null); - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public NetworkTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onNetworkTaskFinishedListener) { + super(onTaskStartedListener, null); + this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener; } public NetworkTask() {} @@ -49,7 +49,7 @@ public abstract class NetworkTask extends ExternalAsyncTask return new Parcel<>(NetworkResultCodes.NETWORK_ERROR, null); } try { - T data = performTask(Jsoup.parse(responseBodyString)); + T data = performTask(Jsoup.parse(responseBodyString), response); int resultCode = getResultCode(response, data); return new Parcel<>(resultCode, data); } catch (ParseException pe) { @@ -63,8 +63,8 @@ public abstract class NetworkTask extends ExternalAsyncTask @Override protected void onPostExecute(Parcel tParcel) { - if (onParseTaskFinishedListener != null) - onParseTaskFinishedListener.onParseFinish(tParcel.getResultCode(), tParcel.getData()); + if (onNetworkTaskFinishedListener != null) + onNetworkTaskFinishedListener.onNetworkTaskFinished(tParcel.getResultCode(), tParcel.getData()); else super.onPostExecute(tParcel); } @@ -77,15 +77,15 @@ public abstract class NetworkTask extends ExternalAsyncTask return client.newCall(request).execute(); } - protected abstract T performTask(Document document); + protected abstract T performTask(Document document, Response response); protected abstract int getResultCode(Response response, T data); - public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public void setOnNetworkTaskFinishedListener(OnNetworkTaskFinishedListener onNetworkTaskFinishedListener) { + this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener; } - public interface OnParseTaskFinishedListener { - void onParseFinish(int resultCode, T data); + public interface OnNetworkTaskFinishedListener { + void onNetworkTaskFinished(int resultCode, T data); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index 51749f2a..def14c2f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -3,28 +3,29 @@ package gr.thmmy.mthmmy.utils.parsing; import org.jsoup.nodes.Document; import gr.thmmy.mthmmy.utils.NetworkTask; +import okhttp3.Response; public abstract class NewParseTask extends NetworkTask { - public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskCancelledListener, onParseTaskFinishedListener); + public NewParseTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, + OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onTaskCancelledListener, onParseTaskFinishedListener); } - public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public NewParseTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } public NewParseTask() {} @Override - protected final T performTask(Document document) { + protected final T performTask(Document document, Response response) { try { - return parse(document); + return parse(document, response); } catch (Exception e) { throw new ParseException("Parse failed.", e); } } - protected abstract T parse (Document document) throws ParseException; + protected abstract T parse (Document document, Response response) throws ParseException; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java index 804c9e85..52669582 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java @@ -181,9 +181,10 @@ public class ParseHelpers { * @return the base URL of the given topic */ public static String getBaseURL(String topicURL) { - Matcher baseUrlMatcher = Pattern.compile(".+topic=[0-9]+").matcher(topicURL); + String forumUrl = "https://www.thmmy.gr/smf/index.php?"; + Matcher baseUrlMatcher = Pattern.compile("topic=[0-9]+").matcher(topicURL); if (baseUrlMatcher.find()) - return topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end()); + return forumUrl + topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end()); else return ""; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 5bc1f894..540d4917 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -5,6 +5,9 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.RadioGroup; import java.util.ArrayList; @@ -16,12 +19,17 @@ import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReplyResult; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; +import gr.thmmy.mthmmy.activities.topic.tasks.SubmitVoteTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTaskResult; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.session.SessionManager; +import gr.thmmy.mthmmy.utils.ExternalAsyncTask; +import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -44,7 +52,6 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa * holds the adapter position of the post being edited */ private int postBeingEditedPosition; - private ArrayList selectedVoteIndices = new ArrayList<>(); private TopicTask currentTopicTask; private PrepareForEditTask currentPrepareForEditTask; @@ -52,12 +59,14 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa //callbacks for topic activity private TopicTask.TopicTaskObserver topicTaskObserver; - private DeleteTask.OnParseTaskStartedListener deleteTaskStartedListener; - private DeleteTask.OnParseTaskFinishedListener deleteTaskFinishedListener; + private ExternalAsyncTask.OnTaskStartedListener deleteTaskStartedListener; + private NetworkTask.OnNetworkTaskFinishedListener deleteTaskFinishedListener; private ReplyTask.ReplyTaskCallbacks replyFinishListener; private PrepareForEditTask.PrepareForEditCallbacks prepareForEditCallbacks; private EditTask.EditTaskCallbacks editTaskCallbacks; private PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks; + private ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener; + private NetworkTask.OnNetworkTaskFinishedListener voteTaskFinishedListener; /** * Holds the value (index) of the page to be requested when a user interaction with bottom @@ -106,16 +115,25 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } } - public void viewVoteResults() { - if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); - Timber.i("Viewing poll results"); - loadUrl(ParseHelpers.getBaseURL(topicUrl) + ";viewResults"); - } - - public void loadBaseUrl() { - if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); - Timber.i("Viewing poll results"); - loadUrl(ParseHelpers.getBaseURL(topicUrl)); + public void submitVote(LinearLayout optionsLayout) { + if (topicItems.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); + ArrayList votes = new ArrayList<>(); + if (optionsLayout.getChildAt(0) instanceof RadioGroup) { + RadioGroup optionsRadioGroup = (RadioGroup) optionsLayout.getChildAt(0); + votes.add(optionsRadioGroup.getCheckedRadioButtonId()); + } else if (optionsLayout.getChildAt(0) instanceof CheckBox) { + for (int i = 0; i < optionsLayout.getChildCount(); i++) { + if (((CheckBox) optionsLayout.getChildAt(i)).isChecked()) + votes.add(i); + } + } + int[] votesArray = new int[votes.size()]; + for (int i = 0; i < votes.size(); i++) votesArray[i] = votes.get(i); + Poll poll = (Poll) topicItems.getValue().get(0); + SubmitVoteTask submitVoteTask = new SubmitVoteTask(votesArray); + submitVoteTask.setOnTaskStartedListener(voteTaskStartedListener); + submitVoteTask.setOnNetworkTaskFinishedListener(voteTaskFinishedListener); + submitVoteTask.execute(poll.getPollFormUrl(), poll.getSc()); } public void prepareForReply() { @@ -259,17 +277,16 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) performPageChange(); } - public void onVoteCheckboxClicked(int index, boolean checked) { - if (checked) selectedVoteIndices.add(index); - else selectedVoteIndices.remove(index); - } + // <-------------Just getters, setters and helper methods below here----------------> + - public void onRadioButtonCLicked(int index) { - selectedVoteIndices.clear(); - selectedVoteIndices.add(index); + public void setVoteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener) { + this.voteTaskStartedListener = voteTaskStartedListener; } - // <-------------Just getters, setters and helper methods below here----------------> + public void setVoteTaskFinishedListener(NetworkTask.OnNetworkTaskFinishedListener voteTaskFinishedListener) { + this.voteTaskFinishedListener = voteTaskFinishedListener; + } public MutableLiveData getTopicViewers() { return topicViewers; @@ -339,11 +356,11 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } - public void setDeleteTaskStartedListener(DeleteTask.OnParseTaskStartedListener deleteTaskStartedListener) { + public void setDeleteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener deleteTaskStartedListener) { this.deleteTaskStartedListener = deleteTaskStartedListener; } - public void setDeleteTaskFinishedListener(DeleteTask.OnParseTaskFinishedListener deleteTaskFinishedListener) { + public void setDeleteTaskFinishedListener(NetworkTask.OnNetworkTaskFinishedListener deleteTaskFinishedListener) { this.deleteTaskFinishedListener = deleteTaskFinishedListener; } From 687e4a42f05da2ab90f272227b4a35faa5c08635 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Mon, 24 Sep 2018 13:12:57 +0300 Subject: [PATCH 16/16] polish poll tasks, set chart start at 0 --- .../activities/topic/TopicActivity.java | 30 +++++++++++---- .../mthmmy/activities/topic/TopicAdapter.java | 6 +-- .../topic/tasks/RemoveVoteTask.java | 20 ++++++++++ .../topic/tasks/SubmitVoteTask.java | 4 -- .../mthmmy/viewmodel/TopicViewModel.java | 38 ++++++++++++++++--- 5 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java 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 4a997e49..c21a5b05 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 @@ -50,7 +50,6 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; -import gr.thmmy.mthmmy.utils.ExternalAsyncTask; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.NetworkTask; @@ -423,7 +422,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) { autoIncrement = false; paginationEnabled(true); - viewModel.performPageChange(); + viewModel.loadPageIndicated(); } else if (rect != null && event.getAction() == MotionEvent.ACTION_MOVE) { if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { autoIncrement = false; @@ -467,7 +466,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) { autoDecrement = false; paginationEnabled(true); - viewModel.performPageChange(); + viewModel.loadPageIndicated(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (rect != null && !rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { @@ -602,12 +601,27 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo }); viewModel.setVoteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); viewModel.setVoteTaskFinishedListener((resultCode, data) -> { - if (resultCode == NetworkResultCodes.SUCCESSFUL) - Toast.makeText(this, "success", Toast.LENGTH_LONG).show(); - else - Toast.makeText(this, "fail", Toast.LENGTH_LONG).show(); progressBar.setVisibility(View.GONE); - viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); + if (resultCode == NetworkResultCodes.SUCCESSFUL) { + Timber.i("Vote sent"); + viewModel.resetPage(); + } + else { + Timber.w("Failed to send vote"); + Toast.makeText(this, "Failed to send vote", Toast.LENGTH_LONG).show(); + } + }); + viewModel.setRemoveVoteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); + viewModel.setRemoveVoteTaskFinishedListener((resultCode, data) -> { + progressBar.setVisibility(View.GONE); + if (resultCode == NetworkResultCodes.SUCCESSFUL) { + Timber.i("Vote removed"); + viewModel.resetPage(); + } + else { + Timber.w("Failed to remove vote"); + Toast.makeText(this, "Failed to remove vote", Toast.LENGTH_LONG).show(); + } }); // observe the chages in data viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> { 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 b7e1ccef..01759f34 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 @@ -200,6 +200,7 @@ class TopicAdapter extends RecyclerView.Adapter { YAxis yAxisLeft = holder.voteChart.getAxisLeft(); yAxisLeft.setGranularity(1f); yAxisLeft.setTextColor(context.getResources().getColor(R.color.primary_text)); + yAxisLeft.setAxisMinimum(0); YAxis yAxisRight = holder.voteChart.getAxisRight(); yAxisRight.setEnabled(false); @@ -223,10 +224,7 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.setVisibility(View.VISIBLE); } if (poll.getRemoveVoteUrl() != null) { - holder.removeVotesButton.setOnClickListener(v -> { - viewModel.loadUrl(poll.getRemoveVoteUrl()); - viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); - }); + holder.removeVotesButton.setOnClickListener(v -> viewModel.removeVote()); holder.removeVotesButton.setVisibility(View.VISIBLE); } else holder.removeVotesButton.setVisibility(View.GONE); if (poll.getShowVoteResultsUrl() != null) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java new file mode 100644 index 00000000..f94ae027 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java @@ -0,0 +1,20 @@ +package gr.thmmy.mthmmy.activities.topic.tasks; + +import org.jsoup.nodes.Document; + +import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; +import okhttp3.Response; + +public class RemoveVoteTask extends NetworkTask { + + @Override + protected Void performTask(Document document, Response response) { + return null; + } + + @Override + protected int getResultCode(Response response, Void data) { + return NetworkResultCodes.SUCCESSFUL; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java index 886264d6..ec3773f7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java @@ -3,7 +3,6 @@ package gr.thmmy.mthmmy.activities.topic.tasks; import org.jsoup.nodes.Document; import java.io.IOException; -import java.util.Arrays; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.NetworkTask; @@ -11,7 +10,6 @@ import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import timber.log.Timber; public class SubmitVoteTask extends NetworkTask { @@ -29,7 +27,6 @@ public class SubmitVoteTask extends NetworkTask { for (int vote : votes) { postBodyBuilder.addFormDataPart("options[]", Integer.toString(vote)); } - Timber.d("response" + Arrays.toString(votes)); Request voteRequest = new Request.Builder() .url(input[0]) @@ -46,7 +43,6 @@ public class SubmitVoteTask extends NetworkTask { @Override protected int getResultCode(Response response, Void data) { - Timber.d("response" + response); return NetworkResultCodes.SUCCESSFUL; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 540d4917..1175980a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -18,6 +18,7 @@ import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditResult; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReplyResult; +import gr.thmmy.mthmmy.activities.topic.tasks.RemoveVoteTask; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; import gr.thmmy.mthmmy.activities.topic.tasks.SubmitVoteTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; @@ -28,7 +29,6 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.ExternalAsyncTask; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -67,6 +67,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa private PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks; private ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener; private NetworkTask.OnNetworkTaskFinishedListener voteTaskFinishedListener; + private ExternalAsyncTask.OnTaskStartedListener removeVoteTaskStartedListener; + private NetworkTask.OnNetworkTaskFinishedListener removeVoteTaskFinishedListener; /** * Holds the value (index) of the page to be requested when a user interaction with bottom @@ -102,7 +104,17 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa loadUrl(topicUrl); } - public void performPageChange() { + /** + * In contrasto to {@link TopicViewModel#reloadPage()} this method gets rid of any arguements + * in the url before refreshing + */ + public void resetPage() { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Reseting page"); + loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + String.valueOf(currentPageIndex * 15)); + } + + public void loadPageIndicated() { if (pageIndicatorIndex.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); int pageRequested = pageIndicatorIndex.getValue() - 1; @@ -136,6 +148,14 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa submitVoteTask.execute(poll.getPollFormUrl(), poll.getSc()); } + public void removeVote() { + if (topicItems.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); + RemoveVoteTask removeVoteTask = new RemoveVoteTask(); + removeVoteTask.setOnTaskStartedListener(removeVoteTaskStartedListener); + removeVoteTask.setOnNetworkTaskFinishedListener(removeVoteTaskFinishedListener); + removeVoteTask.execute(((Poll) topicItems.getValue().get(0)).getRemoveVoteUrl()); + } + public void prepareForReply() { if (replyPageUrl.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); @@ -255,7 +275,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() + step); } else pageIndicatorIndex.setValue(pageCount); - if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) performPageChange(); + if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) loadPageIndicated(); } public void decrementPageRequestValue(int step, boolean changePage) { @@ -266,7 +286,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() - step); } else pageIndicatorIndex.setValue(1); - if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) performPageChange(); + if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) loadPageIndicated(); } public void setPageIndicatorIndex(int pageIndicatorIndex, boolean changePage) { @@ -274,12 +294,20 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa throw new NullPointerException("No page has been loaded yet!"); int oldIndicatorIndex = this.pageIndicatorIndex.getValue(); this.pageIndicatorIndex.setValue(pageIndicatorIndex); - if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) performPageChange(); + if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) loadPageIndicated(); } // <-------------Just getters, setters and helper methods below here----------------> + public void setRemoveVoteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener removeVoteTaskStartedListener) { + this.removeVoteTaskStartedListener = removeVoteTaskStartedListener; + } + + public void setRemoveVoteTaskFinishedListener(NetworkTask.OnNetworkTaskFinishedListener removeVoteTaskFinishedListener) { + this.removeVoteTaskFinishedListener = removeVoteTaskFinishedListener; + } + public void setVoteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener) { this.voteTaskStartedListener = voteTaskStartedListener; }