mirror of https://github.com/tasks/tasks
Convert TaskListFragment to Kotlin
parent
1d1f132806
commit
3801c46f31
@ -1,883 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.astrid.activity;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static com.google.common.base.Strings.padStart;
|
||||
import static com.google.common.collect.Lists.transform;
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.assertMainThread;
|
||||
import static org.tasks.activities.RemoteListPicker.newRemoteListSupportPicker;
|
||||
import static org.tasks.caldav.CaldavCalendarSettingsActivity.EXTRA_CALDAV_CALENDAR;
|
||||
import static org.tasks.db.DbUtils.collect;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.speech.RecognizerIntent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuItem.OnActionExpandListener;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.appcompat.view.ActionMode.Callback;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.SearchView.OnQueryTextListener;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.paging.PagedList;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.adapter.TaskAdapterProvider;
|
||||
import com.todoroo.astrid.api.CaldavFilter;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.api.GtasksFilter;
|
||||
import com.todoroo.astrid.api.IdListFilter;
|
||||
import com.todoroo.astrid.api.SearchFilter;
|
||||
import com.todoroo.astrid.api.TagFilter;
|
||||
import com.todoroo.astrid.core.BuiltInFilterExposer;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.service.TaskCreator;
|
||||
import com.todoroo.astrid.service.TaskDeleter;
|
||||
import com.todoroo.astrid.service.TaskDuplicator;
|
||||
import com.todoroo.astrid.service.TaskMover;
|
||||
import com.todoroo.astrid.timers.TimerPlugin;
|
||||
import com.todoroo.astrid.utility.Flags;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.LocalBroadcastManager;
|
||||
import org.tasks.R;
|
||||
import org.tasks.ShortcutManager;
|
||||
import org.tasks.activities.FilterSettingsActivity;
|
||||
import org.tasks.activities.GoogleTaskListSettingsActivity;
|
||||
import org.tasks.activities.PlaceSettingsActivity;
|
||||
import org.tasks.activities.RemoteListPicker;
|
||||
import org.tasks.activities.TagSettingsActivity;
|
||||
import org.tasks.caldav.CaldavCalendarSettingsActivity;
|
||||
import org.tasks.data.CaldavAccount;
|
||||
import org.tasks.data.CaldavCalendar;
|
||||
import org.tasks.data.CaldavDao;
|
||||
import org.tasks.data.Place;
|
||||
import org.tasks.data.TagDataDao;
|
||||
import org.tasks.data.TaskContainer;
|
||||
import org.tasks.dialogs.DateTimePicker;
|
||||
import org.tasks.dialogs.DialogBuilder;
|
||||
import org.tasks.dialogs.SortDialog;
|
||||
import org.tasks.etesync.EteSyncCalendarSettingsActivity;
|
||||
import org.tasks.filters.PlaceFilter;
|
||||
import org.tasks.injection.ForActivity;
|
||||
import org.tasks.injection.FragmentComponent;
|
||||
import org.tasks.injection.InjectingFragment;
|
||||
import org.tasks.intents.TaskIntents;
|
||||
import org.tasks.notifications.NotificationManager;
|
||||
import org.tasks.preferences.Device;
|
||||
import org.tasks.preferences.Preferences;
|
||||
import org.tasks.sync.SyncAdapters;
|
||||
import org.tasks.tags.TagPickerActivity;
|
||||
import org.tasks.tasklist.DragAndDropRecyclerAdapter;
|
||||
import org.tasks.tasklist.PagedListRecyclerAdapter;
|
||||
import org.tasks.tasklist.TaskListRecyclerAdapter;
|
||||
import org.tasks.tasklist.ViewHolderFactory;
|
||||
import org.tasks.themes.ColorProvider;
|
||||
import org.tasks.themes.ThemeColor;
|
||||
import org.tasks.ui.TaskListViewModel;
|
||||
import org.tasks.ui.Toaster;
|
||||
|
||||
public final class TaskListFragment extends InjectingFragment
|
||||
implements OnRefreshListener,
|
||||
OnMenuItemClickListener,
|
||||
OnActionExpandListener,
|
||||
OnQueryTextListener,
|
||||
Callback {
|
||||
|
||||
public static final String TAGS_METADATA_JOIN = "for_tags"; // $NON-NLS-1$
|
||||
public static final String GTASK_METADATA_JOIN = "googletask"; // $NON-NLS-1$
|
||||
public static final String CALDAV_METADATA_JOIN = "for_caldav"; // $NON-NLS-1$
|
||||
public static final String ACTION_RELOAD = "action_reload";
|
||||
public static final String ACTION_DELETED = "action_deleted";
|
||||
private static final String EXTRA_SELECTED_TASK_IDS = "extra_selected_task_ids";
|
||||
private static final String EXTRA_SEARCH = "extra_search";
|
||||
private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
|
||||
private static final String EXTRA_FILTER = "extra_filter";
|
||||
private static final String FRAG_TAG_REMOTE_LIST_PICKER = "frag_tag_remote_list_picker";
|
||||
private static final String FRAG_TAG_SORT_DIALOG = "frag_tag_sort_dialog";
|
||||
private static final String FRAG_TAG_DATE_TIME_PICKER = "frag_tag_date_time_picker";
|
||||
private static final int REQUEST_LIST_SETTINGS = 10101;
|
||||
private static final int REQUEST_MOVE_TASKS = 10103;
|
||||
private static final int REQUEST_TAG_TASKS = 10106;
|
||||
|
||||
private static final int SEARCH_DEBOUNCE_TIMEOUT = 300;
|
||||
private final RefreshReceiver refreshReceiver = new RefreshReceiver();
|
||||
private CompositeDisposable disposables;
|
||||
@Inject SyncAdapters syncAdapters;
|
||||
@Inject TaskDeleter taskDeleter;
|
||||
@Inject @ForActivity Context context;
|
||||
@Inject Preferences preferences;
|
||||
@Inject DialogBuilder dialogBuilder;
|
||||
@Inject TaskCreator taskCreator;
|
||||
@Inject TimerPlugin timerPlugin;
|
||||
@Inject ViewHolderFactory viewHolderFactory;
|
||||
@Inject LocalBroadcastManager localBroadcastManager;
|
||||
@Inject Device device;
|
||||
@Inject TaskMover taskMover;
|
||||
@Inject Toaster toaster;
|
||||
@Inject TaskAdapterProvider taskAdapterProvider;
|
||||
@Inject TaskDao taskDao;
|
||||
@Inject TaskDuplicator taskDuplicator;
|
||||
@Inject TagDataDao tagDataDao;
|
||||
@Inject CaldavDao caldavDao;
|
||||
@Inject ThemeColor defaultThemeColor;
|
||||
@Inject ColorProvider colorProvider;
|
||||
@Inject NotificationManager notificationManager;
|
||||
@Inject ShortcutManager shortcutManager;
|
||||
|
||||
@BindView(R.id.swipe_layout)
|
||||
SwipeRefreshLayout swipeRefreshLayout;
|
||||
|
||||
@BindView(R.id.swipe_layout_empty)
|
||||
SwipeRefreshLayout emptyRefreshLayout;
|
||||
|
||||
@BindView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
|
||||
@BindView(R.id.task_list_coordinator)
|
||||
CoordinatorLayout coordinatorLayout;
|
||||
|
||||
@BindView(R.id.recycler_view)
|
||||
RecyclerView recyclerView;
|
||||
|
||||
private TaskListViewModel taskListViewModel;
|
||||
private TaskAdapter taskAdapter = null;
|
||||
private TaskListRecyclerAdapter recyclerAdapter;
|
||||
private Filter filter;
|
||||
private final PublishSubject<String> searchSubject = PublishSubject.create();
|
||||
private Disposable searchDisposable;
|
||||
private MenuItem search;
|
||||
private String searchQuery;
|
||||
private ActionMode mode = null;
|
||||
private ThemeColor themeColor;
|
||||
|
||||
private TaskListFragmentCallbackHandler callbacks;
|
||||
|
||||
static TaskListFragment newTaskListFragment(Context context, Filter filter) {
|
||||
TaskListFragment fragment = new TaskListFragment();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(
|
||||
EXTRA_FILTER,
|
||||
filter == null ? BuiltInFilterExposer.getMyTasksFilter(context.getResources()) : filter);
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
disposables.add(
|
||||
syncAdapters
|
||||
.sync(true)
|
||||
.doOnSuccess(
|
||||
initiated -> {
|
||||
if (!initiated) {
|
||||
refresh();
|
||||
}
|
||||
})
|
||||
.delay(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
initiated -> {
|
||||
if (initiated) {
|
||||
setSyncOngoing();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void setSyncOngoing() {
|
||||
assertMainThread();
|
||||
|
||||
boolean ongoing = preferences.isSyncOngoing();
|
||||
|
||||
swipeRefreshLayout.setRefreshing(ongoing);
|
||||
emptyRefreshLayout.setRefreshing(ongoing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
|
||||
super.onViewStateRestored(savedInstanceState);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
long[] longArray = savedInstanceState.getLongArray(EXTRA_SELECTED_TASK_IDS);
|
||||
if (longArray != null && longArray.length > 0) {
|
||||
taskAdapter.setSelected(longArray);
|
||||
startActionMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
callbacks = (TaskListFragmentCallbackHandler) activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(FragmentComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
List<Long> selectedTaskIds = taskAdapter.getSelected();
|
||||
outState.putLongArray(EXTRA_SELECTED_TASK_IDS, Longs.toArray(selectedTaskIds));
|
||||
outState.putString(EXTRA_SEARCH, searchQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View parent = inflater.inflate(R.layout.fragment_task_list, container, false);
|
||||
ButterKnife.bind(this, parent);
|
||||
|
||||
filter = getFilter();
|
||||
|
||||
themeColor = filter.tint != 0 ? colorProvider.getThemeColor(filter.tint, true) : defaultThemeColor;
|
||||
|
||||
filter.setFilterQueryOverride(null);
|
||||
|
||||
// set up list adapters
|
||||
taskAdapter = taskAdapterProvider.createTaskAdapter(filter);
|
||||
|
||||
taskListViewModel = new ViewModelProvider(getActivity()).get(TaskListViewModel.class);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
searchQuery = savedInstanceState.getString(EXTRA_SEARCH);
|
||||
}
|
||||
|
||||
taskListViewModel.setFilter(searchQuery == null ? filter : createSearchFilter(searchQuery));
|
||||
|
||||
((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
|
||||
taskListViewModel.observe(
|
||||
this,
|
||||
list -> {
|
||||
submitList(list);
|
||||
|
||||
if (list.isEmpty()) {
|
||||
swipeRefreshLayout.setVisibility(View.GONE);
|
||||
emptyRefreshLayout.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
swipeRefreshLayout.setVisibility(View.VISIBLE);
|
||||
emptyRefreshLayout.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
setupRefresh(swipeRefreshLayout);
|
||||
setupRefresh(emptyRefreshLayout);
|
||||
|
||||
toolbar.setTitle(filter.listingTitle);
|
||||
toolbar.setNavigationIcon(R.drawable.ic_outline_menu_24px);
|
||||
toolbar.setNavigationOnClickListener(v -> callbacks.onNavigationIconClicked());
|
||||
toolbar.setOnMenuItemClickListener(this);
|
||||
setupMenu();
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
private void submitList(List<TaskContainer> tasks) {
|
||||
if (tasks instanceof PagedList) {
|
||||
if (!(recyclerAdapter instanceof PagedListRecyclerAdapter)) {
|
||||
setAdapter(
|
||||
new PagedListRecyclerAdapter(
|
||||
taskAdapter, recyclerView, viewHolderFactory, this, tasks, taskDao));
|
||||
return;
|
||||
}
|
||||
} else if (!(recyclerAdapter instanceof DragAndDropRecyclerAdapter)) {
|
||||
setAdapter(
|
||||
new DragAndDropRecyclerAdapter(
|
||||
taskAdapter, recyclerView, viewHolderFactory, this, tasks, taskDao));
|
||||
return;
|
||||
}
|
||||
|
||||
recyclerAdapter.submitList(tasks);
|
||||
}
|
||||
|
||||
private void setAdapter(TaskListRecyclerAdapter adapter) {
|
||||
recyclerAdapter = adapter;
|
||||
recyclerView.setAdapter(adapter);
|
||||
taskAdapter.setHelper(adapter);
|
||||
}
|
||||
|
||||
private void setupMenu() {
|
||||
Menu menu = toolbar.getMenu();
|
||||
menu.clear();
|
||||
if (filter.hasBeginningMenu()) {
|
||||
toolbar.inflateMenu(filter.getBeginningMenu());
|
||||
}
|
||||
toolbar.inflateMenu(R.menu.menu_task_list_fragment);
|
||||
if (filter.hasMenu()) {
|
||||
toolbar.inflateMenu(filter.getMenu());
|
||||
}
|
||||
MenuItem hidden = menu.findItem(R.id.menu_show_hidden);
|
||||
MenuItem completed = menu.findItem(R.id.menu_show_completed);
|
||||
if (!taskAdapter.supportsHiddenTasks() || !filter.supportsHiddenTasks()) {
|
||||
completed.setChecked(true);
|
||||
completed.setEnabled(false);
|
||||
hidden.setChecked(true);
|
||||
hidden.setEnabled(false);
|
||||
} else {
|
||||
hidden.setChecked(preferences.getBoolean(R.string.p_show_hidden_tasks, false));
|
||||
completed.setChecked(preferences.getBoolean(R.string.p_show_completed_tasks, false));
|
||||
}
|
||||
MenuItem sortMenu = menu.findItem(R.id.menu_sort);
|
||||
if (!filter.supportsSorting()) {
|
||||
sortMenu.setEnabled(false);
|
||||
sortMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
}
|
||||
if (preferences.disableSubtasks()
|
||||
|| !filter.supportSubtasks()
|
||||
|| taskAdapter.supportsManualSorting()) {
|
||||
menu.findItem(R.id.menu_collapse_subtasks).setVisible(false);
|
||||
menu.findItem(R.id.menu_expand_subtasks).setVisible(false);
|
||||
}
|
||||
menu.findItem(R.id.menu_voice_add).setVisible(device.voiceInputAvailable());
|
||||
|
||||
search = menu.findItem(R.id.menu_search).setOnActionExpandListener(this);
|
||||
((SearchView) search.getActionView()).setOnQueryTextListener(this);
|
||||
|
||||
themeColor.apply(toolbar);
|
||||
}
|
||||
|
||||
private void openFilter(@Nullable Filter filter) {
|
||||
if (filter == null) {
|
||||
startActivity(TaskIntents.getTaskListByIdIntent(context, null));
|
||||
} else {
|
||||
startActivity(TaskIntents.getTaskListIntent(context, filter));
|
||||
}
|
||||
}
|
||||
|
||||
private void searchByQuery(@Nullable String query) {
|
||||
searchQuery = query == null ? "" : query.trim();
|
||||
if (searchQuery.isEmpty()) {
|
||||
taskListViewModel.searchByFilter(
|
||||
BuiltInFilterExposer.getMyTasksFilter(context.getResources()));
|
||||
} else {
|
||||
Filter savedFilter = createSearchFilter(searchQuery);
|
||||
taskListViewModel.searchByFilter(savedFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private Filter createSearchFilter(String query) {
|
||||
return new SearchFilter(getString(R.string.FLA_search_filter, query), query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_voice_add:
|
||||
Intent recognition = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
|
||||
recognition.putExtra(
|
||||
RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
|
||||
recognition.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
|
||||
recognition.putExtra(
|
||||
RecognizerIntent.EXTRA_PROMPT, getString(R.string.voice_create_prompt));
|
||||
startActivityForResult(recognition, TaskListFragment.VOICE_RECOGNITION_REQUEST_CODE);
|
||||
return true;
|
||||
case R.id.menu_sort:
|
||||
SortDialog.newSortDialog(filter.supportsManualSort())
|
||||
.show(getChildFragmentManager(), FRAG_TAG_SORT_DIALOG);
|
||||
return true;
|
||||
case R.id.menu_show_hidden:
|
||||
item.setChecked(!item.isChecked());
|
||||
preferences.setBoolean(R.string.p_show_hidden_tasks, item.isChecked());
|
||||
loadTaskListContent();
|
||||
localBroadcastManager.broadcastRefresh();
|
||||
return true;
|
||||
case R.id.menu_show_completed:
|
||||
item.setChecked(!item.isChecked());
|
||||
preferences.setBoolean(R.string.p_show_completed_tasks, item.isChecked());
|
||||
loadTaskListContent();
|
||||
localBroadcastManager.broadcastRefresh();
|
||||
return true;
|
||||
case R.id.menu_clear_completed:
|
||||
dialogBuilder
|
||||
.newDialog(R.string.clear_completed_tasks_confirmation)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> clearCompleted())
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
return true;
|
||||
case R.id.menu_filter_settings:
|
||||
Intent filterSettings = new Intent(getActivity(), FilterSettingsActivity.class);
|
||||
filterSettings.putExtra(FilterSettingsActivity.TOKEN_FILTER, filter);
|
||||
startActivityForResult(filterSettings, REQUEST_LIST_SETTINGS);
|
||||
return true;
|
||||
case R.id.menu_caldav_list_fragment:
|
||||
CaldavCalendar calendar = ((CaldavFilter) filter).getCalendar();
|
||||
CaldavAccount account = caldavDao.getAccountByUuid(calendar.getAccount());
|
||||
Intent caldavSettings =
|
||||
new Intent(
|
||||
getActivity(),
|
||||
account.isCaldavAccount()
|
||||
? CaldavCalendarSettingsActivity.class
|
||||
: EteSyncCalendarSettingsActivity.class);
|
||||
caldavSettings.putExtra(EXTRA_CALDAV_CALENDAR, calendar);
|
||||
startActivityForResult(caldavSettings, REQUEST_LIST_SETTINGS);
|
||||
return true;
|
||||
case R.id.menu_location_settings:
|
||||
Place place = ((PlaceFilter) filter).getPlace();
|
||||
Intent intent =
|
||||
new Intent(
|
||||
getActivity(),
|
||||
PlaceSettingsActivity.class);
|
||||
intent.putExtra(PlaceSettingsActivity.EXTRA_PLACE, (Parcelable) place);
|
||||
startActivityForResult(intent, REQUEST_LIST_SETTINGS);
|
||||
return true;
|
||||
case R.id.menu_gtasks_list_settings:
|
||||
Intent gtasksSettings = new Intent(getActivity(), GoogleTaskListSettingsActivity.class);
|
||||
gtasksSettings.putExtra(
|
||||
GoogleTaskListSettingsActivity.EXTRA_STORE_DATA, ((GtasksFilter) filter).getList());
|
||||
startActivityForResult(gtasksSettings, REQUEST_LIST_SETTINGS);
|
||||
return true;
|
||||
case R.id.menu_tag_settings:
|
||||
Intent tagSettings = new Intent(getActivity(), TagSettingsActivity.class);
|
||||
tagSettings.putExtra(TagSettingsActivity.EXTRA_TAG_DATA, ((TagFilter) filter).getTagData());
|
||||
startActivityForResult(tagSettings, REQUEST_LIST_SETTINGS);
|
||||
return true;
|
||||
case R.id.menu_expand_subtasks:
|
||||
taskDao.setCollapsed(taskListViewModel.getValue(), false);
|
||||
localBroadcastManager.broadcastRefresh();
|
||||
return true;
|
||||
case R.id.menu_collapse_subtasks:
|
||||
taskDao.setCollapsed(taskListViewModel.getValue(), true);
|
||||
localBroadcastManager.broadcastRefresh();
|
||||
return true;
|
||||
case R.id.menu_open_map:
|
||||
((PlaceFilter) filter).openMap(context);
|
||||
return true;
|
||||
case R.id.menu_share:
|
||||
send(taskDao.fetchTasks(preferences, filter));
|
||||
return true;
|
||||
default:
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCompleted() {
|
||||
disposables.add(
|
||||
Single.fromCallable(() -> taskDeleter.clearCompleted(filter))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
count -> toaster.longToast(R.string.delete_multiple_tasks_confirmation, count)));
|
||||
}
|
||||
|
||||
@OnClick(R.id.fab)
|
||||
void createNewTask() {
|
||||
shortcutManager.reportShortcutUsed(ShortcutManager.SHORTCUT_NEW_TASK);
|
||||
onTaskListItemClicked(addTask(""));
|
||||
}
|
||||
|
||||
private Task addTask(String title) {
|
||||
return taskCreator.createWithValues(filter, title);
|
||||
}
|
||||
|
||||
private void setupRefresh(SwipeRefreshLayout layout) {
|
||||
layout.setOnRefreshListener(this);
|
||||
layout.setColorSchemeColors(
|
||||
colorProvider.getPriorityColor(0, true),
|
||||
colorProvider.getPriorityColor(1, true),
|
||||
colorProvider.getPriorityColor(2, true),
|
||||
colorProvider.getPriorityColor(3, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
disposables = new CompositeDisposable();
|
||||
|
||||
localBroadcastManager.registerRefreshReceiver(refreshReceiver);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
public Snackbar makeSnackbar(@StringRes int res, Object... args) {
|
||||
return makeSnackbar(getString(res, args));
|
||||
}
|
||||
|
||||
private Snackbar makeSnackbar(String text) {
|
||||
Snackbar snackbar =
|
||||
Snackbar.make(coordinatorLayout, text, 8000)
|
||||
.setTextColor(context.getColor(R.color.snackbar_text_color))
|
||||
.setActionTextColor(context.getColor(R.color.snackbar_action_color));
|
||||
snackbar.getView().setBackgroundColor(context.getColor(R.color.snackbar_background));
|
||||
return snackbar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
disposables.dispose();
|
||||
|
||||
localBroadcastManager.unregisterReceiver(refreshReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if (searchDisposable != null && !searchDisposable.isDisposed()) {
|
||||
searchDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
boolean collapseSearchView() {
|
||||
return search.isActionViewExpanded()
|
||||
&& (search.collapseActionView() || !search.isActionViewExpanded());
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
loadTaskListContent();
|
||||
|
||||
setSyncOngoing();
|
||||
}
|
||||
|
||||
public void loadTaskListContent() {
|
||||
taskListViewModel.invalidate();
|
||||
}
|
||||
|
||||
public Filter getFilter() {
|
||||
return getArguments().getParcelable(EXTRA_FILTER);
|
||||
}
|
||||
|
||||
private void onTaskCreated(List<Task> tasks) {
|
||||
for (Task task : tasks) {
|
||||
onTaskCreated(task.getUuid());
|
||||
}
|
||||
syncAdapters.sync();
|
||||
loadTaskListContent();
|
||||
}
|
||||
|
||||
void onTaskCreated(String uuid) {
|
||||
taskAdapter.onTaskCreated(uuid);
|
||||
}
|
||||
|
||||
private void onTaskDelete(Task task) {
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
if (activity != null) {
|
||||
TaskEditFragment tef = activity.getTaskEditFragment();
|
||||
if (tef != null && task.getId() == tef.model.getId()) {
|
||||
tef.discard();
|
||||
}
|
||||
}
|
||||
timerPlugin.stopTimer(task);
|
||||
taskAdapter.onTaskDeleted(task);
|
||||
loadTaskListContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case VOICE_RECOGNITION_REQUEST_CODE:
|
||||
if (resultCode == RESULT_OK) {
|
||||
List<String> match = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
|
||||
if (match != null && match.size() > 0 && match.get(0).length() > 0) {
|
||||
String recognizedSpeech = match.get(0);
|
||||
recognizedSpeech =
|
||||
recognizedSpeech.substring(0, 1).toUpperCase()
|
||||
+ recognizedSpeech.substring(1).toLowerCase();
|
||||
|
||||
onTaskListItemClicked(addTask(recognizedSpeech));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REQUEST_MOVE_TASKS:
|
||||
if (resultCode == RESULT_OK) {
|
||||
taskMover.move(
|
||||
taskAdapter.getSelected(),
|
||||
data.getParcelableExtra(RemoteListPicker.EXTRA_SELECTED_FILTER));
|
||||
finishActionMode();
|
||||
}
|
||||
break;
|
||||
case REQUEST_LIST_SETTINGS:
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
String action = data.getAction();
|
||||
if (ACTION_DELETED.equals(action)) {
|
||||
openFilter(null);
|
||||
} else if (ACTION_RELOAD.equals(action)) {
|
||||
openFilter(data.getParcelableExtra(MainActivity.OPEN_FILTER));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REQUEST_TAG_TASKS:
|
||||
if (resultCode == RESULT_OK) {
|
||||
List<Long> modified =
|
||||
tagDataDao.applyTags(
|
||||
taskDao.fetch(
|
||||
(ArrayList<Long>) data.getSerializableExtra(TagPickerActivity.EXTRA_TASKS)),
|
||||
data.getParcelableArrayListExtra(TagPickerActivity.EXTRA_PARTIALLY_SELECTED),
|
||||
data.getParcelableArrayListExtra(TagPickerActivity.EXTRA_SELECTED));
|
||||
taskDao.touch(modified);
|
||||
finishActionMode();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(android.view.MenuItem item) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public void onTaskListItemClicked(Task task) {
|
||||
callbacks.onTaskListItemClicked(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
searchDisposable =
|
||||
searchSubject
|
||||
.debounce(SEARCH_DEBOUNCE_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::searchByQuery);
|
||||
if (searchQuery == null) {
|
||||
searchByQuery("");
|
||||
}
|
||||
Menu menu = toolbar.getMenu();
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
menu.getItem(i).setVisible(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||
taskListViewModel.searchByFilter(filter);
|
||||
searchDisposable.dispose();
|
||||
searchQuery = null;
|
||||
setupMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
openFilter(createSearchFilter(query.trim()));
|
||||
search.collapseActionView();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String query) {
|
||||
searchSubject.onNext(query);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void broadcastRefresh() {
|
||||
localBroadcastManager.broadcastRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
MenuInflater inflater = actionMode.getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_multi_select, menu);
|
||||
themeColor.colorMenu(menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
ArrayList<Long> selected = taskAdapter.getSelected();
|
||||
switch (item.getItemId()) {
|
||||
case R.id.edit_tags:
|
||||
Pair<Set<String>, Set<String>> tags = tagDataDao.getTagSelections(selected);
|
||||
Intent intent = new Intent(context, TagPickerActivity.class);
|
||||
intent.putExtra(TagPickerActivity.EXTRA_TASKS, selected);
|
||||
intent.putParcelableArrayListExtra(
|
||||
TagPickerActivity.EXTRA_PARTIALLY_SELECTED,
|
||||
new ArrayList<>(tagDataDao.getByUuid(tags.first)));
|
||||
intent.putParcelableArrayListExtra(
|
||||
TagPickerActivity.EXTRA_SELECTED, new ArrayList<>(tagDataDao.getByUuid(tags.second)));
|
||||
startActivityForResult(intent, REQUEST_TAG_TASKS);
|
||||
return true;
|
||||
case R.id.move_tasks:
|
||||
Filter singleFilter = taskMover.getSingleFilter(selected);
|
||||
(singleFilter == null
|
||||
? newRemoteListSupportPicker(this, REQUEST_MOVE_TASKS)
|
||||
: newRemoteListSupportPicker(singleFilter, this, REQUEST_MOVE_TASKS))
|
||||
.show(getParentFragmentManager(), FRAG_TAG_REMOTE_LIST_PICKER);
|
||||
return true;
|
||||
case R.id.menu_select_all:
|
||||
taskAdapter.setSelected(
|
||||
transform(taskDao.fetchTasks(preferences, filter), TaskContainer::getId));
|
||||
updateModeTitle();
|
||||
recyclerAdapter.notifyDataSetChanged();
|
||||
return true;
|
||||
case R.id.menu_share:
|
||||
send(
|
||||
collect(
|
||||
taskAdapter.getSelected(),
|
||||
ids -> taskDao.fetchTasks(preferences, new IdListFilter(ids))));
|
||||
return true;
|
||||
case R.id.delete:
|
||||
dialogBuilder
|
||||
.newDialog(R.string.delete_selected_tasks)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok, (dialogInterface, i) -> deleteSelectedItems(selected))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
return true;
|
||||
case R.id.copy_tasks:
|
||||
dialogBuilder
|
||||
.newDialog(R.string.copy_selected_tasks)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok, ((dialogInterface, i) -> copySelectedItems(selected)))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void send(List<TaskContainer> tasks) {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
String output =
|
||||
Joiner.on("\n")
|
||||
.join(
|
||||
transform(
|
||||
tasks, t -> {
|
||||
String checkbox = t.isCompleted() ? "☑" : "☐";
|
||||
checkbox = padStart(checkbox, 1 + t.getIndent() * 3, ' ');
|
||||
return String.format("%s %s", checkbox, t.getTitle());
|
||||
}));
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, filter.listingTitle);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, output);
|
||||
intent.setType("text/plain");
|
||||
|
||||
startActivity(Intent.createChooser(intent, null));
|
||||
|
||||
finishActionMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
this.mode = null;
|
||||
if (taskAdapter.getNumSelected() > 0) {
|
||||
taskAdapter.clearSelections();
|
||||
recyclerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void showDateTimePicker(TaskContainer task) {
|
||||
FragmentManager fragmentManager = getParentFragmentManager();
|
||||
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_TIME_PICKER) == null) {
|
||||
DateTimePicker.Companion.newDateTimePicker(
|
||||
task.getId(),
|
||||
task.getDueDate(),
|
||||
preferences.getBoolean(R.string.p_auto_dismiss_datetime_list_screen, false))
|
||||
.show(fragmentManager, FRAG_TAG_DATE_TIME_PICKER);
|
||||
}
|
||||
}
|
||||
|
||||
public interface TaskListFragmentCallbackHandler {
|
||||
void onTaskListItemClicked(Task task);
|
||||
|
||||
void onNavigationIconClicked();
|
||||
}
|
||||
|
||||
protected class RefreshReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActionModeActive() {
|
||||
return mode != null;
|
||||
}
|
||||
|
||||
public void startActionMode() {
|
||||
if (mode == null) {
|
||||
mode = ((AppCompatActivity) getActivity()).startSupportActionMode(this);
|
||||
updateModeTitle();
|
||||
if (taskAdapter.supportsParentingOrManualSort()) {
|
||||
Flags.set(Flags.TLFP_NO_INTERCEPT_TOUCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void finishActionMode() {
|
||||
if (mode != null) {
|
||||
mode.finish();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateModeTitle() {
|
||||
if (mode != null) {
|
||||
int count = Math.max(1, taskAdapter.getNumSelected());
|
||||
mode.setTitle(Integer.toString(count));
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteSelectedItems(List<Long> tasks) {
|
||||
finishActionMode();
|
||||
List<Task> result = taskDeleter.markDeleted(tasks);
|
||||
for (Task task : result) {
|
||||
onTaskDelete(task);
|
||||
}
|
||||
makeSnackbar(R.string.delete_multiple_tasks_confirmation, Integer.toString(result.size()))
|
||||
.show();
|
||||
}
|
||||
|
||||
private void copySelectedItems(List<Long> tasks) {
|
||||
finishActionMode();
|
||||
List<Task> duplicates = taskDuplicator.duplicate(tasks);
|
||||
onTaskCreated(duplicates);
|
||||
makeSnackbar(R.string.copy_multiple_tasks_confirmation, Integer.toString(duplicates.size()))
|
||||
.show();
|
||||
}
|
||||
}
|
@ -0,0 +1,771 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.activity
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.speech.RecognizerIntent
|
||||
import android.view.*
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.paging.PagedList
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.todoroo.andlib.utility.AndroidUtilities
|
||||
import com.todoroo.astrid.adapter.TaskAdapter
|
||||
import com.todoroo.astrid.adapter.TaskAdapterProvider
|
||||
import com.todoroo.astrid.api.*
|
||||
import com.todoroo.astrid.core.BuiltInFilterExposer
|
||||
import com.todoroo.astrid.dao.TaskDao
|
||||
import com.todoroo.astrid.data.Task
|
||||
import com.todoroo.astrid.service.TaskCreator
|
||||
import com.todoroo.astrid.service.TaskDeleter
|
||||
import com.todoroo.astrid.service.TaskDuplicator
|
||||
import com.todoroo.astrid.service.TaskMover
|
||||
import com.todoroo.astrid.timers.TimerPlugin
|
||||
import com.todoroo.astrid.utility.Flags
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import org.tasks.LocalBroadcastManager
|
||||
import org.tasks.R
|
||||
import org.tasks.ShortcutManager
|
||||
import org.tasks.activities.*
|
||||
import org.tasks.caldav.BaseCaldavCalendarSettingsActivity
|
||||
import org.tasks.caldav.CaldavCalendarSettingsActivity
|
||||
import org.tasks.data.CaldavDao
|
||||
import org.tasks.data.TagDataDao
|
||||
import org.tasks.data.TaskContainer
|
||||
import org.tasks.db.DbUtils
|
||||
import org.tasks.dialogs.DateTimePicker.Companion.newDateTimePicker
|
||||
import org.tasks.dialogs.DialogBuilder
|
||||
import org.tasks.dialogs.SortDialog
|
||||
import org.tasks.etesync.EteSyncCalendarSettingsActivity
|
||||
import org.tasks.filters.PlaceFilter
|
||||
import org.tasks.injection.FragmentComponent
|
||||
import org.tasks.injection.InjectingFragment
|
||||
import org.tasks.intents.TaskIntents
|
||||
import org.tasks.notifications.NotificationManager
|
||||
import org.tasks.preferences.Device
|
||||
import org.tasks.preferences.Preferences
|
||||
import org.tasks.sync.SyncAdapters
|
||||
import org.tasks.tags.TagPickerActivity
|
||||
import org.tasks.tasklist.DragAndDropRecyclerAdapter
|
||||
import org.tasks.tasklist.PagedListRecyclerAdapter
|
||||
import org.tasks.tasklist.TaskListRecyclerAdapter
|
||||
import org.tasks.tasklist.ViewHolderFactory
|
||||
import org.tasks.themes.ColorProvider
|
||||
import org.tasks.themes.ThemeColor
|
||||
import org.tasks.ui.TaskListViewModel
|
||||
import org.tasks.ui.Toaster
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
|
||||
class TaskListFragment : InjectingFragment(), OnRefreshListener, Toolbar.OnMenuItemClickListener, MenuItem.OnActionExpandListener, SearchView.OnQueryTextListener, ActionMode.Callback {
|
||||
private val refreshReceiver = RefreshReceiver()
|
||||
private var disposables: CompositeDisposable? = null
|
||||
|
||||
@Inject lateinit var syncAdapters: SyncAdapters
|
||||
@Inject lateinit var taskDeleter: TaskDeleter
|
||||
@Inject lateinit var preferences: Preferences
|
||||
@Inject lateinit var dialogBuilder: DialogBuilder
|
||||
@Inject lateinit var taskCreator: TaskCreator
|
||||
@Inject lateinit var timerPlugin: TimerPlugin
|
||||
@Inject lateinit var viewHolderFactory: ViewHolderFactory
|
||||
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||
@Inject lateinit var device: Device
|
||||
@Inject lateinit var taskMover: TaskMover
|
||||
@Inject lateinit var toaster: Toaster
|
||||
@Inject lateinit var taskAdapterProvider: TaskAdapterProvider
|
||||
@Inject lateinit var taskDao: TaskDao
|
||||
@Inject lateinit var taskDuplicator: TaskDuplicator
|
||||
@Inject lateinit var tagDataDao: TagDataDao
|
||||
@Inject lateinit var caldavDao: CaldavDao
|
||||
@Inject lateinit var defaultThemeColor: ThemeColor
|
||||
@Inject lateinit var colorProvider: ColorProvider
|
||||
@Inject lateinit var notificationManager: NotificationManager
|
||||
@Inject lateinit var shortcutManager: ShortcutManager
|
||||
|
||||
@BindView(R.id.swipe_layout)
|
||||
lateinit var swipeRefreshLayout: SwipeRefreshLayout
|
||||
|
||||
@BindView(R.id.swipe_layout_empty)
|
||||
lateinit var emptyRefreshLayout: SwipeRefreshLayout
|
||||
|
||||
@BindView(R.id.toolbar)
|
||||
lateinit var toolbar: Toolbar
|
||||
|
||||
@BindView(R.id.task_list_coordinator)
|
||||
lateinit var coordinatorLayout: CoordinatorLayout
|
||||
|
||||
@BindView(R.id.recycler_view)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
|
||||
private lateinit var taskListViewModel: TaskListViewModel
|
||||
private lateinit var taskAdapter: TaskAdapter
|
||||
private var recyclerAdapter: TaskListRecyclerAdapter? = null
|
||||
private lateinit var filter: Filter
|
||||
private val searchSubject = PublishSubject.create<String>()
|
||||
private var searchDisposable: Disposable? = null
|
||||
private lateinit var search: MenuItem
|
||||
private var searchQuery: String? = null
|
||||
private var mode: ActionMode? = null
|
||||
private lateinit var themeColor: ThemeColor
|
||||
private lateinit var callbacks: TaskListFragmentCallbackHandler
|
||||
|
||||
override fun onRefresh() {
|
||||
disposables!!.add(
|
||||
syncAdapters
|
||||
.sync(true)
|
||||
.doOnSuccess { initiated: Boolean ->
|
||||
if (!initiated) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
.delay(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
|
||||
.subscribe { initiated: Boolean ->
|
||||
if (initiated) {
|
||||
setSyncOngoing()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setSyncOngoing() {
|
||||
AndroidUtilities.assertMainThread()
|
||||
val ongoing = preferences.isSyncOngoing
|
||||
swipeRefreshLayout.isRefreshing = ongoing
|
||||
emptyRefreshLayout.isRefreshing = ongoing
|
||||
}
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
if (savedInstanceState != null) {
|
||||
val longArray = savedInstanceState.getLongArray(EXTRA_SELECTED_TASK_IDS)
|
||||
if (longArray?.isNotEmpty() == true) {
|
||||
taskAdapter.setSelected(*longArray)
|
||||
startActionMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach(activity: Activity) {
|
||||
super.onAttach(activity)
|
||||
callbacks = activity as TaskListFragmentCallbackHandler
|
||||
}
|
||||
|
||||
public override fun inject(component: FragmentComponent) = component.inject(this)
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
val selectedTaskIds: List<Long> = taskAdapter.selected
|
||||
outState.putLongArray(EXTRA_SELECTED_TASK_IDS, selectedTaskIds.toLongArray())
|
||||
outState.putString(EXTRA_SEARCH, searchQuery)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val parent = inflater.inflate(R.layout.fragment_task_list, container, false)
|
||||
ButterKnife.bind(this, parent)
|
||||
filter = getFilter()
|
||||
themeColor = if (filter.tint != 0) colorProvider.getThemeColor(filter.tint, true) else defaultThemeColor
|
||||
filter.setFilterQueryOverride(null)
|
||||
|
||||
// set up list adapters
|
||||
taskAdapter = taskAdapterProvider.createTaskAdapter(filter)
|
||||
taskListViewModel = ViewModelProvider(requireActivity()).get(TaskListViewModel::class.java)
|
||||
if (savedInstanceState != null) {
|
||||
searchQuery = savedInstanceState.getString(EXTRA_SEARCH)
|
||||
}
|
||||
taskListViewModel.setFilter((if (searchQuery == null) filter else createSearchFilter(searchQuery!!)))
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
taskListViewModel.observe(
|
||||
this,
|
||||
Observer { list: List<TaskContainer> ->
|
||||
submitList(list)
|
||||
if (list.isEmpty()) {
|
||||
swipeRefreshLayout.visibility = View.GONE
|
||||
emptyRefreshLayout.visibility = View.VISIBLE
|
||||
} else {
|
||||
swipeRefreshLayout.visibility = View.VISIBLE
|
||||
emptyRefreshLayout.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
setupRefresh(swipeRefreshLayout)
|
||||
setupRefresh(emptyRefreshLayout)
|
||||
toolbar.title = filter.listingTitle
|
||||
toolbar.setNavigationIcon(R.drawable.ic_outline_menu_24px)
|
||||
toolbar.setNavigationOnClickListener { callbacks.onNavigationIconClicked() }
|
||||
toolbar.setOnMenuItemClickListener(this)
|
||||
setupMenu()
|
||||
return parent
|
||||
}
|
||||
|
||||
private fun submitList(tasks: List<TaskContainer>) {
|
||||
if (tasks is PagedList<*>) {
|
||||
if (recyclerAdapter !is PagedListRecyclerAdapter) {
|
||||
setAdapter(
|
||||
PagedListRecyclerAdapter(
|
||||
taskAdapter, recyclerView, viewHolderFactory, this, tasks, taskDao))
|
||||
return
|
||||
}
|
||||
} else if (recyclerAdapter !is DragAndDropRecyclerAdapter) {
|
||||
setAdapter(
|
||||
DragAndDropRecyclerAdapter(
|
||||
taskAdapter, recyclerView, viewHolderFactory, this, tasks, taskDao))
|
||||
return
|
||||
}
|
||||
recyclerAdapter!!.submitList(tasks)
|
||||
}
|
||||
|
||||
private fun setAdapter(adapter: TaskListRecyclerAdapter) {
|
||||
recyclerAdapter = adapter
|
||||
recyclerView.adapter = adapter
|
||||
taskAdapter.setHelper(adapter)
|
||||
}
|
||||
|
||||
private fun setupMenu() {
|
||||
val menu = toolbar.menu
|
||||
menu.clear()
|
||||
if (filter.hasBeginningMenu()) {
|
||||
toolbar.inflateMenu(filter.beginningMenu)
|
||||
}
|
||||
toolbar.inflateMenu(R.menu.menu_task_list_fragment)
|
||||
if (filter.hasMenu()) {
|
||||
toolbar.inflateMenu(filter.menu)
|
||||
}
|
||||
val hidden = menu.findItem(R.id.menu_show_hidden)
|
||||
val completed = menu.findItem(R.id.menu_show_completed)
|
||||
if (!taskAdapter.supportsHiddenTasks() || !filter.supportsHiddenTasks()) {
|
||||
completed.isChecked = true
|
||||
completed.isEnabled = false
|
||||
hidden.isChecked = true
|
||||
hidden.isEnabled = false
|
||||
} else {
|
||||
hidden.isChecked = preferences.getBoolean(R.string.p_show_hidden_tasks, false)
|
||||
completed.isChecked = preferences.getBoolean(R.string.p_show_completed_tasks, false)
|
||||
}
|
||||
val sortMenu = menu.findItem(R.id.menu_sort)
|
||||
if (!filter.supportsSorting()) {
|
||||
sortMenu.isEnabled = false
|
||||
sortMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||
}
|
||||
if (preferences.disableSubtasks()
|
||||
|| !filter.supportSubtasks()
|
||||
|| taskAdapter.supportsManualSorting()) {
|
||||
menu.findItem(R.id.menu_collapse_subtasks).isVisible = false
|
||||
menu.findItem(R.id.menu_expand_subtasks).isVisible = false
|
||||
}
|
||||
menu.findItem(R.id.menu_voice_add).isVisible = device.voiceInputAvailable()
|
||||
search = menu.findItem(R.id.menu_search).setOnActionExpandListener(this)
|
||||
(search.actionView as SearchView).setOnQueryTextListener(this)
|
||||
themeColor.apply(toolbar)
|
||||
}
|
||||
|
||||
private fun openFilter(filter: Filter?) {
|
||||
if (filter == null) {
|
||||
startActivity(TaskIntents.getTaskListByIdIntent(context, null))
|
||||
} else {
|
||||
startActivity(TaskIntents.getTaskListIntent(context, filter))
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchByQuery(query: String?) {
|
||||
searchQuery = query?.trim { it <= ' ' } ?: ""
|
||||
if (searchQuery?.isEmpty() == true) {
|
||||
taskListViewModel.searchByFilter(
|
||||
BuiltInFilterExposer.getMyTasksFilter(requireContext().resources))
|
||||
} else {
|
||||
val savedFilter = createSearchFilter(searchQuery!!)
|
||||
taskListViewModel.searchByFilter(savedFilter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSearchFilter(query: String): Filter {
|
||||
return SearchFilter(getString(R.string.FLA_search_filter, query), query)
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.menu_voice_add -> {
|
||||
val recognition = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
|
||||
recognition.putExtra(
|
||||
RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
|
||||
recognition.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1)
|
||||
recognition.putExtra(
|
||||
RecognizerIntent.EXTRA_PROMPT, getString(R.string.voice_create_prompt))
|
||||
startActivityForResult(recognition, VOICE_RECOGNITION_REQUEST_CODE)
|
||||
true
|
||||
}
|
||||
R.id.menu_sort -> {
|
||||
SortDialog.newSortDialog(filter.supportsManualSort())
|
||||
.show(childFragmentManager, FRAG_TAG_SORT_DIALOG)
|
||||
true
|
||||
}
|
||||
R.id.menu_show_hidden -> {
|
||||
item.isChecked = !item.isChecked
|
||||
preferences.setBoolean(R.string.p_show_hidden_tasks, item.isChecked)
|
||||
loadTaskListContent()
|
||||
localBroadcastManager.broadcastRefresh()
|
||||
true
|
||||
}
|
||||
R.id.menu_show_completed -> {
|
||||
item.isChecked = !item.isChecked
|
||||
preferences.setBoolean(R.string.p_show_completed_tasks, item.isChecked)
|
||||
loadTaskListContent()
|
||||
localBroadcastManager.broadcastRefresh()
|
||||
true
|
||||
}
|
||||
R.id.menu_clear_completed -> {
|
||||
dialogBuilder
|
||||
.newDialog(R.string.clear_completed_tasks_confirmation)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> clearCompleted() }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
true
|
||||
}
|
||||
R.id.menu_filter_settings -> {
|
||||
val filterSettings = Intent(activity, FilterSettingsActivity::class.java)
|
||||
filterSettings.putExtra(FilterSettingsActivity.TOKEN_FILTER, filter)
|
||||
startActivityForResult(filterSettings, REQUEST_LIST_SETTINGS)
|
||||
true
|
||||
}
|
||||
R.id.menu_caldav_list_fragment -> {
|
||||
val calendar = (filter as CaldavFilter).calendar
|
||||
val account = caldavDao.getAccountByUuid(calendar.account!!)
|
||||
val caldavSettings = Intent(
|
||||
activity,
|
||||
if (account!!.isCaldavAccount) CaldavCalendarSettingsActivity::class.java else EteSyncCalendarSettingsActivity::class.java)
|
||||
caldavSettings.putExtra(BaseCaldavCalendarSettingsActivity.EXTRA_CALDAV_CALENDAR, calendar)
|
||||
startActivityForResult(caldavSettings, REQUEST_LIST_SETTINGS)
|
||||
true
|
||||
}
|
||||
R.id.menu_location_settings -> {
|
||||
val place = (filter as PlaceFilter).place
|
||||
val intent = Intent(activity, PlaceSettingsActivity::class.java)
|
||||
intent.putExtra(PlaceSettingsActivity.EXTRA_PLACE, place as Parcelable)
|
||||
startActivityForResult(intent, REQUEST_LIST_SETTINGS)
|
||||
true
|
||||
}
|
||||
R.id.menu_gtasks_list_settings -> {
|
||||
val gtasksSettings = Intent(activity, GoogleTaskListSettingsActivity::class.java)
|
||||
gtasksSettings.putExtra(
|
||||
GoogleTaskListSettingsActivity.EXTRA_STORE_DATA, (filter as GtasksFilter).list)
|
||||
startActivityForResult(gtasksSettings, REQUEST_LIST_SETTINGS)
|
||||
true
|
||||
}
|
||||
R.id.menu_tag_settings -> {
|
||||
val tagSettings = Intent(activity, TagSettingsActivity::class.java)
|
||||
tagSettings.putExtra(TagSettingsActivity.EXTRA_TAG_DATA, (filter as TagFilter).tagData)
|
||||
startActivityForResult(tagSettings, REQUEST_LIST_SETTINGS)
|
||||
true
|
||||
}
|
||||
R.id.menu_expand_subtasks -> {
|
||||
taskDao.setCollapsed(taskListViewModel.value, false)
|
||||
localBroadcastManager.broadcastRefresh()
|
||||
true
|
||||
}
|
||||
R.id.menu_collapse_subtasks -> {
|
||||
taskDao.setCollapsed(taskListViewModel.value, true)
|
||||
localBroadcastManager.broadcastRefresh()
|
||||
true
|
||||
}
|
||||
R.id.menu_open_map -> {
|
||||
(filter as PlaceFilter).openMap(context)
|
||||
true
|
||||
}
|
||||
R.id.menu_share -> {
|
||||
send(taskDao.fetchTasks(preferences, filter))
|
||||
true
|
||||
}
|
||||
else -> onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearCompleted() {
|
||||
disposables!!.add(
|
||||
Single.fromCallable { taskDeleter.clearCompleted(filter) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { count: Int -> toaster.longToast(R.string.delete_multiple_tasks_confirmation, count) })
|
||||
}
|
||||
|
||||
@OnClick(R.id.fab)
|
||||
fun createNewTask() {
|
||||
shortcutManager.reportShortcutUsed(ShortcutManager.SHORTCUT_NEW_TASK)
|
||||
onTaskListItemClicked(addTask(""))
|
||||
}
|
||||
|
||||
private fun addTask(title: String): Task {
|
||||
return taskCreator.createWithValues(filter, title)
|
||||
}
|
||||
|
||||
private fun setupRefresh(layout: SwipeRefreshLayout) {
|
||||
layout.setOnRefreshListener(this)
|
||||
layout.setColorSchemeColors(
|
||||
colorProvider.getPriorityColor(0, true),
|
||||
colorProvider.getPriorityColor(1, true),
|
||||
colorProvider.getPriorityColor(2, true),
|
||||
colorProvider.getPriorityColor(3, true))
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposables = CompositeDisposable()
|
||||
localBroadcastManager.registerRefreshReceiver(refreshReceiver)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun makeSnackbar(@StringRes res: Int, vararg args: Any?): Snackbar {
|
||||
return makeSnackbar(getString(res, *args))
|
||||
}
|
||||
|
||||
private fun makeSnackbar(text: String): Snackbar {
|
||||
val snackbar = Snackbar.make(coordinatorLayout, text, 8000)
|
||||
.setTextColor(requireActivity().getColor(R.color.snackbar_text_color))
|
||||
.setActionTextColor(requireActivity().getColor(R.color.snackbar_action_color))
|
||||
snackbar.view.setBackgroundColor(requireActivity().getColor(R.color.snackbar_background))
|
||||
return snackbar
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposables?.dispose()
|
||||
localBroadcastManager.unregisterReceiver(refreshReceiver)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
if (searchDisposable != null && !searchDisposable!!.isDisposed) {
|
||||
searchDisposable!!.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
fun collapseSearchView(): Boolean {
|
||||
return (search.isActionViewExpanded
|
||||
&& (search.collapseActionView() || !search.isActionViewExpanded))
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
loadTaskListContent()
|
||||
setSyncOngoing()
|
||||
}
|
||||
|
||||
fun loadTaskListContent() {
|
||||
taskListViewModel.invalidate()
|
||||
}
|
||||
|
||||
fun getFilter(): Filter {
|
||||
return requireArguments().getParcelable(EXTRA_FILTER)!!
|
||||
}
|
||||
|
||||
private fun onTaskCreated(tasks: List<Task>) {
|
||||
for (task in tasks) {
|
||||
onTaskCreated(task.uuid)
|
||||
}
|
||||
syncAdapters.sync()
|
||||
loadTaskListContent()
|
||||
}
|
||||
|
||||
fun onTaskCreated(uuid: String?) {
|
||||
taskAdapter.onTaskCreated(uuid)
|
||||
}
|
||||
|
||||
private fun onTaskDelete(task: Task) {
|
||||
val activity = activity as MainActivity?
|
||||
if (activity != null) {
|
||||
val tef = activity.taskEditFragment
|
||||
if (tef != null && task.id == tef.model.id) {
|
||||
tef.discard()
|
||||
}
|
||||
}
|
||||
timerPlugin.stopTimer(task)
|
||||
taskAdapter.onTaskDeleted(task)
|
||||
loadTaskListContent()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
when (requestCode) {
|
||||
VOICE_RECOGNITION_REQUEST_CODE -> if (resultCode == Activity.RESULT_OK) {
|
||||
val match: List<String>? = data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
|
||||
if (match != null && match.isNotEmpty() && match[0].isNotEmpty()) {
|
||||
var recognizedSpeech = match[0]
|
||||
recognizedSpeech = (recognizedSpeech.substring(0, 1).toUpperCase()
|
||||
+ recognizedSpeech.substring(1).toLowerCase())
|
||||
onTaskListItemClicked(addTask(recognizedSpeech))
|
||||
}
|
||||
}
|
||||
REQUEST_MOVE_TASKS -> if (resultCode == Activity.RESULT_OK) {
|
||||
taskMover.move(
|
||||
taskAdapter.selected,
|
||||
data!!.getParcelableExtra(RemoteListPicker.EXTRA_SELECTED_FILTER))
|
||||
finishActionMode()
|
||||
}
|
||||
REQUEST_LIST_SETTINGS -> if (resultCode == Activity.RESULT_OK) {
|
||||
val action = data!!.action
|
||||
if (ACTION_DELETED == action) {
|
||||
openFilter(null)
|
||||
} else if (ACTION_RELOAD == action) {
|
||||
openFilter(data.getParcelableExtra(MainActivity.OPEN_FILTER))
|
||||
}
|
||||
}
|
||||
REQUEST_TAG_TASKS -> if (resultCode == Activity.RESULT_OK) {
|
||||
val modified = tagDataDao.applyTags(
|
||||
taskDao.fetch(
|
||||
data!!.getSerializableExtra(TagPickerActivity.EXTRA_TASKS) as ArrayList<Long>),
|
||||
data.getParcelableArrayListExtra(TagPickerActivity.EXTRA_PARTIALLY_SELECTED)!!,
|
||||
data.getParcelableArrayListExtra(TagPickerActivity.EXTRA_SELECTED)!!)
|
||||
taskDao.touch(modified)
|
||||
finishActionMode()
|
||||
}
|
||||
else -> super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onContextItemSelected(item: MenuItem): Boolean {
|
||||
return onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
fun onTaskListItemClicked(task: Task?) {
|
||||
callbacks.onTaskListItemClicked(task)
|
||||
}
|
||||
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
searchDisposable = searchSubject
|
||||
.debounce(SEARCH_DEBOUNCE_TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { query: String? -> searchByQuery(query) }
|
||||
if (searchQuery == null) {
|
||||
searchByQuery("")
|
||||
}
|
||||
val menu = toolbar.menu
|
||||
for (i in 0 until menu.size()) {
|
||||
menu.getItem(i).isVisible = false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||
taskListViewModel.searchByFilter(filter)
|
||||
searchDisposable?.dispose()
|
||||
searchQuery = null
|
||||
setupMenu()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
openFilter(createSearchFilter(query.trim { it <= ' ' }))
|
||||
search.collapseActionView()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(query: String): Boolean {
|
||||
searchSubject.onNext(query)
|
||||
return true
|
||||
}
|
||||
|
||||
fun broadcastRefresh() {
|
||||
localBroadcastManager.broadcastRefresh()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(actionMode: ActionMode, menu: Menu): Boolean {
|
||||
val inflater = actionMode.menuInflater
|
||||
inflater.inflate(R.menu.menu_multi_select, menu)
|
||||
themeColor.colorMenu(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
val selected = taskAdapter.selected
|
||||
return when (item.itemId) {
|
||||
R.id.edit_tags -> {
|
||||
val tags = tagDataDao.getTagSelections(selected)
|
||||
val intent = Intent(context, TagPickerActivity::class.java)
|
||||
intent.putExtra(TagPickerActivity.EXTRA_TASKS, selected)
|
||||
intent.putParcelableArrayListExtra(
|
||||
TagPickerActivity.EXTRA_PARTIALLY_SELECTED,
|
||||
ArrayList(tagDataDao.getByUuid(tags.first!!)))
|
||||
intent.putParcelableArrayListExtra(
|
||||
TagPickerActivity.EXTRA_SELECTED, ArrayList(tagDataDao.getByUuid(tags.second!!)))
|
||||
startActivityForResult(intent, REQUEST_TAG_TASKS)
|
||||
true
|
||||
}
|
||||
R.id.move_tasks -> {
|
||||
val singleFilter = taskMover.getSingleFilter(selected)
|
||||
(if (singleFilter == null) RemoteListPicker.newRemoteListSupportPicker(this, REQUEST_MOVE_TASKS) else RemoteListPicker.newRemoteListSupportPicker(singleFilter, this, REQUEST_MOVE_TASKS))
|
||||
.show(parentFragmentManager, FRAG_TAG_REMOTE_LIST_PICKER)
|
||||
true
|
||||
}
|
||||
R.id.menu_select_all -> {
|
||||
taskAdapter.setSelected(taskDao.fetchTasks(preferences, filter).map(TaskContainer::getId))
|
||||
updateModeTitle()
|
||||
recyclerAdapter!!.notifyDataSetChanged()
|
||||
true
|
||||
}
|
||||
R.id.menu_share -> {
|
||||
send(
|
||||
DbUtils.collect(
|
||||
taskAdapter.selected
|
||||
) { ids: List<Long?>? -> taskDao.fetchTasks(preferences, IdListFilter(ids)) })
|
||||
true
|
||||
}
|
||||
R.id.delete -> {
|
||||
dialogBuilder
|
||||
.newDialog(R.string.delete_selected_tasks)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok) { _, _ -> deleteSelectedItems(selected) }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
true
|
||||
}
|
||||
R.id.copy_tasks -> {
|
||||
dialogBuilder
|
||||
.newDialog(R.string.copy_selected_tasks)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok) { _, _ -> copySelectedItems(selected) }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun send(tasks: List<TaskContainer>) {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
val output = tasks.joinToString("\n") { t -> Task
|
||||
"${(if (t.isCompleted) "☑" else "☐").padStart(1 + t.getIndent() * 3, ' ')} ${t.title}"
|
||||
}
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, filter.listingTitle)
|
||||
intent.putExtra(Intent.EXTRA_TEXT, output)
|
||||
intent.type = "text/plain"
|
||||
startActivity(Intent.createChooser(intent, null))
|
||||
finishActionMode()
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode) {
|
||||
this.mode = null
|
||||
if (taskAdapter.numSelected > 0) {
|
||||
taskAdapter.clearSelections()
|
||||
recyclerAdapter!!.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
fun showDateTimePicker(task: TaskContainer) {
|
||||
val fragmentManager = parentFragmentManager
|
||||
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_TIME_PICKER) == null) {
|
||||
newDateTimePicker(
|
||||
task.id,
|
||||
task.dueDate,
|
||||
preferences.getBoolean(R.string.p_auto_dismiss_datetime_list_screen, false))
|
||||
.show(fragmentManager, FRAG_TAG_DATE_TIME_PICKER)
|
||||
}
|
||||
}
|
||||
|
||||
interface TaskListFragmentCallbackHandler {
|
||||
fun onTaskListItemClicked(task: Task?)
|
||||
fun onNavigationIconClicked()
|
||||
}
|
||||
|
||||
private inner class RefreshReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
val isActionModeActive: Boolean
|
||||
get() = mode != null
|
||||
|
||||
fun startActionMode() {
|
||||
if (mode == null) {
|
||||
mode = (activity as AppCompatActivity).startSupportActionMode(this)
|
||||
updateModeTitle()
|
||||
if (taskAdapter.supportsParentingOrManualSort()) {
|
||||
Flags.set(Flags.TLFP_NO_INTERCEPT_TOUCH)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun finishActionMode() {
|
||||
mode?.finish()
|
||||
}
|
||||
|
||||
fun updateModeTitle() {
|
||||
if (mode != null) {
|
||||
val count = max(1, taskAdapter.numSelected)
|
||||
mode!!.title = count.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteSelectedItems(tasks: List<Long>) {
|
||||
finishActionMode()
|
||||
|
||||
val result = taskDeleter.markDeleted(tasks)
|
||||
result.forEach(this::onTaskDelete)
|
||||
makeSnackbar(R.string.delete_multiple_tasks_confirmation, result.size.toString()).show()
|
||||
}
|
||||
|
||||
private fun copySelectedItems(tasks: List<Long>) {
|
||||
finishActionMode()
|
||||
val duplicates = taskDuplicator.duplicate(tasks)
|
||||
onTaskCreated(duplicates)
|
||||
makeSnackbar(R.string.copy_multiple_tasks_confirmation, duplicates.size.toString()).show()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAGS_METADATA_JOIN = "for_tags" // $NON-NLS-1$
|
||||
const val GTASK_METADATA_JOIN = "googletask" // $NON-NLS-1$
|
||||
const val CALDAV_METADATA_JOIN = "for_caldav" // $NON-NLS-1$
|
||||
const val ACTION_RELOAD = "action_reload"
|
||||
const val ACTION_DELETED = "action_deleted"
|
||||
private const val EXTRA_SELECTED_TASK_IDS = "extra_selected_task_ids"
|
||||
private const val EXTRA_SEARCH = "extra_search"
|
||||
private const val VOICE_RECOGNITION_REQUEST_CODE = 1234
|
||||
private const val EXTRA_FILTER = "extra_filter"
|
||||
private const val FRAG_TAG_REMOTE_LIST_PICKER = "frag_tag_remote_list_picker"
|
||||
private const val FRAG_TAG_SORT_DIALOG = "frag_tag_sort_dialog"
|
||||
private const val FRAG_TAG_DATE_TIME_PICKER = "frag_tag_date_time_picker"
|
||||
private const val REQUEST_LIST_SETTINGS = 10101
|
||||
private const val REQUEST_MOVE_TASKS = 10103
|
||||
private const val REQUEST_TAG_TASKS = 10106
|
||||
private const val SEARCH_DEBOUNCE_TIMEOUT = 300
|
||||
fun newTaskListFragment(context: Context, filter: Filter?): TaskListFragment {
|
||||
val fragment = TaskListFragment()
|
||||
val bundle = Bundle()
|
||||
bundle.putParcelable(
|
||||
EXTRA_FILTER,
|
||||
filter ?: BuiltInFilterExposer.getMyTasksFilter(context.resources))
|
||||
fragment.arguments = bundle
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue