/* * Copyright 2011 Azwan Adli Abdullah * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gh4a.activities; import android.app.DatePickerDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TextInputLayout; import android.support.v4.app.DialogFragment; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.DatePicker; import android.widget.EditText; import android.widget.TextView; import com.gh4a.BaseActivity; import com.gh4a.Gh4Application; import com.gh4a.ProgressDialogTask; import com.gh4a.R; import com.gh4a.utils.ApiHelpers; import com.gh4a.utils.UiUtils; import org.eclipse.egit.github.core.Milestone; import org.eclipse.egit.github.core.RepositoryId; import org.eclipse.egit.github.core.service.MilestoneService; import java.io.IOException; import java.util.Calendar; import java.util.Date; public class IssueMilestoneEditActivity extends BaseActivity implements View.OnClickListener { public static Intent makeEditIntent(Context context, String repoOwner, String repoName, Milestone milestone, boolean fromPullRequest) { return makeCreateIntent(context, repoOwner, repoName, fromPullRequest) .putExtra("milestone", milestone); } public static Intent makeCreateIntent(Context context, String repoOwner, String repoName, boolean fromPullRequest) { return new Intent(context, IssueMilestoneEditActivity.class) .putExtra("owner", repoOwner) .putExtra("repo", repoName) .putExtra("from_pr", fromPullRequest); } private String mRepoOwner; private String mRepoName; private boolean mFromPullRequest; private Milestone mMilestone; private TextInputLayout mTitleWrapper; private EditText mTitleView; private EditText mDescriptionView; private TextView mDueView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!Gh4Application.get().isAuthorized()) { Intent intent = new Intent(this, Github4AndroidActivity.class); startActivity(intent); finish(); return; } setContentView(R.layout.issue_create_milestone); LayoutInflater headerInflater = LayoutInflater.from(UiUtils.makeHeaderThemedContext(this)); View header = headerInflater.inflate(R.layout.issue_create_header, null); addHeaderView(header, false); mTitleWrapper = (TextInputLayout) header.findViewById(R.id.title_wrapper); mTitleView = (EditText) header.findViewById(R.id.et_title); mDescriptionView = (EditText) header.findViewById(R.id.et_desc); mDueView = (TextView) findViewById(R.id.tv_due); CoordinatorLayout rootLayout = getRootLayout(); FloatingActionButton fab = (FloatingActionButton) getLayoutInflater().inflate(R.layout.accept_fab, rootLayout, false); fab.setOnClickListener(this); rootLayout.addView(fab); findViewById(R.id.due_container).setOnClickListener(this); ActionBar actionBar = getSupportActionBar(); actionBar.setTitle(isInEditMode() ? R.string.issue_milestone_edit : R.string.issue_milestone_new); actionBar.setSubtitle(mRepoOwner + "/" + mRepoName); actionBar.setDisplayShowTitleEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true); if (mMilestone == null) { mMilestone = new Milestone(); mMilestone.setState(ApiHelpers.IssueState.OPEN); } mTitleView.addTextChangedListener(new UiUtils.ButtonEnableTextWatcher(mTitleView, fab)); mTitleView.addTextChangedListener(new UiUtils.EmptinessWatchingTextWatcher(mTitleView) { @Override public void onIsEmpty(boolean isEmpty) { if (isEmpty) { mTitleWrapper.setError(getString(R.string.issue_error_milestone_title)); } else { mTitleWrapper.setErrorEnabled(false); } } }); mTitleView.setText(mMilestone.getTitle()); mDescriptionView.setText(mMilestone.getDescription()); updateLabels(); setToolbarScrollable(false); } @Override protected void onInitExtras(Bundle extras) { super.onInitExtras(extras); mRepoOwner = extras.getString("owner"); mRepoName = extras.getString("repo"); mFromPullRequest = extras.getBoolean("from_pr", false); mMilestone = (Milestone) extras.getSerializable("milestone"); } private boolean isInEditMode() { return getIntent().hasExtra("milestone"); } @Override protected boolean canSwipeToRefresh() { // swipe-to-refresh doesn't make much sense in the // interaction model of this activity return false; } @Override public boolean onCreateOptionsMenu(Menu menu) { if (isInEditMode()) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.edit_milestone_menu, menu); if (mMilestone.getState().equals(ApiHelpers.MilestoneState.OPEN)) { menu.removeItem(R.id.milestone_reopen); } else if (mMilestone.getState().equals(ApiHelpers.MilestoneState.CLOSED)) { menu.removeItem(R.id.milestone_close); } } return super.onCreateOptionsMenu(menu); } @Override protected Intent navigateUp() { return IssueMilestoneListActivity.makeIntent(this, mRepoOwner, mRepoName, mFromPullRequest); } @Override public void onClick(View view) { if (view.getId() == R.id.due_container) { DialogFragment newFragment = new DatePickerFragment(); newFragment.show(getSupportFragmentManager(), "datePicker"); } else if (view instanceof FloatingActionButton) { String title = mTitleView.getText().toString(); String desc = mDescriptionView.getText() != null ? mDescriptionView.getText().toString() : null; mMilestone.setTitle(title); mMilestone.setDescription(desc); new SaveIssueMilestoneTask(mMilestone).schedule(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.milestone_close: case R.id.milestone_reopen: showOpenCloseConfirmDialog(item.getItemId() == R.id.milestone_reopen); return true; case R.id.delete: new AlertDialog.Builder(this) .setMessage(getString(R.string.issue_dialog_delete_message, mMilestone.getTitle())) .setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { new DeleteIssueMilestoneTask(mMilestone.getNumber()).schedule(); } }) .setNegativeButton(R.string.cancel, null) .show(); return true; } return super.onOptionsItemSelected(item); } private void showOpenCloseConfirmDialog(final boolean reopen) { @StringRes int messageResId = reopen ? R.string.issue_milestone_reopen_message : R.string.issue_milestone_close_message; @StringRes int buttonResId = reopen ? R.string.pull_request_reopen : R.string.pull_request_close; new AlertDialog.Builder(this) .setMessage(messageResId) .setPositiveButton(buttonResId, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mMilestone.setState(reopen ? ApiHelpers.MilestoneState.OPEN : ApiHelpers.MilestoneState.CLOSED); new OpenCloseIssueMilestoneTask(mMilestone, reopen).schedule(); } }) .setNegativeButton(R.string.cancel, null) .show(); } private void setDueOn(int year, int month, int day) { Calendar cal = Calendar.getInstance(); cal.set(Calendar.DAY_OF_MONTH, day); cal.set(Calendar.MONTH, month); cal.set(Calendar.YEAR, year); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); mMilestone.setDueOn(cal.getTime()); updateLabels(); } private void resetDueOn() { mMilestone.setDueOn(null); updateLabels(); } private void updateLabels() { Date dueOn = mMilestone.getDueOn(); if (dueOn != null) { mDueView.setText(DateFormat.getMediumDateFormat(this).format(dueOn)); } else { mDueView.setText(R.string.issue_milestone_due_unset); } } private class SaveIssueMilestoneTask extends ProgressDialogTask<Void> { private final Milestone mMilestone; public SaveIssueMilestoneTask(Milestone milestone) { super(IssueMilestoneEditActivity.this, R.string.saving_msg); mMilestone = milestone; } @Override protected ProgressDialogTask<Void> clone() { return new SaveIssueMilestoneTask(mMilestone); } @Override protected Void run() throws IOException { MilestoneService milestoneService = (MilestoneService) Gh4Application.get().getService(Gh4Application.MILESTONE_SERVICE); RepositoryId repoId = new RepositoryId(mRepoOwner, mRepoName); if (isInEditMode()) { milestoneService.editMilestone(repoId, mMilestone); } else { milestoneService.createMilestone(repoId, mMilestone); } return null; } @Override protected void onSuccess(Void result) { setResult(RESULT_OK); finish(); } @Override protected String getErrorMessage() { return getContext().getString(R.string.issue_error_create_milestone, mMilestone.getTitle()); } } private class DeleteIssueMilestoneTask extends ProgressDialogTask<Void> { private final int mNumber; public DeleteIssueMilestoneTask(int number) { super(IssueMilestoneEditActivity.this, R.string.deleting_msg); mNumber = number; } @Override protected ProgressDialogTask<Void> clone() { return new DeleteIssueMilestoneTask(mNumber); } @Override protected Void run() throws IOException { MilestoneService milestoneService = (MilestoneService) Gh4Application.get().getService(Gh4Application.MILESTONE_SERVICE); milestoneService.deleteMilestone(mRepoOwner, mRepoName, mNumber); return null; } @Override protected void onSuccess(Void result) { setResult(RESULT_OK); finish(); } @Override protected String getErrorMessage() { return getContext().getString(R.string.issue_error_delete_milestone); } } private class OpenCloseIssueMilestoneTask extends ProgressDialogTask<Void> { private final Milestone mMilestone; private final boolean mOpen; public OpenCloseIssueMilestoneTask(Milestone milestone, boolean open) { super(IssueMilestoneEditActivity.this, open ? R.string.opening_msg : R.string.closing_msg); mMilestone = milestone; mOpen = open; } @Override protected ProgressDialogTask<Void> clone() { return new OpenCloseIssueMilestoneTask(mMilestone, mOpen); } @Override protected Void run() throws IOException { MilestoneService milestoneService = (MilestoneService) Gh4Application.get().getService(Gh4Application.MILESTONE_SERVICE); RepositoryId repoId = new RepositoryId(mRepoOwner, mRepoName); milestoneService.editMilestone(repoId, mMilestone); return null; } @Override protected void onSuccess(Void result) { supportInvalidateOptionsMenu(); setResult(RESULT_OK); } @Override protected String getErrorMessage() { return getContext().getString(mOpen ? R.string.issue_milestone_reopen_error : R.string.issue_milestone_close_error, mMilestone.getTitle()); } } public static class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener, DialogInterface.OnClickListener { private boolean mStopping; @Override public @NonNull Dialog onCreateDialog(@NonNull Bundle savedInstanceState) { final IssueMilestoneEditActivity activity = (IssueMilestoneEditActivity) getActivity(); final Calendar c = Calendar.getInstance(); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH); int day = c.get(Calendar.DAY_OF_MONTH); Date dueOn = activity.mMilestone.getDueOn(); if (dueOn != null) { c.setTime(dueOn); year = c.get(Calendar.YEAR); month = c.get(Calendar.MONTH); day = c.get(Calendar.DAY_OF_MONTH); } DatePickerDialog dialog = new DatePickerDialog(activity, this, year, month, day) { @Override protected void onStop() { mStopping = true; super.onStop(); mStopping = false; } }; dialog.setButton(DialogInterface.BUTTON_NEUTRAL, getString(R.string.unset), this); return dialog; } @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_NEUTRAL) { getEditActivity().resetDueOn(); } } @Override public void onDateSet(DatePicker view, int year, int month, int day) { if (!mStopping) { getEditActivity().setDueOn(year, month, day); } } private IssueMilestoneEditActivity getEditActivity() { return (IssueMilestoneEditActivity) getActivity(); } } }