package de.westnordost.streetcomplete.quests; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.UiThread; import android.support.design.widget.BottomSheetBehavior; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.TextView; import java.util.ArrayList; import java.util.List; import de.westnordost.osmapi.map.data.OsmElement; import de.westnordost.streetcomplete.R; import de.westnordost.streetcomplete.data.QuestGroup; import de.westnordost.streetcomplete.view.dialogs.AlertDialogBuilder; /** Abstract base class for any dialog with which the user answers a specific quest(ion) */ public abstract class AbstractQuestAnswerFragment extends Fragment { public static final String ELEMENT = "element"; private String titleText; private TextView title; private ViewGroup content; private LinearLayout bottomSheet; private QuestAnswerComponent questAnswerComponent; private LinearLayout buttonPanel; protected Button buttonOtherAnswers; private ImageButton buttonClose; public AbstractQuestAnswerFragment() { super(); questAnswerComponent = new QuestAnswerComponent(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.quest_answer_fragment, container, false); bottomSheet = (LinearLayout) view.findViewById(R.id.bottomSheet); bottomSheet.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { // not immediately because this is called during layout change (view.getTop() == 0) final Handler handler = new Handler(); handler.post(new Runnable() { @Override public void run() { updateCloseButtonVisibility(); } }); } }); title = (TextView) view.findViewById(R.id.title); updateTitle(); buttonPanel = (LinearLayout) view.findViewById(R.id.buttonPanel); buttonOtherAnswers = (Button) buttonPanel.findViewById(R.id.buttonOtherAnswers); buttonClose = (ImageButton) view.findViewById(R.id.close_btn); buttonClose.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getActivity().onBackPressed(); } }); BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { updateCloseButtonVisibility(); } }); final List<Integer> otherAnswers = getOtherAnswerResourceIds(); if(otherAnswers.isEmpty()) { buttonOtherAnswers.setVisibility(View.INVISIBLE); } else if(otherAnswers.size() == 1) { buttonOtherAnswers.setText(otherAnswers.get(0)); buttonOtherAnswers.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onClickOtherAnswer(otherAnswers.get(0)); } }); } else { buttonOtherAnswers.setText(R.string.quest_generic_otherAnswers); buttonOtherAnswers.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { PopupMenu popup = new PopupMenu(getActivity(), buttonOtherAnswers); for(int i = 0; i<otherAnswers.size(); ++i) { int otherAnswer = otherAnswers.get(i); popup.getMenu().add(Menu.NONE, otherAnswer, otherAnswers.size()-i, otherAnswer); } popup.show(); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { return onClickOtherAnswer(item.getItemId()); } }); } }); } content = (ViewGroup) view.findViewById(R.id.content); return view; } private void updateCloseButtonVisibility() { // this is called asynchronously. It may happen that the activity is already gone when this // method is finally called if(getActivity() == null) return; int toolbarHeight = getActivity().findViewById(R.id.toolbar).getHeight(); boolean coversToolbar = bottomSheet.getTop() < toolbarHeight; buttonClose.setVisibility(coversToolbar ? View.VISIBLE : View.GONE); } @Override public void onCreate(Bundle inState) { super.onCreate(inState); questAnswerComponent.onCreate(getArguments()); } @Override public void onAttach(Context ctx) { super.onAttach(ctx); questAnswerComponent.onAttach((OsmQuestAnswerListener) ctx); } @Override public void onAttach(Activity activity) { super.onAttach(activity); questAnswerComponent.onAttach((OsmQuestAnswerListener) activity); } protected List<Integer> getOtherAnswerResourceIds() { List<Integer> answers = new ArrayList<>(); answers.add(R.string.quest_generic_answer_notApplicable); return answers; } protected boolean onClickOtherAnswer(int itemResourceId) { if(itemResourceId == R.string.quest_generic_answer_notApplicable) { onClickCantSay(); return true; } return false; } protected final void onClickCantSay() { DialogFragment leaveNote = new LeaveNoteDialog(); Bundle leaveNoteArgs = questAnswerComponent.getArguments(); leaveNoteArgs.putString(LeaveNoteDialog.ARG_QUEST_TITLE, titleText); leaveNote.setArguments(leaveNoteArgs); leaveNote.show(getFragmentManager(), null); } /** Request to close the form through user interaction (back button, clicked other quest,..), * requires user confirmation if any changes have been made */ @UiThread public void onClickClose(final Runnable confirmed) { if (!hasChanges()) { confirmed.run(); } else { DialogInterface.OnClickListener onYes = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { confirmed.run(); } }; new AlertDialogBuilder(getActivity()) .setMessage(R.string.confirmation_discard_title) .setPositiveButton(R.string.confirmation_discard_positive, onYes) .setNegativeButton(R.string.confirmation_discard_negative, null) .show(); } } protected final void applyImmediateAnswer(Bundle data) { questAnswerComponent.onAnswerQuest(data); } protected final void skipQuest() { questAnswerComponent.onSkippedQuest(); } public final void setTitle(int resourceId) { if(resourceId != -1) titleText = getResources().getString(resourceId); updateTitle(); } public final void setTitle(String string) { titleText = string; updateTitle(); } private void updateTitle() { if(title != null && titleText != null) { title.setText(titleText); } } protected final View setContentView(int resourceId) { return getActivity().getLayoutInflater().inflate(resourceId, content); } protected final View setButtonsView(int resourceId) { return getActivity().getLayoutInflater().inflate(resourceId, buttonPanel); } public abstract boolean hasChanges(); public final long getQuestId() { return questAnswerComponent.getQuestId(); } public final QuestGroup getQuestGroup() { return questAnswerComponent.getQuestGroup(); } protected final OsmElement getOsmElement() { return (OsmElement) getArguments().getSerializable(AbstractQuestAnswerFragment.ELEMENT); } }