Display survey info && can cancel the response to a survey

This commit is contained in:
Pierre HUBERT 2018-09-06 19:01:30 +02:00
parent c66365b002
commit 79f2fa3c2d
17 changed files with 701 additions and 6 deletions

View File

@ -71,6 +71,23 @@ public class PostsList extends ArrayList<Post> {
}
/**
* Search a post by ID in the list
*
* Warning ! The post MUST be in the list else an exception will be thrown
*
* @param id The ID of the post to find
* @return Information about the post
*/
public Post find(int id) {
for (Post post : this){
if(post.getId() == id)
return post;
}
throw new AssertionError();
}
/**
* Get IDs of the related groups
*

View File

@ -0,0 +1,28 @@
package org.communiquons.android.comunic.client.data.arrays;
import org.communiquons.android.comunic.client.data.models.SurveyChoice;
import java.util.ArrayList;
/**
* Handles a list of SurveyChoicesList
*
* @author Pierre HUBERT
*/
public class SurveyChoicesList extends ArrayList<SurveyChoice> {
/**
* Find a choice specified by its ID in the list
*
* @param id The ID of the choice to find
* @return Matching choice
*/
public SurveyChoice find(int id) {
for(SurveyChoice choice : this)
if(choice.getChoiceID() == id)
return choice;
throw new AssertionError();
}
}

View File

@ -39,6 +39,11 @@ public enum PostTypes {
*/
COUNTDOWN,
/**
* Survey
*/
SURVEY,
/**
* Unknown type
*/

View File

@ -4,17 +4,17 @@ import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.communiquons.android.comunic.client.data.arrays.PostsList;
import org.communiquons.android.comunic.client.data.enums.PageType;
import org.communiquons.android.comunic.client.data.enums.PostTypes;
import org.communiquons.android.comunic.client.data.enums.PostUserAccess;
import org.communiquons.android.comunic.client.data.enums.PostVisibilityLevels;
import org.communiquons.android.comunic.client.data.models.APIFileRequest;
import org.communiquons.android.comunic.client.data.models.APIPostFile;
import org.communiquons.android.comunic.client.data.models.APIRequest;
import org.communiquons.android.comunic.client.data.models.APIResponse;
import org.communiquons.android.comunic.client.data.models.CreatePost;
import org.communiquons.android.comunic.client.data.enums.PageType;
import org.communiquons.android.comunic.client.data.models.Post;
import org.communiquons.android.comunic.client.data.enums.PostTypes;
import org.communiquons.android.comunic.client.data.enums.PostUserAccess;
import org.communiquons.android.comunic.client.data.enums.PostVisibilityLevels;
import org.communiquons.android.comunic.client.data.arrays.PostsList;
import org.communiquons.android.comunic.client.data.models.WebLink;
import org.json.JSONArray;
import org.json.JSONException;
@ -412,6 +412,10 @@ public class PostsHelper {
if(!json.isNull("time_end"))
post.setTime_end(json.getInt("time_end"));
//Get information about survey if required
if(post.getType() == PostTypes.SURVEY)
post.setSurvey(SurveyHelper.APIToSurvey(json.getJSONObject("data_survey")));
return post;
}
@ -469,6 +473,9 @@ public class PostsHelper {
case "countdown":
return PostTypes.COUNTDOWN;
case "survey":
return PostTypes.SURVEY;
default:
return PostTypes.UNKNOWN;

View File

@ -0,0 +1,83 @@
package org.communiquons.android.comunic.client.data.helpers;
import android.content.Context;
import org.communiquons.android.comunic.client.data.models.APIRequest;
import org.communiquons.android.comunic.client.data.models.APIResponse;
import org.communiquons.android.comunic.client.data.models.Survey;
import org.communiquons.android.comunic.client.data.models.SurveyChoice;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Iterator;
/**
* Survey helper
*
* @author Pierre HUBERT
*/
public class SurveyHelper extends BaseHelper {
public SurveyHelper(Context context) {
super(context);
}
/**
* Cancel the response to a survey
*
* @param postID The ID of the target post
* @return TRUE in case of success / FALSE else
*/
public boolean cancelResponse(int postID){
APIRequest request = new APIRequest(getContext(), "surveys/cancel_response");
request.addInt("postID", postID);
try {
return new APIRequestHelper().exec(request).getResponse_code() == 200;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Turn an API JSON object into a Survey
*
* @param object The object to parse
* @return Generated Survey
* @throws JSONException In case of failure
*/
public static Survey APIToSurvey(JSONObject object) throws JSONException {
Survey survey = new Survey();
survey.setId(object.getInt("ID"));
survey.setUserID(object.getInt("userID"));
survey.setPostID(object.getInt("postID"));
survey.setCreate_time(object.getInt("creation_time"));
survey.setQuestion(object.getString("question"));
survey.setUser_choice(object.getInt("user_choice"));
JSONObject choicesObject = object.getJSONObject("choices");
for (Iterator<String> it = choicesObject.keys(); it.hasNext(); ) {
String key = it.next();
survey.addChoice(APIToSurveyChoice(choicesObject.getJSONObject(key)));
}
return survey;
}
/**
* Turn an API JSON object into a SurveyChoice object
*
* @param object The object to convert
* @return Generated SurveyChoice object
* @throws JSONException in case of failure
*/
private static SurveyChoice APIToSurveyChoice(JSONObject object) throws JSONException {
SurveyChoice surveyChoice = new SurveyChoice();
surveyChoice.setChoiceID(object.getInt("choiceID"));
surveyChoice.setName(object.getString("name"));
surveyChoice.setResponses(object.getInt("responses"));
return surveyChoice;
}
}

View File

@ -52,6 +52,9 @@ public class Post {
//Countdown timer
private int time_end;
//Survey
private Survey survey;
//Set and get the ID of the post
public void setId(int id) {
@ -240,5 +243,17 @@ public class Post {
public void setTime_end(int time_end) {
this.time_end = time_end;
}
public Survey getSurvey() {
return survey;
}
public boolean hasSurvey(){
return this.survey != null;
}
public void setSurvey(Survey survey) {
this.survey = survey;
}
}

View File

@ -0,0 +1,88 @@
package org.communiquons.android.comunic.client.data.models;
import org.communiquons.android.comunic.client.data.arrays.SurveyChoicesList;
import java.util.ArrayList;
/**
* Base survey object
*
* @author Pierre HUBERT
*/
public class Survey {
//Private fields
private int id;
private int userID;
private int postID;
private int create_time;
private String question;
private int user_choice;
private SurveyChoicesList choices = new SurveyChoicesList();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID = userID;
}
public int getPostID() {
return postID;
}
public void setPostID(int postID) {
this.postID = postID;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public int getUser_choice() {
return user_choice;
}
public boolean hasUserResponded(){
return user_choice > 0;
}
public void setUser_choice(int user_choice) {
this.user_choice = user_choice;
}
public SurveyChoicesList getChoices() {
return choices;
}
public void addChoice(SurveyChoice choice){
if(this.choices == null)
this.choices = new SurveyChoicesList();
choices.add(choice);
}
public void setChoices(SurveyChoicesList choices) {
this.choices = choices;
}
}

View File

@ -0,0 +1,47 @@
package org.communiquons.android.comunic.client.data.models;
/**
* Survey choice base model
*
* @author Pierre HUBERT
*/
public class SurveyChoice {
//Private field
private int choiceID;
private String name;
private int responses;
public int getChoiceID() {
return choiceID;
}
public void setChoiceID(int choiceID) {
this.choiceID = choiceID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getResponses() {
return responses;
}
public void addOneResponse(){
responses++;
}
public void removeOneResponse(){
responses--;
}
public void setResponses(int responses) {
this.responses = responses;
}
}

View File

@ -30,6 +30,7 @@ import org.communiquons.android.comunic.client.ui.views.EnlargeableWebImageView;
import org.communiquons.android.comunic.client.ui.views.LikeButtonView;
import org.communiquons.android.comunic.client.ui.views.MovieView;
import org.communiquons.android.comunic.client.ui.views.PDFLinkButtonView;
import org.communiquons.android.comunic.client.ui.views.SurveyView;
import org.communiquons.android.comunic.client.ui.views.WebLinkView;
import org.communiquons.android.comunic.client.ui.views.WebUserAccountImage;
@ -58,6 +59,7 @@ public class PostsAdapter extends BaseRecyclerViewAdapter {
private static final int VIEW_TYPE_POST_PDF = 3;
private static final int VIEW_TYPE_POST_WEBLINK = 4;
private static final int VIEW_TYPE_POST_COUNTDOWN = 5;
private static final int VIEW_TYPE_POST_SURVEY = 6;
/**
* Posts list
@ -123,6 +125,9 @@ public class PostsAdapter extends BaseRecyclerViewAdapter {
case COUNTDOWN:
return VIEW_TYPE_POST_COUNTDOWN;
case SURVEY:
return VIEW_TYPE_POST_SURVEY;
case TEXT:
default:
return VIEW_TYPE_POST_TEXT;
@ -152,6 +157,9 @@ public class PostsAdapter extends BaseRecyclerViewAdapter {
case VIEW_TYPE_POST_COUNTDOWN:
return new CountdownPostHolder(view);
case VIEW_TYPE_POST_SURVEY:
return new SurveyPostHolder(view);
default:
return new TextPostHolder(view);
}
@ -510,4 +518,29 @@ public class PostsAdapter extends BaseRecyclerViewAdapter {
mCountDownView.setTime_end(getPost(position).getTime_end());
}
}
/**
* Survey post holder
*/
private class SurveyPostHolder extends TextPostHolder {
private SurveyView mSurveyView;
SurveyPostHolder(@NonNull View itemView) {
super(itemView);
mSurveyView = new SurveyView(getContext());
mSurveyView.setOnSurveyUpdateListener(mListener);
getAdditionalViewsLayout().addView(mSurveyView, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
}
@Override
void bind(int position) {
super.bind(position);
mSurveyView.setSurvey(getPost(position).getSurvey());
}
}
}

View File

@ -0,0 +1,21 @@
package org.communiquons.android.comunic.client.ui.asynctasks;
import android.content.Context;
import org.communiquons.android.comunic.client.data.helpers.SurveyHelper;
/**
* Cancel the response to a survey
*
* @author Pierre HUBERT
*/
public class CancelSurveyResponseTask extends SafeAsyncTask<Integer, Void, Boolean> {
public CancelSurveyResponseTask(Context context) {
super(context);
}
@Override
protected Boolean doInBackground(Integer... integers) {
return new SurveyHelper(getContext()).cancelResponse(integers[0]);
}
}

View File

@ -34,10 +34,14 @@ import org.communiquons.android.comunic.client.data.helpers.LikesHelper;
import org.communiquons.android.comunic.client.data.helpers.PostsHelper;
import org.communiquons.android.comunic.client.data.models.Comment;
import org.communiquons.android.comunic.client.data.models.Post;
import org.communiquons.android.comunic.client.data.models.Survey;
import org.communiquons.android.comunic.client.data.models.SurveyChoice;
import org.communiquons.android.comunic.client.data.models.UserInfo;
import org.communiquons.android.comunic.client.data.utils.AccountUtils;
import org.communiquons.android.comunic.client.data.utils.StringsUtils;
import org.communiquons.android.comunic.client.ui.adapters.PostsAdapter;
import org.communiquons.android.comunic.client.ui.asynctasks.CancelSurveyResponseTask;
import org.communiquons.android.comunic.client.ui.asynctasks.SafeAsyncTask;
import org.communiquons.android.comunic.client.ui.listeners.OnScrollChangeDetectListener;
import org.communiquons.android.comunic.client.ui.listeners.onPostUpdateListener;
import org.communiquons.android.comunic.client.ui.views.EditCommentContentView;
@ -913,4 +917,48 @@ public abstract class AbstractPostsListFragment extends AbstractFragment
return super.onContextItemSelected(item);
}
@Override
public void onCancelSurveyResponse(Survey survey) {
final int postID = survey.getPostID();
getTasksManager().unsetSpecificTasks(CancelSurveyResponseTask.class);
CancelSurveyResponseTask cancelSurveyResponseTask =
new CancelSurveyResponseTask(getActivity());
cancelSurveyResponseTask.setOnPostExecuteListener(new SafeAsyncTask.OnPostExecuteListener<Boolean>() {
@Override
public void OnPostExecute(Boolean success) {
delete_callback(postID, success);
}
});
cancelSurveyResponseTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, survey.getPostID());
getTasksManager().addTask(cancelSurveyResponseTask);
}
/**
* Delete survey callback
*
* @param postID The ID of the related post
* @param success TRUE in case of success / FALSE else
*/
private void delete_callback(int postID, boolean success){
//Check for failure
if(!success){
Toast.makeText(getActivity(), R.string.err_cancel_response, Toast.LENGTH_SHORT).show();
return;
}
Survey survey = getPostsList().find(postID).getSurvey();
survey.getChoices().find(survey.getUser_choice()).removeOneResponse();
survey.setUser_choice(0);
mPostsAdapter.notifyDataSetChanged();
}
@Override
public void onRespondToSurvey(Survey survey, int choiceID) {
}
}

View File

@ -0,0 +1,26 @@
package org.communiquons.android.comunic.client.ui.listeners;
import org.communiquons.android.comunic.client.data.models.Survey;
/**
* Actions done when there is the need to perform an update on a survey
*
* @author Pierre HUBERT
*/
public interface OnSurveyUpdateListener {
/**
* This method is called when the user requests to cancel the response to a survey
*
* @param survey The target survey
*/
void onCancelSurveyResponse(Survey survey);
/**
* This method is called when the user want to respond to survey
*
* @param survey The target survey
* @param choiceID Selected choice by the user
*/
void onRespondToSurvey(Survey survey, int choiceID);
}

View File

@ -12,7 +12,7 @@ import org.communiquons.android.comunic.client.ui.views.EditCommentContentView;
*
* @author Pierre HUBERT
*/
public interface onPostUpdateListener {
public interface onPostUpdateListener extends OnSurveyUpdateListener {
/**
* This method is called when a comment creation request is made

View File

@ -0,0 +1,158 @@
package org.communiquons.android.comunic.client.ui.views;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.models.Survey;
import org.communiquons.android.comunic.client.data.models.SurveyChoice;
import org.communiquons.android.comunic.client.ui.listeners.OnSurveyUpdateListener;
import org.communiquons.android.comunic.client.ui.utils.UiUtils;
public class SurveyView extends BaseFrameLayoutView implements View.OnClickListener {
/**
* Current survey
*/
private Survey mSurvey;
/**
* Update listener
*/
private OnSurveyUpdateListener mOnSurveyUpdateListener;
/**
* Views
*/
private TextView mQuestion;
private LinearLayout mChoicesList;
private ConstraintLayout mCancelSurveyResponseForm;
private TextView mSelectedChoiceView;
private Button mCancelButton;
private ConstraintLayout mSendResponseForm;
private Spinner mResponsesSpinner;
private Button mResponseButton;
public SurveyView(@NonNull Context context) {
this(context, null);
}
public SurveyView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SurveyView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
View view = inflate(getContext(), R.layout.view_survey, this);
mQuestion = view.findViewById(R.id.question);
mCancelSurveyResponseForm = view.findViewById(R.id.cancelSurveyResponseForm);
mChoicesList = view.findViewById(R.id.choicesTarget);
mSelectedChoiceView = view.findViewById(R.id.selectedChoiceView);
mCancelButton = view.findViewById(R.id.cancelButton);
mSendResponseForm = view.findViewById(R.id.sendResponseForm);
mResponsesSpinner = view.findViewById(R.id.responsesSpinner);
mResponseButton = view.findViewById(R.id.respondButton);
mCancelButton.setOnClickListener(this);
mResponseButton.setOnClickListener(this);
}
/**
* Set the survey updates listener
*
* @param onSurveyUpdateListener The new listener
*/
public void setOnSurveyUpdateListener(@Nullable OnSurveyUpdateListener onSurveyUpdateListener) {
this.mOnSurveyUpdateListener = onSurveyUpdateListener;
}
/**
* Change the current survey
*
* @param survey The new survey to display
*/
public void setSurvey(Survey survey){
this.mSurvey = survey;
mChoicesList.removeAllViews();
mQuestion.setText(survey.getQuestion());
//Process the list of choices
for(SurveyChoice choice : survey.getChoices()){
TextView textView = new TextView(getContext());
textView.setText(UiUtils.getString(getContext(), R.string.survey_choice,
choice.getResponses(), choice.getName()));
mChoicesList.addView(textView, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
mCancelSurveyResponseForm.setVisibility(survey.hasUserResponded() ?
View.VISIBLE : View.GONE);
mSendResponseForm.setVisibility(survey.hasUserResponded() ?
View.GONE : View.VISIBLE);
//Render the right part of the view
if (survey.hasUserResponded()) {
renderCancelResponseForm();
} else {
renderRespondForm();
}
}
/**
* Render cancel response form
*/
private void renderCancelResponseForm(){
//Display the choice of the user
mSelectedChoiceView.setText(UiUtils.getString(getContext(),
R.string.survey_your_choice,
mSurvey.getChoices().find(mSurvey.getUser_choice()).getName()));
}
/**
* Render respond form
*/
private void renderRespondForm(){
}
@Override
public void onClick(View v) {
//Cancel response to survey
if(v.equals(mCancelButton)){
if(mOnSurveyUpdateListener != null)
mOnSurveyUpdateListener.onCancelSurveyResponse(mSurvey);
}
//Respond to a survey
if(v.equals(mResponseButton)){
if(mOnSurveyUpdateListener != null)
mOnSurveyUpdateListener.onRespondToSurvey(mSurvey, -1);
//TODO : implement
}
}
}

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/choicesTarget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/question" />
<android.support.constraint.ConstraintLayout
android:id="@+id/cancelSurveyResponseForm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/choicesTarget">
<TextView
android:id="@+id/selectedChoiceView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/cancelButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Your choice: A response" />
<Button
android:id="@+id/cancelButton"
style="@style/Base.Widget.AppCompat.Button.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:backgroundTint="@color/holo_red_dark"
android:text="@string/action_cancel_response_survey"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
<android.support.constraint.ConstraintLayout
android:id="@+id/sendResponseForm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cancelSurveyResponseForm">
<Spinner
android:id="@+id/responsesSpinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/respondButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/respondButton"
style="@style/Base.Widget.AppCompat.Button.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:text="@string/action_send_survey_response"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="A survey question" />
</android.support.constraint.ConstraintLayout>

View File

@ -291,4 +291,6 @@
<string name="err_update_account_image_visibility">Une erreur a survenu lors de la mise à jour du niveau de visibilité de l\'image de compte !</string>
<string name="err_find_tag">Le tag spécifié n\'a pas été trouvé !</string>
<string name="err_groups_not_supported">Les groupes ne sont pas encore supportés sur l\'application Android…</string>
<string name="survey_choice">(%1$d) %2$s</string>
<string name="survey_your_choice">Votre choix : %1$s</string>
</resources>

View File

@ -290,4 +290,9 @@
<string name="err_update_account_image_visibility">Could not update account image visibility level!</string>
<string name="err_find_tag">Could not find requested tag!</string>
<string name="err_groups_not_supported">Groups are not supported yet by the Android application!</string>
<string name="survey_choice">(%1$d) %2$s</string>
<string name="survey_your_choice">Your choice : %1$s</string>
<string name="action_cancel_response_survey">Cancel</string>
<string name="action_send_survey_response">Respond</string>
<string name="err_cancel_response">Could not cancel your response to the survey!</string>
</resources>