package de.blau.android.tasks; import android.annotation.SuppressLint; import android.app.Activity; import android.content.DialogInterface; import android.content.DialogInterface.OnShowListener; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatDialog; import android.text.Editable; import android.text.Html; import android.text.TextWatcher; import android.text.method.LinkMovementMethod; import android.text.util.Linkify; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import de.blau.android.App; import de.blau.android.Main; import de.blau.android.PostAsyncActionHandler; import de.blau.android.R; import de.blau.android.exception.OsmException; import de.blau.android.listener.UpdateViewListener; import de.blau.android.osm.BoundingBox; import de.blau.android.osm.OsmElement; import de.blau.android.osm.StorageDelegator; import de.blau.android.prefs.Preferences; import de.blau.android.tasks.Task.State; import de.blau.android.util.GeoMath; import de.blau.android.util.IssueAlert; /** * Very simple dialog fragment to display bug or notes * @author simon * */ public class TaskFragment extends DialogFragment { private static final String DEBUG_TAG = TaskFragment.class.getSimpleName(); private UpdateViewListener mListener; /** */ static public TaskFragment newInstance(Task b) { TaskFragment f = new TaskFragment(); Bundle args = new Bundle(); args.putSerializable("bug", b); f.setArguments(args); f.setShowsDialog(true); return f; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @NonNull @SuppressLint({ "NewApi", "InflateParams" }) @Override public AppCompatDialog onCreateDialog(Bundle savedInstanceState) { final Task bug = (Task) getArguments().getSerializable("bug"); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // Get the layout inflater LayoutInflater inflater = getActivity().getLayoutInflater(); final Preferences prefs = new Preferences(getActivity()); // Inflate and set the layout for the dialog // Pass null as the parent view because its going in the dialog layout final View v = inflater.inflate(R.layout.openstreetbug_edit, null); builder.setView(v) // Add action buttons - slightly convoluted .setPositiveButton(bug instanceof Note && bug.isNew() ? (App.getTaskStorage().contains(bug) ? R.string.delete : R.string.openstreetbug_commitbutton): R.string.save, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (bug instanceof Note && bug.isNew() && App.getTaskStorage().contains(bug)) { deleteBug(bug); return; } saveBug(v,bug); if (bug.hasBeenChanged() && bug.isClosed()) { IssueAlert.cancel(getActivity(), bug); } } }) .setNeutralButton(R.string.transfer_download_current_upload, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { saveBug(v,bug); if (bug instanceof Note) { Note n = (Note)bug; NoteComment nc = n.getLastComment(); TransferTasks.uploadNote(getActivity(), prefs.getServer(), n, (nc != null && nc.isNew()) ? nc.getText() : null, n.state == State.CLOSED, false, null); } else if (bug instanceof OsmoseBug) { TransferTasks.uploadOsmoseBug(getActivity(), (OsmoseBug)bug, null); } if (bug.hasBeenChanged() && bug.isClosed()) { IssueAlert.cancel(getActivity(), bug); } } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { } }); final Spinner state = (Spinner)v.findViewById(R.id.openstreetbug_state); ArrayAdapter<CharSequence> adapter = null; TextView title = (TextView)v.findViewById(R.id.openstreetbug_title); TextView comments = (TextView)v.findViewById(R.id.openstreetbug_comments); EditText comment = (EditText)v.findViewById(R.id.openstreetbug_comment); TextView commentLabel = (TextView)v.findViewById(R.id.openstreetbug_comment_label); LinearLayout elementLayout = (LinearLayout)v.findViewById(R.id.openstreetbug_element_layout); if (bug instanceof Note) { title.setText(getString((bug.isNew() && ((Note)bug).count() == 0) ? R.string.openstreetbug_new_title : R.string.openstreetbug_edit_title)); comments.setText(Html.fromHtml(((Note)bug).getComment())); // ugly comments.setAutoLinkMask(Linkify.WEB_URLS); comments.setMovementMethod(LinkMovementMethod.getInstance()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { comments.setTextIsSelectable(true); } NoteComment nc = ((Note) bug).getLastComment(); elementLayout.setVisibility(View.GONE); // not used for notes if ((bug.isNew() && ((Note)bug).count() == 0) || (nc != null && !nc.isNew())) { // only show comment field if we don't have an unsaved comment Log.d(DEBUG_TAG,"enabling comment field"); comment.setText(""); comment.setFocusable(true); comment.setFocusableInTouchMode(true); comment.setEnabled(true); } else { commentLabel.setVisibility(View.GONE); comment.setVisibility(View.GONE); } adapter = ArrayAdapter.createFromResource(getActivity(), R.array.note_state, android.R.layout.simple_spinner_item); } else if (bug instanceof OsmoseBug) { title.setText(R.string.openstreetbug_bug_title); comments.setText(Html.fromHtml(((OsmoseBug)bug).getLongDescription(getActivity(), false))); final StorageDelegator storageDelegator = App.getDelegator(); for (final OsmElement e:((OsmoseBug)bug).getElements()) { String text; if (e.getOsmVersion() < 0) { // fake element text = e.getName() + " (" + getActivity().getString(R.string.openstreetbug_not_downloaded) + ") #" + e.getOsmId(); } else { // real text = e.getName() + " " + e.getDescription(false); } TextView tv = new TextView(getActivity()); tv.setClickable(true); tv.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // FIXME assumption that we are being called from Main dismiss(); final FragmentActivity activity = getActivity(); final int lonE7 = bug.getLon(); final int latE7 = bug.getLat(); if (e.getOsmVersion() < 0) { // fake element try { BoundingBox b = GeoMath.createBoundingBoxForCoordinates(latE7/1E7D, lonE7/1E7, 50, true); App.getLogic().downloadBox(activity, b, true, new PostAsyncActionHandler(){ @Override public void onSuccess(){ OsmElement osm = storageDelegator.getOsmElement(e.getName(), e.getOsmId()); if (osm != null && activity != null && activity instanceof Main) { ((Main)activity).zoomToAndEdit(lonE7, latE7, osm); } } @Override public void onError() { } }); } catch (OsmException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } else if (activity != null && activity instanceof Main) { // real ((Main)activity).zoomToAndEdit(lonE7, latE7, e); } }}); tv.setTextColor(ContextCompat.getColor(getActivity(),R.color.holo_blue_light)); tv.setText(text); elementLayout.addView(tv); } // these are not used for osmose bugs commentLabel.setVisibility(View.GONE); comment.setVisibility(View.GONE); // adapter = ArrayAdapter.createFromResource(getActivity(), R.array.bug_state, android.R.layout.simple_spinner_item); } else { // unknown bug type Log.d(DEBUG_TAG, "Unknown bug type " + bug.getDescription()); return null; } // Specify the layout to use when the list of choices appears adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // Apply the adapter to the spinner state.setAdapter(adapter); if (bug.state == State.OPEN) { state.setSelection(State.OPEN.ordinal()); } else if (bug.state == State.CLOSED) { state.setSelection(State.CLOSED.ordinal()); } else if (bug.state == State.FALSE_POSITIVE) { if (adapter.getCount() == 3) { state.setSelection(State.FALSE_POSITIVE.ordinal()); } else { Log.d(DEBUG_TAG, "ArrayAdapter too short"); } } state.setEnabled(!bug.isNew()); // new bugs always open AppCompatDialog d = builder.create(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { d.setOnShowListener(new OnShowListener() { // old API, buttons are enabled by default @Override public void onShow(DialogInterface dialog) { // final Button save = ((AlertDialog) dialog) .getButton(AlertDialog.BUTTON_POSITIVE); if ((bug instanceof Note && bug.isNew() && ((Note)bug).count() == 1 && !App.getTaskStorage().contains(bug)) || !bug.hasBeenChanged()) { save.setEnabled(false); } final Button upload = ((AlertDialog) dialog) .getButton(AlertDialog.BUTTON_NEUTRAL); if (!bug.hasBeenChanged()) { upload.setEnabled(false); } state.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){ @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { save.setEnabled(true); upload.setEnabled(true); } @Override public void onNothingSelected(AdapterView<?> arg0) { } }); EditText comment = (EditText)v.findViewById(R.id.openstreetbug_comment); comment.addTextChangedListener(new TextWatcher(){ @Override public void afterTextChanged(Editable arg0) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { save.setEnabled(true); upload.setEnabled(true); state.setSelection(State.OPEN.ordinal()); } }); } }); } // d.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); // not a good idea on small screens return d; } @Override public void onAttach(Activity activity) { super.onAttach(activity); Log.d(DEBUG_TAG, "onAttach"); try { mListener = (UpdateViewListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnPresetSelectedListener"); } } @Override public void onDismiss(DialogInterface dialog) { super.onDismiss(dialog); if (mListener != null) { mListener.update(); } } private static State pos2state(int pos) { if (pos == State.CLOSED.ordinal()) { return State.CLOSED; } else if (pos == State.OPEN.ordinal()) { return State.OPEN; } else if (pos == State.FALSE_POSITIVE.ordinal()) { return State.FALSE_POSITIVE; } return State.OPEN; } /** * saves bug to storage if it is new, otherwise update comment and/or state * @param v * @param bug */ private void saveBug(View v, Task bug) { if (bug.isNew() && ((Note)bug).count() == 0) { App.getTaskStorage().add(bug); // sets dirty } String c = ((EditText)v.findViewById(R.id.openstreetbug_comment)).getText().toString(); if (c.length() > 0) { ((Note)bug).addComment(c); } final Spinner state = (Spinner)v.findViewById(R.id.openstreetbug_state); bug.state = pos2state(state.getSelectedItemPosition()); bug.changed = true; App.getTaskStorage().setDirty(); } /** * Delete a new, non-saved, bug from storage * @param bug */ private void deleteBug(Task bug) { if (bug.isNew()) { App.getTaskStorage().delete(bug); // sets dirty } } }