diff --git a/src/androidTest/java/com/todoroo/astrid/reminders/NotifyAtDeadlineTest.java b/src/androidTest/java/com/todoroo/astrid/reminders/NotifyAtDeadlineTest.java index 0b570613a..e28e6bb39 100644 --- a/src/androidTest/java/com/todoroo/astrid/reminders/NotifyAtDeadlineTest.java +++ b/src/androidTest/java/com/todoroo/astrid/reminders/NotifyAtDeadlineTest.java @@ -19,7 +19,7 @@ public class NotifyAtDeadlineTest extends AndroidTestCase { @Override public void setUp() { - Preferences preferences = new Preferences(getContext(), null, null); + Preferences preferences = new Preferences(getContext(), null); reminderService = new ReminderService(getContext(), preferences, mock(AlarmManager.class)); freezeAt(new DateTime(2014, 1, 24, 17, 23, 37)); } diff --git a/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.java b/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.java index 6572577e0..3e5b7b5ac 100644 --- a/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.java +++ b/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.java @@ -233,14 +233,14 @@ public class TitleParserTest extends DatabaseTestCase { String title = "Jog " + acceptedString; task.setTitle(title); //test at end of task. should set importance. taskService.createWithValues(task, null, title); - assertEquals((int)task.getImportance(), Task.IMPORTANCE_LEAST); + assertEquals((int)task.getImportance(), Task.IMPORTANCE_NONE); } for (String acceptedString:acceptedStrings){ task = new Task(); String title = acceptedString + " jog"; task.setTitle(title); //test at beginning of task. should not set importance. taskService.createWithValues(task, null, title); - assertNotSame(task.getImportance(),Task.IMPORTANCE_LEAST); + assertNotSame(task.getImportance(),Task.IMPORTANCE_NONE); } } diff --git a/src/generic/java/org/tasks/location/PlacePicker.java b/src/generic/java/org/tasks/location/PlacePicker.java index 021ca0224..187568317 100644 --- a/src/generic/java/org/tasks/location/PlacePicker.java +++ b/src/generic/java/org/tasks/location/PlacePicker.java @@ -1,6 +1,7 @@ package org.tasks.location; import android.app.Activity; +import android.content.Context; import android.content.Intent; import org.tasks.preferences.Preferences; @@ -10,7 +11,7 @@ public class PlacePicker { return null; } - public static Geofence getPlace(Activity activity, Intent data, Preferences preferences) { + public static Geofence getPlace(Context context, Intent data, Preferences preferences) { return null; } } diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index c5df556b3..9ed0ffe17 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -97,6 +97,10 @@ + + @@ -377,7 +381,7 @@ + android:theme="@style/Theme.AppCompat.Dialog" /> controlSetMap = new HashMap<>(); - private FilesControlSet filesControlSet; - private TimerActionControlSet timerAction; + private final Map controlSetFragments = new HashMap<>(); + private final List displayedFragments = new ArrayList<>(); private EditNoteActivity editNotes; - private HideUntilControlSet hideUntilControls; - private ReminderControlSet reminderControlSet; - @Bind(R.id.title) EditText title; @Bind(R.id.pager) ViewPager mPager; @Bind(R.id.updatesFooter) View commentsBar; - @Bind(R.id.completeBox) CheckableImageView checkbox; - @Bind(R.id.timer_container) LinearLayout timerShortcut; @Bind(R.id.basic_controls) LinearLayout basicControls; @Bind(R.id.edit_scroll) ScrollView scrollView; @Bind(R.id.commentField) EditText commentField; - private final List controls = Collections.synchronizedList(new ArrayList()); - // --- other instance variables /** true if editing started with a new task */ @@ -206,7 +176,6 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot private String uuid = RemoteModel.NO_UUID; private boolean showEditComments; - private boolean showTimerShortcut; /* * ====================================================================== @@ -231,9 +200,8 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot } showEditComments = preferences.getBoolean(R.string.p_show_task_edit_comments, true); - showTimerShortcut = preferences.getBoolean(R.string.p_show_timer_shortcut, false); - getActivity().setResult(Activity.RESULT_OK); + getActivity().setResult(RESULT_OK); } /* @@ -247,9 +215,90 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot Bundle savedInstanceState) { View view = inflater.inflate(R.layout.task_edit_activity, container, false); ButterKnife.bind(this, view); + + loadItem(getActivity().getIntent()); + + registerFragment(R.string.TEA_ctrl_title_pref); + registerFragment(R.string.TEA_ctrl_when_pref); + registerFragment(R.string.TEA_ctrl_gcal); + registerFragment(R.string.TEA_ctrl_importance_pref); + registerFragment(R.string.TEA_ctrl_notes_pref); + registerFragment(R.string.TEA_ctrl_hide_until_pref); + registerFragment(R.string.TEA_ctrl_reminders_pref); + registerFragment(R.string.TEA_ctrl_files_pref); + registerFragment(R.string.TEA_ctrl_timer_pref); + registerFragment(R.string.TEA_ctrl_lists_pref); + registerFragment(R.string.TEA_ctrl_repeat_pref); + + ArrayList controlOrder = BeastModePreferences.constructOrderedControlList(preferences, getActivity()); + controlOrder.add(0, getString(R.string.TEA_ctrl_title_pref)); + + String hideAlwaysTrigger = getString(R.string.TEA_ctrl_hide_section_pref); + + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + + for (String item : controlOrder) { + if (item.equals(hideAlwaysTrigger)) { + break; + } + Integer fragmentId = controlSetFragments.get(item); + if (fragmentId == null) { + Timber.e("Unknown task edit control %s", item); + continue; + } + displayedFragments.add(fragmentId); + if (fragmentManager.findFragmentByTag(item) == null) { + TaskEditControlFragment fragment = createFragment(controlSetFragments.get(item)); + if (fragment != null) { + fragment.initialize(isNewTask, model); + fragmentTransaction.add(basicControls.getId(), fragment, item); + } + } + } + + fragmentTransaction.commit(); + + if (!showEditComments) { + commentsBar.setVisibility(View.GONE); + } + return view; } + private void registerFragment(int resId) { + controlSetFragments.put(getString(resId), resId); + } + + private TaskEditControlFragment createFragment(int fragmentId) { + switch (fragmentId) { + case R.string.TEA_ctrl_title_pref: + return new EditTitleControlSet(); + case R.string.TEA_ctrl_when_pref: + return new DeadlineControlSet(); + case R.string.TEA_ctrl_importance_pref: + return new PriorityControlSet(); + case R.string.TEA_ctrl_notes_pref: + return new DescriptionControlSet(); + case R.string.TEA_ctrl_gcal: + return new CalendarControlSet(); + case R.string.TEA_ctrl_hide_until_pref: + return new HideUntilControlSet(); + case R.string.TEA_ctrl_reminders_pref: + return new ReminderControlSet(); + case R.string.TEA_ctrl_files_pref: + return new FilesControlSet(); + case R.string.TEA_ctrl_timer_pref: + return new TimerControlSet(); + case R.string.TEA_ctrl_lists_pref: + return new TagsControlSet(); + case R.string.TEA_ctrl_repeat_pref: + return new RepeatControlSet(); + default: + throw new RuntimeException("Unsupported fragment"); + } + } + @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -267,81 +316,6 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot } } - // populate control set - EditTitleControlSet editTitle = new EditTitleControlSet( - taskService, - getActivity(), - title, - checkbox); - controls.add(editTitle); - - timerAction = new TimerActionControlSet(notificationManager, taskService, getActivity(), getView()); - controls.add(timerAction); - - TagsControlSet tagsControlSet = new TagsControlSet(metadataDao, tagDataDao, preferences, tagService, getActivity(), dialogBuilder); - controls.add(tagsControlSet); - controlSetMap.put(getString(R.string.TEA_ctrl_lists_pref), tagsControlSet); - - RepeatControlSet repeatControls = new RepeatControlSet(preferences, getActivity(), dialogBuilder); - controlSetMap.put(getString(R.string.TEA_ctrl_repeat_pref), repeatControls); - - GCalControlSet gcalControl = new GCalControlSet(gcalHelper, preferences, this, permissionRequestor); - controlSetMap.put(getString(R.string.TEA_ctrl_gcal), gcalControl); - - // The deadline control set contains the repeat controls and the - // calendar controls. - // NOTE: we add the gcalControl AFTER the - // deadline control, because - // otherwise the correct date may not be written to the calendar event. - // Order matters! - DeadlineControlSet deadlineControl = new DeadlineControlSet(getActivity(), preferences); - controlSetMap.put(getString(R.string.TEA_ctrl_when_pref), deadlineControl); - controls.add(repeatControls); - - repeatControls.addListener(editTitle); - controls.add(deadlineControl); - controls.add(gcalControl); - - PriorityControlSet importanceControl = new PriorityControlSet(getActivity()); - controls.add(importanceControl); - importanceControl.addListener(editTitle); - controlSetMap.put(getString(R.string.TEA_ctrl_importance_pref), - importanceControl); - - DescriptionControlSet notesControlSet = new DescriptionControlSet(getActivity()); - controls.add(notesControlSet); - controlSetMap.put(getString(R.string.TEA_ctrl_notes_pref), - notesControlSet); - - reminderControlSet = new ReminderControlSet(alarmService, geofenceService, this, permissionRequestor, device); - controls.add(reminderControlSet); - controlSetMap.put(getString(R.string.TEA_ctrl_reminders_pref), reminderControlSet); - - hideUntilControls = new HideUntilControlSet(this); - controls.add(hideUntilControls); - controlSetMap.put(getString(R.string.TEA_ctrl_hide_until_pref), hideUntilControls); - - // TODO: Fix the fact that hideUntil doesn't update accordingly with date changes when lazy loaded. Until then, don't lazy load. - hideUntilControls.getView(); - - TimerControlSet timerControl = new TimerControlSet(preferences, getActivity(), dialogBuilder); - timerAction.addListener(timerControl); - controls.add(timerControl); - controlSetMap.put(getString(R.string.TEA_ctrl_timer_pref), timerControl); - - filesControlSet = new FilesControlSet(preferences, taskAttachmentDao, this); - controls.add(filesControlSet); - controlSetMap.put(getString(R.string.TEA_ctrl_files_pref), filesControlSet); - - loadEditPageOrder(); - - if (!showEditComments) { - commentsBar.setVisibility(View.GONE); - } - if (!showTimerShortcut) { - timerShortcut.setVisibility(View.GONE); - } - // Load task data in background new TaskEditBackgroundLoader().start(); } @@ -349,7 +323,7 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot private void instantiateEditNotes() { if (showEditComments) { long idParam = getActivity().getIntent().getLongExtra(TOKEN_ID, -1L); - editNotes = new EditNoteActivity(actFmCameraModule, preferences, metadataDao, userActivityDao, + editNotes = new EditNoteActivity(actFmCameraModule, metadataDao, userActivityDao, taskService, this, getView(), idParam); editNotes.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); @@ -373,12 +347,11 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot editNotes.loadViewForTaskID(idParam); } - if (timerAction != null && editNotes != null) { - timerAction.removeListener(editNotes); - timerAction.addListener(editNotes); - } - if (editNotes != null) { + TimerControlSet timerControl = getTimerControl(); + if (timerControl != null) { + timerControl.setEditNotes(editNotes); + } editNotes.addListener(this); } @@ -406,40 +379,14 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot mPager.setCurrentItem(position); } - private void loadEditPageOrder() { - ArrayList controlOrder = BeastModePreferences.constructOrderedControlList(preferences, getActivity()); - String[] itemOrder = controlOrder.toArray(new String[controlOrder.size()]); - - String hideAlwaysTrigger = getString(R.string.TEA_ctrl_hide_section_pref); - - Class openControl = (Class) getActivity().getIntent().getSerializableExtra(TOKEN_OPEN_CONTROL); - - for (String item : itemOrder) { - if (item.equals(hideAlwaysTrigger)) { - break; // As soon as we hit the hide section, we're done - } else { - View controlSet = null; - TaskEditControlSet curr = controlSetMap.get(item); - - if (curr != null) { - controlSet = curr.getView(); - } - - if (controlSet != null) { - ImageView icon = (ImageView) controlSet.findViewById(R.id.icon); - if (icon != null) { - icon.setImageResource(curr.getIcon()); - } - basicControls.addView(controlSet); - } - - if (curr != null && curr.getClass().equals(openControl) && curr instanceof PopupControlSet) { - curr.getView().performClick(); - } - } - } + public Task stopTimer() { + TimerPlugin.stopTimer(notificationManager, taskService, context, model); + return model; + } - getActivity().getIntent().removeExtra(TOKEN_OPEN_CONTROL); + public Task startTimer() { + TimerPlugin.startTimer(notificationManager, taskService, context, model); + return model; } /** @@ -538,61 +485,44 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot public void repopulateFromScratch(Intent intent) { model = null; uuid = RemoteModel.NO_UUID; - populateFields(intent); loadMoreContainer(); } - /** Populate UI component values from the model */ - public void populateFields(Intent intent) { - loadItem(intent); - - synchronized (controls) { - for (TaskEditControlSet controlSet : controls) { - controlSet.readFromTask(model); - } - } + private String getTitle() { + return getEditTitleControlSet().getTitle(); } /** Save task model from values in UI components */ public void save(boolean onPause) { + String title = getTitle(); if (title == null) { return; } - if (title.getText().length() > 0) { + if (title.length() > 0) { model.setDeletionDate(0L); } - if (title.getText().length() == 0) { + if (title.length() == 0) { return; } - synchronized (controls) { - for (TaskEditControlSet controlSet : controls) { - if (controlSet instanceof PopupControlSet) { // Save open control set - PopupControlSet popup = (PopupControlSet) controlSet; - Dialog d = popup.getDialog(); - if (d != null && d.isShowing()) { - getActivity().getIntent().putExtra(TOKEN_OPEN_CONTROL, popup.getClass()); - } - } - controlSet.writeToModel(model); + if (!onPause) { + for (Integer fragmentId : displayedFragments) { + getFragment(fragmentId).apply(model); } - } - - boolean tagsChanged = Flags.check(Flags.TAGS_CHANGED); - model.putTransitory(TaskService.TRANS_EDIT_SAVE, true); // TODO: not used? - taskService.save(model); + taskService.save(model); - if (!onPause) { boolean taskEditActivity = (getActivity() instanceof TaskEditActivity); + boolean tagsChanged = Flags.check(Flags.TAGS_CHANGED); + if (taskEditActivity) { Intent data = new Intent(); data.putExtra(TOKEN_TAGS_CHANGED, tagsChanged); data.putExtra(TOKEN_ID, model.getId()); data.putExtra(TOKEN_UUID, model.getUuid()); - getActivity().setResult(Activity.RESULT_OK, data); + getActivity().setResult(RESULT_OK, data); } else { // Notify task list fragment in multi-column case @@ -611,13 +541,29 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot removeExtrasFromIntent(getActivity().getIntent()); shouldSaveState = false; getActivity().onBackPressed(); - } } + private EditTitleControlSet getEditTitleControlSet() { + return getFragment(R.string.TEA_ctrl_title_pref); + } + + private FilesControlSet getFilesControlSet() { + return getFragment(R.string.TEA_ctrl_files_pref); + } + + private TimerControlSet getTimerControl() { + return getFragment(R.string.TEA_ctrl_timer_pref); + } + + @SuppressWarnings("unchecked") + private T getFragment(int tag) { + return (T) getFragmentManager().findFragmentByTag(getString(tag)); + } + public boolean onKeyDown(int keyCode) { if (keyCode == KeyEvent.KEYCODE_BACK) { - if(title.getText().length() == 0) { + if(getTitle().length() == 0) { discardButtonClick(); } else { saveButtonClick(); @@ -640,11 +586,11 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot } if (activity instanceof TaskListActivity) { - if (title.getText().length() == 0 && isNewTask && model != null && model.isSaved()) { + if (getTitle().length() == 0 && isNewTask && model != null && model.isSaved()) { taskDeleter.delete(model); } } else if (activity instanceof TaskEditActivity) { - if (title.getText().length() == 0 && isNewTask && model != null && model.isSaved()) { + if (getTitle().length() == 0 && isNewTask && model != null && model.isSaved()) { taskDeleter.delete(model); } } @@ -674,7 +620,7 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot shouldSaveState = false; // abandon editing in this case - if (title.getText().toString().trim().length() == 0 || TextUtils.isEmpty(model.getTitle())) { + if (getTitle().trim().length() == 0 || TextUtils.isEmpty(model.getTitle())) { if (isNewTask) { TimerPlugin.stopTimer(notificationManager, taskService, getActivity(), model); taskDeleter.delete(model); @@ -700,7 +646,7 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot Activity a = getActivity(); if (a instanceof TaskEditActivity) { - getActivity().setResult(Activity.RESULT_OK); + getActivity().setResult(RESULT_OK); getActivity().onBackPressed(); } else if (a instanceof TaskListActivity) { discardButtonClick(); @@ -738,7 +684,7 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot deleteButtonClick(); return true; case android.R.id.home: - if (title.getText().toString().trim().length() == 0) { + if (getTitle().trim().length() == 0) { discardButtonClick(); } else { saveButtonClick(); @@ -768,59 +714,18 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot } } - @Override - public void onStart() { - super.onStart(); - populateFields(getActivity().getIntent()); - if (isNewTask) { - title.requestFocus(); - title.setCursorVisible(true); - getActivity().getWindow() - .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - } - } - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (editNotes == null) { instantiateEditNotes(); } - if (requestCode == HideUntilControlSet.REQUEST_HIDE_UNTIL && resultCode == Activity.RESULT_OK) { - long timestamp = data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L); - if (timestamp > 0) { - hideUntilControls.setCustomDate(timestamp); - } else { - Timber.e("Invalid timestamp"); - } - } else if (requestCode == ReminderControlSet.REQUEST_NEW_ALARM && resultCode == Activity.RESULT_OK) { - long timestamp = data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L); - if (timestamp > 0) { - reminderControlSet.addAlarmRow(timestamp); - } else { - Timber.e("Invalid timestamp"); - } - } else if (requestCode == ReminderControlSet.REQUEST_LOCATION_REMINDER) { - if (resultCode == Activity.RESULT_OK) { - Geofence geofence = PlacePicker.getPlace(getActivity(), data, preferences); - if (geofence != null) { - reminderControlSet.addGeolocationReminder(geofence); - } else { - Timber.e("Invalid geofence"); - } - } - } else if (requestCode == REQUEST_CODE_RECORD && resultCode == Activity.RESULT_OK) { + if (requestCode == REQUEST_CODE_RECORD && resultCode == RESULT_OK) { String recordedAudioPath = data.getStringExtra(AACRecordingActivity.RESULT_OUTFILE); String recordedAudioName = data.getStringExtra(AACRecordingActivity.RESULT_FILENAME); - filesControlSet.createNewFileAttachment(recordedAudioPath, recordedAudioName, TaskAttachment.FILE_TYPE_AUDIO + "m4a"); //$NON-NLS-1$ - } else if (requestCode == REQUEST_ADD_ATTACHMENT && resultCode == Activity.RESULT_OK) { - String path = data.getStringExtra(AddAttachmentActivity.EXTRA_PATH); - File file = new File(path); - String extension = path.substring(path.lastIndexOf('.') + 1); - filesControlSet.createNewFileAttachment(path, file.getName(), TaskAttachment.FILE_TYPE_IMAGE + extension); + getFilesControlSet().createNewFileAttachment(recordedAudioPath, recordedAudioName, TaskAttachment.FILE_TYPE_AUDIO + "m4a"); //$NON-NLS-1$ } else if (requestCode == REQUEST_CODE_CAMERA) { - if (editNotes != null && resultCode == Activity.RESULT_OK) { + if (editNotes != null && resultCode == RESULT_OK) { Uri uri = data.getParcelableExtra(CameraActivity.EXTRA_URI); editNotes.setPictureUri(uri); } @@ -901,8 +806,16 @@ public final class TaskEditFragment extends InjectingFragment implements EditNot } private void hideKeyboard() { - AndroidUtilities.hideSoftInputForViews(getActivity(), title, commentField); - title.setCursorVisible(false); + getEditTitleControlSet().hideKeyboard(); + AndroidUtilities.hideSoftInputForViews(getActivity(), commentField); commentField.setCursorVisible(false); } + + public void onPriorityChange(int priority) { + getEditTitleControlSet().setPriority(priority); + } + + public void onRepeatChanged(boolean repeat) { + getEditTitleControlSet().repeatChanged(repeat); + } } diff --git a/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java b/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java index 45b20d91e..bd4d282c9 100644 --- a/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java @@ -391,11 +391,11 @@ public class TaskAdapter extends CursorAdapter implements Filterable { } private void showFilesDialog(Task task) { - FilesControlSet filesControlSet = new FilesControlSet( - preferences, taskAttachmentDao, fragment); - filesControlSet.hideAddAttachmentButton(); - filesControlSet.readFromTask(task); - filesControlSet.getView().performClick(); + // TODO: reimplement this +// FilesControlSet filesControlSet = new FilesControlSet(); +// filesControlSet.hideAddAttachmentButton(); +// filesControlSet.readFromTask(task); +// filesControlSet.getView().performClick(); } /* ====================================================================== diff --git a/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java b/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java index 68de8789e..0eed70a68 100644 --- a/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java +++ b/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java @@ -73,7 +73,9 @@ public class DefaultsPreferences extends InjectingPreferenceActivity { } private void startCalendarSelectionActivity() { - startActivityForResult(new Intent(DefaultsPreferences.this, CalendarSelectionActivity.class), REQUEST_CALENDAR_SELECTION); + startActivityForResult(new Intent(DefaultsPreferences.this, CalendarSelectionActivity.class) {{ + putExtra(CalendarSelectionActivity.EXTRA_SHOW_NONE, true); + }}, REQUEST_CALENDAR_SELECTION); } @Override diff --git a/src/main/java/com/todoroo/astrid/dao/TagDataDao.java b/src/main/java/com/todoroo/astrid/dao/TagDataDao.java index 787b6760a..9aa6a6ad9 100644 --- a/src/main/java/com/todoroo/astrid/dao/TagDataDao.java +++ b/src/main/java/com/todoroo/astrid/dao/TagDataDao.java @@ -55,6 +55,10 @@ public class TagDataDao { .orderBy(Order.asc(TagData.ID))); } + public TagData getByUuid(String uuid) { + return getByUuid(uuid, TagData.PROPERTIES); + } + public TagData getByUuid(String uuid, Property... properties) { return dao.getFirst(Query.select(properties).where(TagData.UUID.eq(uuid))); } diff --git a/src/main/java/com/todoroo/astrid/data/TagData.java b/src/main/java/com/todoroo/astrid/data/TagData.java index 7516dec1b..c9a69d8d9 100644 --- a/src/main/java/com/todoroo/astrid/data/TagData.java +++ b/src/main/java/com/todoroo/astrid/data/TagData.java @@ -110,6 +110,7 @@ public final class TagData extends RemoteModel { setValue(LAST_AUTOSYNC, lastAutosync); } + // TODO: remove? public String getUUID() { return getValue(UUID); } diff --git a/src/main/java/com/todoroo/astrid/data/Task.java b/src/main/java/com/todoroo/astrid/data/Task.java index ba0ebf83b..ea3aa7cd4 100644 --- a/src/main/java/com/todoroo/astrid/data/Task.java +++ b/src/main/java/com/todoroo/astrid/data/Task.java @@ -150,17 +150,6 @@ public class Task extends RemoteModel { /** * @return colors that correspond to importance values */ - public static int[] getImportanceColors(Resources r) { - return new int[] { - r.getColor(R.color.importance_1), - r.getColor(R.color.importance_2), - r.getColor(R.color.importance_3), - r.getColor(R.color.importance_4) - }; - } - - public static int IMPORTANCE_MOST = IMPORTANCE_DO_OR_DIE; - public static int IMPORTANCE_LEAST = IMPORTANCE_NONE; // --- defaults @@ -544,10 +533,14 @@ public class Task extends RemoteModel { return getValue(ESTIMATED_SECONDS); } - public void setELAPSED_SECONDS(Integer elapsedSeconds) { + public void setElapsedSeconds(Integer elapsedSeconds) { setValue(ELAPSED_SECONDS, elapsedSeconds); } + public void setEstimatedSeconds(Integer estimatedSeconds) { + setValue(ESTIMATED_SECONDS, estimatedSeconds); + } + public void setCalendarUri(String calendarUri) { setValue(CALENDAR_URI, calendarUri); } diff --git a/src/main/java/com/todoroo/astrid/files/FilesControlSet.java b/src/main/java/com/todoroo/astrid/files/FilesControlSet.java index ba6f878ad..c1bbe25ef 100644 --- a/src/main/java/com/todoroo/astrid/files/FilesControlSet.java +++ b/src/main/java/com/todoroo/astrid/files/FilesControlSet.java @@ -6,17 +6,20 @@ package com.todoroo.astrid.files; import android.app.Activity; -import android.app.Fragment; import android.content.ActivityNotFoundException; import android.content.ClipData; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.media.MediaPlayer; import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.Nullable; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.webkit.MimeTypeMap; import android.widget.LinearLayout; import android.widget.TextView; @@ -24,46 +27,112 @@ import android.widget.Toast; import com.todoroo.andlib.data.Callback; import com.todoroo.andlib.utility.AndroidUtilities; -import com.todoroo.astrid.activity.TaskEditFragment; import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskAttachment; -import com.todoroo.astrid.helper.TaskEditControlSetBase; import org.tasks.R; import org.tasks.activities.AddAttachmentActivity; import org.tasks.dialogs.DialogBuilder; -import org.tasks.preferences.ActivityPreferences; +import org.tasks.injection.ForActivity; +import org.tasks.ui.TaskEditControlFragment; import java.io.File; import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.OnClick; import timber.log.Timber; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop; -public class FilesControlSet extends TaskEditControlSetBase { - - private final ArrayList files = new ArrayList<>(); - private final LayoutInflater inflater; - private final TaskAttachmentDao taskAttachmentDao; - private final Fragment fragment; - private final DialogBuilder dialogBuilder; - private LinearLayout attachmentContainer; - private TextView addAttachment; - - public FilesControlSet(ActivityPreferences preferences, TaskAttachmentDao taskAttachmentDao, - Fragment fragment) { - super(fragment.getActivity(), R.layout.control_set_files); - this.taskAttachmentDao = taskAttachmentDao; - this.fragment = fragment; - this.dialogBuilder = new DialogBuilder(activity, preferences); - inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); +public class FilesControlSet extends TaskEditControlFragment { + + private static final int REQUEST_ADD_ATTACHMENT = 50; + private static final String EXTRA_UUID = "extra_uuid"; + + @Inject TaskAttachmentDao taskAttachmentDao; + @Inject DialogBuilder dialogBuilder; + @Inject @ForActivity Context context; + + @Bind(R.id.attachment_container) LinearLayout attachmentContainer; + @Bind(R.id.add_attachment) TextView addAttachment; + + private String taskUuid; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + + if (savedInstanceState != null) { + taskUuid = savedInstanceState.getString(EXTRA_UUID); + } + + final List files = new ArrayList<>(); + taskAttachmentDao.getAttachments(taskUuid, new Callback() { + @Override + public void apply(TaskAttachment attachment) { + files.add(attachment); + addAttachment(attachment); + } + }); + validateFiles(files); + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putString(EXTRA_UUID, taskUuid); + } + + @OnClick(R.id.add_attachment) + void addAttachment(View view) { + startActivityForResult(new Intent(context, AddAttachmentActivity.class), REQUEST_ADD_ATTACHMENT); + } + + @Override + protected int getLayout() { + return R.layout.control_set_files; + } + + @Override + public int getIcon() { + return R.drawable.ic_attachment_24dp; + } + + @Override + public void initialize(boolean isNewTask, Task task) { + taskUuid = task.getUuid(); + } + + @Override + public void apply(Task task) { + + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_ADD_ATTACHMENT) { + if (resultCode == Activity.RESULT_OK) { + String path = data.getStringExtra(AddAttachmentActivity.EXTRA_PATH); + File file = new File(path); + String extension = path.substring(path.lastIndexOf('.') + 1); + createNewFileAttachment(path, file.getName(), TaskAttachment.FILE_TYPE_IMAGE + extension); + } + } else { + super.onActivityResult(requestCode, resultCode, data); + } } private void addAttachment(TaskAttachment taskAttachment) { - View fileRow = inflater.inflate(R.layout.file_row, null); + View fileRow = getActivity().getLayoutInflater().inflate(R.layout.file_row, null); fileRow.setTag(taskAttachment); attachmentContainer.addView(fileRow); addAttachment(taskAttachment, fileRow); @@ -71,7 +140,6 @@ public class FilesControlSet extends TaskEditControlSetBase { private void addAttachment(final TaskAttachment taskAttachment, final View fileRow) { TextView nameView = (TextView) fileRow.findViewById(R.id.file_text); - nameView.setTextColor(themeColor); String name = taskAttachment.getName(); nameView.setText(name); nameView.setOnClickListener(new OnClickListener() { @@ -93,7 +161,6 @@ public class FilesControlSet extends TaskEditControlSetBase { File f = new File(taskAttachment.getFilePath()); f.delete(); } - files.remove(taskAttachment); attachmentContainer.removeView(fileRow); } }) @@ -103,28 +170,7 @@ public class FilesControlSet extends TaskEditControlSetBase { }); } - @Override - public int getIcon() { - return R.drawable.ic_attachment_24dp; - } - - public void refreshMetadata() { - if (model != null) { - files.clear(); - taskAttachmentDao.getAttachments(model.getUuid(), new Callback() { - @Override - public void apply(TaskAttachment attachment) { - files.add(attachment); - } - }); - validateFiles(); - if (initialized) { - afterInflate(); - } - } - } - - private void validateFiles() { + private void validateFiles(List files) { for (int i = 0; i < files.size(); i++) { TaskAttachment m = files.get(i); if (m.containsNonNullValue(TaskAttachment.FILE_PATH)) { @@ -140,34 +186,6 @@ public class FilesControlSet extends TaskEditControlSetBase { } } - @Override - protected void readFromTaskOnInitialize() { - attachmentContainer.removeAllViews(); - taskAttachmentDao.getAttachments(model.getUuid(), new Callback() { - @Override - public void apply(TaskAttachment entry) { - addAttachment(entry); - } - }); - } - - @Override - protected void writeToModelAfterInitialized(Task task) { - // Nothing to write - } - - @Override - protected void afterInflate() { - attachmentContainer = (LinearLayout) getView().findViewById(R.id.attachment_container); - addAttachment = (TextView) getView().findViewById(R.id.add_attachment); - addAttachment.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - fragment.startActivityForResult(new Intent(activity, AddAttachmentActivity.class), TaskEditFragment.REQUEST_ADD_ATTACHMENT); - } - }); - } - public void hideAddAttachmentButton() { addAttachment.setVisibility(View.GONE); } @@ -210,10 +228,10 @@ public class FilesControlSet extends TaskEditControlSetBase { if (atLeastLollipop()) { intent.setClipData(ClipData.newRawUri(null, uri)); } - activity.startActivity(intent); + getActivity().startActivity(intent); } catch(ActivityNotFoundException e) { Timber.e(e, e.getMessage()); - Toast.makeText(activity, R.string.no_application_found, Toast.LENGTH_SHORT).show(); + Toast.makeText(context, R.string.no_application_found, Toast.LENGTH_SHORT).show(); } } else { String useType = fileType; @@ -240,17 +258,16 @@ public class FilesControlSet extends TaskEditControlSetBase { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(file)), type); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - activity.startActivity(intent); + getActivity().startActivity(intent); } catch (ActivityNotFoundException e) { Timber.e(e, e.getMessage()); - Toast.makeText(activity, R.string.file_type_unhandled, Toast.LENGTH_LONG).show(); + Toast.makeText(context, R.string.file_type_unhandled, Toast.LENGTH_LONG).show(); } } public void createNewFileAttachment(String path, String fileName, String fileType) { - TaskAttachment attachment = TaskAttachment.createNewAttachment(model.getUuid(), path, fileName, fileType); + TaskAttachment attachment = TaskAttachment.createNewAttachment(taskUuid, path, fileName, fileType); taskAttachmentDao.createNew(attachment); - refreshMetadata(); addAttachment(attachment); } } diff --git a/src/main/java/com/todoroo/astrid/gcal/Calendars.java b/src/main/java/com/todoroo/astrid/gcal/Calendars.java index e56f54e26..ceb45c7be 100644 --- a/src/main/java/com/todoroo/astrid/gcal/Calendars.java +++ b/src/main/java/com/todoroo/astrid/gcal/Calendars.java @@ -19,7 +19,6 @@ public class Calendars { public static final String ID_COLUMN_NAME = "_id"; public static final String CALENDARS_DISPLAY_COL = CalendarContract.Calendars.CALENDAR_DISPLAY_NAME; - public static final String CALENDARS_ACCESS_LEVEL_COL = CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL; public static final String EVENTS_DTSTART_COL = CalendarContract.Events.DTSTART; public static final String EVENTS_DTEND_COL = CalendarContract.Events.DTEND; public static final String EVENTS_NAME_COL = CalendarContract.Events.TITLE; @@ -34,7 +33,7 @@ public class Calendars { // Only show calendars that the user can modify. Access level 500 // corresponds to Calendars.CONTRIBUTOR_ACCESS - public static final String CALENDARS_WHERE = CALENDARS_ACCESS_LEVEL_COL + ">= 500"; + public static final String CALENDARS_WHERE = CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + ">= 500"; public static final String CALENDARS_SORT = CALENDARS_DISPLAY_COL + " ASC"; diff --git a/src/main/java/com/todoroo/astrid/gcal/GCalControlSet.java b/src/main/java/com/todoroo/astrid/gcal/GCalControlSet.java deleted file mode 100644 index 7af590c5a..000000000 --- a/src/main/java/com/todoroo/astrid/gcal/GCalControlSet.java +++ /dev/null @@ -1,266 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.gcal; - -import android.app.FragmentManager; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.text.TextUtils; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import com.todoroo.astrid.activity.TaskEditFragment; -import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; - -import org.tasks.R; -import org.tasks.activities.CalendarSelectionDialog; -import org.tasks.preferences.PermissionRequestor; -import org.tasks.preferences.Preferences; - -import timber.log.Timber; - -/** - * Control Set for managing repeats - * - * @author Tim Su - * - */ -public class GCalControlSet extends TaskEditControlSetBase implements CalendarSelectionDialog.CalendarSelectionHandler { - - private static final String FRAG_TAG_CALENDAR_SELECTION = "frag_tag_calendar_selection"; - - // --- instance variables - - private final GCalHelper gcal; - private Preferences preferences; - private final TaskEditFragment taskEditFragment; - private PermissionRequestor permissionRequestor; - - private Uri calendarUri = null; - - private boolean hasEvent = false; - private TextView calendar; - private ImageView cancelButton; - private String calendarId; - private String calendarName; - - public GCalControlSet(GCalHelper gcal, Preferences preferences, - TaskEditFragment taskEditFragment, PermissionRequestor permissionRequestor) { - super(taskEditFragment.getActivity(), R.layout.control_set_gcal_display); - this.gcal = gcal; - this.preferences = preferences; - this.taskEditFragment = taskEditFragment; - this.permissionRequestor = permissionRequestor; - } - - @Override - protected void afterInflate() { - View view = getView(); - calendar = (TextView) view.findViewById(R.id.calendar_display_which); - cancelButton = (ImageView) view.findViewById(R.id.clear); - calendar.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (hasEvent) { - viewCalendarEvent(); - } else { - // TODO: show calendar selection if permission has just been granted - // can't do this now because the app saves state when TEA is paused, - // which triggers calendar creation if there is a default add to calendar. - if (permissionRequestor.requestCalendarPermissions()) { - showCalendarSelectionDialog(); - } - } - } - }); - cancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - clearEvent(); - refreshDisplayView(); - } - }); - } - - public void showCalendarSelectionDialog() { - FragmentManager fragmentManager = taskEditFragment.getFragmentManager(); - CalendarSelectionDialog fragmentByTag = (CalendarSelectionDialog) fragmentManager.findFragmentByTag(FRAG_TAG_CALENDAR_SELECTION); - if (fragmentByTag == null) { - fragmentByTag = new CalendarSelectionDialog(); - fragmentByTag.show(fragmentManager, FRAG_TAG_CALENDAR_SELECTION); - } - fragmentByTag.setCalendarSelectionHandler(GCalControlSet.this); - } - - @Override - protected void readFromTaskOnInitialize() { - String uri = gcal.getTaskEventUri(model); - if(!TextUtils.isEmpty(uri)) { - try { - calendarUri = Uri.parse(uri); - - // try to load calendar - ContentResolver cr = activity.getContentResolver(); - Cursor cursor = cr.query(calendarUri, new String[] { "dtstart" }, null, null, null); //$NON-NLS-1$ - try { - boolean deleted = cursor.getCount() == 0; - - if(deleted) { - clearEvent(); - hasEvent = false; - } else { - hasEvent = true; - } - } finally { - cursor.close(); - } - } catch (Exception e) { - Timber.e(e, "unable-to-parse-calendar: %s", model.getCalendarURI()); - } - } else { - hasEvent = false; - clearEvent(); - } - refreshDisplayView(); - } - - private void clearEvent() { - calendarId = null; - calendarUri = null; - calendarName = null; - } - - @Override - protected void writeToModelAfterInitialized(Task task) { - if (!task.hasDueDate()) { - return; - } - - if ((preferences.isDefaultCalendarSet() || calendarId != null) && calendarUri == null) { - try{ - ContentResolver cr = activity.getContentResolver(); - - ContentValues values = new ContentValues(); - values.put("calendar_id", calendarId); - calendarUri = gcal.createTaskEvent(task, cr, values); - if(calendarUri != null) { - task.setCalendarUri(calendarUri.toString()); - - if (!hasEvent) { - // pop up the new event - Intent intent = new Intent(Intent.ACTION_VIEW, calendarUri); - intent.putExtra("beginTime", values.getAsLong("dtstart")); - intent.putExtra("endTime", values.getAsLong("dtend")); - activity.startActivity(intent); - } - } - - } catch (Exception e) { - Timber.e(e, e.getMessage()); - } - } else if(calendarUri != null) { - try { - ContentValues updateValues = new ContentValues(); - - // check if we need to update the item - ContentValues setValues = task.getSetValues(); - if(setValues.containsKey(Task.TITLE.name)) { - updateValues.put("title", task.getTitle()); - } - if(setValues.containsKey(Task.NOTES.name)) { - updateValues.put("description", task.getNotes()); - } - if(setValues.containsKey(Task.DUE_DATE.name) || setValues.containsKey(Task.ESTIMATED_SECONDS.name)) { - gcal.createStartAndEndDate(task, updateValues); - } - - ContentResolver cr = activity.getContentResolver(); - cr.update(calendarUri, updateValues, null, null); - } catch (Exception e) { - Timber.e(e, "unable-to-update-calendar: %s", task.getCalendarURI()); - } - } - } - - private void viewCalendarEvent() { - if(calendarUri == null) { - return; - } - - ContentResolver cr = activity.getContentResolver(); - Intent intent = new Intent(Intent.ACTION_VIEW, calendarUri); - Cursor cursor = cr.query(calendarUri, new String[] { "dtstart", "dtend" }, - null, null, null); - try { - if(cursor.getCount() == 0) { - // event no longer exists, recreate it - calendarUri = null; - writeToModel(model); - return; - } - cursor.moveToFirst(); - intent.putExtra("beginTime", cursor.getLong(0)); - intent.putExtra("endTime", cursor.getLong(1)); - - } catch (Exception e) { - Timber.e(e, e.getMessage()); - Toast.makeText(activity, R.string.gcal_TEA_error, Toast.LENGTH_LONG).show(); - } finally { - cursor.close(); - } - - activity.startActivity(intent); - } - - private void refreshDisplayView() { - calendar.setTextColor(themeColor); - if (initialized) { - if (hasEvent) { - calendar.setText(R.string.gcal_TEA_showCalendar_label); - cancelButton.setVisibility(View.GONE); - } else if (calendarName != null) { - calendar.setText(calendarName); - cancelButton.setVisibility(View.VISIBLE); - } else { - calendar.setTextColor(unsetColor); - calendar.setText(R.string.gcal_TEA_addToCalendar_label); - cancelButton.setVisibility(View.GONE); - } - } else { - cancelButton.setVisibility(View.GONE); - if (TextUtils.isEmpty(model.getCalendarURI())) { - calendar.setTextColor(unsetColor); - calendar.setText(R.string.gcal_TEA_addToCalendar_label); - } else { - calendar.setText(R.string.gcal_TEA_showCalendar_label); - } - } - } - - @Override - public int getIcon() { - return R.drawable.ic_event_24dp; - } - - @Override - public void selectedCalendar(AndroidCalendar androidCalendar) { - this.calendarId = androidCalendar.getId(); - this.calendarName = androidCalendar.getName(); - refreshDisplayView(); - } - - @Override - public void dismiss() { - - } -} diff --git a/src/main/java/com/todoroo/astrid/gcal/GCalHelper.java b/src/main/java/com/todoroo/astrid/gcal/GCalHelper.java index 3dc5b9ab4..0571d34fd 100644 --- a/src/main/java/com/todoroo/astrid/gcal/GCalHelper.java +++ b/src/main/java/com/todoroo/astrid/gcal/GCalHelper.java @@ -194,7 +194,7 @@ public class GCalHelper { return eventDeleted; } - void createStartAndEndDate(Task task, ContentValues values) { + public void createStartAndEndDate(Task task, ContentValues values) { long dueDate = task.getDueDate(); long tzCorrectedDueDate = dueDate + TimeZone.getDefault().getOffset(dueDate); long tzCorrectedDueDateNow = DateUtilities.now() + TimeZone.getDefault().getOffset(DateUtilities.now()); @@ -232,6 +232,26 @@ public class GCalHelper { } } + public AndroidCalendar getCalendar(String id) { + ContentResolver cr = context.getContentResolver(); + + Cursor c = cr.query(getCalendarContentUri(Calendars.CALENDAR_CONTENT_CALENDARS), Calendars.CALENDARS_PROJECTION, + Calendars.CALENDARS_WHERE + " AND Calendars._id=" + id, null, Calendars.CALENDARS_SORT); + try { + if (c.moveToFirst()) { + int nameColumn = c.getColumnIndex(Calendars.CALENDARS_DISPLAY_COL); + String name = c.getString(nameColumn); + return new AndroidCalendar(id, name); + } + } finally { + if(c != null) { + c.close(); + } + } + + return null; + } + /** * Appends all user-modifiable calendars to listPreference. */ diff --git a/src/main/java/com/todoroo/astrid/helper/TaskEditControlSet.java b/src/main/java/com/todoroo/astrid/helper/TaskEditControlSet.java deleted file mode 100644 index 4cbf2e169..000000000 --- a/src/main/java/com/todoroo/astrid/helper/TaskEditControlSet.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.todoroo.astrid.helper; - -import android.view.View; - -import com.todoroo.astrid.data.Task; - -public interface TaskEditControlSet { - View getView(); - - void readFromTask(Task task); - - void writeToModel(Task task); - - int getIcon(); -} diff --git a/src/main/java/com/todoroo/astrid/helper/TaskEditControlSetBase.java b/src/main/java/com/todoroo/astrid/helper/TaskEditControlSetBase.java deleted file mode 100644 index e1ef65ba7..000000000 --- a/src/main/java/com/todoroo/astrid/helper/TaskEditControlSetBase.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.helper; - -import android.app.Activity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.LinearLayout; - -import com.todoroo.astrid.data.Task; - -import org.tasks.R; - -import static org.tasks.preferences.ResourceResolver.getData; - -// --- interface - -/** - * Interface for working with controls that alter task data - */ -public abstract class TaskEditControlSetBase implements TaskEditControlSet { - - protected final Activity activity; - private final int viewLayout; - private boolean useTemplate; - private View view; - protected Task model; - protected boolean initialized = false; - protected final int themeColor; - protected final int unsetColor; - - public TaskEditControlSetBase(Activity activity, int viewLayout) { - this(activity, viewLayout, true); - } - - public TaskEditControlSetBase(Activity activity, int viewLayout, boolean useTemplate) { - this.activity = activity; - this.viewLayout = viewLayout; - this.useTemplate = useTemplate; - if (viewLayout == -1) { - initialized = true; - } - - themeColor = getData(activity, R.attr.asTextColor); - unsetColor = getData(activity, R.attr.asTextColorHint); - } - - protected View inflateWithTemplate(int layout) { - LayoutInflater layoutInflater = LayoutInflater.from(activity); - View template = layoutInflater.inflate(R.layout.control_set_template, null); - LinearLayout content = (LinearLayout) template.findViewById(R.id.content); - content.addView(layoutInflater.inflate(layout, null)); - return template; - } - - @Override - public View getView() { - if (view == null && !initialized) { - if (viewLayout != -1) { - view = useTemplate ? inflateWithTemplate(viewLayout) : LayoutInflater.from(activity).inflate(viewLayout, null); - afterInflate(); - } - if (model != null) { - readFromTaskOnInitialize(); - } - this.initialized = true; - } - return view; - } - - /** - * Read data from model to update the control set - */ - @Override - public void readFromTask(Task task) { - this.model = task; - if (initialized) { - readFromTaskOnInitialize(); - } - } - - - /** - * Called once to setup the ui with data from the task - */ - protected abstract void readFromTaskOnInitialize(); - - /** - * Write data from control set to model - */ - @Override - public void writeToModel(Task task) { - if (initialized) { - writeToModelAfterInitialized(task); - } - } - - /** - * Write to model, if initialization logic has been called - */ - protected abstract void writeToModelAfterInitialized(Task task); - - /** - * Called when views need to be inflated - */ - protected abstract void afterInflate(); -} diff --git a/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java b/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java index 19b38ab77..e0b3bfb9d 100644 --- a/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java +++ b/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java @@ -44,11 +44,10 @@ import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.UserActivity; import com.todoroo.astrid.service.TaskService; -import com.todoroo.astrid.timers.TimerActionControlSet.TimerActionListener; +import com.todoroo.astrid.timers.TimerActionListener; import org.json.JSONObject; import org.tasks.R; -import org.tasks.preferences.Preferences; import java.util.ArrayList; import java.util.Collections; @@ -67,14 +66,12 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene private Task task; private ActFmCameraModule actFmCameraModule; - private final Preferences preferences; private final MetadataDao metadataDao; private final UserActivityDao userActivityDao; private final TaskService taskService; private final ArrayList items = new ArrayList<>(); private EditText commentField; private final View commentsBar; - private View timerView; private View commentButton; private int commentItems = 10; private ImageButton pictureButton; @@ -94,7 +91,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene public EditNoteActivity( ActFmCameraModule actFmCameraModule, - Preferences preferences, MetadataDao metadataDao, UserActivityDao userActivityDao, TaskService taskService, @@ -103,7 +99,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene long t) { super(fragment.getActivity()); this.actFmCameraModule = actFmCameraModule; - this.preferences = preferences; this.metadataDao = metadataDao; this.userActivityDao = userActivityDao; this.taskService = taskService; @@ -141,26 +136,9 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene // --- UI preparation private void setUpInterface() { - timerView = commentsBar.findViewById(R.id.timer_container); commentButton = commentsBar.findViewById(R.id.commentButton); commentField = (EditText) commentsBar.findViewById(R.id.commentField); - final boolean showTimerShortcut = preferences.getBoolean(R.string.p_show_timer_shortcut, false); - - if (showTimerShortcut) { - commentField.setOnFocusChangeListener(new OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - timerView.setVisibility(View.GONE); - commentButton.setVisibility(View.VISIBLE); - } else { - timerView.setVisibility(View.VISIBLE); - commentButton.setVisibility(View.GONE); - } - } - }); - } commentField.setHorizontallyScrolling(false); commentField.setMaxLines(Integer.MAX_VALUE); commentField.setOnKeyListener(new OnKeyListener() { @@ -185,10 +163,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene public void afterTextChanged(Editable s) { commentButton.setVisibility((s.length() > 0 || pendingCommentPicture != null) ? View.VISIBLE : View.GONE); - if (showTimerShortcut) { - timerView.setVisibility((s.length() > 0 || pendingCommentPicture != null) ? View.GONE - : View.VISIBLE); - } } @Override @@ -241,7 +215,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene } }); if(!TextUtils.isEmpty(task.getNotes())) { - TextView notes = new TextView(getContext()); + TextView notes = new TextView(activity); notes.setLinkTextColor(Color.rgb(100, 160, 255)); notes.setTextSize(18); notes.setText(task.getNotes()); @@ -294,7 +268,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene } if (items.size() > commentItems) { - Button loadMore = new Button(getContext()); + Button loadMore = new Button(activity); loadMore.setText(R.string.TEA_load_more); loadMore.setTextColor(activity.getResources().getColor(R.color.task_edit_deadline_gray)); loadMore.setBackgroundColor(Color.alpha(0)); @@ -315,7 +289,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene } public View getUpdateNotes(NoteOrUpdate note, ViewGroup parent) { - View convertView = ((Activity)getContext()).getLayoutInflater().inflate( + View convertView = ((Activity)activity).getLayoutInflater().inflate( R.layout.comment_adapter_row, parent, false); bindView(convertView, note); return convertView; @@ -364,7 +338,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene private void addComment() { addComment(commentField.getText().toString(), UserActivity.ACTION_TASK_COMMENT, task.getUuid(), true); - AndroidUtilities.hideSoftInputForViews(getContext(), commentField); + AndroidUtilities.hideSoftInputForViews(activity, commentField); commentField.setCursorVisible(false); } @@ -459,8 +433,8 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene @Override public void timerStarted(Task t) { addComment(String.format("%s %s", //$NON-NLS-1$ - getContext().getString(R.string.TEA_timer_comment_started), - DateUtilities.getTimeString(getContext(), newDateTime())), + activity.getString(R.string.TEA_timer_comment_started), + DateUtilities.getTimeString(activity, newDateTime())), UserActivity.ACTION_TASK_COMMENT, t.getUuid(), false); @@ -470,9 +444,9 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene public void timerStopped(Task t) { String elapsedTime = DateUtils.formatElapsedTime(t.getElapsedSeconds()); addComment(String.format("%s %s\n%s %s", //$NON-NLS-1$ - getContext().getString(R.string.TEA_timer_comment_stopped), - DateUtilities.getTimeString(getContext(), newDateTime()), - getContext().getString(R.string.TEA_timer_comment_spent), + activity.getString(R.string.TEA_timer_comment_stopped), + DateUtilities.getTimeString(activity, newDateTime()), + activity.getString(R.string.TEA_timer_comment_spent), elapsedTime), UserActivity.ACTION_TASK_COMMENT, t.getUuid(), false); diff --git a/src/main/java/com/todoroo/astrid/provider/Astrid2TaskProvider.java b/src/main/java/com/todoroo/astrid/provider/Astrid2TaskProvider.java index c8ae08d9b..bbb487611 100644 --- a/src/main/java/com/todoroo/astrid/provider/Astrid2TaskProvider.java +++ b/src/main/java/com/todoroo/astrid/provider/Astrid2TaskProvider.java @@ -25,10 +25,12 @@ import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.tags.TagService; import org.tasks.injection.InjectingContentProvider; +import org.tasks.ui.CheckBoxes; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.List; import javax.inject.Inject; @@ -80,6 +82,7 @@ public class Astrid2TaskProvider extends InjectingContentProvider { @Inject Lazy taskService; @Inject Lazy tagService; + @Inject Lazy checkBoxes; static { URI_MATCHER.addURI(AUTHORITY, "tasks", URI_TASKS); @@ -167,7 +170,7 @@ public class Astrid2TaskProvider extends InjectingContentProvider { TaskCriteria.isVisible())). orderBy(SortHelper.defaultTaskOrder()).limit(MAX_NUMBER_OF_TASKS)); try { - int[] importanceColors = Task.getImportanceColors(getContext().getResources()); + List importanceColors = checkBoxes.get().getPriorityColors(); for (int i = 0; i < cursor.getCount(); i++) { cursor.moveToNext(); Task task = new Task(cursor); @@ -176,7 +179,7 @@ public class Astrid2TaskProvider extends InjectingContentProvider { Object[] values = new Object[7]; values[0] = task.getTitle(); - values[1] = importanceColors[task.getImportance()]; + values[1] = importanceColors.get(task.getImportance()); values[2] = task.getDueDate(); values[3] = task.getDueDate(); values[4] = task.getImportance(); diff --git a/src/main/java/com/todoroo/astrid/repeats/RepeatControlSet.java b/src/main/java/com/todoroo/astrid/repeats/RepeatControlSet.java index 2aaf1cdc2..285106632 100644 --- a/src/main/java/com/todoroo/astrid/repeats/RepeatControlSet.java +++ b/src/main/java/com/todoroo/astrid/repeats/RepeatControlSet.java @@ -7,10 +7,16 @@ package com.todoroo.astrid.repeats; import android.app.Activity; import android.app.Dialog; +import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; import android.text.TextUtils; +import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup.LayoutParams; +import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; @@ -22,6 +28,7 @@ import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; +import com.google.common.base.Strings; import com.google.ical.values.Frequency; import com.google.ical.values.RRule; import com.google.ical.values.Weekday; @@ -30,21 +37,24 @@ import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.ui.NumberPickerDialog; import com.todoroo.astrid.ui.NumberPickerDialog.OnNumberPickedListener; -import com.todoroo.astrid.ui.PopupControlSet; -import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; import org.tasks.R; +import org.tasks.activities.DatePickerActivity; import org.tasks.dialogs.DialogBuilder; -import org.tasks.dialogs.MyDatePickerDialog; +import org.tasks.injection.ForActivity; import org.tasks.preferences.ActivityPreferences; import org.tasks.time.DateTime; +import org.tasks.ui.TaskEditControlFragment; import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Calendar; -import java.util.LinkedList; import java.util.List; +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.OnClick; import timber.log.Timber; import static org.tasks.date.DateTimeUtils.newDateTime; @@ -55,9 +65,16 @@ import static org.tasks.date.DateTimeUtils.newDateTime; * @author Tim Su * */ -public class RepeatControlSet extends PopupControlSet { +public class RepeatControlSet extends TaskEditControlFragment { + + public interface RepeatChangedListener { + void repeatChanged(boolean repeat); + } - private static final String FRAG_TAG_REPEAT_UNTIL = "frag_tag_repeat_until"; + private static final int REQUEST_PICK_DATE = 505; + private static final String EXTRA_RECURRENCE = "extra_recurrence"; + private static final String EXTRA_REPEAT_UNTIL = "extra_repeat_until"; + private static final String EXTRA_REPEAT_AFTER_COMPLETION = "extra_repeat_after_completion"; // --- spinner constants @@ -77,7 +94,14 @@ public class RepeatControlSet extends PopupControlSet { private Spinner interval; private Spinner type; private Spinner repeatUntil; - private ImageView clear; + + @Inject DialogBuilder dialogBuilder; + @Inject ActivityPreferences preferences; + @Inject @ForActivity Context context; + + @Bind(R.id.clear) ImageView clear; + @Bind(R.id.display_row_edit) TextView displayView; + private ArrayAdapter repeatUntilAdapter; private final List repeatUntilOptions = new ArrayList<>(); private LinearLayout daysOfWeekContainer; @@ -87,227 +111,49 @@ public class RepeatControlSet extends PopupControlSet { private int repeatValue; private int intervalValue; private long repeatUntilValue; + private View dialogView; + private AlertDialog dialog; - private final List listeners = new LinkedList<>(); - - public interface RepeatChangedListener { - void repeatChanged(boolean repeat); - } - - // --- implementation - - public RepeatControlSet(ActivityPreferences preferences, Activity activity, DialogBuilder dialogBuilder) { - super(preferences, activity, R.layout.control_set_repeat, R.layout.control_set_repeat_display, R.string.repeat_enabled, dialogBuilder); - - clear = (ImageView) getView().findViewById(R.id.clear); - } - - /** Set up the repeat value button */ - private void setRepeatValue(int newValue) { - repeatValue = newValue; - value.setText(activity.getString(R.string.repeat_every, newValue)); - } - - private void setRepeatUntilValue(long newValue) { - repeatUntilValue = newValue; - updateRepeatUntilOptions(); - } - - protected void repeatValueClick() { - int dialogValue = repeatValue; - if(dialogValue == 0) { - dialogValue = 1; - } - - new NumberPickerDialog(activity, preferences.getDialogTheme(), new OnNumberPickedListener() { - @Override - public void onNumberPicked(int number) { - setRepeatValue(number); - } - }, activity.getResources().getString(R.string.repeat_interval_prompt), - dialogValue, 1, 1, 365).show(); - } - - private void repeatUntilClick() { - MyDatePickerDialog dialog = new MyDatePickerDialog(); - DateTime initial = repeatUntilValue > 0 ? newDateTime(repeatUntilValue) : newDateTime(); - dialog.initialize(new DatePickerDialog.OnDateSetListener() { - @Override - public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) { - setRepeatUntilValue(new DateTime(year, month + 1, day, 0, 0, 0, 0).getMillis()); - } - }, initial.getYear(), initial.getMonthOfYear() - 1, initial.getDayOfMonth()); - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - setRepeatUntilValue(repeatUntilValue); - } - }); - dialog.show(activity.getFragmentManager(), FRAG_TAG_REPEAT_UNTIL); - } + private RepeatChangedListener callback; - public void addListener(RepeatChangedListener listener) { - listeners.add(listener); - } + private boolean repeatAfterCompletion; + @Nullable @Override - public void readFromTask(Task task) { - super.readFromTask(task); - recurrence = model.sanitizedRecurrence(); - if(recurrence == null) { - recurrence = ""; + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + if (savedInstanceState != null) { + recurrence = savedInstanceState.getString(EXTRA_RECURRENCE); + repeatUntilValue = savedInstanceState.getLong(EXTRA_REPEAT_UNTIL); + repeatAfterCompletion = savedInstanceState.getBoolean(EXTRA_REPEAT_AFTER_COMPLETION); } - repeatUntilValue = model.getRepeatUntil(); - - if(recurrence.length() > 0) { - try { - RRule rrule = new RRule(recurrence); - repeatValue = rrule.getInterval(); - switch(rrule.getFreq()) { - case DAILY: - intervalValue = INTERVAL_DAYS; - break; - case WEEKLY: { - intervalValue = INTERVAL_WEEKS; - break; - } - case MONTHLY: - intervalValue = INTERVAL_MONTHS; - break; - case HOURLY: - intervalValue = INTERVAL_HOURS; - break; - case MINUTELY: - intervalValue = INTERVAL_MINUTES; - break; - case YEARLY: - intervalValue = INTERVAL_YEARS; - break; - default: - Timber.e(new Exception("Unhandled rrule frequency: " + recurrence), "repeat-unhandled-rule"); - } - } catch (Exception e) { - // invalid RRULE - recurrence = ""; //$NON-NLS-1$ - Timber.e(e, e.getMessage()); - } - } - doRepeat = recurrence.length() > 0; - getDialogView(); - refreshDisplayView(); - } - - @Override - public int getIcon() { - return R.drawable.ic_repeat_24dp; - } - - @Override - protected void readFromTaskOnInitialize() { - DateTime date; - if(model.getDueDate() != 0) { - date = newDateTime(model.getDueDate()); - - int dayOfWeek = date.getDayOfWeek(); - for(int i = 0; i < 7; i++) { - daysOfWeek[i].setChecked(i == dayOfWeek); - } - } - - // read recurrence rule - if(recurrence.length() > 0) { - try { - RRule rrule = new RRule(recurrence); - - setRepeatValue(rrule.getInterval()); - setRepeatUntilValue(model.getRepeatUntil()); - interval.setSelection(intervalValue); - - // clear all day of week checks, then update them - for(int i = 0; i < 7; i++) { - daysOfWeek[i].setChecked(false); - } - - for(WeekdayNum day : rrule.getByDay()) { - for(int i = 0; i < 7; i++) { - if (daysOfWeek[i].getTag().equals(day.wday)) { - daysOfWeek[i].setChecked(true); - } - } - } - } catch (Exception e) { - // invalid RRULE - recurrence = ""; //$NON-NLS-1$ - Timber.e(e, e.getMessage()); - } - } - doRepeat = recurrence.length() > 0; - - // read flag - if(model.repeatAfterCompletion()) { - type.setSelection(TYPE_COMPLETION_DATE); - } else { - type.setSelection(TYPE_DUE_DATE); - } - - refreshDisplayView(); - } - - @Override - protected void afterInflate() { - View dialogView = getDialogView(); + dialogView = inflater.inflate(R.layout.control_set_repeat, null); value = (Button) dialogView.findViewById(R.id.repeatValue); interval = (Spinner) dialogView.findViewById(R.id.repeatInterval); - interval.setAdapter(new ArrayAdapter(activity, android.R.layout.simple_spinner_item, activity.getResources().getStringArray(R.array.repeat_interval)) {{ + interval.setAdapter(new ArrayAdapter(context, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.repeat_interval)) {{ setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); }}); type = (Spinner) dialogView.findViewById(R.id.repeatType); - type.setAdapter(new ArrayAdapter(activity, android.R.layout.simple_spinner_item, activity.getResources().getStringArray(R.array.repeat_type)) {{ + type.setAdapter(new ArrayAdapter(context, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.repeat_type)) {{ setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); }}); daysOfWeekContainer = (LinearLayout) dialogView.findViewById(R.id.repeatDayOfWeekContainer); repeatUntil = (Spinner) dialogView.findViewById(R.id.repeat_until); - repeatUntilAdapter = new ArrayAdapter<>(activity, android.R.layout.simple_spinner_item, repeatUntilOptions); + repeatUntilAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, repeatUntilOptions); repeatUntilAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); repeatUntil.setAdapter(repeatUntilAdapter); - setRepeatValue(1); - setRepeatUntilValue(0); - clear.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - doRepeat = false; - refreshDisplayView(); - - for (RepeatChangedListener l : listeners) { - l.repeatChanged(doRepeat); - } - } - }); // set up days of week DateFormatSymbols dfs = new DateFormatSymbols(); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek()); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1.0f/14); - LinearLayout.LayoutParams textLp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1.0f/14); for(int i = 0; i < 7; i++) { - CheckBox checkBox = new CheckBox(activity); + CheckBox checkBox = (CheckBox) daysOfWeekContainer.getChildAt(i); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); - checkBox.setPadding(0, 0, 0, 0); - checkBox.setLayoutParams(lp); checkBox.setTag(Weekday.values()[dayOfWeek - 1]); - checkBox.setButtonDrawable(R.drawable.btn_check_small); - - TextView label = new TextView(activity); - label.setTextAppearance(activity, R.style.TextAppearance); - label.setLayoutParams(textLp); - label.setTextSize(14); - label.setText(dfs.getShortWeekdays()[dayOfWeek].substring(0, 1)); - + checkBox.setText(dfs.getShortWeekdays()[dayOfWeek].substring(0, 1)); daysOfWeek[i] = checkBox; calendar.add(Calendar.DATE, 1); - daysOfWeekContainer.addView(checkBox); - daysOfWeekContainer.addView(label); } // set up listeners @@ -318,6 +164,7 @@ public class RepeatControlSet extends PopupControlSet { } }); + setRepeatValue(1); interval.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parentView, View view, int position, long id) { @@ -331,6 +178,7 @@ public class RepeatControlSet extends PopupControlSet { } }); + setRepeatUntilValue(repeatUntilValue); repeatUntil.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView adapterView, View view, int i, long l) { @@ -356,10 +204,147 @@ public class RepeatControlSet extends PopupControlSet { }); daysOfWeekContainer.setVisibility(View.GONE); + type.setSelection(repeatAfterCompletion ? TYPE_COMPLETION_DATE : TYPE_DUE_DATE); + applyRecurrence(); + refreshDisplayView(); + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putString(EXTRA_RECURRENCE, getRecurrence()); + outState.putLong(EXTRA_REPEAT_UNTIL, repeatUntilValue); + outState.putBoolean(EXTRA_REPEAT_AFTER_COMPLETION, repeatAfterCompletion); } @Override - protected void writeToModelAfterInitialized(Task task) { + public void onAttach(Activity activity) { + super.onAttach(activity); + + callback = (RepeatChangedListener) activity; + } + + @OnClick(R.id.clear) + void clearRepeat(View view) { + doRepeat = false; + refreshDisplayView(); + callback.repeatChanged(doRepeat); + } + + @OnClick(R.id.display_row_edit) + void openPopup(View view) { + if (dialog == null) { + buildDialog(); + } + dialog.show(); + } + + protected Dialog buildDialog() { + AlertDialog.Builder builder = dialogBuilder.newDialog() + .setView(dialogView) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + doRepeat = true; + + callback.repeatChanged(doRepeat); + + refreshDisplayView(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + refreshDisplayView(); + } + }); + dialog = builder.show(); + return dialog; + } + + @Override + protected int getLayout() { + return R.layout.control_set_repeat_display; + } + + @Override + public int getIcon() { + return R.drawable.ic_repeat_24dp; + } + + @Override + public void initialize(boolean isNewTask, Task task) { + repeatAfterCompletion = task.repeatAfterCompletion(); + recurrence = task.sanitizedRecurrence(); + repeatUntilValue = task.getRepeatUntil(); + } + + @Override + public void apply(Task task) { + String result = getRecurrence(); + + if (type.getSelectedItemPosition() == TYPE_COMPLETION_DATE && !TextUtils.isEmpty(result)) { + result += ";FROM=COMPLETION"; //$NON-NLS-1$ + } + + task.setRecurrence(result); + task.setRepeatUntil(repeatUntilValue); + } + + private void applyRecurrence() { + doRepeat = !Strings.isNullOrEmpty(recurrence); + if (!doRepeat) { + return; + } + + // read recurrence rule + try { + RRule rrule = new RRule(recurrence); + + setRepeatValue(rrule.getInterval()); + + for(WeekdayNum day : rrule.getByDay()) { + for(int i = 0; i < 7; i++) { + if (daysOfWeek[i].getTag().equals(day.wday)) { + daysOfWeek[i].setChecked(true); + } + } + } + + switch(rrule.getFreq()) { + case DAILY: + intervalValue = INTERVAL_DAYS; + break; + case WEEKLY: + intervalValue = INTERVAL_WEEKS; + break; + case MONTHLY: + intervalValue = INTERVAL_MONTHS; + break; + case HOURLY: + intervalValue = INTERVAL_HOURS; + break; + case MINUTELY: + intervalValue = INTERVAL_MINUTES; + break; + case YEARLY: + intervalValue = INTERVAL_YEARS; + break; + default: + Timber.e(new Exception("Unhandled rrule frequency: " + recurrence), "repeat-unhandled-rule"); + } + interval.setSelection(intervalValue); + + } catch (Exception e) { + // invalid RRULE + recurrence = ""; //$NON-NLS-1$ + Timber.e(e, e.getMessage()); + } + } + + private String getRecurrence() { String result; if(!doRepeat) { result = ""; //$NON-NLS-1$ @@ -367,60 +352,93 @@ public class RepeatControlSet extends PopupControlSet { RRule rrule = new RRule(); rrule.setInterval(repeatValue); switch(interval.getSelectedItemPosition()) { - case INTERVAL_DAYS: - rrule.setFreq(Frequency.DAILY); - break; - case INTERVAL_WEEKS: { - rrule.setFreq(Frequency.WEEKLY); - - ArrayList days = new ArrayList<>(); - for (CompoundButton dayOfWeek : daysOfWeek) { - if (dayOfWeek.isChecked()) { - days.add(new WeekdayNum(0, (Weekday) dayOfWeek.getTag())); + case INTERVAL_DAYS: + rrule.setFreq(Frequency.DAILY); + break; + case INTERVAL_WEEKS: { + rrule.setFreq(Frequency.WEEKLY); + + ArrayList days = new ArrayList<>(); + for (CompoundButton dayOfWeek : daysOfWeek) { + if (dayOfWeek.isChecked()) { + days.add(new WeekdayNum(0, (Weekday) dayOfWeek.getTag())); + } } + rrule.setByDay(days); + break; } - rrule.setByDay(days); - break; - } - case INTERVAL_MONTHS: - rrule.setFreq(Frequency.MONTHLY); - break; - case INTERVAL_HOURS: - rrule.setFreq(Frequency.HOURLY); - break; - case INTERVAL_MINUTES: - rrule.setFreq(Frequency.MINUTELY); - break; - case INTERVAL_YEARS: - rrule.setFreq(Frequency.YEARLY); - break; + case INTERVAL_MONTHS: + rrule.setFreq(Frequency.MONTHLY); + break; + case INTERVAL_HOURS: + rrule.setFreq(Frequency.HOURLY); + break; + case INTERVAL_MINUTES: + rrule.setFreq(Frequency.MINUTELY); + break; + case INTERVAL_YEARS: + rrule.setFreq(Frequency.YEARLY); + break; } result = rrule.toIcal(); } - if (type.getSelectedItemPosition() == TYPE_COMPLETION_DATE && !TextUtils.isEmpty(result)) { - result = result + ";FROM=COMPLETION"; //$NON-NLS-1$ - } + return result; + } - task.setRecurrence(result); - task.setRepeatUntil(repeatUntilValue); + /** Set up the repeat value button */ + private void setRepeatValue(int newValue) { + repeatValue = newValue; + value.setText(getString(R.string.repeat_every, newValue)); + } - if(task.repeatAfterCompletion()) { - type.setSelection(1); + private void setRepeatUntilValue(long newValue) { + repeatUntilValue = newValue; + updateRepeatUntilOptions(); + } + + protected void repeatValueClick() { + int dialogValue = repeatValue; + if(dialogValue == 0) { + dialogValue = 1; } + + new NumberPickerDialog(context, preferences.getDialogTheme(), new OnNumberPickedListener() { + @Override + public void onNumberPicked(int number) { + setRepeatValue(number); + } + }, getResources().getString(R.string.repeat_interval_prompt), + dialogValue, 1, 1, 365).show(); + } + + private void repeatUntilClick() { + startActivityForResult(new Intent(context, DatePickerActivity.class) {{ + putExtra(DatePickerActivity.EXTRA_TIMESTAMP, repeatUntilValue > 0 ? repeatUntilValue : 0L); + }}, REQUEST_PICK_DATE); } @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_PICK_DATE) { + if (resultCode == Activity.RESULT_OK) { + setRepeatUntilValue(data.getLongExtra(DatePickerActivity.EXTRA_TIMESTAMP, 0L)); + } else { + setRepeatUntilValue(repeatUntilValue); + } + } + super.onActivityResult(requestCode, resultCode, data); + } + protected void refreshDisplayView() { - TextView repeatDisplay = (TextView) getView().findViewById(R.id.display_row_edit); if (doRepeat) { - repeatDisplay.setText(getRepeatString()); - repeatDisplay.setTextColor(themeColor); + displayView.setText(getRepeatString()); + displayView.setAlpha(1.0f); clear.setVisibility(View.VISIBLE); } else { - repeatDisplay.setTextColor(unsetColor); - repeatDisplay.setText(R.string.repeat_never); + displayView.setAlpha(0.5f); + displayView.setText(R.string.repeat_never); clear.setVisibility(View.GONE); } } @@ -428,40 +446,23 @@ public class RepeatControlSet extends PopupControlSet { private String getRepeatString() { int arrayResource = R.array.repeat_interval; - String[] dates = activity.getResources().getStringArray( + String[] dates = getResources().getStringArray( arrayResource); String date = String.format("%s %s", repeatValue, dates[intervalValue]); //$NON-NLS-1$ if (repeatUntilValue > 0) { - return activity.getString(R.string.repeat_detail_duedate_until, date, getDisplayString()); + return getString(R.string.repeat_detail_duedate_until, date, getDisplayString()); } else { - return activity.getString(R.string.repeat_detail_duedate, date); // Every freq int + return getString(R.string.repeat_detail_duedate, date); // Every freq int } } - @Override - protected Dialog buildDialog(String title, final PopupDialogClickListener okListener, final DialogInterface.OnCancelListener cancelListener) { - PopupDialogClickListener doRepeatButton = new PopupDialogClickListener() { - @Override - public boolean onClick(DialogInterface d, int which) { - doRepeat = true; - - for (RepeatChangedListener l : listeners) { - l.repeatChanged(doRepeat); - } - return okListener.onClick(d, which); - } - }; - - return super.buildDialog(title, doRepeatButton, cancelListener); - } - private void updateRepeatUntilOptions() { repeatUntilOptions.clear(); if (repeatUntilValue > 0) { - repeatUntilOptions.add(activity.getString(R.string.repeat_until, getDisplayString())); + repeatUntilOptions.add(getString(R.string.repeat_until, getDisplayString())); } - repeatUntilOptions.add(activity.getString(R.string.repeat_forever)); - repeatUntilOptions.add(activity.getString(R.string.repeat_until, "").trim()); + repeatUntilOptions.add(getString(R.string.repeat_forever)); + repeatUntilOptions.add(getString(R.string.repeat_until, "").trim()); repeatUntilAdapter.notifyDataSetChanged(); repeatUntil.setSelection(0); } @@ -473,7 +474,7 @@ public class RepeatControlSet extends PopupControlSet { displayString.append(DateUtilities.getDateString(d)); if (Task.hasDueTime(repeatUntilValue)) { displayString.append(", "); //$NON-NLS-1$ //$NON-NLS-2$ - displayString.append(DateUtilities.getTimeString(activity, repeatUntilValue)); + displayString.append(DateUtilities.getTimeString(context, repeatUntilValue)); } } return displayString.toString(); diff --git a/src/main/java/com/todoroo/astrid/service/TaskService.java b/src/main/java/com/todoroo/astrid/service/TaskService.java index 65c5308e5..9eacba998 100644 --- a/src/main/java/com/todoroo/astrid/service/TaskService.java +++ b/src/main/java/com/todoroo/astrid/service/TaskService.java @@ -49,8 +49,6 @@ import timber.log.Timber; @Singleton public class TaskService { - public static final String TRANS_EDIT_SAVE = "task-edit-save"; //$NON-NLS-1$ - public static final String TRANS_REPEAT_COMPLETE = "repeat-complete"; //$NON-NLS-1$ private final TagDataDao tagDataDao; diff --git a/src/main/java/com/todoroo/astrid/tags/TagService.java b/src/main/java/com/todoroo/astrid/tags/TagService.java index e7d45ca3a..7016ba85b 100644 --- a/src/main/java/com/todoroo/astrid/tags/TagService.java +++ b/src/main/java/com/todoroo/astrid/tags/TagService.java @@ -82,14 +82,14 @@ public final class TagService { return tagDataDao.getByUuid(uuid, TagData.PROPERTIES); } - public List getTagNames(long taskId) { + public ArrayList getTagNames(long taskId) { Query query = Query.select(TaskToTagMetadata.TAG_NAME, TaskToTagMetadata.TAG_UUID).where( Criterion.and( MetadataCriteria.withKey(TaskToTagMetadata.KEY), Metadata.DELETION_DATE.eq(0), MetadataCriteria.byTask(taskId))) .orderBy(Order.asc(Functions.upper(TaskToTagMetadata.TAG_NAME))); - final List tagNames = new ArrayList<>(); + final ArrayList tagNames = new ArrayList<>(); metadataDao.query(query, new Callback() { @Override public void apply(Metadata entry) { diff --git a/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java b/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java index 4f2631ec4..a40091dd9 100644 --- a/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java +++ b/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java @@ -5,13 +5,18 @@ */ package com.todoroo.astrid.tags; -import android.app.Activity; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; @@ -20,12 +25,12 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; -import com.google.common.base.Strings; import com.google.common.base.Function; import com.google.common.base.Predicate; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.todoroo.andlib.data.AbstractModel; +import com.google.common.collect.Sets; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.DateUtilities; @@ -34,21 +39,26 @@ import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.ui.PopupControlSet; import com.todoroo.astrid.utility.Flags; import org.tasks.R; import org.tasks.dialogs.DialogBuilder; -import org.tasks.preferences.ActivityPreferences; +import org.tasks.ui.TaskEditControlFragment; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.OnClick; + +import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Lists.transform; import static com.google.common.collect.Sets.difference; import static com.google.common.collect.Sets.newHashSet; @@ -58,32 +68,23 @@ import static com.google.common.collect.Sets.newHashSet; * @author Tim Su * */ -public final class TagsControlSet extends PopupControlSet { +public final class TagsControlSet extends TaskEditControlFragment { - // --- instance variables + private static final String EXTRA_TAGS = "extra_tags"; - private static final String TRANSITORY_TAGS = "tags";//$NON-NLS-1$ + @Inject MetadataDao metadataDao; + @Inject TagDataDao tagDataDao; + @Inject TagService tagService; + @Inject DialogBuilder dialogBuilder; - private ArrayList allTagNames; + @Bind(R.id.display_row_edit) TextView tagsDisplay; + private long taskId; + private ArrayList allTagNames; private LinearLayout newTags; private ListView selectedTags; - private boolean populated = false; - - //private final LinearLayout tagsContainer; - private final TextView tagsDisplay; - - private final MetadataDao metadataDao; - private final TagDataDao tagDataDao; - private final TagService tagService; - - public TagsControlSet(MetadataDao metadataDao, TagDataDao tagDataDao, ActivityPreferences preferences, TagService tagService, Activity activity, DialogBuilder dialogBuilder) { - super(preferences, activity, R.layout.control_set_tag_list, R.layout.control_set_tags, R.string.TEA_tags_label_long, dialogBuilder); - this.metadataDao = metadataDao; - this.tagDataDao = tagDataDao; - this.tagService = tagService; - tagsDisplay = (TextView) getView().findViewById(R.id.display_row_edit); - } + private View dialogView; + private AlertDialog dialog; private String buildTagString() { StringBuilder builder = new StringBuilder(); @@ -103,6 +104,86 @@ public final class TagsControlSet extends PopupControlSet { return builder.toString(); } + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + ArrayList selected; + if (savedInstanceState != null) { + selected = savedInstanceState.getStringArrayList(EXTRA_TAGS); + } else { + selected = tagService.getTagNames(taskId); + } + allTagNames = newArrayList(ImmutableSet.copyOf(transform(tagService.getTagList(), new Function() { + @Override + public String apply(TagData tagData) { + return tagData.getName(); + } + }))); + dialogView = inflater.inflate(R.layout.control_set_tag_list, null); + newTags = (LinearLayout) dialogView.findViewById(R.id.newTags); + selectedTags = (ListView) dialogView.findViewById(R.id.existingTags); + selectedTags.setAdapter(new ArrayAdapter<>(getActivity(), R.layout.simple_list_item_multiple_choice_themed, allTagNames)); + addTag(""); + for (String tag : selected) { + setTagSelected(tag); + } + refreshDisplayView(); + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putStringArrayList(EXTRA_TAGS, getTagList()); + } + + @Override + protected int getLayout() { + return R.layout.control_set_tags; + } + + @Override + public void initialize(boolean isNewTask, Task task) { + taskId = task.getId(); + } + + @Override + public void apply(Task task) { + if (synchronizeTags(task.getId(), task.getUUID())) { + Flags.set(Flags.TAGS_CHANGED); + task.setModificationDate(DateUtilities.now()); + } + } + + @OnClick(R.id.display_row_edit) + void openPopup(View view) { + if (dialog == null) { + buildDialog(); + } + dialog.show(); + } + + protected Dialog buildDialog() { + android.support.v7.app.AlertDialog.Builder builder = dialogBuilder.newDialog() + .setView(dialogView) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + refreshDisplayView(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + refreshDisplayView(); + } + }); + dialog = builder.show(); + return dialog; + } + private void setTagSelected(String tag) { int index = allTagNames.indexOf(tag); if (index >= 0) { @@ -113,37 +194,31 @@ public final class TagsControlSet extends PopupControlSet { } } - private List getTagList() { + private ArrayList getTagList() { Set tags = new LinkedHashSet<>(); - if (initialized) { - for(int i = 0; i < selectedTags.getAdapter().getCount(); i++) { - if (selectedTags.isItemChecked(i)) { - tags.add(allTagNames.get(i)); - } + for(int i = 0; i < selectedTags.getAdapter().getCount(); i++) { + if (selectedTags.isItemChecked(i)) { + tags.add(allTagNames.get(i)); } - for (int i = newTags.getChildCount() - 1 ; i >= 0 ; i--) { - TextView tagName = (TextView) newTags.getChildAt(i).findViewById(R.id.text1); - final String text = tagName.getText().toString(); - if (Strings.isNullOrEmpty(text)) { - continue; - } - TagData tagByName = tagDataDao.getTagByName(text, TagData.PROPERTIES); - if (tagByName != null) { - setTagSelected(tagByName.getName()); - tags.add(tagByName.getName()); - newTags.removeViewAt(i); - } else if (!Iterables.any(tags, new Predicate() { - @Override - public boolean apply(String input) { - return text.equalsIgnoreCase(input); - } - })) { - tags.add(text); - } + } + for (int i = newTags.getChildCount() - 1 ; i >= 0 ; i--) { + TextView tagName = (TextView) newTags.getChildAt(i).findViewById(R.id.text1); + final String text = tagName.getText().toString(); + if (Strings.isNullOrEmpty(text)) { + continue; } - } else { - if (model.getTransitory(TRANSITORY_TAGS) != null) { - return (List) model.getTransitory(TRANSITORY_TAGS); + TagData tagByName = tagDataDao.getTagByName(text, TagData.PROPERTIES); + if (tagByName != null) { + setTagSelected(tagByName.getName()); + tags.add(tagByName.getName()); + newTags.removeViewAt(i); + } else if (!Iterables.any(tags, new Predicate() { + @Override + public boolean apply(String input) { + return text.equalsIgnoreCase(input); + } + })) { + tags.add(text); } } return newArrayList(tags); @@ -151,7 +226,7 @@ public final class TagsControlSet extends PopupControlSet { /** Adds a tag to the tag field */ void addTag(String tagName) { - LayoutInflater inflater = activity.getLayoutInflater(); + LayoutInflater inflater = getActivity().getLayoutInflater(); // check if already exists TextView lastText; @@ -235,142 +310,73 @@ public final class TagsControlSet extends PopupControlSet { return (TextView) lastItem.findViewById(R.id.text1); } - @Override - public void readFromTask(Task task) { - super.readFromTask(task); - if(model.getId() != AbstractModel.NO_ID) { - model.putTransitory(TRANSITORY_TAGS, tagService.getTagNames(model.getId())); - refreshDisplayView(); - } - } - @Override public int getIcon() { return R.drawable.ic_label_24dp; } - @Override - protected void readFromTaskOnInitialize() { - newTags.removeAllViews(); - - for (int i = 0; i < selectedTags.getCount(); i++) { // clear all selected items - selectedTags.setItemChecked(i, false); - } - if(model.getId() != AbstractModel.NO_ID) { - selectTagsFromModel(); - } - addTag(""); //$NON-NLS-1$ - refreshDisplayView(); - populated = true; - } - - private void selectTagsFromModel() { - List tags = (List) model.getTransitory(TRANSITORY_TAGS); - if (tags != null) { - for (String tag : tags) { - setTagSelected(tag); - } - } - } - - @Override - protected void afterInflate() { - allTagNames = newArrayList(ImmutableSet.copyOf(transform(tagService.getTagList(), new Function() { - @Override - public String apply(TagData tagData) { - return tagData.getName(); - } - }))); - - selectedTags = (ListView) getDialogView().findViewById(R.id.existingTags); - selectedTags.setAdapter(new ArrayAdapter<>(activity, - R.layout.simple_list_item_multiple_choice_themed, allTagNames)); - selectedTags.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - newTags = (LinearLayout) getDialogView().findViewById(R.id.newTags); - } - - @Override - protected void writeToModelAfterInitialized(Task task) { - // this is a case where we're asked to save but the UI was not yet populated - if(!populated) { - return; - } - - synchronizeTags(task.getId(), task.getUUID()); - Flags.set(Flags.TAGS_CHANGED); - task.setModificationDate(DateUtilities.now()); - } - - @Override protected void refreshDisplayView() { String tagString = buildTagString(); if (!TextUtils.isEmpty(tagString)) { tagsDisplay.setText(tagString); - tagsDisplay.setTextColor(themeColor); + tagsDisplay.setAlpha(1.0f); } else { tagsDisplay.setText(R.string.tag_FEx_untagged); - tagsDisplay.setTextColor(unsetColor); + tagsDisplay.setAlpha(0.5f); } } /** * Save the given array of tags into the database */ - private void synchronizeTags(long taskId, String taskUuid) { + private boolean synchronizeTags(long taskId, String taskUuid) { Query query = Query.select(Metadata.PROPERTIES).where( Criterion.and( TaskToTagMetadata.TASK_UUID.eq(taskUuid), Metadata.DELETION_DATE.eq(0)) ); - Set existingTagIds = newHashSet(transform(metadataDao.toList(query), new Function() { + Set existingTags = newHashSet(transform(metadataDao.toList(query), new Function() { @Override - public String apply(Metadata tagData) { - return tagData.getValue(TaskToTagMetadata.TAG_UUID); + public TagData apply(Metadata metadata) { + return tagDataDao.getByUuid(metadata.getValue(TaskToTagMetadata.TAG_UUID)); } })); - List tags = getTagList(); - // create missing tags - for (String tag : tags) { - TagData tagData = tagDataDao.getTagByName(tag, TagData.ID); - if (tagData == null) { - tagData = new TagData(); - tagData.setName(tag); - tagDataDao.persist(tagData); - } - } - List selectedTags = newArrayList(transform(tags, new Function() { + Set selectedTags = newHashSet(transform(getTagList(), new Function() { @Override - public TagData apply(String tag) { - return tagDataDao.getTagByName(tag, TagData.PROPERTIES); + public TagData apply(String tagName) { + TagData tagData = tagDataDao.getTagByName(tagName, TagData.PROPERTIES); + if (tagData == null) { + // create missing tags + tagData = new TagData(); + tagData.setName(tagName); + tagDataDao.persist(tagData); + } + return tagData; } })); - deleteLinks(taskId, taskUuid, difference(existingTagIds, newHashSet(Iterables.transform(selectedTags, new Function() { - @Override - public String apply(TagData tagData) { - return tagData.getUUID(); - } - })))); - for (TagData tagData : selectedTags) { - if (!existingTagIds.contains(tagData.getUUID())) { - Metadata newLink = TaskToTagMetadata.newTagMetadata(taskId, taskUuid, tagData.getName(), tagData.getUUID()); - metadataDao.createNew(newLink); - } + Sets.SetView added = difference(selectedTags, existingTags); + Sets.SetView removed = difference(existingTags, selectedTags); + deleteLinks(taskId, taskUuid, removed); + for (TagData tagData : added) { + Metadata newLink = TaskToTagMetadata.newTagMetadata(taskId, taskUuid, tagData.getName(), tagData.getUuid()); + metadataDao.createNew(newLink); } + return !removed.isEmpty() || !added.isEmpty(); } /** * Delete all links between the specified task and the list of tags */ - private void deleteLinks(long taskId, String taskUuid, Iterable tagUuids) { + private void deleteLinks(long taskId, String taskUuid, Iterable tags) { Metadata deleteTemplate = new Metadata(); deleteTemplate.setTask(taskId); // Need this for recording changes in outstanding table deleteTemplate.setDeletionDate(DateUtilities.now()); - for (String uuid : tagUuids) { + for (TagData tag : tags) { // TODO: Right now this is in a loop because each deleteTemplate needs the individual tagUuid in order to record // the outstanding entry correctly. If possible, this should be improved to a single query - deleteTemplate.setValue(TaskToTagMetadata.TAG_UUID, uuid); // Need this for recording changes in outstanding table + deleteTemplate.setValue(TaskToTagMetadata.TAG_UUID, tag.getUuid()); // Need this for recording changes in outstanding table metadataDao.update(Criterion.and(MetadataDao.MetadataCriteria.withKey(TaskToTagMetadata.KEY), Metadata.DELETION_DATE.eq(0), - TaskToTagMetadata.TASK_UUID.eq(taskUuid), TaskToTagMetadata.TAG_UUID.eq(uuid)), deleteTemplate); + TaskToTagMetadata.TASK_UUID.eq(taskUuid), TaskToTagMetadata.TAG_UUID.eq(tag.getUuid())), deleteTemplate); } } } diff --git a/src/main/java/com/todoroo/astrid/timers/TimerActionControlSet.java b/src/main/java/com/todoroo/astrid/timers/TimerActionControlSet.java deleted file mode 100644 index e174ab534..000000000 --- a/src/main/java/com/todoroo/astrid/timers/TimerActionControlSet.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.timers; - -import android.app.Activity; -import android.graphics.drawable.Drawable; -import android.os.SystemClock; -import android.support.v4.graphics.drawable.DrawableCompat; -import android.text.format.DateFormat; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Chronometer; -import android.widget.Chronometer.OnChronometerTickListener; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; -import com.todoroo.astrid.service.TaskService; - -import org.tasks.R; -import org.tasks.notifications.NotificationManager; - -import java.util.LinkedList; -import java.util.List; - -public class TimerActionControlSet extends TaskEditControlSetBase { - - private final ImageView timerButton; - private final Chronometer chronometer; - private boolean timerActive; - private final List listeners = new LinkedList<>(); - - public TimerActionControlSet(final NotificationManager notificationManager, final TaskService taskService, final Activity activity, View parent) { - super(activity, -1); - - LinearLayout timerContainer = (LinearLayout) parent.findViewById(R.id.timer_container); - timerButton = (ImageView) parent.findViewById(R.id.timer_button); - OnClickListener timerListener = new OnClickListener() { - @Override - public void onClick(View v) { - if (timerActive) { - TimerPlugin.stopTimer(notificationManager, taskService, activity, model); - - for (TimerActionListener listener : listeners) { - listener.timerStopped(model); - } - chronometer.stop(); - } else { - TimerPlugin.startTimer(notificationManager, taskService, activity, model); - for (TimerActionListener listener : listeners) { - listener.timerStarted(model); - } - chronometer.start(); - } - timerActive = !timerActive; - updateDisplay(); - } - }; - timerContainer.setOnClickListener(timerListener); - chronometer = (Chronometer) parent.findViewById(R.id.timer); - } - - @Override - protected void readFromTaskOnInitialize() { - timerActive = model.getTimerStart() != 0; - - updateDisplay(); - } - - @Override - protected void afterInflate() { - // Do nothing - } - - @Override - protected void writeToModelAfterInitialized(Task task) { - // Nothing to do here - } - - private void updateDisplay() { - int drawableRes = timerActive ? R.drawable.ic_pause_24dp : R.drawable.ic_play_arrow_24dp; - final Drawable drawable = DrawableCompat.wrap(activity.getResources().getDrawable(drawableRes)); - DrawableCompat.setTint(drawable, activity.getResources().getColor(android.R.color.white)); - timerButton.setImageDrawable(drawable); - - long elapsed = model.getElapsedSeconds() * 1000L; - if (timerActive) { - chronometer.setVisibility(View.VISIBLE); - elapsed += DateUtilities.now() - model.getTimerStart(); - chronometer.setBase(SystemClock.elapsedRealtime() - elapsed); - if (elapsed > DateUtilities.ONE_DAY) { - chronometer.setOnChronometerTickListener(new OnChronometerTickListener() { - @Override - public void onChronometerTick(Chronometer cArg) { - long t = SystemClock.elapsedRealtime() - cArg.getBase(); - cArg.setText(DateFormat.format("d'd' h:mm", t)); //$NON-NLS-1$ - } - }); - - } - chronometer.start(); - } else { - chronometer.setVisibility(View.GONE); - chronometer.stop(); - } - } - - @Override - public int getIcon() { - return -1; - } - - public interface TimerActionListener { - void timerStopped(Task task); - void timerStarted(Task task); - } - - public void addListener(TimerActionListener listener) { - this.listeners.add(listener); - } - - public void removeListener(TimerActionListener listener) { - if (listeners.contains(listener)) { - listeners.remove(listener); - } - } -} diff --git a/src/main/java/com/todoroo/astrid/timers/TimerActionListener.java b/src/main/java/com/todoroo/astrid/timers/TimerActionListener.java new file mode 100644 index 000000000..536fcad74 --- /dev/null +++ b/src/main/java/com/todoroo/astrid/timers/TimerActionListener.java @@ -0,0 +1,8 @@ +package com.todoroo.astrid.timers; + +import com.todoroo.astrid.data.Task; + +public interface TimerActionListener { + void timerStopped(Task task); + void timerStarted(Task task); +} diff --git a/src/main/java/com/todoroo/astrid/timers/TimerControlSet.java b/src/main/java/com/todoroo/astrid/timers/TimerControlSet.java index 71c4a544f..837021824 100644 --- a/src/main/java/com/todoroo/astrid/timers/TimerControlSet.java +++ b/src/main/java/com/todoroo/astrid/timers/TimerControlSet.java @@ -1,26 +1,46 @@ /** * Copyright (c) 2012 Todoroo Inc - * + *

* See the file "LICENSE" for the full license governing this code. */ package com.todoroo.astrid.timers; import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.os.SystemClock; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; import android.text.TextUtils; +import android.text.format.DateFormat; import android.text.format.DateUtils; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; +import android.widget.Chronometer; +import android.widget.ImageView; import android.widget.TextView; -import com.todoroo.andlib.data.Property.IntegerProperty; +import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; -import com.todoroo.astrid.timers.TimerActionControlSet.TimerActionListener; -import com.todoroo.astrid.ui.PopupControlSet; +import com.todoroo.astrid.notes.EditNoteActivity; import com.todoroo.astrid.ui.TimeDurationControlSet; import org.tasks.R; import org.tasks.dialogs.DialogBuilder; +import org.tasks.injection.ForActivity; import org.tasks.preferences.ActivityPreferences; +import org.tasks.ui.TaskEditControlFragment; + +import java.util.LinkedList; +import java.util.List; + +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.OnClick; /** * Control Set for managing repeats @@ -28,104 +48,162 @@ import org.tasks.preferences.ActivityPreferences; * @author Tim Su * */ -public class TimerControlSet extends PopupControlSet implements TimerActionListener { +public class TimerControlSet extends TaskEditControlFragment { - TimeDurationTaskEditControlSet estimated, elapsed; - private final TextView displayEdit; - private ActivityPreferences preferences; + public interface TimerControlSetCallback { + Task stopTimer(); + Task startTimer(); + } - public TimerControlSet(ActivityPreferences preferences, final Activity activity, DialogBuilder dialogBuilder) { - super(preferences, activity, R.layout.control_set_timers_dialog, R.layout.control_set_timers, R.string.TEA_timer_controls, dialogBuilder); - this.preferences = preferences; + private static final String EXTRA_STARTED = "extra_started"; + private static final String EXTRA_ESTIMATED = "extra_estimated"; + private static final String EXTRA_ELAPSED = "extra_elapsed"; - displayEdit = (TextView) getView().findViewById(R.id.display_row_edit); - displayEdit.setText(R.string.TEA_timer_controls); - displayEdit.setTextColor(unsetColor); + @Inject ActivityPreferences preferences; + @Inject DialogBuilder dialogBuilder; + @Inject @ForActivity Context context; - estimated = new TimeDurationTaskEditControlSet(activity, getDialogView(), Task.ESTIMATED_SECONDS,R.id.estimatedDuration); - elapsed = new TimeDurationTaskEditControlSet(activity, getDialogView(), Task.ELAPSED_SECONDS, R.id.elapsedDuration); - } + @Bind(R.id.display_row_edit) TextView displayEdit; + @Bind(R.id.timer) Chronometer chronometer; + @Bind(R.id.timer_button) ImageView timerButton; - @Override - protected void readFromTaskOnInitialize() { - estimated.readFromTask(model); - elapsed.readFromTask(model); - } - - @Override - protected void afterInflate() { - // Nothing to do here - } + private TimeDurationControlSet estimated; + private TimeDurationControlSet elapsed; + private long timerStarted; + private final List listeners = new LinkedList<>(); + protected AlertDialog dialog; + private View dialogView; + private int elapsedSeconds; + private int estimatedSeconds; + private TimerControlSetCallback callback; + @Nullable @Override - protected void writeToModelAfterInitialized(Task task) { - if (initialized) { - estimated.writeToModel(task); - elapsed.writeToModel(task); + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + if (savedInstanceState != null) { + timerStarted = savedInstanceState.getLong(EXTRA_STARTED); + elapsedSeconds = savedInstanceState.getInt(EXTRA_ELAPSED); + estimatedSeconds = savedInstanceState.getInt(EXTRA_ESTIMATED); } + + dialogView = inflater.inflate(R.layout.control_set_timers_dialog, null); + estimated = new TimeDurationControlSet(context, dialogView, R.id.estimatedDuration, preferences); + elapsed = new TimeDurationControlSet(context, dialogView, R.id.elapsedDuration, preferences); + estimated.setTimeDuration(estimatedSeconds); + elapsed.setTimeDuration(elapsedSeconds); + refresh(); + return view; } @Override - public int getIcon() { - return R.drawable.ic_timer_24dp; + public void onAttach(Activity activity) { + super.onAttach(activity); + + callback = (TimerControlSetCallback) activity; } - // --- TimeDurationTaskEditControlSet + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); - /** - * Control set for mapping a Property to a TimeDurationControlSet - * @author Tim Su - * - */ - public class TimeDurationTaskEditControlSet extends TaskEditControlSetBase { - private final TimeDurationControlSet controlSet; - private final IntegerProperty property; + outState.putInt(EXTRA_ELAPSED, elapsed.getTimeDurationInSeconds()); + outState.putInt(EXTRA_ESTIMATED, estimated.getTimeDurationInSeconds()); + outState.putLong(EXTRA_STARTED, timerStarted); + } - public TimeDurationTaskEditControlSet(Activity activity, View v, IntegerProperty property, int timeButtonId) { - super(activity, -1); - this.property = property; - this.controlSet = new TimeDurationControlSet(activity, v, property, timeButtonId, preferences); + @OnClick(R.id.display_row_edit) + void openPopup(View view) { + if (dialog == null) { + buildDialog(); } + dialog.show(); + } - @Override - public void readFromTaskOnInitialize() { - controlSet.setModel(model); - controlSet.setTimeDuration(model.getValue(property)); - } + protected Dialog buildDialog() { + AlertDialog.Builder builder = dialogBuilder.newDialog() + .setView(dialogView) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + refreshDisplayView(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + refreshDisplayView(); + } + }); + dialog = builder.show(); + return dialog; + } - @Override - protected void afterInflate() { - // Nothing + @OnClick(R.id.timer_container) + void timerClicked(View view) { + if (timerActive()) { + Task task = callback.stopTimer(); + elapsed.setTimeDuration(task.getElapsedSeconds()); + timerStarted = 0; + for (TimerActionListener listener : listeners) { + listener.timerStopped(task); + } + chronometer.stop(); + refreshDisplayView(); + } else { + Task task = callback.startTimer(); + timerStarted = task.getTimerStart(); + chronometer.start(); + for (TimerActionListener listener : listeners) { + listener.timerStarted(task); + } } + updateChronometer(); + } - @Override - protected void writeToModelAfterInitialized(Task task) { - task.setValue(property, controlSet.getTimeDurationInSeconds()); - } + @Override + protected int getLayout() { + return R.layout.control_set_timers; + } - public String getDisplayString() { - int seconds = controlSet.getTimeDurationInSeconds(); - if (seconds > 0) { - return DateUtils.formatElapsedTime(controlSet.getTimeDurationInSeconds()); - } - return null; - } + @Override + public int getIcon() { + return R.drawable.ic_timer_24dp; + } - @Override - public int getIcon() { - return -1; - } + @Override + public void initialize(boolean isNewTask, Task task) { + timerStarted = task.getTimerStart(); + elapsedSeconds = task.getElapsedSeconds(); + estimatedSeconds = task.getEstimatedSeconds(); } @Override - protected void refreshDisplayView() { - String est = estimated.getDisplayString(); - if (!TextUtils.isEmpty(est)) { - est = activity.getString(R.string.TEA_timer_est, est); + public void apply(Task task) { + task.setElapsedSeconds(elapsed.getTimeDurationInSeconds()); + task.setEstimatedSeconds(estimated.getTimeDurationInSeconds()); + } + + public void setEditNotes(EditNoteActivity editNotes) { + removeListener(editNotes); + addListener(editNotes); + } + + private void refresh() { + refreshDisplayView(); + updateChronometer(); + } + + private void refreshDisplayView() { + String est = null; + int estimatedSeconds = estimated.getTimeDurationInSeconds(); + if (estimatedSeconds > 0) { + est = getString(R.string.TEA_timer_est, DateUtils.formatElapsedTime(estimatedSeconds)); } - String elap = elapsed.getDisplayString(); - if (!TextUtils.isEmpty(elap)) { - elap = activity.getString(R.string.TEA_timer_elap, elap); + String elap = null; + int elapsedSeconds = elapsed.getTimeDurationInSeconds(); + if (elapsedSeconds > 0) { + elap = getString(R.string.TEA_timer_elap, DateUtils.formatElapsedTime(elapsedSeconds)); } String toDisplay; @@ -142,20 +220,51 @@ public class TimerControlSet extends PopupControlSet implements TimerActionListe if (!TextUtils.isEmpty(toDisplay)) { displayEdit.setText(toDisplay); - displayEdit.setTextColor(themeColor); + displayEdit.setAlpha(1.0f); } else { displayEdit.setText(R.string.TEA_timer_controls); - displayEdit.setTextColor(unsetColor); + displayEdit.setAlpha(0.5f); } } - @Override - public void timerStopped(Task task) { - elapsed.readFromTask(task); + private void updateChronometer() { + timerButton.setImageResource(timerActive() + ? R.drawable.ic_pause_24dp + : R.drawable.ic_play_arrow_24dp); + + long elapsed = this.elapsed.getTimeDurationInSeconds() * 1000L; + if (timerActive()) { + chronometer.setVisibility(View.VISIBLE); + elapsed += DateUtilities.now() - timerStarted; + chronometer.setBase(SystemClock.elapsedRealtime() - elapsed); + if (elapsed > DateUtilities.ONE_DAY) { + chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() { + @Override + public void onChronometerTick(Chronometer cArg) { + long t = SystemClock.elapsedRealtime() - cArg.getBase(); + cArg.setText(DateFormat.format("d'd' h:mm", t)); //$NON-NLS-1$ + } + }); + + } + chronometer.start(); + } else { + chronometer.setVisibility(View.GONE); + chronometer.stop(); + } } - @Override - public void timerStarted(Task task) { + public void addListener(TimerActionListener listener) { + this.listeners.add(listener); + } + + public void removeListener(TimerActionListener listener) { + if (listeners.contains(listener)) { + listeners.remove(listener); + } } + private boolean timerActive() { + return timerStarted > 0; + } } diff --git a/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java b/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java index c5df3935d..759c4b196 100644 --- a/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java +++ b/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java @@ -61,8 +61,7 @@ public class TimerPlugin { if(task.getTimerStart() > 0) { int newElapsed = (int)((DateUtilities.now() - task.getTimerStart()) / 1000L); task.setTimerStart(0L); - task.setELAPSED_SECONDS( - task.getElapsedSeconds() + newElapsed); + task.setElapsedSeconds(task.getElapsedSeconds() + newElapsed); } } taskService.save(task); diff --git a/src/main/java/com/todoroo/astrid/ui/DeadlineNumberPicker.java b/src/main/java/com/todoroo/astrid/ui/DeadlineNumberPicker.java deleted file mode 100644 index 69c3f5afd..000000000 --- a/src/main/java/com/todoroo/astrid/ui/DeadlineNumberPicker.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.ui; - -import android.content.Context; -import android.util.AttributeSet; - -import org.tasks.R; - -public class DeadlineNumberPicker extends NumberPicker { - - public DeadlineNumberPicker(Context context) { - super(context); - } - - public DeadlineNumberPicker(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected int getLayout() { - return R.layout.deadline_number_picker; - } - - @Override - protected int getMaxDigits() { - return 2; - } -} diff --git a/src/main/java/com/todoroo/astrid/ui/DescriptionControlSet.java b/src/main/java/com/todoroo/astrid/ui/DescriptionControlSet.java deleted file mode 100644 index 524556281..000000000 --- a/src/main/java/com/todoroo/astrid/ui/DescriptionControlSet.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.ui; - -import android.app.Activity; -import android.widget.EditText; - -import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; - -import org.tasks.R; - -public class DescriptionControlSet extends TaskEditControlSetBase { - - protected EditText editText; - - public DescriptionControlSet(Activity activity) { - super(activity, R.layout.control_set_description); - } - - @Override - protected void afterInflate() { - editText = (EditText) getView().findViewById(R.id.notes); - } - - @Override - protected void readFromTaskOnInitialize() { - editText.setTextKeepState(model.getNotes()); - } - - @Override - protected void writeToModelAfterInitialized(Task task) { - task.setNotes(editText.getText().toString().trim()); - } - - @Override - public int getIcon() { - return R.drawable.ic_event_note_24dp; - } -} diff --git a/src/main/java/com/todoroo/astrid/ui/EditTitleControlSet.java b/src/main/java/com/todoroo/astrid/ui/EditTitleControlSet.java index 8ecf138b1..61c635a41 100644 --- a/src/main/java/com/todoroo/astrid/ui/EditTitleControlSet.java +++ b/src/main/java/com/todoroo/astrid/ui/EditTitleControlSet.java @@ -7,53 +7,85 @@ package com.todoroo.astrid.ui; import android.app.Activity; import android.graphics.Paint; +import android.os.Bundle; +import android.support.annotation.Nullable; import android.text.TextUtils; import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnKeyListener; +import android.view.ViewGroup; +import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.TextView; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSet; -import com.todoroo.astrid.repeats.RepeatControlSet.RepeatChangedListener; import com.todoroo.astrid.service.TaskService; +import org.tasks.R; import org.tasks.ui.CheckBoxes; -import org.tasks.ui.PriorityControlSet.ImportanceChangedListener; +import org.tasks.ui.TaskEditControlFragment; + +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.ButterKnife; +import butterknife.OnClick; /** * Control set for mapping a Property to an EditText * @author Tim Su * */ -public class EditTitleControlSet implements TaskEditControlSet, ImportanceChangedListener, RepeatChangedListener { +public class EditTitleControlSet extends TaskEditControlFragment { + + private static final String EXTRA_COMPLETE = "extra_complete"; + private static final String EXTRA_TITLE = "extra_title"; + private static final String EXTRA_REPEATING = "extra_repeating"; + private static final String EXTRA_PRIORITY = "extra_priority"; - private final EditText editText; - private CheckableImageView completeBox; + @Inject TaskService taskService; - private final CheckBoxes checkBoxes; + @Bind(R.id.title) EditText editText; + @Bind(R.id.completeBox) CheckableImageView completeBox; + + private CheckBoxes checkBoxes; + private boolean isComplete; private boolean isRepeating; private int importanceValue; - private Task model; - private final TaskService taskService; + private boolean isNewTask; + private String title; + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); - public EditTitleControlSet(TaskService taskService, final Activity activity, final EditText editText, CheckableImageView completeBox) { - this.checkBoxes = new CheckBoxes(activity); - this.editText = editText; - this.completeBox = completeBox; - this.taskService = taskService; + checkBoxes = new CheckBoxes(activity); + } + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(getLayout(), null); + ButterKnife.bind(this, view); + if (savedInstanceState != null) { + isComplete = savedInstanceState.getBoolean(EXTRA_COMPLETE); + title = savedInstanceState.getString(EXTRA_TITLE); + isRepeating = savedInstanceState.getBoolean(EXTRA_REPEATING); + importanceValue = savedInstanceState.getInt(EXTRA_PRIORITY); + } + completeBox.setChecked(isComplete); + editText.setTextKeepState(title); editText.setHorizontallyScrolling(false); editText.setMaxLines(Integer.MAX_VALUE); editText.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER) { - AndroidUtilities.hideSoftInputForViews(activity, editText); + AndroidUtilities.hideSoftInputForViews(getActivity(), editText); return true; } return false; @@ -74,39 +106,46 @@ public class EditTitleControlSet implements TaskEditControlSet, ImportanceChange return false; } }); + updateCompleteBox(); + return view; } - protected void readFromTaskOnInitialize() { - editText.setTextKeepState(model.getTitle()); - completeBox.setChecked(model.isCompleted()); - completeBox.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - // set check box to actual action item state - updateCompleteBox(); - } - }); + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putBoolean(EXTRA_COMPLETE, completeBox.isChecked()); + outState.putString(EXTRA_TITLE, getTitle()); + outState.putBoolean(EXTRA_REPEATING, isRepeating); + outState.putInt(EXTRA_PRIORITY, importanceValue); } - @Override - public void importanceChanged(int i) { - importanceValue = i; + @OnClick(R.id.completeBox) + void toggleComplete(View view) { updateCompleteBox(); } - @Override - public void repeatChanged(boolean repeat) { - isRepeating = repeat; + public void onStart() { + super.onStart(); + + if (isNewTask) { + editText.requestFocus(); + editText.setCursorVisible(true); + getActivity().getWindow() + .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + } + + public void setPriority(int priority) { + importanceValue = priority; updateCompleteBox(); } - @Override - public void readFromTask(Task task) { - this.model = task; - readFromTaskOnInitialize(); - isRepeating = !TextUtils.isEmpty(task.getRecurrence()); - importanceValue = model.getImportance(); + public void repeatChanged(boolean repeat) { + isRepeating = repeat; + updateCompleteBox(); } private void updateCompleteBox() { @@ -128,12 +167,8 @@ public class EditTitleControlSet implements TaskEditControlSet, ImportanceChange } @Override - public void writeToModel(Task task) { - task.setTitle(editText.getText().toString()); - boolean newState = completeBox.isChecked(); - if (newState != task.isCompleted()) { - taskService.setComplete(task, newState); - } + protected int getLayout() { + return R.layout.control_set_title; } @Override @@ -142,7 +177,30 @@ public class EditTitleControlSet implements TaskEditControlSet, ImportanceChange } @Override - public View getView() { - throw new RuntimeException(); + public void initialize(boolean isNewTask, Task task) { + this.isNewTask = isNewTask; + + isComplete = task.isCompleted(); + title = task.getTitle(); + isRepeating = !TextUtils.isEmpty(task.getRecurrence()); + importanceValue = task.getImportance(); + } + + @Override + public void apply(Task task) { + task.setTitle(getTitle()); + boolean newState = completeBox.isChecked(); + if (newState != task.isCompleted()) { + taskService.setComplete(task, newState); + } + } + + public String getTitle() { + return editText.getText().toString(); + } + + public void hideKeyboard() { + AndroidUtilities.hideSoftInputForViews(getActivity(), editText); + editText.setCursorVisible(false); } } diff --git a/src/main/java/com/todoroo/astrid/ui/HideUntilControlSet.java b/src/main/java/com/todoroo/astrid/ui/HideUntilControlSet.java index 771da5fa8..08bb4dfb6 100644 --- a/src/main/java/com/todoroo/astrid/ui/HideUntilControlSet.java +++ b/src/main/java/com/todoroo/astrid/ui/HideUntilControlSet.java @@ -5,9 +5,14 @@ */ package com.todoroo.astrid.ui; +import android.app.Activity; +import android.content.Context; import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; @@ -16,18 +21,24 @@ import android.widget.Spinner; import android.widget.TextView; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.astrid.activity.TaskEditFragment; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; import org.tasks.R; import org.tasks.activities.DateAndTimePickerActivity; +import org.tasks.activities.TimePickerActivity; +import org.tasks.injection.ForActivity; import org.tasks.time.DateTime; import org.tasks.ui.HiddenTopArrayAdapter; +import org.tasks.ui.TaskEditControlFragment; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.OnClick; + import static java.util.Arrays.asList; import static org.tasks.date.DateTimeUtils.newDateTime; @@ -37,29 +48,145 @@ import static org.tasks.date.DateTimeUtils.newDateTime; * @author Tim Su * */ -public class HideUntilControlSet extends TaskEditControlSetBase implements OnItemSelectedListener { +public class HideUntilControlSet extends TaskEditControlFragment implements OnItemSelectedListener { + + private static String EXTRA_CUSTOM = "extra_custom"; + private static String EXTRA_SELECTION = "extra_selection"; private static final int SPECIFIC_DATE = -1; private static final int EXISTING_TIME_UNSET = -2; - public static final int REQUEST_HIDE_UNTIL = 11011; + private static final int REQUEST_HIDE_UNTIL = 11011; + + @Inject @ForActivity Context context; //private final CheckBox enabled; - private Spinner spinner; + @Bind(R.id.hideUntil) Spinner spinner; + @Bind(R.id.clear) ImageView clearButton; + + private ArrayAdapter adapter; + private long initialHideUntil; + private int previousSetting = Task.HIDE_UNTIL_NONE; private int selection; - private long existingDate = EXISTING_TIME_UNSET; - private TaskEditFragment taskEditFragment; - private TextView textDisplay; - private ImageView clearButton; private final List spinnerItems = new ArrayList<>(); - public HideUntilControlSet(TaskEditFragment taskEditFragment) { - super(taskEditFragment.getActivity(), R.layout.control_set_hide); - this.taskEditFragment = taskEditFragment; + @OnClick(R.id.clear) + void clearHideUntil(View view) { + updateSpinnerOptions(0); + selection = 0; + spinner.setSelection(selection); + refreshDisplayView(); } - private ArrayAdapter adapter; + @Nullable + @Override + public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + adapter = new HiddenTopArrayAdapter(context, android.R.layout.simple_spinner_item, spinnerItems) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + int selectedItemPosition = position; + if (parent instanceof AdapterView) { + selectedItemPosition = ((AdapterView) parent).getSelectedItemPosition(); + } + TextView tv = (TextView) inflater.inflate(android.R.layout.simple_spinner_item, parent, false); + HideUntilValue value = getItem(selectedItemPosition); + if (value.setting == Task.HIDE_UNTIL_NONE) { + clearButton.setVisibility(View.GONE); + tv.setText(value.label); + } else { + String display = value.label; + if (value.setting != Task.HIDE_UNTIL_SPECIFIC_DAY && value.setting != Task.HIDE_UNTIL_SPECIFIC_DAY_TIME) { + display = display.toLowerCase(); + } + tv.setText(getString(R.string.TEA_hideUntil_display, display)); + } + return tv; + } + }; + if (savedInstanceState == null) { + updateSpinnerOptions(initialHideUntil); + } else { + updateSpinnerOptions(savedInstanceState.getLong(EXTRA_CUSTOM)); + selection = savedInstanceState.getInt(EXTRA_SELECTION); + } + spinner.setAdapter(adapter); + spinner.setSelection(selection); + spinner.setOnItemSelectedListener(this); + refreshDisplayView(); + return view; + } + + @Override + protected int getLayout() { + return R.layout.control_set_hide; + } + + @Override + protected int getIcon() { + return R.drawable.ic_visibility_off_24dp; + } + + @Override + public void initialize(boolean isNewTask, Task task) { + long dueDate = task.getDueDate(); + long hideUntil = task.getHideUntil(); + + DateTime dueDay = newDateTime(dueDate) + .withHourOfDay(0) + .withMinuteOfHour(0) + .withSecondOfMinute(0) + .withMillisOfSecond(0); + + // For the hide until due case, we need the time component + long dueTime = dueDate/1000L*1000L; + + if(hideUntil == 0) { + selection = 0; + hideUntil = 0; + } else if(hideUntil == dueDay.getMillis()) { + selection = 1; + hideUntil = 0; + } else if (hideUntil == dueTime){ + selection = 2; + hideUntil = 0; + } else if(hideUntil + DateUtilities.ONE_DAY == dueDay.getMillis()) { + selection = 3; + hideUntil = 0; + } else if(hideUntil + DateUtilities.ONE_WEEK == dueDay.getMillis()) { + selection = 4; + hideUntil = 0; + } + + initialHideUntil = hideUntil; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_HIDE_UNTIL) { + if (resultCode == Activity.RESULT_OK) { + setCustomDate(data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L)); + } + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + public void apply(Task task) { + HideUntilValue selectedItem = (HideUntilValue) spinner.getSelectedItem(); + long hideUntil = task.createHideUntil(selectedItem.setting, selectedItem.date); + task.setHideUntil(hideUntil); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putLong(EXTRA_CUSTOM, existingDate); + outState.putInt(EXTRA_SELECTION, selection); + } /** * Container class for urgencies @@ -91,7 +218,7 @@ public class HideUntilControlSet extends TaskEditControlSetBase implements OnIte private void updateSpinnerOptions(long specificDate) { spinnerItems.clear(); // set up base values - String[] labels = activity.getResources().getStringArray(R.array.TEA_hideUntil); + String[] labels = getResources().getStringArray(R.array.TEA_hideUntil); spinnerItems.addAll(new ArrayList<>(asList( new HideUntilValue(labels[0], Task.HIDE_UNTIL_DUE), new HideUntilValue(labels[1], Task.HIDE_UNTIL_DUE_TIME), @@ -100,22 +227,26 @@ public class HideUntilControlSet extends TaskEditControlSetBase implements OnIte new HideUntilValue(labels[4], Task.HIDE_UNTIL_SPECIFIC_DAY, -1)))); if(specificDate > 0) { - DateTime hideUntilAsDate = newDateTime(specificDate); - if(hideUntilAsDate.getHourOfDay() == 0 && hideUntilAsDate.getMinuteOfHour() == 0 && hideUntilAsDate.getSecondOfMinute() == 0) { - spinnerItems.add(0, new HideUntilValue(DateUtilities.getDateString(newDateTime(specificDate)), - Task.HIDE_UNTIL_SPECIFIC_DAY, specificDate)); - } else { - spinnerItems.add(0, new HideUntilValue(DateUtilities.getDateStringWithTime(activity, specificDate), - Task.HIDE_UNTIL_SPECIFIC_DAY_TIME, specificDate)); - } + spinnerItems.add(0, getHideUntilValue(specificDate)); existingDate = specificDate; } else { - spinnerItems.add(0, new HideUntilValue("", Task.HIDE_UNTIL_NONE)); + spinnerItems.add(0, new HideUntilValue(getString(R.string.TEA_hideUntil_label), Task.HIDE_UNTIL_NONE)); existingDate = EXISTING_TIME_UNSET; } adapter.notifyDataSetChanged(); } + private HideUntilValue getHideUntilValue(long timestamp) { + DateTime hideUntilAsDate = newDateTime(timestamp); + if(hideUntilAsDate.getHourOfDay() == 0 && hideUntilAsDate.getMinuteOfHour() == 0 && hideUntilAsDate.getSecondOfMinute() == 0) { + return new HideUntilValue(DateUtilities.getDateString(newDateTime(timestamp)), + Task.HIDE_UNTIL_SPECIFIC_DAY, timestamp); + } else { + return new HideUntilValue(DateUtilities.getDateStringWithTime(context, timestamp), + Task.HIDE_UNTIL_SPECIFIC_DAY_TIME, timestamp); + } + } + // --- listening for events @Override @@ -124,11 +255,12 @@ public class HideUntilControlSet extends TaskEditControlSetBase implements OnIte // ... at conclusion of dialog, update our list HideUntilValue item = adapter.getItem(position); if(item.date == SPECIFIC_DATE) { - customDate = + final DateTime customDate = newDateTime(existingDate == EXISTING_TIME_UNSET ? DateUtilities.now() : existingDate) .withSecondOfMinute(0); - taskEditFragment.startActivityForResult(new Intent(taskEditFragment.getActivity(), DateAndTimePickerActivity.class) {{ + final Activity activity = getActivity(); + startActivityForResult(new Intent(activity, DateAndTimePickerActivity.class) {{ putExtra(DateAndTimePickerActivity.EXTRA_TIMESTAMP, customDate.getMillis()); }}, REQUEST_HIDE_UNTIL); spinner.setSelection(previousSetting); @@ -140,8 +272,9 @@ public class HideUntilControlSet extends TaskEditControlSetBase implements OnIte } public void setCustomDate(long timestamp) { - customDate = new DateTime(timestamp); - customDateFinished(); + updateSpinnerOptions(timestamp); + spinner.setSelection(0); + refreshDisplayView(); } @Override @@ -149,121 +282,16 @@ public class HideUntilControlSet extends TaskEditControlSetBase implements OnIte // ignore } - DateTime customDate; - - private void customDateFinished() { - updateSpinnerOptions(customDate.getMillis()); - spinner.setSelection(0); - refreshDisplayView(); - } - // --- setting up values private void refreshDisplayView() { HideUntilValue value = adapter.getItem(selection); if (value.setting == Task.HIDE_UNTIL_NONE) { - textDisplay.setText(R.string.TEA_hideUntil_label); - textDisplay.setTextColor(unsetColor); + spinner.setAlpha(0.5f); clearButton.setVisibility(View.GONE); } else { - String display = value.toString(); - if (value.setting != Task.HIDE_UNTIL_SPECIFIC_DAY && value.setting != Task.HIDE_UNTIL_SPECIFIC_DAY_TIME) { - display = display.toLowerCase(); - } - - textDisplay.setText(activity.getString(R.string.TEA_hideUntil_display, display)); - textDisplay.setTextColor(themeColor); + spinner.setAlpha(1.0f); clearButton.setVisibility(View.VISIBLE); } } - - @Override - protected void afterInflate() { - textDisplay = (TextView) getView().findViewById(R.id.display_row_edit); - clearButton = (ImageView) getView().findViewById(R.id.clear); - clearButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - updateSpinnerOptions(0); - selection = 0; - spinner.setSelection(selection); - refreshDisplayView(); - } - }); - textDisplay.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (spinner == null) { - getView(); - } - spinner.performClick(); - } - }); - this.spinner = (Spinner) getView().findViewById(R.id.hideUntil); - adapter = new HiddenTopArrayAdapter<>(activity, android.R.layout.simple_spinner_item, spinnerItems); - spinner.setAdapter(adapter); - this.spinner.setOnItemSelectedListener(this); - } - - @Override - public void readFromTask(Task task) { - long date = task.getHideUntil(); - - DateTime dueDay = newDateTime(task.getDueDate()) - .withHourOfDay(0) - .withMinuteOfHour(0) - .withSecondOfMinute(0) - .withMillisOfSecond(0); - - // For the hide until due case, we need the time component - long dueTime = task.getDueDate()/1000L*1000L; - - if(date == 0) { - selection = 0; - date = 0; - } else if(date == dueDay.getMillis()) { - selection = 1; - date = 0; - } else if (date == dueTime){ - selection = 2; - date = 0; - } else if(date + DateUtilities.ONE_DAY == dueDay.getMillis()) { - selection = 3; - date = 0; - } else if(date + DateUtilities.ONE_WEEK == dueDay.getMillis()) { - selection = 4; - date = 0; - } - - updateSpinnerOptions(date); - - super.readFromTask(task); - } - - @Override - public int getIcon() { - return R.drawable.ic_visibility_off_24dp; - } - - @Override - protected void readFromTaskOnInitialize() { - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(adapter); - - spinner.setSelection(selection); - refreshDisplayView(); - } - - @Override - protected void writeToModelAfterInitialized(Task task) { - if(adapter == null || spinner == null) { - return; - } - HideUntilValue item = adapter.getItem(spinner.getSelectedItemPosition()); - if(item == null) { - return; - } - long value = task.createHideUntil(item.setting, item.date); - task.setHideUntil(value); - } } diff --git a/src/main/java/com/todoroo/astrid/ui/PopupControlSet.java b/src/main/java/com/todoroo/astrid/ui/PopupControlSet.java deleted file mode 100644 index d82211493..000000000 --- a/src/main/java/com/todoroo/astrid/ui/PopupControlSet.java +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.ui; - -import android.app.Activity; -import android.app.Dialog; -import android.content.DialogInterface; -import android.support.v7.app.AlertDialog; -import android.view.View; -import android.view.View.OnClickListener; - -import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; - -import org.tasks.dialogs.DialogBuilder; -import org.tasks.preferences.ActivityPreferences; - -public abstract class PopupControlSet extends TaskEditControlSetBase { - - protected final View displayView; - protected final ActivityPreferences preferences; - private DialogBuilder dialogBuilder; - protected AlertDialog dialog; - private final String titleString; - - public interface PopupDialogClickListener { - boolean onClick(DialogInterface d, int which); - } - - final PopupDialogClickListener okListener = new PopupDialogClickListener() { - @Override - public boolean onClick(DialogInterface d, int which) { - onOkClick(); - return true; - } - }; - - final DialogInterface.OnCancelListener cancelListener = new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface d) { - onCancelClick(); - } - }; - - public PopupControlSet(ActivityPreferences preferences, Activity activity, int viewLayout, - int taskEditViewLayout, final int title, DialogBuilder dialogBuilder) { - super(activity, viewLayout, false); - this.preferences = preferences; - this.dialogBuilder = dialogBuilder; - if (taskEditViewLayout != -1) { - this.displayView = inflateWithTemplate(taskEditViewLayout); - } else { - this.displayView = null; - } - - titleString = (title > 0) ? activity.getString(title) : ""; //$NON-NLS-1$ - - if (displayView != null) { - displayView.setOnClickListener(getDisplayClickListener()); - } - } - - @Override - public View getView() { - return displayView; - } - - protected View getDialogView() { - return super.getView(); - } - - protected Dialog buildDialog(String title, final PopupDialogClickListener okClickListener, DialogInterface.OnCancelListener cancelClickListener) { - AlertDialog.Builder builder = dialogBuilder.newDialog() - .setView(getDialogView()) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (okClickListener.onClick(dialog, 0)) { - dialog.dismiss(); - } - } - }) - .setOnCancelListener(cancelClickListener); - dialog = builder.show(); - return dialog; - } - - protected OnClickListener getDisplayClickListener() { - return new OnClickListener() { - @Override - public void onClick(View v) { - if (dialog == null) { - buildDialog(titleString, okListener, cancelListener); - } - dialog.show(); - } - }; - } - - protected void onOkClick() { - refreshDisplayView(); - } - - protected void onCancelClick() { - refreshDisplayView(); - } - - public Dialog getDialog() { - return dialog; - } - - @Override - public void writeToModel(Task task) { - if (initialized && dialog != null) { - dialog.dismiss(); - } - super.writeToModel(task); - } - - @Override - public void readFromTask(Task task) { - super.readFromTask(task); - refreshDisplayView(); - } - - protected abstract void refreshDisplayView(); -} diff --git a/src/main/java/com/todoroo/astrid/ui/RandomReminderControlSet.java b/src/main/java/com/todoroo/astrid/ui/RandomReminderControlSet.java index b9b577cfb..d6efad2ef 100644 --- a/src/main/java/com/todoroo/astrid/ui/RandomReminderControlSet.java +++ b/src/main/java/com/todoroo/astrid/ui/RandomReminderControlSet.java @@ -5,13 +5,12 @@ */ package com.todoroo.astrid.ui; -import android.app.Activity; +import android.content.Context; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Spinner; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.astrid.data.Task; import org.tasks.R; @@ -27,35 +26,26 @@ public class RandomReminderControlSet { private final int[] hours; - public RandomReminderControlSet(Activity activity, View parentView) { + public RandomReminderControlSet(Context context, View parentView, long reminderPeriod) { periodSpinner = (Spinner) parentView.findViewById(R.id.reminder_random_interval); periodSpinner.setVisibility(View.VISIBLE); // create adapter ArrayAdapter adapter = new ArrayAdapter<>( - activity, android.R.layout.simple_spinner_item, - activity.getResources().getStringArray(R.array.TEA_reminder_random)); + context, android.R.layout.simple_spinner_item, + context.getResources().getStringArray(R.array.TEA_reminder_random)); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); periodSpinner.setAdapter(adapter); // create hour array - String[] hourStrings = activity.getResources().getStringArray(R.array.TEA_reminder_random_hours); + String[] hourStrings = context.getResources().getStringArray(R.array.TEA_reminder_random_hours); hours = new int[hourStrings.length]; for(int i = 0; i < hours.length; i++) { hours[i] = Integer.parseInt(hourStrings[i]); } - } - - public void readFromTaskOnInitialize(Task model) { - long time = model.getReminderPeriod(); - - if(time <= 0) { - /* default interval for spinner if date is unselected */ - time = DateUtilities.ONE_WEEK * 2; - } int i; for(i = 0; i < hours.length - 1; i++) { - if (hours[i] * DateUtilities.ONE_HOUR >= time) { + if (hours[i] * DateUtilities.ONE_HOUR >= reminderPeriod) { break; } } diff --git a/src/main/java/com/todoroo/astrid/ui/ReminderControlSet.java b/src/main/java/com/todoroo/astrid/ui/ReminderControlSet.java index ad2396c0d..6049b7237 100644 --- a/src/main/java/com/todoroo/astrid/ui/ReminderControlSet.java +++ b/src/main/java/com/todoroo/astrid/ui/ReminderControlSet.java @@ -5,41 +5,55 @@ */ package com.todoroo.astrid.ui; +import android.app.Activity; +import android.content.Context; import android.content.Intent; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; -import android.widget.AdapterView; +import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; +import com.google.common.primitives.Longs; import com.todoroo.andlib.data.Callback; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.astrid.activity.TaskEditFragment; import com.todoroo.astrid.alarms.AlarmFields; import com.todoroo.astrid.alarms.AlarmService; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; import org.tasks.R; import org.tasks.activities.DateAndTimePickerActivity; +import org.tasks.activities.TimePickerActivity; +import org.tasks.injection.ForActivity; import org.tasks.location.Geofence; import org.tasks.location.GeofenceService; import org.tasks.location.PlacePicker; import org.tasks.preferences.Device; import org.tasks.preferences.PermissionRequestor; +import org.tasks.preferences.Preferences; import org.tasks.ui.HiddenTopArrayAdapter; +import org.tasks.ui.TaskEditControlFragment; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.TimeUnit; -import timber.log.Timber; +import javax.inject.Inject; +import butterknife.Bind; +import butterknife.OnClick; +import butterknife.OnItemSelected; + +import static com.google.common.collect.Lists.newArrayList; import static com.todoroo.andlib.utility.DateUtilities.getLongDateStringWithTime; import static org.tasks.date.DateTimeUtils.newDateTime; @@ -49,40 +63,227 @@ import static org.tasks.date.DateTimeUtils.newDateTime; * @author Tim Su * */ -public class ReminderControlSet extends TaskEditControlSetBase implements AdapterView.OnItemSelectedListener { +public class ReminderControlSet extends TaskEditControlFragment { + + private static final int REQUEST_NEW_ALARM = 12152; + private static final int REQUEST_LOCATION_REMINDER = 12153; + + private static final String EXTRA_TASK_ID = "extra_task_id"; + private static final String EXTRA_FLAGS = "extra_flags"; + private static final String EXTRA_RANDOM_REMINDER = "extra_random_reminder"; + private static final String EXTRA_ALARMS = "extra_alarms"; + private static final String EXTRA_GEOFENCES = "extra_geofences"; + + @Inject AlarmService alarmService; + @Inject GeofenceService geofenceService; + @Inject PermissionRequestor permissionRequestor; + @Inject Device device; + @Inject Preferences preferences; + @Inject @ForActivity Context context; - public static final int REQUEST_NEW_ALARM = 12152; - public static final int REQUEST_LOCATION_REMINDER = 12153; + @Bind(R.id.alert_container) LinearLayout alertContainer; + @Bind(R.id.reminder_alarm) Spinner mode; + @Bind(R.id.alarms_add_spinner) Spinner addSpinner; - private Spinner mode; - private Spinner addSpinner; - private TextView modeDisplay; + private long taskId; + private int flags; + private long randomReminder; private RandomReminderControlSet randomControlSet; - private LinearLayout alertContainer; private boolean whenDue; private boolean whenOverdue; - private AlarmService alarmService; - private GeofenceService geofenceService; - private TaskEditFragment taskEditFragment; - private PermissionRequestor permissionRequestor; - private Device device; private List spinnerOptions = new ArrayList<>(); private ArrayAdapter remindAdapter; + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + + remindAdapter = new HiddenTopArrayAdapter(context, android.R.layout.simple_spinner_item, spinnerOptions); + String[] modes = getResources().getStringArray(R.array.reminder_ring_modes); + ArrayAdapter modeAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, modes); + modeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mode.setAdapter(modeAdapter); + + if (savedInstanceState != null) { + taskId = savedInstanceState.getLong(EXTRA_TASK_ID); + flags = savedInstanceState.getInt(EXTRA_FLAGS); + randomReminder = savedInstanceState.getLong(EXTRA_RANDOM_REMINDER); + List geofences = new ArrayList<>(); + List geofenceArray = savedInstanceState.getParcelableArrayList(EXTRA_GEOFENCES); + for (Parcelable geofence : geofenceArray) { + geofences.add((Geofence) geofence); + } + setup(Longs.asList(savedInstanceState.getLongArray(EXTRA_ALARMS)), geofences); + } else { + final List alarms = new ArrayList<>(); + alarmService.getAlarms(taskId, new Callback() { + @Override + public void apply(Metadata entry) { + alarms.add(entry.getValue(AlarmFields.TIME)); + } + }); + setup(alarms, geofenceService.getGeofences(taskId)); + } + + addSpinner.setAdapter(remindAdapter); + + return view; + } + + @OnItemSelected(R.id.alarms_add_spinner) + void addAlarm(int position) { + String selected = spinnerOptions.get(position); + if (selected.equals(getString(R.string.when_due))) { + addDue(); + } else if(selected.equals(getString(R.string.when_overdue))) { + addOverdue(); + } else if (selected.equals(getString(R.string.randomly))) { + addRandomReminder(TimeUnit.DAYS.toMillis(14)); + } else if (selected.equals(getString(R.string.pick_a_date_and_time))) { + addNewAlarm(); + } else if (selected.equals(getString(R.string.pick_a_location))) { + if (permissionRequestor.requestFineLocation()) { + pickLocation(); + } + } + if (position != 0) { + updateSpinner(); + } + } + + @OnClick(R.id.alarms_add) + void addAlarm(View view) { + if (spinnerOptions.size() == 2) { + addNewAlarm(); + } else { + addSpinner.performClick(); + } + } + + @Override + protected int getLayout() { + return R.layout.control_set_reminders; + } + + @Override + public int getIcon() { + return R.drawable.ic_notifications_24dp; + } + + @Override + public void initialize(boolean isNewTask, Task task) { + taskId = task.getId(); + flags = task.getReminderFlags(); + randomReminder = task.getReminderPeriod(); + } + + private void setup(List alarms, List geofences) { + setValue(flags); + + alertContainer.removeAllViews(); + if (whenDue) { + addDue(); + } + if (whenOverdue) { + addOverdue(); + } + if (randomReminder > 0) { + addRandomReminder(randomReminder); + } + for (long timestamp : alarms) { + addAlarmRow(timestamp); + } + for (Geofence geofence : geofences) { + addGeolocationReminder(geofence); + } + updateSpinner(); + } + + @Override + public void apply(Task task) { + task.setReminderFlags(getValue()); + + task.setReminderPeriod(getRandomReminderPeriod()); + + if(alarmService.synchronizeAlarms(task.getId(), getAlarms())) { + task.setModificationDate(DateUtilities.now()); + } + if (geofenceService.synchronizeGeofences(task.getId(), getGeofences())) { + task.setModificationDate(DateUtilities.now()); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putLong(EXTRA_TASK_ID, taskId); + outState.putInt(EXTRA_FLAGS, getValue()); + outState.putLong(EXTRA_RANDOM_REMINDER, getRandomReminderPeriod()); + outState.putLongArray(EXTRA_ALARMS, Longs.toArray(getAlarms())); + outState.putParcelableArrayList(EXTRA_GEOFENCES, newArrayList(getGeofences())); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_NEW_ALARM) { + if (resultCode == Activity.RESULT_OK) { + addAlarmRow(data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L)); + } + } else if (requestCode == REQUEST_LOCATION_REMINDER) { + if (resultCode == Activity.RESULT_OK) { + addGeolocationReminder(PlacePicker.getPlace(context, data, preferences)); + } + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } + + private Set getAlarms() { + Set alarms = new LinkedHashSet<>(); + for (int i = 0 ; i < alertContainer.getChildCount() ; i++) { + Object tag = alertContainer.getChildAt(i).getTag(); + if (tag instanceof Long) { + alarms.add((Long) tag); + } + } + return alarms; + } + + private Set getGeofences() { + Set geofences = new LinkedHashSet<>(); + for (int i = 0 ; i < alertContainer.getChildCount() ; i++) { + Object tag = alertContainer.getChildAt(i).getTag(); + if (tag instanceof Geofence) { + geofences.add((Geofence) tag); + } + } + return geofences; + } - public ReminderControlSet(AlarmService alarmService, GeofenceService geofenceService, - TaskEditFragment taskEditFragment, PermissionRequestor permissionRequestor, - Device device) { - super(taskEditFragment.getActivity(), R.layout.control_set_reminders); - this.alarmService = alarmService; - this.geofenceService = geofenceService; - this.taskEditFragment = taskEditFragment; - this.permissionRequestor = permissionRequestor; - this.device = device; + public void addAlarmRow(final Long timestamp) { + addAlarmRow(getLongDateStringWithTime(context, timestamp), timestamp, null); + } + + public void pickLocation() { + Intent intent = PlacePicker.getIntent(getActivity()); + if (intent != null) { + startActivityForResult(intent, REQUEST_LOCATION_REMINDER); + } + } + + public void addGeolocationReminder(final Geofence geofence) { + View alertItem = addAlarmRow(geofence.getName(), null, new OnClickListener() { + @Override + public void onClick(View v) { + } + }); + alertItem.setTag(geofence); } - public int getValue() { + private int getValue() { int value = 0; if(whenDue) { value |= Task.NOTIFY_AT_DEADLINE; @@ -101,40 +302,18 @@ public class ReminderControlSet extends TaskEditControlSetBase implements Adapte return value; } + private long getRandomReminderPeriod() { + return randomControlSet == null ? 0L : randomControlSet.getReminderPeriod(); + } + private void addNewAlarm() { - taskEditFragment.startActivityForResult(new Intent(taskEditFragment.getActivity(), DateAndTimePickerActivity.class) {{ + startActivityForResult(new Intent(getActivity(), DateAndTimePickerActivity.class) {{ putExtra(DateAndTimePickerActivity.EXTRA_TIMESTAMP, newDateTime().startOfDay().getMillis()); }}, REQUEST_NEW_ALARM); } - public void addAlarmRow(final Long timestamp) { - final View alertItem = addAlarmRow(getLongDateStringWithTime(activity, timestamp), timestamp, null); - TextView display = (TextView) alertItem.findViewById(R.id.alarm_string); - display.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { -// pickNewAlarm(newDateTime(timestamp), new DateAndTimePickerDialog.OnDateTimePicked() { -// @Override -// public void onDateTimePicked(DateTime dateTime) { -// long millis = dateTime.getMillis(); -// addAlarmRow(alertItem, getDisplayString(millis), millis, null); -// } -// }); - } - }); - } - - public void addGeolocationReminder(final Geofence geofence) { - View alertItem = addAlarmRow(geofence.getName(), null, new OnClickListener() { - @Override - public void onClick(View v) { - } - }); - alertItem.setTag(geofence); - } - private View addAlarmRow(String text, Long timestamp, final OnClickListener onRemove) { - final View alertItem = LayoutInflater.from(activity).inflate(R.layout.alarm_edit_row, null); + final View alertItem = getActivity().getLayoutInflater().inflate(R.layout.alarm_edit_row, null); alertContainer.addView(alertItem); addAlarmRow(alertItem, text, timestamp, onRemove); return alertItem; @@ -162,106 +341,24 @@ public class ReminderControlSet extends TaskEditControlSetBase implements Adapte spinnerOptions.clear(); spinnerOptions.add(""); if (!whenDue) { - spinnerOptions.add(taskEditFragment.getString(R.string.when_due)); + spinnerOptions.add(getString(R.string.when_due)); } if (!whenOverdue) { - spinnerOptions.add(taskEditFragment.getString(R.string.when_overdue)); + spinnerOptions.add(getString(R.string.when_overdue)); } if (randomControlSet == null) { - spinnerOptions.add(taskEditFragment.getString(R.string.randomly)); + spinnerOptions.add(getString(R.string.randomly)); } if (device.supportsLocationServices()) { - spinnerOptions.add(taskEditFragment.getString(R.string.pick_a_location)); + spinnerOptions.add(getString(R.string.pick_a_location)); } - spinnerOptions.add(taskEditFragment.getString(R.string.pick_a_date_and_time)); + spinnerOptions.add(getString(R.string.pick_a_date_and_time)); remindAdapter.notifyDataSetChanged(); } - @Override - protected void afterInflate() { - alertContainer = (LinearLayout) getView().findViewById(R.id.alert_container); - getView().findViewById(R.id.alarms_add).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - if (spinnerOptions.size() == 2) { - addNewAlarm(); - } else { - addSpinner.performClick(); - } - } - }); - addSpinner = (Spinner) getView().findViewById(R.id.alarms_add_spinner); - addSpinner.setOnItemSelectedListener(ReminderControlSet.this); - remindAdapter = new HiddenTopArrayAdapter(activity, android.R.layout.simple_spinner_item, spinnerOptions); - addSpinner.setAdapter(remindAdapter); - modeDisplay = (TextView) getView().findViewById(R.id.reminder_alarm_display); - mode = (Spinner) getView().findViewById(R.id.reminder_alarm); - modeDisplay.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mode.performClick(); - } - }); - - String[] list = new String[] { - activity.getString(R.string.ring_once), - activity.getString(R.string.ring_five_times), - activity.getString(R.string.ring_nonstop), - }; - final ArrayAdapter modeAdapter = new ArrayAdapter<>( - activity, android.R.layout.simple_spinner_item, list); - modeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mode.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView parent, View view, - int position, long id) { - modeDisplay.setText(modeAdapter.getItem(position)); - } - - @Override - public void onNothingSelected(AdapterView parent) { -// TODO Auto-generated method stub - - } - }); - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - mode.setAdapter(modeAdapter); - } - }); - } - - @Override - protected void readFromTaskOnInitialize() { - setValue(model.getReminderFlags()); - - alertContainer.removeAllViews(); - if (whenDue) { - addDue(); - } - if (whenOverdue) { - addOverdue(); - } - if (model.hasRandomReminder()) { - addRandomReminder(); - } - alarmService.getAlarms(model.getId(), new Callback() { - @Override - public void apply(Metadata entry) { - addAlarmRow(entry.getValue(AlarmFields.TIME)); - } - }); - for (Geofence geofence : geofenceService.getGeofences(model.getId())) { - addGeolocationReminder(geofence); - } - updateSpinner(); - } - private void addDue() { whenDue = true; - addAlarmRow(taskEditFragment.getString(R.string.when_due), null, new OnClickListener() { + addAlarmRow(getString(R.string.when_due), null, new OnClickListener() { @Override public void onClick(View v) { whenDue = false; @@ -271,7 +368,7 @@ public class ReminderControlSet extends TaskEditControlSetBase implements Adapte private void addOverdue() { whenOverdue = true; - addAlarmRow(taskEditFragment.getString(R.string.when_overdue), null, new OnClickListener() { + addAlarmRow(getString(R.string.when_overdue), null, new OnClickListener() { @Override public void onClick(View v) { whenOverdue = false; @@ -279,15 +376,14 @@ public class ReminderControlSet extends TaskEditControlSetBase implements Adapte }); } - private void addRandomReminder() { - View alarmRow = addAlarmRow(taskEditFragment.getString(R.string.randomly_once), null, new OnClickListener() { + private void addRandomReminder(long reminderPeriod) { + View alarmRow = addAlarmRow(getString(R.string.randomly_once), null, new OnClickListener() { @Override public void onClick(View v) { randomControlSet = null; } }); - randomControlSet = new RandomReminderControlSet(activity, alarmRow); - randomControlSet.readFromTaskOnInitialize(model); + randomControlSet = new RandomReminderControlSet(context, alarmRow, reminderPeriod); } private void setValue(int flags) { @@ -302,72 +398,4 @@ public class ReminderControlSet extends TaskEditControlSetBase implements Adapte mode.setSelection(0); } } - - @Override - protected void writeToModelAfterInitialized(Task task) { - task.setReminderFlags(getValue()); - - task.setReminderPeriod(randomControlSet == null ? 0L : randomControlSet.getReminderPeriod()); - - Set alarms = new LinkedHashSet<>(); - Set geofences = new LinkedHashSet<>(); - - for(int i = 0; i < alertContainer.getChildCount(); i++) { - Object tag = alertContainer.getChildAt(i).getTag(); - //noinspection StatementWithEmptyBody - if (tag == null) { - } else if (tag instanceof Long) { - alarms.add((Long) tag); - } else if (tag instanceof Geofence) { - geofences.add((Geofence) tag); - } else { - Timber.e("Unexpected tag: %s", tag); - } - } - - if(alarmService.synchronizeAlarms(task.getId(), alarms)) { - task.setModificationDate(DateUtilities.now()); - } - if (geofenceService.synchronizeGeofences(task.getId(), geofences)) { - task.setModificationDate(DateUtilities.now()); - } - } - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - Timber.i("onItemSelected(%s, %s, %s, %s)", parent, view, position, id); - String selected = spinnerOptions.get(position); - if (selected.equals(taskEditFragment.getString(R.string.when_due))) { - addDue(); - } else if(selected.equals(taskEditFragment.getString(R.string.when_overdue))) { - addOverdue(); - } else if (selected.equals(taskEditFragment.getString(R.string.randomly))) { - addRandomReminder(); - } else if (selected.equals(taskEditFragment.getString(R.string.pick_a_date_and_time))) { - addNewAlarm(); - } else if (selected.equals(taskEditFragment.getString(R.string.pick_a_location))) { - if (permissionRequestor.requestFineLocation()) { - pickLocation(); - } - } - if (position != 0) { - updateSpinner(); - } - } - - public void pickLocation() { - Intent intent = PlacePicker.getIntent(taskEditFragment.getActivity()); - if (intent != null) { - taskEditFragment.startActivityForResult(intent, REQUEST_LOCATION_REMINDER); - } - } - - @Override - public void onNothingSelected(AdapterView parent) { - } - - @Override - public int getIcon() { - return R.drawable.ic_notifications_24dp; - } } diff --git a/src/main/java/com/todoroo/astrid/ui/TimeDurationControlSet.java b/src/main/java/com/todoroo/astrid/ui/TimeDurationControlSet.java index 19666f4af..321795d43 100644 --- a/src/main/java/com/todoroo/astrid/ui/TimeDurationControlSet.java +++ b/src/main/java/com/todoroo/astrid/ui/TimeDurationControlSet.java @@ -5,7 +5,7 @@ */ package com.todoroo.astrid.ui; -import android.app.Activity; +import android.content.Context; import android.content.res.Resources; import android.text.format.DateUtils; import android.view.View; @@ -20,29 +20,22 @@ import org.tasks.preferences.ActivityPreferences; public class TimeDurationControlSet implements OnNNumberPickedListener, View.OnClickListener { - private final Activity activity; + private final Context context; private final TextView timeButton; private int timeDuration; private int[] initialValues = null; private NNumberPickerDialog dialog = null; - private Task model; - private final IntegerProperty property; private ActivityPreferences activityPreferences; - public TimeDurationControlSet(Activity activity, View view, IntegerProperty property, + public TimeDurationControlSet(Context context, View view, int timeButtonId, ActivityPreferences activityPreferences) { - this.activity = activity; - this.property = property; + this.context = context; this.activityPreferences = activityPreferences; timeButton = (TextView)view.findViewById(timeButtonId); ((View) timeButton.getParent()).setOnClickListener(this); } - public void setModel(Task model) { - this.model = model; - } - public int getTimeDurationInSeconds() { return timeDuration; } @@ -54,7 +47,7 @@ public class TimeDurationControlSet implements OnNNumberPickedListener, View.OnC timeDuration = timeDurationInSeconds; - Resources r = activity.getResources(); + Resources r = context.getResources(); if(timeDurationInSeconds == 0) { timeButton.setText(r.getString(R.string.WID_dateButtonUnset)); return; @@ -65,10 +58,6 @@ public class TimeDurationControlSet implements OnNNumberPickedListener, View.OnC int hours = timeDuration / 3600; int minutes = timeDuration / 60 - 60 * hours; initialValues = new int[] { hours, minutes }; - - if (model != null) { - model.setValue(property, timeDuration); - } } /** Called when NumberPicker activity is completed */ @@ -81,8 +70,8 @@ public class TimeDurationControlSet implements OnNNumberPickedListener, View.OnC @Override public void onClick(View v) { if(dialog == null) { - dialog = new NNumberPickerDialog(activity, activityPreferences.getDialogTheme(), this, - activity.getResources().getString(R.string.DLG_hour_minutes), + dialog = new NNumberPickerDialog(context, activityPreferences.getDialogTheme(), this, + context.getResources().getString(R.string.DLG_hour_minutes), new int[] {0, 0}, new int[] {1, 5}, new int[] {0, 0}, new int[] {999, 59}, new String[] {":", null}); final NumberPicker hourPicker = dialog.getPicker(0); diff --git a/src/main/java/org/tasks/activities/CalendarSelectionActivity.java b/src/main/java/org/tasks/activities/CalendarSelectionActivity.java index dcba4bf67..bc6f3af32 100644 --- a/src/main/java/org/tasks/activities/CalendarSelectionActivity.java +++ b/src/main/java/org/tasks/activities/CalendarSelectionActivity.java @@ -2,11 +2,16 @@ package org.tasks.activities; import android.app.FragmentManager; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Bundle; import com.todoroo.astrid.gcal.AndroidCalendar; import org.tasks.injection.InjectingAppCompatActivity; +import org.tasks.preferences.ActivityPreferences; +import org.tasks.preferences.PermissionRequestor; + +import javax.inject.Inject; public class CalendarSelectionActivity extends InjectingAppCompatActivity implements CalendarSelectionDialog.CalendarSelectionHandler { @@ -14,19 +19,20 @@ public class CalendarSelectionActivity extends InjectingAppCompatActivity implem public static final String EXTRA_CALENDAR_ID = "extra_calendar_id"; public static final String EXTRA_CALENDAR_NAME = "extra_calendar_name"; + public static final String EXTRA_SHOW_NONE = "extra_show_none"; + + @Inject PermissionRequestor permissionRequestor; + @Inject ActivityPreferences preferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - FragmentManager fragmentManager = getFragmentManager(); - CalendarSelectionDialog fragmentByTag = (CalendarSelectionDialog) fragmentManager.findFragmentByTag(FRAG_TAG_CALENDAR_PREFERENCE_SELECTION); - if (fragmentByTag == null) { - fragmentByTag = new CalendarSelectionDialog(); - fragmentByTag.enableNone(); - fragmentByTag.show(fragmentManager, FRAG_TAG_CALENDAR_PREFERENCE_SELECTION); + preferences.applyTheme(); + + if (permissionRequestor.requestCalendarPermissions()) { + showDialog(); } - fragmentByTag.setCalendarSelectionHandler(this); } @Override @@ -41,4 +47,30 @@ public class CalendarSelectionActivity extends InjectingAppCompatActivity implem public void dismiss() { finish(); } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == PermissionRequestor.REQUEST_CALENDAR) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + showDialog(); + } else { + finish(); + } + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } + + private void showDialog() { + FragmentManager fragmentManager = getFragmentManager(); + CalendarSelectionDialog fragmentByTag = (CalendarSelectionDialog) fragmentManager.findFragmentByTag(FRAG_TAG_CALENDAR_PREFERENCE_SELECTION); + if (fragmentByTag == null) { + fragmentByTag = new CalendarSelectionDialog(); + if (getIntent().getBooleanExtra(EXTRA_SHOW_NONE, false)) { + fragmentByTag.enableNone(); + } + fragmentByTag.show(fragmentManager, FRAG_TAG_CALENDAR_PREFERENCE_SELECTION); + } + fragmentByTag.setCalendarSelectionHandler(this); + } } diff --git a/src/main/java/org/tasks/activities/DatePickerActivity.java b/src/main/java/org/tasks/activities/DatePickerActivity.java new file mode 100644 index 000000000..b9573e852 --- /dev/null +++ b/src/main/java/org/tasks/activities/DatePickerActivity.java @@ -0,0 +1,70 @@ +package org.tasks.activities; + +import android.app.FragmentManager; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; + +import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; + +import org.tasks.R; +import org.tasks.dialogs.MyDatePickerDialog; +import org.tasks.injection.InjectingAppCompatActivity; +import org.tasks.preferences.ActivityPreferences; +import org.tasks.time.DateTime; + +import javax.inject.Inject; + +import static org.tasks.time.DateTimeUtils.currentTimeMillis; + +public class DatePickerActivity extends InjectingAppCompatActivity + implements DatePickerDialog.OnDateSetListener, DialogInterface.OnDismissListener { + + private static final String FRAG_TAG_DATE_PICKER = "frag_tag_date_picker"; + + public static final String EXTRA_TIMESTAMP = "extra_timestamp"; + + @Inject ActivityPreferences preferences; + + private DateTime initial; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + preferences.applyTheme(); + + long timestamp = getIntent().getLongExtra(EXTRA_TIMESTAMP, currentTimeMillis()); + initial = timestamp > 0 ? new DateTime(timestamp) : new DateTime().startOfDay(); + + FragmentManager fragmentManager = getFragmentManager(); + MyDatePickerDialog dialog = (MyDatePickerDialog) fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER); + if (dialog == null) { + dialog = new MyDatePickerDialog(); + dialog.initialize(null, initial.getYear(), initial.getMonthOfYear() - 1, initial.getDayOfMonth()); + if (preferences.isDarkTheme()) { + dialog.setAccentColor(getResources().getColor(R.color.black_text_hint)); + } + dialog.show(fragmentManager, FRAG_TAG_DATE_PICKER); + } + dialog.setOnDismissListener(this); + dialog.setOnDateSetListener(this); + } + + + @Override + public void onDateSet(DatePickerDialog view, final int year, final int monthOfYear, final int dayOfMonth) { + setResult(RESULT_OK, new Intent() {{ + putExtra(EXTRA_TIMESTAMP, initial + .withYear(year) + .withMonthOfYear(monthOfYear + 1) + .withDayOfMonth(dayOfMonth) + .getMillis()); + }}); + } + + @Override + public void onDismiss(DialogInterface dialog) { + finish(); + } +} diff --git a/src/main/java/org/tasks/injection/ActivityModule.java b/src/main/java/org/tasks/injection/ActivityModule.java index 201b5c2b3..1cab16bb6 100644 --- a/src/main/java/org/tasks/injection/ActivityModule.java +++ b/src/main/java/org/tasks/injection/ActivityModule.java @@ -29,6 +29,7 @@ import org.tasks.activities.CameraActivity; import org.tasks.activities.ClearAllDataActivity; import org.tasks.activities.ClearGtaskDataActivity; import org.tasks.activities.DateAndTimePickerActivity; +import org.tasks.activities.DatePickerActivity; import org.tasks.activities.DeleteAllCalendarEventsActivity; import org.tasks.activities.DeleteCompletedActivity; import org.tasks.activities.DeleteCompletedEventsActivity; @@ -103,6 +104,7 @@ import dagger.Provides; AddAttachmentActivity.class, ShortcutActivity.class, CameraActivity.class, + DatePickerActivity.class, TimePickerActivity.class, DateAndTimePickerActivity.class }) diff --git a/src/main/java/org/tasks/injection/FragmentModule.java b/src/main/java/org/tasks/injection/FragmentModule.java index 0ec7ec8af..e572efc9b 100644 --- a/src/main/java/org/tasks/injection/FragmentModule.java +++ b/src/main/java/org/tasks/injection/FragmentModule.java @@ -7,12 +7,23 @@ import android.content.Context; import com.todoroo.astrid.actfm.TagViewFragment; import com.todoroo.astrid.activity.TaskEditFragment; import com.todoroo.astrid.activity.TaskListFragment; +import com.todoroo.astrid.files.FilesControlSet; import com.todoroo.astrid.gtasks.GtasksListFragment; +import com.todoroo.astrid.repeats.RepeatControlSet; import com.todoroo.astrid.subtasks.SubtasksListFragment; import com.todoroo.astrid.subtasks.SubtasksTagListFragment; +import com.todoroo.astrid.tags.TagsControlSet; +import com.todoroo.astrid.timers.TimerControlSet; +import com.todoroo.astrid.ui.EditTitleControlSet; +import com.todoroo.astrid.ui.HideUntilControlSet; import com.todoroo.astrid.ui.QuickAddBar; +import com.todoroo.astrid.ui.ReminderControlSet; +import org.tasks.ui.CalendarControlSet; +import org.tasks.ui.DeadlineControlSet; +import org.tasks.ui.DescriptionControlSet; import org.tasks.ui.NavigationDrawerFragment; +import org.tasks.ui.PriorityControlSet; import javax.inject.Singleton; @@ -28,7 +39,18 @@ import dagger.Provides; TagViewFragment.class, TaskEditFragment.class, NavigationDrawerFragment.class, - QuickAddBar.class + QuickAddBar.class, + CalendarControlSet.class, + DeadlineControlSet.class, + PriorityControlSet.class, + DescriptionControlSet.class, + HideUntilControlSet.class, + ReminderControlSet.class, + FilesControlSet.class, + EditTitleControlSet.class, + TimerControlSet.class, + TagsControlSet.class, + RepeatControlSet.class }) public class FragmentModule { diff --git a/src/main/java/org/tasks/location/Geofence.java b/src/main/java/org/tasks/location/Geofence.java index 5d12a6029..db705a562 100644 --- a/src/main/java/org/tasks/location/Geofence.java +++ b/src/main/java/org/tasks/location/Geofence.java @@ -1,10 +1,13 @@ package org.tasks.location; +import android.os.Parcel; +import android.os.Parcelable; + import com.todoroo.astrid.data.Metadata; import java.io.Serializable; -public class Geofence implements Serializable { +public class Geofence implements Serializable, Parcelable { private final String name; private final double latitude; private final double longitude; @@ -63,4 +66,31 @@ public class Geofence implements Serializable { ", metadataId=" + metadataId + '}'; } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel out, int flags) { + out.writeString(name); + out.writeDouble(latitude); + out.writeDouble(longitude); + out.writeInt(radius); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public Geofence createFromParcel(Parcel source) { + String name = source.readString(); + double latitude = source.readDouble(); + double longitude = source.readDouble(); + int radius = source.readInt(); + return new Geofence(name, latitude, longitude, radius); + } + + @Override + public Geofence[] newArray(int size) { + return new Geofence[size]; + } + }; } \ No newline at end of file diff --git a/src/main/java/org/tasks/preferences/ResourceResolver.java b/src/main/java/org/tasks/preferences/ResourceResolver.java index 2f05bcc2c..aaf330588 100644 --- a/src/main/java/org/tasks/preferences/ResourceResolver.java +++ b/src/main/java/org/tasks/preferences/ResourceResolver.java @@ -1,6 +1,7 @@ package org.tasks.preferences; import android.app.Activity; +import android.content.Context; import android.util.TypedValue; import javax.inject.Inject; @@ -21,19 +22,9 @@ public class ResourceResolver { return getData(activity, attr); } - public int getResource(int attr) { - return getResource(activity, attr); - } - - public static int getResource(Activity activity, int attr) { - TypedValue typedValue = new TypedValue(); - activity.getTheme().resolveAttribute(attr, typedValue, true); - return typedValue.resourceId; - } - - public static int getData(Activity activity, int attr) { + public static int getData(Context context, int attr) { TypedValue typedValue = new TypedValue(); - activity.getTheme().resolveAttribute(attr, typedValue, true); + context.getTheme().resolveAttribute(attr, typedValue, true); return typedValue.data; } } diff --git a/src/main/java/org/tasks/ui/CalendarControlSet.java b/src/main/java/org/tasks/ui/CalendarControlSet.java new file mode 100644 index 000000000..9bedf0e5a --- /dev/null +++ b/src/main/java/org/tasks/ui/CalendarControlSet.java @@ -0,0 +1,246 @@ +package org.tasks.ui; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.common.base.Strings; +import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.gcal.AndroidCalendar; +import com.todoroo.astrid.gcal.GCalHelper; + +import org.tasks.R; +import org.tasks.activities.CalendarSelectionActivity; +import org.tasks.injection.ForActivity; +import org.tasks.preferences.Preferences; + +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.OnClick; +import timber.log.Timber; + +import static com.google.common.base.Strings.isNullOrEmpty; + +public class CalendarControlSet extends TaskEditControlFragment { + + private static final int REQUEST_CODE_CALENDAR = 70; + private static final String EXTRA_URI = "extra_uri"; + private static final String EXTRA_ID = "extra_id"; + private static final String EXTRA_NAME = "extra_name"; + + @Bind(R.id.clear) View cancelButton; + @Bind(R.id.calendar_display_which) TextView calendar; + + @Inject GCalHelper gcalHelper; + @Inject Preferences preferences; + @Inject @ForActivity Context context; + + private String calendarId; + private String calendarName; + private String eventUri; + private boolean isNewTask; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + if (savedInstanceState != null) { + eventUri = savedInstanceState.getString(EXTRA_URI); + calendarName = savedInstanceState.getString(EXTRA_NAME); + calendarId = savedInstanceState.getString(EXTRA_ID); + } else if (isNewTask) { + calendarId = preferences.getDefaultCalendar(); + if (!Strings.isNullOrEmpty(calendarId)) { + AndroidCalendar defaultCalendar = gcalHelper.getCalendar(calendarId); + if (defaultCalendar == null) { + calendarId = null; + } else { + calendarName = defaultCalendar.getName(); + } + } + } + if (!calendarEntryExists(eventUri)) { + eventUri = null; + } + refreshDisplayView(); + return view; + } + + @Override + protected int getLayout() { + return R.layout.control_set_gcal_display; + } + + @Override + protected int getIcon() { + return R.drawable.ic_event_24dp; + } + + @Override + public void initialize(boolean isNewTask, Task task) { + this.isNewTask = isNewTask; + eventUri = task.getCalendarURI(); + } + + @Override + public void apply(Task task) { + if (!task.hasDueDate()) { + return; + } + + if (calendarEntryExists(task.getCalendarURI())) { + ContentResolver cr = context.getContentResolver(); + try { + ContentValues updateValues = new ContentValues(); + + // check if we need to update the item + ContentValues setValues = task.getSetValues(); + if(setValues.containsKey(Task.TITLE.name)) { + updateValues.put("title", task.getTitle()); + } + if(setValues.containsKey(Task.NOTES.name)) { + updateValues.put("description", task.getNotes()); + } + if(setValues.containsKey(Task.DUE_DATE.name) || setValues.containsKey(Task.ESTIMATED_SECONDS.name)) { + gcalHelper.createStartAndEndDate(task, updateValues); + } + + cr.update(Uri.parse(task.getCalendarURI()), updateValues, null, null); + } catch (Exception e) { + Timber.e(e, "unable-to-update-calendar: %s", task.getCalendarURI()); + } + + return; + } + + if (!isNullOrEmpty(calendarId)) { + ContentResolver cr = context.getContentResolver(); + try{ + ContentValues values = new ContentValues(); + values.put("calendar_id", calendarId); + Uri uri = gcalHelper.createTaskEvent(task, cr, values); + if(uri != null) { + task.setCalendarUri(uri.toString()); + // pop up the new event + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.putExtra("beginTime", values.getAsLong("dtstart")); + intent.putExtra("endTime", values.getAsLong("dtend")); + startActivity(intent); + } + } catch (Exception e) { + Timber.e(e, e.getMessage()); + } + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putString(EXTRA_URI, eventUri); + outState.putString(EXTRA_NAME, calendarName); + outState.putString(EXTRA_ID, calendarId); + } + + @OnClick(R.id.clear) + void clearCalendar(View view) { + calendarName = null; + calendarId = null; + eventUri = null; + refreshDisplayView(); + } + + @OnClick(R.id.calendar_display_which) + void clickCalendar(View view) { + if (Strings.isNullOrEmpty(eventUri)) { + startActivityForResult(new Intent(context, CalendarSelectionActivity.class), REQUEST_CODE_CALENDAR); + } else { + ContentResolver cr = getActivity().getContentResolver(); + Uri uri = Uri.parse(eventUri); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + Cursor cursor = cr.query(uri, new String[] { "dtstart", "dtend" }, null, null, null); + try { + if(cursor.getCount() == 0) { + // event no longer exists + eventUri = null; + refreshDisplayView(); + return; + } + cursor.moveToFirst(); + intent.putExtra("beginTime", cursor.getLong(0)); + intent.putExtra("endTime", cursor.getLong(1)); + } catch (Exception e) { + Timber.e(e, e.getMessage()); + Toast.makeText(getActivity(), R.string.gcal_TEA_error, Toast.LENGTH_LONG).show(); + } finally { + cursor.close(); + } + + startActivity(intent); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_CALENDAR) { + if (resultCode == Activity.RESULT_OK) { + calendarId = data.getStringExtra(CalendarSelectionActivity.EXTRA_CALENDAR_ID); + calendarName = data.getStringExtra(CalendarSelectionActivity.EXTRA_CALENDAR_NAME); + refreshDisplayView(); + } + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } + + private void refreshDisplayView() { + if (!Strings.isNullOrEmpty(eventUri)) { + calendar.setAlpha(1.0f); + calendar.setText(R.string.gcal_TEA_showCalendar_label); + cancelButton.setVisibility(View.GONE); + } else if (calendarName != null) { + calendar.setAlpha(1.0f); + calendar.setText(calendarName); + cancelButton.setVisibility(View.VISIBLE); + } else { + calendar.setAlpha(0.5f); + calendar.setText(R.string.gcal_TEA_addToCalendar_label); + cancelButton.setVisibility(View.GONE); + } + } + + private boolean calendarEntryExists(String eventUri) { + if (isNullOrEmpty(eventUri)) { + return false; + } + + try { + Uri uri = Uri.parse(eventUri); + ContentResolver contentResolver = context.getContentResolver(); + Cursor cursor = contentResolver.query(uri, new String[]{"dtstart"}, null, null, null); + try { + if (cursor.getCount() != 0) { + return true; + } + } finally { + cursor.close(); + } + } catch(Exception e) { + Timber.e(e, "%s: %s", eventUri, e.getMessage()); + } + + return false; + } +} diff --git a/src/main/java/org/tasks/ui/CheckBoxes.java b/src/main/java/org/tasks/ui/CheckBoxes.java index 1f048b64c..60f839200 100644 --- a/src/main/java/org/tasks/ui/CheckBoxes.java +++ b/src/main/java/org/tasks/ui/CheckBoxes.java @@ -5,6 +5,8 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.support.v4.graphics.drawable.DrawableCompat; +import com.google.common.collect.ImmutableList; + import org.tasks.R; import org.tasks.injection.ForApplication; @@ -14,8 +16,6 @@ import javax.inject.Inject; import timber.log.Timber; -import static java.util.Arrays.asList; - public class CheckBoxes { private static final int MAX_IMPORTANCE_INDEX = 3; @@ -24,6 +24,7 @@ public class CheckBoxes { private static List checkboxes; private static List repeatingCheckboxes; private static List completedCheckboxes; + private static List priorityColors; @Inject public CheckBoxes(@ForApplication Context context) { @@ -32,10 +33,19 @@ public class CheckBoxes { checkboxes = wrapDrawable(context, R.drawable.ic_check_box_outline_blank_24dp); repeatingCheckboxes = wrapDrawable(context, R.drawable.ic_repeat_24dp); completedCheckboxes = wrapDrawable(context, R.drawable.ic_check_box_24dp); + priorityColors = ImmutableList.of( + context.getResources().getColor(R.color.importance_1), + context.getResources().getColor(R.color.importance_2), + context.getResources().getColor(R.color.importance_3), + context.getResources().getColor(R.color.importance_4)); initialized = true; } } + public List getPriorityColors() { + return priorityColors; + } + List getCheckBoxes() { return checkboxes; } @@ -49,7 +59,7 @@ public class CheckBoxes { } private static List wrapDrawable(Context context, int resId) { - return asList( + return ImmutableList.of( getDrawable(context, resId, 0), getDrawable(context, resId, 1), getDrawable(context, resId, 2), diff --git a/src/main/java/org/tasks/ui/DeadlineControlSet.java b/src/main/java/org/tasks/ui/DeadlineControlSet.java index 4ba979a5c..a076310d1 100644 --- a/src/main/java/org/tasks/ui/DeadlineControlSet.java +++ b/src/main/java/org/tasks/ui/DeadlineControlSet.java @@ -1,10 +1,12 @@ package org.tasks.ui; import android.app.Activity; -import android.content.DialogInterface; +import android.content.Context; +import android.content.Intent; import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v4.graphics.drawable.DrawableCompat; -import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,58 +17,65 @@ import android.widget.TextView; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; -import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; -import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout; -import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; import org.tasks.R; -import org.tasks.dialogs.MyDatePickerDialog; -import org.tasks.dialogs.MyTimePickerDialog; +import org.tasks.activities.DatePickerActivity; +import org.tasks.activities.TimePickerActivity; +import org.tasks.injection.ForActivity; import org.tasks.preferences.ActivityPreferences; import org.tasks.time.DateTime; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; + +import butterknife.Bind; +import butterknife.OnClick; +import butterknife.OnItemSelected; import static java.util.Arrays.asList; import static org.tasks.date.DateTimeUtils.newDateTime; +import static org.tasks.preferences.ResourceResolver.getData; -public class DeadlineControlSet extends TaskEditControlSetBase { +public class DeadlineControlSet extends TaskEditControlFragment { - private static final String FRAG_TAG_PICK_A_DATE = "frag_tag_pick_a_date"; - private static final String FRAG_TAG_PICK_A_TIME = "frag_tag_pick_a_time"; + private static final int REQUEST_DATE = 504; + private static final int REQUEST_TIME = 505; + private static final String EXTRA_DATE = "extra_date"; + private static final String EXTRA_TIME = "extra_time"; private final List dueDateOptions = new ArrayList<>(); private final List dueTimeOptions = new ArrayList<>(); - private final List dueTimeHint; - private final int dateShortcutMorning; - private final int dateShortcutAfternoon; - private final int dateShortcutEvening; - private final int dateShortcutNight; - private final String nightString; - private final String eveningString; - private final String afternoonString; - private final String morningString; - private final String noTimeString; - private final String todayString; - private final String tomorrowString; - - private Activity activity; - private ActivityPreferences preferences; - private Spinner dueDateSpinner; - private Spinner dueTimeSpinner; - private View clearButton; + private List dueTimeHint = new ArrayList<>(); + private int dateShortcutMorning; + private int dateShortcutAfternoon; + private int dateShortcutEvening; + private int dateShortcutNight; + private String nightString; + private String eveningString; + private String afternoonString; + private String morningString; + private String noTimeString; + private String todayString; + private String tomorrowString; + + @Inject ActivityPreferences preferences; + @Inject @ForActivity Context context; + + @Bind(R.id.due_date) Spinner dueDateSpinner; + @Bind(R.id.due_time) Spinner dueTimeSpinner; + @Bind(R.id.clear) View clearButton; + private ArrayAdapter dueDateAdapter; private ArrayAdapter dueTimeAdapter; private long date = 0; private int time = -1; - public DeadlineControlSet(Activity activity, ActivityPreferences preferences) { - super(activity, R.layout.control_set_deadline); - this.activity = activity; - this.preferences = preferences; + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + dateShortcutMorning = preferences.getDateShortcutMorning(); dateShortcutAfternoon = preferences.getDateShortcutAfternoon(); dateShortcutEvening = preferences.getDateShortcutEvening(); @@ -101,95 +110,35 @@ public class DeadlineControlSet extends TaskEditControlSetBase { activity.getString(R.string.pick_a_time))); } - private String getTimeHint(int millisOfDay) { - DateTime dateTime = newDateTime().withMillisOfDay(millisOfDay); - return DateUtilities.getTimeString(activity, dateTime); - } - - private void refreshDisplayView() { - updateDueDateOptions(); - updateDueTimeOptions(); - clearButton.setVisibility(date > 0 ? View.VISIBLE : View.GONE); - } - - private void updateDueDateOptions() { - DateTime today = newDateTime().startOfDay(); - String nextWeekString = activity.getString(R.string.next, today.plusWeeks(1).toString("EEEE")); - if (date == 0) { - dueDateOptions.set(0, activity.getString(R.string.TEA_no_date)); - } else { - if (date == today.getMillis()) { - dueDateOptions.set(0, todayString); - } else if (date == today.plusDays(1).getMillis()) { - dueDateOptions.set(0, tomorrowString); - } else if (date == today.plusWeeks(1).getMillis()) { - dueDateOptions.set(0, nextWeekString); - } else { - dueDateOptions.set(0, DateUtilities.getLongDateString(newDateTime(date))); - } - } - dueDateOptions.set(3, nextWeekString); - dueDateAdapter.notifyDataSetChanged(); - dueDateSpinner.setSelection(0); - } - - private void updateDueTimeOptions() { - if (time == -1) { - dueTimeOptions.set(0, noTimeString); - } else { - int compareTime = newDateTime() - .withMillisOfDay(time) - .withSecondOfMinute(0) - .withMillisOfSecond(0) - .getMillisOfDay(); - if (compareTime == dateShortcutMorning) { - dueTimeOptions.set(0, morningString); - } else if (compareTime == dateShortcutAfternoon) { - dueTimeOptions.set(0, afternoonString); - } else if (compareTime == dateShortcutEvening) { - dueTimeOptions.set(0, eveningString); - } else if (compareTime == dateShortcutNight) { - dueTimeOptions.set(0, nightString); - } else { - dueTimeOptions.set(0, DateUtilities.getTimeString(activity, newDateTime().withMillisOfDay(time))); - } - } - dueTimeAdapter.notifyDataSetChanged(); - dueTimeSpinner.setSelection(0); - } - + @Nullable @Override - protected void afterInflate() { - View view = getView(); - clearButton = view.findViewById(R.id.clear); - clearButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - date = 0; - time = -1; - refreshDisplayView(); - } - }); - dueDateSpinner = (Spinner) view.findViewById(R.id.due_date); - dueDateAdapter = new HiddenTopArrayAdapter(activity, android.R.layout.simple_spinner_item, dueDateOptions) { + public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + if (savedInstanceState != null) { + date = savedInstanceState.getLong(EXTRA_DATE); + time = savedInstanceState.getInt(EXTRA_TIME); + } + final int themeColor = getData(context, R.attr.asTextColor); + final int overdueColor = context.getResources().getColor(R.color.overdue); + dueDateAdapter = new HiddenTopArrayAdapter(context, android.R.layout.simple_spinner_item, dueDateOptions) { @Override public View getView(final int position, final View convertView, final ViewGroup parent) { int selectedItemPosition = position; if (parent instanceof AdapterView) { selectedItemPosition = ((AdapterView) parent).getSelectedItemPosition(); } - TextView tv = (TextView) LayoutInflater.from(activity).inflate(android.R.layout.simple_spinner_item, parent, false); + TextView tv = (TextView) inflater.inflate(android.R.layout.simple_spinner_item, parent, false); tv.setText(dueDateOptions.get(selectedItemPosition)); if (date == 0) { dueDateSpinner.setAlpha(0.5f); - dueDateSpinner.setBackgroundDrawable(getThemedUnderline()); + dueDateSpinner.setBackgroundDrawable(getUnderline(themeColor)); } else { dueDateSpinner.setAlpha(1.0f); if (date < newDateTime().startOfDay().getMillis()) { - dueDateSpinner.setBackgroundDrawable(getRedUnderline()); - tv.setTextColor(activity.getResources().getColor(R.color.overdue)); + dueDateSpinner.setBackgroundDrawable(getUnderline(overdueColor)); + tv.setTextColor(overdueColor); } else { - dueDateSpinner.setBackgroundDrawable(getThemedUnderline()); + dueDateSpinner.setBackgroundDrawable(getUnderline(themeColor)); tv.setTextColor(themeColor); } } @@ -198,26 +147,25 @@ public class DeadlineControlSet extends TaskEditControlSetBase { }; dueDateSpinner.setAdapter(dueDateAdapter); - dueTimeSpinner = (Spinner) view.findViewById(R.id.due_time); - dueTimeAdapter = new HiddenTopArrayAdapter(activity, android.R.layout.simple_spinner_item, dueTimeOptions, dueTimeHint) { + dueTimeAdapter = new HiddenTopArrayAdapter(context, android.R.layout.simple_spinner_item, dueTimeOptions, dueTimeHint) { @Override public View getView(final int position, final View convertView, final ViewGroup parent) { int selectedItemPosition = position; if (parent instanceof AdapterView) { selectedItemPosition = ((AdapterView) parent).getSelectedItemPosition(); } - TextView tv = (TextView) LayoutInflater.from(activity).inflate(android.R.layout.simple_spinner_item, parent, false); + TextView tv = (TextView) inflater.inflate(android.R.layout.simple_spinner_item, parent, false); tv.setText(dueTimeOptions.get(selectedItemPosition)); if (time == -1) { dueTimeSpinner.setAlpha(0.5f); - dueTimeSpinner.setBackgroundDrawable(getThemedUnderline()); + dueTimeSpinner.setBackgroundDrawable(getUnderline(themeColor)); } else { dueTimeSpinner.setAlpha(1.0f); if (newDateTime(date).withMillisOfDay(time).isBeforeNow()) { - dueTimeSpinner.setBackgroundDrawable(getRedUnderline()); - tv.setTextColor(activity.getResources().getColor(R.color.overdue)); + dueTimeSpinner.setBackgroundDrawable(getUnderline(overdueColor)); + tv.setTextColor(overdueColor); } else { - dueTimeSpinner.setBackgroundDrawable(getThemedUnderline()); + dueTimeSpinner.setBackgroundDrawable(getUnderline(themeColor)); tv.setTextColor(themeColor); } } @@ -226,119 +174,197 @@ public class DeadlineControlSet extends TaskEditControlSetBase { }; dueTimeSpinner.setAdapter(dueTimeAdapter); - dueDateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - DateTime today = newDateTime().startOfDay(); - switch (position) { - case 0: - return; - case 1: - setDate(today.getMillis()); - break; - case 2: - setDate(today.plusDays(1).getMillis()); - break; - case 3: - setDate(today.plusWeeks(1).getMillis()); - break; - case 4: - MyDatePickerDialog dialog = new MyDatePickerDialog(); - DateTime initial = date > 0 ? newDateTime(date) : today; - dialog.initialize(new DatePickerDialog.OnDateSetListener() { - @Override - public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) { - setDate(new DateTime(year, month + 1, day, 0, 0, 0, 0).getMillis()); - } - }, initial.getYear(), initial.getMonthOfYear() - 1, initial.getDayOfMonth()); - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - refreshDisplayView(); - } - }); - if (preferences.isDarkTheme()) { - dialog.setAccentColor(activity.getResources().getColor(R.color.black_text_hint)); - } - dialog.show(activity.getFragmentManager(), FRAG_TAG_PICK_A_DATE); - break; - } - } + refreshDisplayView(); - @Override - public void onNothingSelected(AdapterView parent) { + return view; + } - } - }); + @OnClick(R.id.clear) + void clearTime(View view) { + date = 0; + time = -1; + refreshDisplayView(); + } - dueTimeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - switch (position) { - case 0: - return; - case 1: - setTime(-1); - break; - case 2: - setTime(dateShortcutMorning); - break; - case 3: - setTime(dateShortcutAfternoon); - break; - case 4: - setTime(dateShortcutEvening); - break; - case 5: - setTime(dateShortcutNight); - break; - case 6: - MyTimePickerDialog dialog = new MyTimePickerDialog(); - int initialHours = 0; - int initialMinutes = 0; - if (time >= 0) { - DateTime initial = newDateTime(date).withMillisOfDay(time); - initialHours = initial.getHourOfDay(); - initialMinutes = initial.getMinuteOfHour(); - } - dialog.initialize(new TimePickerDialog.OnTimeSetListener() { - @Override - public void onTimeSet(RadialPickerLayout radialPickerLayout, int hour, int minute, int seconds) { - setTime((int) TimeUnit.HOURS.toMillis(hour) + (int) TimeUnit.MINUTES.toMillis(minute)); - } - }, initialHours, initialMinutes, 0, DateFormat.is24HourFormat(activity)); - dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - refreshDisplayView(); - } - }); - if (preferences.isDarkTheme()) { - dialog.setAccentColor(activity.getResources().getColor(R.color.black_text_hint)); - } - dialog.show(activity.getFragmentManager(), FRAG_TAG_PICK_A_TIME); - break; - } + @OnItemSelected(R.id.due_date) + void onDateSelected(int position) { + DateTime today = newDateTime().startOfDay(); + switch (position) { + case 0: + return; + case 1: + setDate(today.getMillis()); + break; + case 2: + setDate(today.plusDays(1).getMillis()); + break; + case 3: + setDate(today.plusWeeks(1).getMillis()); + break; + case 4: + startActivityForResult(new Intent(context, DatePickerActivity.class) {{ + putExtra(DatePickerActivity.EXTRA_TIMESTAMP, getDueDate()); + }}, REQUEST_DATE); + break; + } + } + + @OnItemSelected(R.id.due_time) + void onTimeSelected(int position) { + switch (position) { + case 0: + return; + case 1: + setTime(-1); + break; + case 2: + setTime(dateShortcutMorning); + break; + case 3: + setTime(dateShortcutAfternoon); + break; + case 4: + setTime(dateShortcutEvening); + break; + case 5: + setTime(dateShortcutNight); + break; + case 6: + startActivityForResult(new Intent(context, TimePickerActivity.class) {{ + putExtra(TimePickerActivity.EXTRA_TIMESTAMP, getDueDate()); + }}, REQUEST_TIME); + break; + } + } + + @Override + protected int getLayout() { + return R.layout.control_set_deadline; + } + + @Override + protected int getIcon() { + return R.drawable.ic_schedule_24dp; + } + + @Override + public void initialize(boolean isNewTask, Task task) { + if (task.hasDueDate()) { + DateTime dateTime = newDateTime(task.getDueDate()); + date = dateTime.startOfDay().getMillis(); + time = task.hasDueTime() ? dateTime.getMillisOfDay() : -1; + } else { + date = 0; + time = -1; + } + } + + @Override + public void apply(Task task) { + long dueDate = getDueDate(); + if (dueDate != task.getDueDate()) { + task.setReminderSnooze(0L); + } + task.setDueDate(dueDate); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_DATE) { + if (resultCode == Activity.RESULT_OK) { + long timestamp = data.getLongExtra(DatePickerActivity.EXTRA_TIMESTAMP, 0L); + DateTime dateTime = new DateTime(timestamp); + setDate(dateTime.getMillis()); + } else { + refreshDisplayView(); + } + } else if (requestCode == REQUEST_TIME) { + if (resultCode == Activity.RESULT_OK) { + long timestamp = data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L); + DateTime dateTime = new DateTime(timestamp); + setTime(dateTime.getMillisOfDay()); + } else { + refreshDisplayView(); } + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } - @Override - public void onNothingSelected(AdapterView parent) { + private long getDueDate() { + return time >= 0 + ? Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, newDateTime(date).withMillisOfDay(time).getMillis()) + : Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, date); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putLong(EXTRA_DATE, date); + outState.putInt(EXTRA_TIME, time); + } + + private String getTimeHint(int millisOfDay) { + DateTime dateTime = newDateTime().withMillisOfDay(millisOfDay); + return DateUtilities.getTimeString(context, dateTime); + } + + private void refreshDisplayView() { + updateDueDateOptions(); + updateDueTimeOptions(); + clearButton.setVisibility(date > 0 ? View.VISIBLE : View.GONE); + } + + private void updateDueDateOptions() { + DateTime today = newDateTime().startOfDay(); + String nextWeekString = getString(R.string.next, today.plusWeeks(1).toString("EEEE")); + if (date == 0) { + dueDateOptions.set(0, getString(R.string.TEA_no_date)); + } else { + if (date == today.getMillis()) { + dueDateOptions.set(0, todayString); + } else if (date == today.plusDays(1).getMillis()) { + dueDateOptions.set(0, tomorrowString); + } else if (date == today.plusWeeks(1).getMillis()) { + dueDateOptions.set(0, nextWeekString); + } else { + dueDateOptions.set(0, DateUtilities.getLongDateString(newDateTime(date))); } - }); + } + dueDateOptions.set(3, nextWeekString); + dueDateAdapter.notifyDataSetChanged(); + dueDateSpinner.setSelection(0); } - private Drawable getThemedUnderline() { - Drawable drawable = DrawableCompat.wrap(activity.getResources().getDrawable(R.drawable.textfield_underline_black)); - DrawableCompat.setTint(drawable, activity.getResources().getColor(preferences.isDarkTheme() - ? android.R.color.white - : android.R.color.black)); - return drawable; + private void updateDueTimeOptions() { + if (time == -1) { + dueTimeOptions.set(0, noTimeString); + } else { + int compareTime = newDateTime() + .withMillisOfDay(time) + .withSecondOfMinute(0) + .withMillisOfSecond(0) + .getMillisOfDay(); + if (compareTime == dateShortcutMorning) { + dueTimeOptions.set(0, morningString); + } else if (compareTime == dateShortcutAfternoon) { + dueTimeOptions.set(0, afternoonString); + } else if (compareTime == dateShortcutEvening) { + dueTimeOptions.set(0, eveningString); + } else if (compareTime == dateShortcutNight) { + dueTimeOptions.set(0, nightString); + } else { + dueTimeOptions.set(0, DateUtilities.getTimeString(context, newDateTime().withMillisOfDay(time))); + } + } + dueTimeAdapter.notifyDataSetChanged(); + dueTimeSpinner.setSelection(0); } - private Drawable getRedUnderline() { - Drawable drawable = DrawableCompat.wrap(activity.getResources().getDrawable(R.drawable.textfield_underline_black)); - DrawableCompat.setTint(drawable, activity.getResources().getColor(R.color.overdue)); + private Drawable getUnderline(int color) { + Drawable drawable = DrawableCompat.wrap(context.getResources().getDrawable(R.drawable.textfield_underline_black)); + DrawableCompat.setTint(drawable, color); return drawable; } @@ -363,38 +389,4 @@ public class DeadlineControlSet extends TaskEditControlSetBase { refreshDisplayView(); } - - @Override - protected void readFromTaskOnInitialize() { - Long dueDate = model.getDueDate(); - if (dueDate > 0) { - DateTime dateTime = newDateTime(dueDate); - date = dateTime.startOfDay().getMillis(); - if (Task.hasDueTime(dateTime.getMillis())) { - setTime(dateTime.getMillisOfDay()); - } else { - time = -1; - } - } else { - date = 0; - time = -1; - } - refreshDisplayView(); - } - - @Override - protected void writeToModelAfterInitialized(Task task) { - long dueDate = time >= 0 - ? Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, newDateTime(date).withMillisOfDay(time).getMillis()) - : Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, date); - if (dueDate != task.getDueDate()) { - task.setReminderSnooze(0L); - } - task.setDueDate(dueDate); - } - - @Override - public int getIcon() { - return R.drawable.ic_schedule_24dp; - } } diff --git a/src/main/java/org/tasks/ui/DescriptionControlSet.java b/src/main/java/org/tasks/ui/DescriptionControlSet.java new file mode 100644 index 000000000..a40c48b2d --- /dev/null +++ b/src/main/java/org/tasks/ui/DescriptionControlSet.java @@ -0,0 +1,70 @@ +package org.tasks.ui; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import com.google.common.base.Strings; +import com.todoroo.astrid.data.Task; + +import org.tasks.R; + +import butterknife.Bind; +import butterknife.OnTextChanged; + +public class DescriptionControlSet extends TaskEditControlFragment { + + private static final String EXTRA_DESCRIPTION = "extra_description"; + + @Bind(R.id.notes) EditText editText; + + private String description; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + if (savedInstanceState != null) { + description = savedInstanceState.getString(EXTRA_DESCRIPTION); + } + if (!Strings.isNullOrEmpty(description)) { + editText.setTextKeepState(description); + } + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putString(EXTRA_DESCRIPTION, description); + } + + @Override + protected int getLayout() { + return R.layout.control_set_description; + } + + @Override + protected int getIcon() { + return R.drawable.ic_event_note_24dp; + } + + @OnTextChanged(R.id.notes) + void textChanged(CharSequence text) { + description = text.toString().trim(); + } + + @Override + public void initialize(boolean isNewTask, Task task) { + description = task.getNotes(); + } + + @Override + public void apply(Task task) { + task.setNotes(description); + } +} diff --git a/src/main/java/org/tasks/ui/PriorityControlSet.java b/src/main/java/org/tasks/ui/PriorityControlSet.java index 080fb9013..5dc04a37a 100644 --- a/src/main/java/org/tasks/ui/PriorityControlSet.java +++ b/src/main/java/org/tasks/ui/PriorityControlSet.java @@ -1,104 +1,115 @@ package org.tasks.ui; import android.app.Activity; +import android.content.Context; import android.content.res.ColorStateList; +import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatRadioButton; +import android.view.LayoutInflater; import android.view.View; -import android.widget.RadioGroup; +import android.view.ViewGroup; +import android.widget.CompoundButton; -import com.google.common.primitives.Ints; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.helper.TaskEditControlSetBase; import org.tasks.R; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; +import javax.inject.Inject; -public class PriorityControlSet extends TaskEditControlSetBase { +import butterknife.Bind; +import butterknife.OnClick; - private final List colors; - private final List listeners = new LinkedList<>(); - private RadioGroup radioGroup; +public class PriorityControlSet extends TaskEditControlFragment { - public interface ImportanceChangedListener { - void importanceChanged(int i); + public interface OnPriorityChanged { + void onPriorityChange(int priority); } - public PriorityControlSet(Activity activity) { - super(activity, R.layout.control_set_priority); - colors = Ints.asList(Task.getImportanceColors(activity.getResources())); - Collections.reverse(colors); - } + private static final String EXTRA_PRIORITY = "extra_priority"; - public void notifyImportanceChange(Integer i) { - for (ImportanceChangedListener l : listeners) { - l.importanceChanged(i); - } - } + @Inject CheckBoxes checkBoxes; - private Integer getImportance(int checkedId) { - return getImportance(getView().findViewById(checkedId)); - } + @Bind(R.id.priority_high) AppCompatRadioButton priorityHigh; + @Bind(R.id.priority_medium) AppCompatRadioButton priorityMedium; + @Bind(R.id.priority_low) AppCompatRadioButton priorityLow; + @Bind(R.id.priority_none) AppCompatRadioButton priorityNone; - private Integer getImportance(View view) { - return Integer.parseInt((String) view.getTag()); + private OnPriorityChanged callback; + private int priority; + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + callback = (OnPriorityChanged) activity; } - public void addListener(ImportanceChangedListener listener) { - listeners.add(listener); + @OnClick({R.id.priority_high, R.id.priority_medium, R.id.priority_low, R.id.priority_none}) + void onImportanceChanged(CompoundButton button) { + callback.onPriorityChange(getPriority()); } + @Nullable @Override - protected void afterInflate() { - final View view = getView(); - radioGroup = (RadioGroup) view.findViewById(R.id.importance_group); - radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(RadioGroup group, int checkedId) { - notifyImportanceChange(getImportance(checkedId)); - } - }); - for (int i = 0; i < radioGroup.getChildCount(); i++) { - AppCompatRadioButton radioButton = (AppCompatRadioButton) radioGroup.getChildAt(i); - radioButton.setSupportButtonTintList(new ColorStateList(new int[][]{ - new int[]{-android.R.attr.state_checked}, new int[]{android.R.attr.state_checked}}, - new int[]{colors.get(i), colors.get(i)})); + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final View view = super.onCreateView(inflater, container, savedInstanceState); + if (savedInstanceState != null) { + priority = savedInstanceState.getInt(EXTRA_PRIORITY); + } + if (priority == 0) { + priorityHigh.setChecked(true); + } else if(priority == 1) { + priorityMedium.setChecked(true); + } else if(priority == 2) { + priorityLow.setChecked(true); + } else { + priorityNone.setChecked(true); } + tintRadioButton(priorityHigh, 0); + tintRadioButton(priorityMedium, 1); + tintRadioButton(priorityLow, 2); + tintRadioButton(priorityNone, 3); + return view; } @Override - public void readFromTask(Task task) { - super.readFromTask(task); - setSelected(model.getImportance()); + protected int getLayout() { + return R.layout.control_set_priority; } @Override - public int getIcon() { + protected int getIcon() { return R.drawable.ic_flag_24dp; } @Override - protected void readFromTaskOnInitialize() { - setSelected(model.getImportance()); + public void initialize(boolean isNewTask, Task task) { + priority = task.getImportance(); } - private void setSelected(int importance) { - if (radioGroup == null) { - return; - } + @Override + public void apply(Task task) { + task.setImportance(getPriority()); + } - for (int i = 0; i < radioGroup.getChildCount(); i++) { - AppCompatRadioButton radioButton = (AppCompatRadioButton) radioGroup.getChildAt(i); - if (importance == getImportance(radioButton)) { - radioButton.setChecked(true); - } - } + private void tintRadioButton(AppCompatRadioButton radioButton, int priority) { + int color = checkBoxes.getPriorityColors().get(priority); + radioButton.setSupportButtonTintList(new ColorStateList(new int[][]{ + new int[]{-android.R.attr.state_checked}, new int[]{android.R.attr.state_checked}}, + new int[]{color, color})); } - @Override - protected void writeToModelAfterInitialized(Task task) { - task.setImportance(getImportance(radioGroup.getCheckedRadioButtonId())); + private int getPriority() { + if (priorityHigh.isChecked()) { + return 0; + } + if (priorityMedium.isChecked()) { + return 1; + } + if (priorityLow.isChecked()) { + return 2; + } + return 3; } } diff --git a/src/main/java/org/tasks/ui/TaskEditControlFragment.java b/src/main/java/org/tasks/ui/TaskEditControlFragment.java new file mode 100644 index 000000000..8bf8bf223 --- /dev/null +++ b/src/main/java/org/tasks/ui/TaskEditControlFragment.java @@ -0,0 +1,39 @@ +package org.tasks.ui; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.todoroo.astrid.data.Task; + +import org.tasks.R; +import org.tasks.injection.InjectingFragment; + +import butterknife.ButterKnife; + +public abstract class TaskEditControlFragment extends InjectingFragment { + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final View view = inflater.inflate(R.layout.control_set_template, null); + LinearLayout content = (LinearLayout) view.findViewById(R.id.content); + content.addView(inflater.inflate(getLayout(), null)); + ImageView icon = (ImageView) view.findViewById(R.id.icon); + icon.setImageResource(getIcon()); + ButterKnife.bind(this, view); + return view; + } + + protected abstract int getLayout(); + + protected abstract int getIcon(); + + public abstract void initialize(boolean isNewTask, Task task); + + public abstract void apply(Task task); +} diff --git a/src/main/res/drawable/btn_check.xml b/src/main/res/drawable/btn_check.xml deleted file mode 100644 index 80906df34..000000000 --- a/src/main/res/drawable/btn_check.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - diff --git a/src/main/res/drawable/btn_check_small.xml b/src/main/res/drawable/btn_check_small.xml deleted file mode 100644 index 3ff6790be..000000000 --- a/src/main/res/drawable/btn_check_small.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/main/res/drawable/icn_arrow_down.png b/src/main/res/drawable/icn_arrow_down.png deleted file mode 100644 index 3ffbaac88..000000000 Binary files a/src/main/res/drawable/icn_arrow_down.png and /dev/null differ diff --git a/src/main/res/drawable/icn_arrow_up.png b/src/main/res/drawable/icn_arrow_up.png deleted file mode 100644 index 56ae0016a..000000000 Binary files a/src/main/res/drawable/icn_arrow_up.png and /dev/null differ diff --git a/src/main/res/drawable/icn_check_off.png b/src/main/res/drawable/icn_check_off.png deleted file mode 100644 index 12bfa5215..000000000 Binary files a/src/main/res/drawable/icn_check_off.png and /dev/null differ diff --git a/src/main/res/drawable/icn_check_on.png b/src/main/res/drawable/icn_check_on.png deleted file mode 100644 index a316022ff..000000000 Binary files a/src/main/res/drawable/icn_check_on.png and /dev/null differ diff --git a/src/main/res/layout/control_set_gcal_display.xml b/src/main/res/layout/control_set_gcal_display.xml index 557a79049..e8b222be7 100644 --- a/src/main/res/layout/control_set_gcal_display.xml +++ b/src/main/res/layout/control_set_gcal_display.xml @@ -20,7 +20,7 @@ android:layout_height="wrap_content" android:layout_gravity="top" android:gravity="start" - android:textColor="?attr/asThemeTextColor" + android:textColor="?attr/asTextColor" android:textSize="@dimen/task_edit_text_size" /> diff --git a/src/main/res/layout/control_set_hide.xml b/src/main/res/layout/control_set_hide.xml index 259391d58..0645611ed 100644 --- a/src/main/res/layout/control_set_hide.xml +++ b/src/main/res/layout/control_set_hide.xml @@ -1,32 +1,20 @@ - + - - + android:layout_weight="100" + android:orientation="horizontal"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@null"/> diff --git a/src/main/res/layout/control_set_priority.xml b/src/main/res/layout/control_set_priority.xml index a3a688d01..68e7a6f0d 100644 --- a/src/main/res/layout/control_set_priority.xml +++ b/src/main/res/layout/control_set_priority.xml @@ -17,7 +17,6 @@ android:textSize="@dimen/task_edit_text_size" /> + android:id="@+id/priority_none" + style="@style/priority_button"/> + android:id="@+id/priority_low" + style="@style/priority_button"/> + android:id="@+id/priority_medium" + style="@style/priority_button"/> + android:id="@+id/priority_high" + style="@style/priority_button"/> diff --git a/src/main/res/layout/control_set_reminders.xml b/src/main/res/layout/control_set_reminders.xml index a3bd07a88..608685d55 100644 --- a/src/main/res/layout/control_set_reminders.xml +++ b/src/main/res/layout/control_set_reminders.xml @@ -50,19 +50,14 @@ android:gravity="end" android:layout_weight="50"> - - + android:background="@null" + android:gravity="end" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingRight="10dp" + android:paddingEnd="10dp"/> diff --git a/src/main/res/layout/control_set_repeat.xml b/src/main/res/layout/control_set_repeat.xml index 51e431fe5..28cb6fa35 100644 --- a/src/main/res/layout/control_set_repeat.xml +++ b/src/main/res/layout/control_set_repeat.xml @@ -28,14 +28,16 @@ android:id="@+id/repeatValue" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:layout_weight="1" /> + android:layout_weight="1" + android:textColor="?attr/asTextColor"/> + android:prompt="@string/repeat_interval_prompt" + android:textColor="?attr/asTextColor" /> @@ -44,7 +46,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="5dp" - android:paddingTop="5dp" /> + android:paddingTop="5dp" + android:textColor="?attr/asTextColor" /> + android:paddingTop="5dp"> + + + + + + + + + + + + + + + + + android:paddingTop="5dp" + android:textColor="?attr/asTextColor" /> diff --git a/src/main/res/layout/control_set_repeat_display.xml b/src/main/res/layout/control_set_repeat_display.xml index 6d253dc47..a97bfd9ae 100644 --- a/src/main/res/layout/control_set_repeat_display.xml +++ b/src/main/res/layout/control_set_repeat_display.xml @@ -20,7 +20,7 @@ android:layout_height="wrap_content" android:layout_gravity="top" android:gravity="start" - android:textColor="?attr/asThemeTextColor" + android:textColor="?attr/asTextColor" android:textSize="@dimen/task_edit_text_size" /> diff --git a/src/main/res/layout/control_set_tag_list.xml b/src/main/res/layout/control_set_tag_list.xml index 197408cc0..b0dddbcc2 100644 --- a/src/main/res/layout/control_set_tag_list.xml +++ b/src/main/res/layout/control_set_tag_list.xml @@ -32,6 +32,7 @@ android:layout_height="fill_parent" android:layout_marginLeft="3dip" android:layout_marginRight="3dip" - android:layout_weight="100"/> + android:layout_weight="100" + android:choiceMode="multipleChoice"/> diff --git a/src/main/res/layout/control_set_tags.xml b/src/main/res/layout/control_set_tags.xml index 43f7d576a..620e0b995 100644 --- a/src/main/res/layout/control_set_tags.xml +++ b/src/main/res/layout/control_set_tags.xml @@ -8,5 +8,5 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" - android:textColor="?attr/asThemeTextColor" + android:textColor="?attr/asTextColor" android:textSize="@dimen/task_edit_text_size" /> diff --git a/src/main/res/layout/control_set_timers.xml b/src/main/res/layout/control_set_timers.xml index 292b45354..33438ceaf 100644 --- a/src/main/res/layout/control_set_timers.xml +++ b/src/main/res/layout/control_set_timers.xml @@ -3,9 +3,61 @@ ** ** See the file "LICENSE" for the full license governing this code. --> - + android:orientation="horizontal"> + + + + + + + + + + + + + + + + diff --git a/src/main/res/layout/control_set_timers_dialog.xml b/src/main/res/layout/control_set_timers_dialog.xml index 61a8e700a..bf124c337 100644 --- a/src/main/res/layout/control_set_timers_dialog.xml +++ b/src/main/res/layout/control_set_timers_dialog.xml @@ -32,7 +32,7 @@ android:layout_weight="1" android:gravity="right" android:paddingLeft="10dip" - android:textColor="?attr/asThemeTextColor" /> + android:textColor="?attr/asTextColor" /> + android:textColor="?attr/asTextColor" /> diff --git a/src/main/res/layout/control_set_title.xml b/src/main/res/layout/control_set_title.xml index 1e403971d..0a0bd3ecf 100644 --- a/src/main/res/layout/control_set_title.xml +++ b/src/main/res/layout/control_set_title.xml @@ -1,5 +1,4 @@ - - - - - - - - - - - - - - diff --git a/src/main/res/layout/task_edit_activity.xml b/src/main/res/layout/task_edit_activity.xml index 3c72ec89c..f367c2285 100644 --- a/src/main/res/layout/task_edit_activity.xml +++ b/src/main/res/layout/task_edit_activity.xml @@ -24,13 +24,6 @@ android:orientation="vertical" android:gravity="center_horizontal" > - - - - - - - - - - - - + android:orientation="vertical" + android:layout_gravity="center"> + + + + + + + diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml index 5c13a33c0..fcaf15d77 100644 --- a/src/main/res/values-ar/strings.xml +++ b/src/main/res/values-ar/strings.xml @@ -65,7 +65,6 @@ أنشئت القائمة ظهور تعديل خيارات الشاشه - إظهار إختصار المنبه الإعادة إلى الإفتراضي إظهار عنوان المهمه خيارات قائمة المهام @@ -159,7 +158,6 @@ من تاريخ الموعد من تاريخ الاتمام - أضف للقائمة أدخل اسم للقائمة أولاً غير مصنف مؤقت diff --git a/src/main/res/values-bg-rBG/strings.xml b/src/main/res/values-bg-rBG/strings.xml index 0e89a5ba2..f9955a9a8 100644 --- a/src/main/res/values-bg-rBG/strings.xml +++ b/src/main/res/values-bg-rBG/strings.xml @@ -116,7 +116,6 @@ Изглед Филтри за показване Редактиране на опциите екрана - Покажи прекия път към таймера Настройване изгледа на екрана за редактиране на задача Възстанови по подразбиране Настройване изгледа на екрана за редактиране на задача чрез изтегляне на елементите във всеки ред @@ -255,7 +254,6 @@ месечно на два месеца - Повторения Всеки %d Интервал на повторение Без повторение @@ -276,7 +274,6 @@ Повтаряй завинаги Повтаряй до %s %1$s е насрочено за %2$s - Добави към списъци Нов таг Моля, първо въведете име за този списък! Без категория diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml index f0553441e..d7b6b380b 100644 --- a/src/main/res/values-ca/strings.xml +++ b/src/main/res/values-ca/strings.xml @@ -125,7 +125,6 @@ Inici de Silenci Final de Silenci Notificacions al Atzar - Repeticions Cada %d Interval de Repecitiò Sense repetir diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index daf0b9014..401983999 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -220,7 +220,6 @@ měsíčně každý druhý měsíc - Opakování Každý %d Opakovací interval Bez opakování @@ -240,7 +239,6 @@ Každý %1$s\n až do %2$s Opakovat stále Opakovat až do %s - Přidat na seznam Prosím zadejte jméno pro první seznam Nezařazené Aktivní časovače pro %s! diff --git a/src/main/res/values-da/strings.xml b/src/main/res/values-da/strings.xml index 9ed16bc98..1199cae09 100644 --- a/src/main/res/values-da/strings.xml +++ b/src/main/res/values-da/strings.xml @@ -120,7 +120,6 @@ Stille timer start Stille timer slut Tilfældige påmindelser - Gentagelser Hver %d Interval for gentagelse Gentages ikke diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 0f48c8eda..42fe33d88 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -109,7 +109,6 @@ Erscheinungsbild Angezeigte Filter Bildschirmeinstellungen bearbeiten - Verknüpfung zu Timer anzeigen Erscheinungsbild Aufgabenseite anpassen Auf Standardeinstellungen zurücksetzen Du kannst die Eingabeseite für Aufgaben mit den Schiebereglern links anpassen @@ -235,7 +234,6 @@ monatlich alle zwei Monate - Wiederholungen Jeden %d Wiederholungsintervall Nicht wiederholen @@ -256,7 +254,6 @@ Endlos wiederholen Wiederhole bis %s %1$s verschoben um %2$s - Zur Liste hinzufügen Neues Schlagwort Bitte gib zuerst einen Namen für die Liste ein! Nicht kategorisiert diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml index 94f9b310f..3f6d9e90a 100644 --- a/src/main/res/values-el/strings.xml +++ b/src/main/res/values-el/strings.xml @@ -103,7 +103,6 @@ Εμφάνιση Φίλτρα για εμφάνιση Επεξεργασία επιλογών εμφάνισης - Εμφάνιση συντόμευσης χρονομέτρου Προσαρμόστε τη διάταξη της οθόνης επεξεργασίας της εργασίας Επαναφορά προεπιλογών Προσαρμόστε τη διάταξη της οθόνης επεξεργασίας της εργασίας τραβώντας την αριστερή λαβή σε κάθε σειρά @@ -223,7 +222,6 @@ μηνιαία διμηνιαία - Επαναλήψεις Κάθε %d Διάστημα επανάληψης Μή επαναλαμβανόμενα @@ -243,7 +241,6 @@ Κάθε %1$s\nμέχρι %2$s Επανάληψη επ\'αορίστου Επανάληψη μέχρι %s - Προσθήκη στις λίστες Παρακαλώ εισάγετε ενα όνομα για την λίστα πρώτα! Μη κατηγοριοποιημένο Χρονοδιακόπτες ενεργοί για %s! diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 58b5f6927..ad54dc261 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -113,7 +113,6 @@ Apariencia Filtros a mostrar Editar opciones de pantalla - Mostrar atajo del temporizador Personalizar la disposición de la pantalla de edición de tareas Restablecer valores predeterminados Personalice su pantalla de edición de tareas arrastrando el asa izquierda en cada fila @@ -245,7 +244,6 @@ mensualmente bimensualmente - Repeticiones Cada %d Intervalo de repetición Sin repetir @@ -266,7 +264,6 @@ Repetir por siempre Repetir hasta %s %1$s He reprogramado esta tarea recurrente para %2$s - Añadir a listas Nueva Etiqueta Por favor, ¡introduce un nombre para la primera lista! Sin Categoría diff --git a/src/main/res/values-fa/strings.xml b/src/main/res/values-fa/strings.xml index 345c6c1b2..3fdf5792d 100644 --- a/src/main/res/values-fa/strings.xml +++ b/src/main/res/values-fa/strings.xml @@ -80,7 +80,6 @@ ظاهر فیلترها برای نمایش ویرایش تنظیمات صفحه - نمایش میانبر تایمر شخصی سازی قالب صفحه ویرایش وظیفه برگرداندن به پیش فرض نمایش عنوان کامل وظیفه @@ -178,7 +177,6 @@ هر ماه یک ماه درمیان - تکرارها دوره تکرار بدون تکرار @@ -194,7 +192,6 @@ از تاریخ اتمام تکرار بینهایت - اضافه به لیست تگ جدید لطفا ابتدا یک نام برای لیست انتخاب نمایید دسته بندی نشده diff --git a/src/main/res/values-fi/strings.xml b/src/main/res/values-fi/strings.xml index 92c249f43..59c1431d4 100644 --- a/src/main/res/values-fi/strings.xml +++ b/src/main/res/values-fi/strings.xml @@ -54,7 +54,6 @@ Valitettavasti meillä on yhteysongelmia Google palvelimiin. Ole hyvä ja yritä myöhemmin uudestaa. Google tehtävät Satunnainen muistutus - Ei toistoa Toista %d Toistoväli Ei toistuva @@ -62,7 +61,6 @@ Joka %1$s\nkunnes %2$s Toista loputtomiin Toista kunnes %s - Lisää listaan Ole hyvä syötä ensin nimi tälle listalle! Poista tehtävä Lähdekoodi diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index 16a4155d2..4f9ea5fc1 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -112,7 +112,6 @@ Apparence Filtres à afficher Edition des options d\'affichage - Afficher le raccourci de minuterie Personnaliser la disposition de l\'écran d\'édition de tâche Rétablir les valeurs par défaut Personnalisez votre écran d\'ajout de tâche en faisant glisser chaque ligne vers la gauche @@ -247,7 +246,6 @@ mensuel bi-mensuel - Répétitions Tous les %d Interval de répétition Une fois seulement @@ -268,7 +266,6 @@ Répéter indéfiniment Répéter jusqu\'à %s %1$s replanifiée à %2$s - Ajouter à la liste Nouveau tag Veuillez d\'abord entrer un nom pour cette liste. Non classé diff --git a/src/main/res/values-hu/strings.xml b/src/main/res/values-hu/strings.xml index f8182e45a..ecb6b4a35 100644 --- a/src/main/res/values-hu/strings.xml +++ b/src/main/res/values-hu/strings.xml @@ -100,7 +100,6 @@ Befejezve Szundi Véletlenszerű emlékeztetők - Ismétlések Minden %d Ismétlési időköz Nem ismétlődő @@ -108,7 +107,6 @@ Minden %1$s\neddig: %2$s Ismétlés örökké Ismétlés eddig: %s - Hozzáadás listákhoz Kérlek, először add meg a lista nevét! Feladat törlése diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index bc676df96..fc7aa86ce 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -114,7 +114,6 @@ Aspetto Filtri da visualizzare Modifica opzioni schermo - Mostra scorciatoia timer Personalizza il layout della schermata di modifica attività Ripristina predefiniti Personalizza la schermata di modifica attività trascinando l’indicatore a sinistra di ogni riga @@ -248,7 +247,6 @@ Se visualizzi questo errore più volte, ti consigliamo di cancellare tutti i dat mensilmente bi-mensilmente - Ripetizioni Ogni %d Intervallo di ripetizione Non ricorrente @@ -269,7 +267,6 @@ Se visualizzi questo errore più volte, ti consigliamo di cancellare tutti i dat Ripeti all\'infinito Ripeti fino %s %1$s ripianificata per %2$s - Aggiungi alle liste Nuova etichetta Per cortesia, prima inserisci un nome per questa lista Non classificato diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml index 21e31dff5..b26241583 100644 --- a/src/main/res/values-iw/strings.xml +++ b/src/main/res/values-iw/strings.xml @@ -223,7 +223,6 @@ חודשי דו חודשי - חזרה כל %d אינטרוול חזרות @@ -242,7 +241,6 @@ כל %1$s\nעד %2$s חזור לנצח חזרה עד %s - הוסף לרשימות אנא הכנס שם לרשימה זו קוצב זמן הופעל עבור %s משימות משימות עם הערכת זמן diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index fc359ed48..9c09d3ed3 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -114,7 +114,6 @@ 外観 表示のフィルター 編集画面オプション - タイマーのショートカットを表示 タスク編集画面のレイアウトをカスタマイズ デフォルトにリセット 各行の左側をドラッグしてタスク編集画面をカスタマイズしてください @@ -254,7 +253,6 @@ 毎月 一ヶ月おき - 繰り返し %d 毎 繰り返し間隔 繰り返しなし @@ -275,7 +273,6 @@ 永久に繰り返す %s まで繰り返す %1$s を %2$s にスケジュール変更しました - リストに追加 新しいタグ まずリスト名を記入してください! 未分類 diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml index c64a9d97b..60924fe0f 100644 --- a/src/main/res/values-ko/strings.xml +++ b/src/main/res/values-ko/strings.xml @@ -117,7 +117,6 @@ 보기 설정 표시할 필터 화면 설정 편집하기 - 타이머 바로가기 보기 일정 편집화면 레이아웃 설정하기 기본값으로 초기화하기 각 줄의 왼쪽 손잡이를 끌어서 일정 편집 화면을 사용자 정의하기 @@ -255,7 +254,6 @@ Tasks의 백업에서 당신의 일정을 복구하시기 바랍니다. 매달 격월로 - 반복 설정 매 %d 반복 주기 반복하지 않기 @@ -276,7 +274,6 @@ Tasks의 백업에서 당신의 일정을 복구하시기 바랍니다. 영원히 반복하기 %s 까지 반복 %1$s 이 %2$s 로 변경되었습니다 - 목록에 추가하기 새 태그 이 목록의 이름을 먼저 입력하세요! 미분류 일정 diff --git a/src/main/res/values-nb/strings.xml b/src/main/res/values-nb/strings.xml index 4634a1c4b..d70773ebe 100644 --- a/src/main/res/values-nb/strings.xml +++ b/src/main/res/values-nb/strings.xml @@ -110,7 +110,6 @@ Stilletimer start Stilletimer slutt Tilfeldige påminnelser - Gjentakelser Hver %d Gjentakelsesintervall Hver %s diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 62ee9a757..18cfd1dec 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -114,7 +114,6 @@ Uiterlijk Te tonen filters Scherm opties bewerken - Toon timer snelkoppeling Pas de layout van het Taak Wijzigingsscherm aan Standaardinstellingen herstellen Pas uw taak bewerken scherm aan door de linker handle van elke rij te verslepen @@ -251,7 +250,6 @@ maandelijks tweemaandelijks - Herhalingen Elke %d Herhaal interval Niet herhalend @@ -272,7 +270,6 @@ Altijd herhalen Herhalen tot %s %1$s opnieuw ingepland op %2$s - Voeg toe aan lijsten Nieuwe Label Voer a.u.b. eerst een naam in voor deze lijst! Niet gecategoriseerd diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index 25b0f2978..6bfab901b 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -102,7 +102,6 @@ Wygląd Pokazywane filtry Edytuj ustawienia ekranu - Pokaż skrót minutnika Dostosuj układ strony edycji zadania Przywróć domyślne Dostosuj swój ekran edycji zadania przez przeciąganie za uchwyt po prawej w każdym wierszu @@ -226,7 +225,6 @@ i odzyskanie zadań z kopi zapasowej (Settings->Sync and backup->Backup-&g raz w miesiącu raz na dwa miesiące - Powtarza się Co %d Odstęp powtarzania Jednorazowo @@ -246,7 +244,6 @@ i odzyskanie zadań z kopi zapasowej (Settings->Sync and backup->Backup-&g Co %1$s\ndo %2$s Powtarzaj bez końca Powtarzaj do %s - Dodaj do list Wpisz nazwę dla tej listy najpierw! Na żadnej liście Minutnkiki aktywne przez %s! diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml index 88439c360..60ffbd215 100644 --- a/src/main/res/values-pt-rBR/strings.xml +++ b/src/main/res/values-pt-rBR/strings.xml @@ -102,7 +102,6 @@ Aparência Filtros a mostrar Editar opções da tela - Exibir atalho para temporizador Personalize o layout da tela de edição Restaurar valores padrão Personalize suas tarefas na tela de edição arrastando-as para a esquerda @@ -223,7 +222,6 @@ mensalmente a cada dois meses - Repetir A cada %d Intervalo de repetição Não repetir @@ -243,7 +241,6 @@ Todo %1$s\naté %2$s Repetir para sempre Repetir até %s - Adicionar às listas Entre com o nome da lista primeiro! Sem categoria Temporizador ativado para %s! diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml index 996e72238..adab75a22 100644 --- a/src/main/res/values-pt/strings.xml +++ b/src/main/res/values-pt/strings.xml @@ -113,7 +113,6 @@ Aspeto Filtros a mostrar Opções do ecrã de edição - Mostrar atalho do temporizador Personalizar o esquema do ecrã de edição de tarefas Restaurar definições originas Personalize o ecrã de edição de tarefas arrastando a guia em cada linha @@ -246,7 +245,6 @@ das tarefas através de um backup em Definições->Sincronização e backup-& mensal bimensal - Repete Cada %d Intervalo de repetição Não repete @@ -267,7 +265,6 @@ das tarefas através de um backup em Definições->Sincronização e backup-& Repetir eternamente Repetir até %s %1$s agendada para %2$s - Adicionar às listas Nova etiqueta Introduza o nome para esta lista! Sem categoria diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 8128599a0..dc15003ca 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -114,7 +114,6 @@ Интерфейс Показать фильтры Редактировать настройки экрана - Показать вкладку таймера Настроить внешний вид экрана правки задачи Настройки по умолчанию Настройте экран редактирования задачи, перетаскивая элементы @@ -253,7 +252,6 @@ ежемесячно каждые два месяца - Повторения С интервалом в %d Интервал повтора Без повторений @@ -274,7 +272,6 @@ Повторять всегда Повторять до %s «%1$s» перенесено на %2$s - Добавить в список Новый тег Пожалуйста, для начала введите название списка! Без тега diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml index 3b6a28d09..ab95167bf 100644 --- a/src/main/res/values-sk/strings.xml +++ b/src/main/res/values-sk/strings.xml @@ -111,7 +111,6 @@ Vzhľad Filtre pre zobrazenie Možnosti úprav zobrazenia - Zobraziť skratku časovača Prispôsobiť rozvrhnutie zobrazenia úpravy úloh Obnoviť na predvolené Prispôsob si rozvrhnutie zobrazenia úpravy úloh potiahnutím ľavej rukoväte na každom riadku @@ -239,7 +238,6 @@ mesačne každý druhý mesiac - Opakovanie Každý %d Interval opakovania Neopakovať @@ -260,7 +258,6 @@ Opakovať donekonečna Opakovať do %s %1$s preplánované na %2$s - Pridať do zoznamov Nasledujúci tag Prosím, uveďte najprv názov pre tento zoznam! Nezaradené diff --git a/src/main/res/values-sl-rSI/strings.xml b/src/main/res/values-sl-rSI/strings.xml index ddd0a75bb..3e929d6d0 100644 --- a/src/main/res/values-sl-rSI/strings.xml +++ b/src/main/res/values-sl-rSI/strings.xml @@ -106,7 +106,6 @@ Izgled Filtri za prikaz Uredi možnosti zaslona - Prikaži bližnjico za štoparico Po meri postavi stran za urejevanje opravkov Povrni privzeto nastavitev Stran za urejanje opravkov se postavi po meri s potegom leve ročke posamezne vrstice @@ -227,7 +226,6 @@ mesečno vsake dva meseca - Ponovitve Vsakih %d Pogostost ponovitev Brez ponovitev @@ -247,7 +245,6 @@ Vsak %1$s\n do %2$s Ponavljaj do preklica Ponavljaj do %s - Dodaj na sezname Prosimo, vnesite naziv tega seznama najprej! Nerazvrščen Merilniki časa aktivni za %s! diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index 3c3fa54c4..9d9ba7cdb 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -218,7 +218,6 @@ och återställer dina aktuella uppgifter från en backup varje månad varannan månad - Upprepningar Varje %d Upprepningsintervall Inte upprepande @@ -238,7 +237,6 @@ och återställer dina aktuella uppgifter från en backup Varje %1$s\ntill %2$s Repetera oändligt Repetera till %s - Lägg till på listor Ange först ett namn på listan! Ingen kategori Tidtagarur aktivt för %s! diff --git a/src/main/res/values-th/strings.xml b/src/main/res/values-th/strings.xml index 53a90330f..c27647aa2 100644 --- a/src/main/res/values-th/strings.xml +++ b/src/main/res/values-th/strings.xml @@ -65,7 +65,6 @@ %s (เสร็จสิ้นแล้ว) เสร็จเรียบร้อยแล้ว! หลับ.. - การเกิดซ้ำ วันนี้ พรุ่งนี้ เมื่อวาน diff --git a/src/main/res/values-tr/strings.xml b/src/main/res/values-tr/strings.xml index 0c3f6b496..40869bf39 100644 --- a/src/main/res/values-tr/strings.xml +++ b/src/main/res/values-tr/strings.xml @@ -198,7 +198,6 @@ ayda bir ayda 2 kez - Tekrarlar Her %d Yineleme Aralığı diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml index 0b8e1f9e5..9aa32f668 100644 --- a/src/main/res/values-uk/strings.xml +++ b/src/main/res/values-uk/strings.xml @@ -109,7 +109,6 @@ Інтерфейс Показати фільтри Редагувати налаштування екрану - Показати ярлик таймера Налаштувати зовнішній вигляд екрану редагування завдань Налаштування за замовчуванням Налаштуйте Ваш екран редагування нотатки перетягуванням лівої частини рядків @@ -239,7 +238,6 @@ щомісяця два рази на місяць - Повторення З інтервалом в %d Інтервал повторення Не повторювати @@ -247,7 +245,6 @@ Кожні %1$s\nпоки %2$s Повторювати завжди Повторювати до %s - Додати до списку Введіть назву списку спочатку! Без категорії Для %s діють таймери! diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index efce8bd7b..cd5e4f99b 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -177,7 +177,6 @@ 每月 每两个月 - 重复 每 %d 重复间隔 diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index 608ad9603..6af1dc898 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -208,7 +208,6 @@ 每月 每2個月 - 重複 每 %d 重複間隔 @@ -227,7 +226,6 @@ 每隔 %1$s\n直到 %2$s 永遠重複 重複到 %s - 加入至列表 請先為此列表鍵入一個名稱! 未分類 秒錶啟動了 %s! diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index 00504bb9b..34a3d2954 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -62,4 +62,10 @@ @string/none + + @string/ring_once + @string/ring_five_times + @string/ring_nonstop + + \ No newline at end of file diff --git a/src/main/res/values/keys.xml b/src/main/res/values/keys.xml index b3a6cdd6d..9e9850a8e 100644 --- a/src/main/res/values/keys.xml +++ b/src/main/res/values/keys.xml @@ -112,8 +112,6 @@ fullTaskTitle - p_show_timer_shortcut - diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index b49d7b4c8..bec189d04 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -344,8 +344,6 @@ File %1$s contained %2$s.\n\n Edit screen options - Show timer shortcut - Customize the layout of the task edit screen @@ -696,9 +694,6 @@ File %1$s contained %2$s.\n\n - - Repeats - Every %d @@ -739,13 +734,7 @@ File %1$s contained %2$s.\n\n %1$s rescheduled for %2$s - - - - - Add to lists - - + New Tag diff --git a/src/main/res/xml/preferences_appearance.xml b/src/main/res/xml/preferences_appearance.xml index 2abf69861..e3d501f1b 100644 --- a/src/main/res/xml/preferences_appearance.xml +++ b/src/main/res/xml/preferences_appearance.xml @@ -34,10 +34,6 @@ android:key="@string/p_show_task_edit_comments" android:title="@string/EPr_show_task_edit_comments" /> -