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 c21a5b05..51c7f594 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 @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.app.NotificationManager; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Rect; import android.net.Uri; @@ -36,6 +37,7 @@ import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; +import java.util.function.Consumer; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; @@ -44,6 +46,7 @@ import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Post; @@ -52,12 +55,12 @@ import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; 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; import timber.log.Timber; +import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; import static gr.thmmy.mthmmy.services.NotificationService.NEW_POST_TAG; /** @@ -517,7 +520,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } @Override - public void onReplyTaskFinished(boolean success) { + public void onReplyTaskFinished(Posting.REPLY_STATUS replyStatus) { View view = getCurrentFocus(); if (view != null) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); @@ -526,22 +529,49 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo progressBar.setVisibility(ProgressBar.GONE); - if (success) { - Timber.i("Post reply successful"); - replyFAB.show(); - bottomNavBar.setVisibility(View.VISIBLE); - viewModel.setWritingReply(false); - 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 { - viewModel.reloadPage(); - } - } else { - Timber.w("Post reply unsuccessful"); - Toast.makeText(getBaseContext(), "Post failed!", Toast.LENGTH_SHORT).show(); - recyclerView.getChildAt(topicItems.size() - 1).setAlpha(1); - recyclerView.getChildAt(topicItems.size() - 1).setEnabled(true); + switch (replyStatus) { + case SUCCESSFUL: + BaseApplication.getInstance().logFirebaseAnalyticsEvent("post_creation", null); + Timber.i("Post reply successful"); + replyFAB.show(); + bottomNavBar.setVisibility(View.VISIBLE); + viewModel.setWritingReply(false); + 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 { + viewModel.reloadPage(); + } + case NEW_REPLY_WHILE_POSTING: + Timber.i("New reply while writing a reply"); + TopicAdapter.QuickReplyViewHolder replyHolder = (TopicAdapter.QuickReplyViewHolder) + recyclerView.findViewHolderForAdapterPosition(topicItems.size() - 1); + String subject = replyHolder.quickReplySubject.getText().toString(); + String message = replyHolder.replyEditor.getText().toString(); + Runnable addReply = () -> { + viewModel.setWritingReply(true); + topicItems.add(Post.newQuickReply()); + topicAdapter.notifyItemInserted(topicItems.size()); + recyclerView.scrollToPosition(topicItems.size() - 1); + replyFAB.hide(); + bottomNavBar.setVisibility(View.GONE); + TopicAdapter.QuickReplyViewHolder newReplyHolder = (TopicAdapter.QuickReplyViewHolder) + recyclerView.findViewHolderForAdapterPosition(topicItems.size() - 1); + newReplyHolder.quickReplySubject.setText(subject); + newReplyHolder.replyEditor.setText(message); + AlertDialog.Builder builder = new AlertDialog.Builder(TopicActivity.this, + R.style.AppCompatAlertDialogStyleAccent); + builder.setMessage("A new reply was posted before you completed your new post." + + " Please review it and send your reply again") + .setNeutralButton(getString(R.string.ok), (dialog, which) -> dialog.dismiss()) + .show(); + }; + viewModel.reloadPageThen(addReply); + default: + Timber.w("Post reply unsuccessful"); + Toast.makeText(getBaseContext(), "Post failed!", Toast.LENGTH_SHORT).show(); + recyclerView.getChildAt(topicItems.size() - 1).setAlpha(1); + recyclerView.getChildAt(topicItems.size() - 1).setEnabled(true); } } }); 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 01759f34..13d50f9d 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,6 +166,7 @@ class TopicAdapter extends RecyclerView.Adapter { PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); holder.optionsLayout.removeAllViews(); + holder.errorTooManySelected.setVisibility(View.GONE); if (poll.getAvailableVoteCount() > 1) { for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); @@ -237,7 +238,13 @@ class TopicAdapter extends RecyclerView.Adapter { holder.hidePollResultsButton.setVisibility(View.VISIBLE); } else holder.hidePollResultsButton.setVisibility(View.GONE); if (poll.getPollFormUrl() != null) { - holder.submitButton.setOnClickListener(v -> viewModel.submitVote(holder.optionsLayout)); + holder.submitButton.setOnClickListener(v -> { + if (!viewModel.submitVote(holder.optionsLayout)) { + holder.errorTooManySelected.setText(context.getResources() + .getQuantityText(R.plurals.error_too_many_checked, poll.getAvailableVoteCount())); + holder.errorTooManySelected.setVisibility(View.VISIBLE); + } + }); holder.submitButton.setVisibility(View.VISIBLE); } else holder.submitButton.setVisibility(View.GONE); } else { 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 9c987964..b835472c 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 @@ -495,11 +495,12 @@ 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('>') + 1, columnString.indexOf('<', 2)).trim(); + question = columnString.substring(columnString.indexOf('>') + 1, columnString.indexOf('<', 2)) + .replace(" ", " ").trim(); Element form = secondColumn.select("form").first(); if (form != null) { - // english poll in vote mode + // poll in vote mode pollFormUrl = form.attr("action"); sc = form.select("input[name=sc]").first().attr("value"); @@ -530,7 +531,7 @@ public class TopicParser { showVoteResultsUrl = links.first().attr("href"); } } else { - // english poll in results mode + // poll in results mode 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(j).child(0).text(); @@ -539,7 +540,7 @@ public class TopicParser { integerMatcher.find(); int voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), integerMatcher.end())); - entries.add(new Poll.Entry(optionName, voteCount)); + entries.add(0, new Poll.Entry(optionName, voteCount)); } Elements links = secondColumn.select("a"); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java index 033316d2..dfbdbb7f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java @@ -4,6 +4,7 @@ import android.os.AsyncTask; import java.io.IOException; +import gr.thmmy.mthmmy.activities.topic.Posting; import gr.thmmy.mthmmy.base.BaseApplication; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; @@ -14,7 +15,7 @@ import timber.log.Timber; import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; -public class ReplyTask extends AsyncTask { +public class ReplyTask extends AsyncTask { private ReplyTaskCallbacks listener; private boolean includeAppSignature; @@ -29,7 +30,7 @@ public class ReplyTask extends AsyncTask { } @Override - protected Boolean doInBackground(String... args) { + protected Posting.REPLY_STATUS doInBackground(String... args) { final String sentFrommTHMMY = includeAppSignature ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i][/size][/right]" : ""; @@ -52,30 +53,20 @@ public class ReplyTask extends AsyncTask { OkHttpClient client = BaseApplication.getInstance().getClient(); client.newCall(post).execute(); Response response = client.newCall(post).execute(); - switch (replyStatus(response)) { - case SUCCESSFUL: - BaseApplication.getInstance().logFirebaseAnalyticsEvent("post_creation", null); - return true; - case NEW_REPLY_WHILE_POSTING: - //TODO this... - return true; - default: - Timber.e("Malformed post. Request string: %s", post.toString()); - return true; - } + return replyStatus(response); } catch (IOException e) { Timber.e(e, "Post failed."); - return false; + return Posting.REPLY_STATUS.OTHER_ERROR; } } @Override - protected void onPostExecute(Boolean result) { + protected void onPostExecute(Posting.REPLY_STATUS result) { listener.onReplyTaskFinished(result); } public interface ReplyTaskCallbacks { void onReplyTaskStarted(); - void onReplyTaskFinished(boolean result); + void onReplyTaskFinished(Posting.REPLY_STATUS result); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java index 95acec1b..14a63438 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java @@ -152,6 +152,7 @@ public class EmojiKeyboard extends LinearLayout { public void init(Context context, AttributeSet attrs) { LayoutInflater.from(context).inflate(R.layout.emoji_keyboard, this, true); setOrientation(VERTICAL); + setBackgroundColor(getResources().getColor(R.color.primary)); RecyclerView emojiRecyclerview = findViewById(R.id.emoji_recyclerview); emojiRecyclerview.setHasFixedSize(true); 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 1175980a..0e5997e0 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -104,6 +104,17 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa loadUrl(topicUrl); } + public void reloadPageThen(Runnable runnable) { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Reloading page"); + stopLoading(); + currentTopicTask = new TopicTask(topicTaskObserver, result -> { + TopicViewModel.this.onTopicTaskCompleted(result); + runnable.run(); + }); + currentTopicTask.execute(topicUrl); + } + /** * In contrasto to {@link TopicViewModel#reloadPage()} this method gets rid of any arguements * in the url before refreshing @@ -127,7 +138,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } } - public void submitVote(LinearLayout optionsLayout) { + public boolean 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) { @@ -142,10 +153,12 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa 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); + if (poll.getAvailableVoteCount() < votesArray.length) return false; SubmitVoteTask submitVoteTask = new SubmitVoteTask(votesArray); submitVoteTask.setOnTaskStartedListener(voteTaskStartedListener); submitVoteTask.setOnNetworkTaskFinishedListener(voteTaskFinishedListener); submitVoteTask.execute(poll.getPollFormUrl(), poll.getSc()); + return true; } public void removeVote() { diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 84a7e275..60b7c96d 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -28,7 +28,6 @@ android:id="@+id/error_too_many_checked" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/error_too_many_checked" android:textColor="@color/red" android:visibility="gone" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 071bb9dc..310c407f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,7 +61,10 @@ This topic is either missing or off limits to you Remove vote show results - You may only select %d options + + You may only select %d option + You may only select %d options + hide results