You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java

443 lines
15 KiB
Java

/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.activity;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.Toolbar;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.files.AACRecordingActivity;
import com.todoroo.astrid.files.FilesControlSet;
import com.todoroo.astrid.notes.EditNoteActivity;
import com.todoroo.astrid.service.TaskDeleter;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.timers.TimerPlugin;
import com.todoroo.astrid.ui.EditTitleControlSet;
import com.todoroo.astrid.utility.Flags;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.fragments.TaskEditControlSetFragmentManager;
import org.tasks.injection.ForActivity;
import org.tasks.injection.InjectingFragment;
import org.tasks.notifications.NotificationManager;
import org.tasks.preferences.ActivityPreferences;
import org.tasks.ui.MenuColorizer;
import org.tasks.ui.TaskEditControlFragment;
import java.util.List;
import javax.inject.Inject;
import butterknife.Bind;
import butterknife.ButterKnife;
import static android.app.Activity.RESULT_OK;
import static org.tasks.date.DateTimeUtils.newDateTime;
/**
* This activity is responsible for creating new tasks and editing existing
* ones. It saves a task when it is paused (screen rotated, back button pressed)
* as long as the task has a title.
*
* @author timsu
*
*/
public final class TaskEditFragment extends InjectingFragment implements Toolbar.OnMenuItemClickListener {
public interface TaskEditFragmentCallbackHandler {
void taskEditFinished();
}
public static TaskEditFragment newTaskEditFragment(boolean isNewTask, Task task) {
TaskEditFragment taskEditFragment = new TaskEditFragment();
taskEditFragment.isNewTask = isNewTask;
taskEditFragment.model = task;
return taskEditFragment;
}
public static final String TAG_TASKEDIT_FRAGMENT = "taskedit_fragment"; //$NON-NLS-1$
// --- bundle tokens
/**
* Content Values to set
*/
public static final String TOKEN_VALUES = "v"; //$NON-NLS-1$
/**
* Task in progress (during orientation change)
*/
private static final String EXTRA_TASK = "extra_task"; //$NON-NLS-1$
private static final String EXTRA_IS_NEW_TASK = "extra_is_new_task";
// --- request codes
public static final int REQUEST_CODE_RECORD = 30; // TODO: move this to file control set
@Inject TaskService taskService;
@Inject MetadataDao metadataDao;
@Inject UserActivityDao userActivityDao;
@Inject TaskDeleter taskDeleter;
@Inject NotificationManager notificationManager;
@Inject ActivityPreferences preferences;
@Inject DialogBuilder dialogBuilder;
@Inject @ForActivity Context context;
@Inject TaskEditControlSetFragmentManager taskEditControlSetFragmentManager;
// --- UI components
private EditNoteActivity editNotes;
@Bind(R.id.edit_body) LinearLayout body;
@Bind(R.id.toolbar) Toolbar toolbar;
// --- other instance variables
/** true if editing started with a new task */
private boolean isNewTask = false;
/** task model */
Task model = null;
private boolean showEditComments;
private TaskEditFragmentCallbackHandler callback;
/*
* ======================================================================
* ======================================================= initialization
* ======================================================================
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// if we were editing a task already, restore it
if (savedInstanceState != null) {
model = savedInstanceState.getParcelable(EXTRA_TASK);
isNewTask = savedInstanceState.getBoolean(EXTRA_IS_NEW_TASK);
}
showEditComments = preferences.getBoolean(R.string.p_show_task_edit_comments, true);
getActivity().setResult(RESULT_OK);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
callback = (TaskEditFragmentCallbackHandler) activity;
}
/*
* ======================================================================
* ==================================================== UI initialization
* ======================================================================
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_task_edit, container, false);
ButterKnife.bind(this, view);
Drawable drawable = DrawableCompat.wrap(getResources().getDrawable(R.drawable.ic_save_24dp));
DrawableCompat.setTint(drawable, getResources().getColor(android.R.color.white));
toolbar.setNavigationIcon(drawable);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
save();
}
});
toolbar.inflateMenu(R.menu.task_edit_fragment);
Menu menu = toolbar.getMenu();
for (int i = 0 ; i < menu.size() ; i++) {
MenuColorizer.colorMenuItem(menu.getItem(i), getResources().getColor(android.R.color.white));
}
toolbar.setOnMenuItemClickListener(this);
notificationManager.cancel(model.getId());
if (!showEditComments) {
// TODO: hide comment bar
}
return view;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
AndroidUtilities.hideKeyboard(getActivity());
switch (item.getItemId()) {
case R.id.menu_record_note:
startRecordingAudio();
return true;
case R.id.menu_delete:
deleteButtonClick();
return true;
}
return false;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Load task data in background
new TaskEditBackgroundLoader().start();
}
private void instantiateEditNotes() {
if (showEditComments) {
editNotes = new EditNoteActivity(metadataDao, userActivityDao, taskService, this, model.getId());
editNotes.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
body.addView(editNotes);
}
}
private void loadMoreContainer() {
if (editNotes == null) {
instantiateEditNotes();
} else {
editNotes.loadViewForTaskID(model.getId());
}
}
public Task stopTimer() {
TimerPlugin.stopTimer(notificationManager, taskService, context, model);
String elapsedTime = DateUtils.formatElapsedTime(model.getElapsedSeconds());
addComment(String.format("%s %s\n%s %s", //$NON-NLS-1$
getString(R.string.TEA_timer_comment_stopped),
DateUtilities.getTimeString(getActivity(), newDateTime()),
getString(R.string.TEA_timer_comment_spent),
elapsedTime), UserActivity.ACTION_TASK_COMMENT,
null);
return model;
}
public Task startTimer() {
TimerPlugin.startTimer(notificationManager, taskService, context, model);
addComment(String.format("%s %s",
getString(R.string.TEA_timer_comment_started),
DateUtilities.getTimeString(getActivity(), newDateTime())),
UserActivity.ACTION_TASK_COMMENT,
null);
return model;
}
/**
* Initialize task edit page in the background
*
* @author Tim Su <tim@todoroo.com>
*
*/
private class TaskEditBackgroundLoader extends Thread {
@Override
public void run() {
AndroidUtilities.sleepDeep(500L);
Activity activity = getActivity();
if (activity == null) {
return;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (getActivity() != null) {
// todo: is this necessary?
loadMoreContainer();
}
}
});
}
}
/*
* ======================================================================
* =============================================== model reading / saving
* ======================================================================
*/
/** Save task model from values in UI components */
public void save() {
List<TaskEditControlFragment> fragments = taskEditControlSetFragmentManager.getFragmentsInPersistOrder();
if (hasChanges(fragments)) {
for (TaskEditControlFragment fragment : fragments) {
fragment.apply(model);
}
taskService.save(model);
boolean tagsChanged = Flags.check(Flags.TAGS_CHANGED);
// Notify task list fragment in multi-column case
// since the activity isn't actually finishing
TaskListActivity tla = (TaskListActivity) getActivity();
if (tagsChanged) {
tla.tagsChanged();
}
if (isNewTask) {
tla.getTaskListFragment().onTaskCreated(model.getId(), model.getUuid());
}
callback.taskEditFinished();
} else {
discard();
}
}
private EditTitleControlSet getEditTitleControlSet() {
return getFragment(EditTitleControlSet.TAG);
}
private FilesControlSet getFilesControlSet() {
return getFragment(FilesControlSet.TAG);
}
@SuppressWarnings("unchecked")
private <T extends TaskEditControlFragment> T getFragment(int tag) {
return (T) getFragmentManager().findFragmentByTag(getString(tag));
}
/*
* ======================================================================
* ======================================================= event handlers
* ======================================================================
*/
private boolean hasChanges(List<TaskEditControlFragment> fragments) {
for (TaskEditControlFragment fragment : fragments) {
if (fragment.hasChanges(model)) {
return true;
}
}
return false;
}
public void discardButtonClick() {
if (hasChanges(taskEditControlSetFragmentManager.getFragmentsInPersistOrder())) {
dialogBuilder.newMessageDialog(R.string.discard_confirmation)
.setPositiveButton(R.string.keep_editing, null)
.setNegativeButton(R.string.discard, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
discard();
}
})
.show();
} else {
discard();
}
}
public void discard() {
if (isNewTask) {
TimerPlugin.stopTimer(notificationManager, taskService, getActivity(), model);
taskDeleter.delete(model);
}
callback.taskEditFinished();
}
protected void deleteButtonClick() {
dialogBuilder.newMessageDialog(R.string.DLG_delete_this_task_question)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
TimerPlugin.stopTimer(notificationManager, taskService, getActivity(), model);
taskDeleter.delete(model);
callback.taskEditFinished();
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
private void startRecordingAudio() {
Intent recordAudio = new Intent(getActivity(), AACRecordingActivity.class);
startActivityForResult(recordAudio, REQUEST_CODE_RECORD);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (editNotes == null) {
instantiateEditNotes();
}
if (requestCode == REQUEST_CODE_RECORD && resultCode == RESULT_OK) {
String recordedAudioPath = data.getStringExtra(AACRecordingActivity.RESULT_OUTFILE);
String recordedAudioName = data.getStringExtra(AACRecordingActivity.RESULT_FILENAME);
getFilesControlSet().createNewFileAttachment(recordedAudioPath, recordedAudioName, TaskAttachment.FILE_TYPE_AUDIO + "m4a"); //$NON-NLS-1$
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(EXTRA_TASK, model);
outState.putBoolean(EXTRA_IS_NEW_TASK, isNewTask);
}
/*
* ======================================================================
* ========================================== UI component helper classes
* ======================================================================
*/
public void onPriorityChange(int priority) {
getEditTitleControlSet().setPriority(priority);
}
public void onRepeatChanged(boolean repeat) {
getEditTitleControlSet().repeatChanged(repeat);
}
public void addComment(String message, String actionCode, String picture) {
UserActivity userActivity = new UserActivity();
userActivity.setMessage(message);
userActivity.setAction(actionCode);
userActivity.setTargetId(model.getUuid());
userActivity.setCreatedAt(DateUtilities.now());
if (picture != null) {
userActivity.setPicture(picture);
}
userActivityDao.createNew(userActivity);
editNotes.reloadView();
}
}