mirror of https://github.com/tasks/tasks
Convert injected view models to Kotlin
parent
641b60be9b
commit
c3896a4ab1
@ -1,106 +0,0 @@
|
||||
package org.tasks.tags;
|
||||
|
||||
import static com.google.common.collect.Iterables.any;
|
||||
import static org.tasks.Strings.isNullOrEmpty;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.data.TagData;
|
||||
import org.tasks.data.TagDataDao;
|
||||
import org.tasks.tags.CheckBoxTriStates.State;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "RedundantSuppression"})
|
||||
public class TagPickerViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<List<TagData>> tags = new MutableLiveData<>();
|
||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||
|
||||
@Inject TagDataDao tagDataDao;
|
||||
|
||||
private final Set<TagData> selected = new HashSet<>();
|
||||
private final Set<TagData> partiallySelected = new HashSet<>();
|
||||
private String text;
|
||||
|
||||
public void observe(LifecycleOwner owner, Observer<List<TagData>> observer) {
|
||||
tags.observe(owner, observer);
|
||||
}
|
||||
|
||||
public void setSelected(List<TagData> selected, @Nullable List<TagData> partiallySelected) {
|
||||
this.selected.addAll(selected);
|
||||
if (partiallySelected != null) {
|
||||
this.partiallySelected.addAll(partiallySelected);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<TagData> getSelected() {
|
||||
return new ArrayList<>(selected);
|
||||
}
|
||||
|
||||
ArrayList<TagData> getPartiallySelected() {
|
||||
return new ArrayList<>(partiallySelected);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void search(String text) {
|
||||
if (!text.equalsIgnoreCase(this.text)) {
|
||||
disposables.add(
|
||||
Single.fromCallable(() -> tagDataDao.searchTags(text))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onUpdate));
|
||||
}
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
private void onUpdate(List<TagData> results) {
|
||||
if (!isNullOrEmpty(text) && !any(results, t -> text.equalsIgnoreCase(t.getName()))) {
|
||||
results.add(0, new TagData(text));
|
||||
}
|
||||
tags.setValue(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
disposables.dispose();
|
||||
}
|
||||
|
||||
State getState(TagData tagData) {
|
||||
if (partiallySelected.contains(tagData)) {
|
||||
return State.PARTIALLY_CHECKED;
|
||||
}
|
||||
return selected.contains(tagData) ? State.CHECKED : State.UNCHECKED;
|
||||
}
|
||||
|
||||
State toggle(TagData tagData, boolean checked) {
|
||||
if (tagData.getId() == null) {
|
||||
tagData = new TagData(tagData.getName());
|
||||
tagDataDao.createNew(tagData);
|
||||
}
|
||||
|
||||
partiallySelected.remove(tagData);
|
||||
|
||||
if (checked) {
|
||||
selected.add(tagData);
|
||||
return State.CHECKED;
|
||||
} else {
|
||||
selected.remove(tagData);
|
||||
return State.UNCHECKED;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package org.tasks.tags
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModel
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.tasks.Strings.isNullOrEmpty
|
||||
import org.tasks.data.TagData
|
||||
import org.tasks.data.TagDataDao
|
||||
import org.tasks.tags.CheckBoxTriStates.State
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class TagPickerViewModel : ViewModel() {
|
||||
private val tags = MutableLiveData<List<TagData>>()
|
||||
private val disposables = CompositeDisposable()
|
||||
|
||||
@Inject lateinit var tagDataDao: TagDataDao
|
||||
|
||||
private val selected: MutableSet<TagData> = HashSet()
|
||||
private val partiallySelected: MutableSet<TagData> = HashSet()
|
||||
var text: String? = null
|
||||
private set
|
||||
|
||||
fun observe(owner: LifecycleOwner, observer: Observer<List<TagData>>) =
|
||||
tags.observe(owner, observer)
|
||||
|
||||
fun setSelected(selected: List<TagData>, partiallySelected: List<TagData>?) {
|
||||
this.selected.addAll(selected)
|
||||
if (partiallySelected != null) {
|
||||
this.partiallySelected.addAll(partiallySelected)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSelected() = ArrayList(selected)
|
||||
|
||||
fun getPartiallySelected() = ArrayList(partiallySelected)
|
||||
|
||||
fun search(text: String) {
|
||||
if (!text.equals(this.text, ignoreCase = true)) {
|
||||
disposables.add(
|
||||
Single.fromCallable { tagDataDao.searchTags(text) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { results: List<TagData> -> onUpdate(results.toMutableList()) })
|
||||
}
|
||||
this.text = text
|
||||
}
|
||||
|
||||
private fun onUpdate(results: MutableList<TagData>) {
|
||||
if (!isNullOrEmpty(text) && !results.any { text.equals(it.name, ignoreCase = true) }) {
|
||||
results.add(0, TagData(text))
|
||||
}
|
||||
tags.value = results
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
disposables.dispose()
|
||||
}
|
||||
|
||||
fun getState(tagData: TagData): State {
|
||||
if (partiallySelected.contains(tagData)) {
|
||||
return State.PARTIALLY_CHECKED
|
||||
}
|
||||
return if (selected.contains(tagData)) State.CHECKED else State.UNCHECKED
|
||||
}
|
||||
|
||||
fun toggle(tagData: TagData, checked: Boolean): State {
|
||||
var tagData = tagData
|
||||
if (tagData.id == null) {
|
||||
tagData = TagData(tagData.name)
|
||||
tagDataDao.createNew(tagData)
|
||||
}
|
||||
partiallySelected.remove(tagData)
|
||||
return if (checked) {
|
||||
selected.add(tagData)
|
||||
State.CHECKED
|
||||
} else {
|
||||
selected.remove(tagData)
|
||||
State.UNCHECKED
|
||||
}
|
||||
}
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
package org.tasks.ui;
|
||||
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.assertMainThread;
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.assertNotMainThread;
|
||||
import static com.todoroo.andlib.utility.DateUtilities.now;
|
||||
import static io.reactivex.Single.fromCallable;
|
||||
import static org.tasks.data.TaskListQuery.getQuery;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.paging.DataSource.Factory;
|
||||
import androidx.paging.LivePagedListBuilder;
|
||||
import androidx.paging.PagedList;
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.BuildConfig;
|
||||
import org.tasks.data.SubtaskInfo;
|
||||
import org.tasks.data.TaskContainer;
|
||||
import org.tasks.preferences.Preferences;
|
||||
import timber.log.Timber;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "RedundantSuppression"})
|
||||
public class TaskListViewModel extends ViewModel implements Observer<PagedList<TaskContainer>> {
|
||||
|
||||
private static final PagedList.Config PAGED_LIST_CONFIG =
|
||||
new PagedList.Config.Builder().setPageSize(20).build();
|
||||
|
||||
@Inject Preferences preferences;
|
||||
@Inject TaskDao taskDao;
|
||||
private MutableLiveData<List<TaskContainer>> tasks = new MutableLiveData<>();
|
||||
private Filter filter;
|
||||
private boolean manualSortFilter;
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
private LiveData<PagedList<TaskContainer>> internal;
|
||||
|
||||
public void setFilter(@NonNull Filter filter) {
|
||||
if (!filter.equals(this.filter)
|
||||
|| !filter.getSqlQuery().equals(this.filter.getSqlQuery())) {
|
||||
this.filter = filter;
|
||||
tasks = new MutableLiveData<>();
|
||||
invalidate();
|
||||
}
|
||||
manualSortFilter =
|
||||
(filter.supportsManualSort() && preferences.isManualSort())
|
||||
|| (filter.supportsAstridSorting() && preferences.isAstridSort());
|
||||
}
|
||||
|
||||
public void observe(LifecycleOwner owner, Observer<List<TaskContainer>> observer) {
|
||||
tasks.observe(owner, observer);
|
||||
}
|
||||
|
||||
public void searchByFilter(Filter filter) {
|
||||
this.filter = filter;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void removeObserver() {
|
||||
if (internal != null) {
|
||||
internal.removeObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
assertMainThread();
|
||||
|
||||
removeObserver();
|
||||
|
||||
if (filter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
disposable.add(
|
||||
Single.fromCallable(taskDao::getSubtaskInfo)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
subtasks -> {
|
||||
if (manualSortFilter || !preferences.usePagedQueries()) {
|
||||
performNonPagedQuery(subtasks);
|
||||
} else {
|
||||
performPagedListQuery();
|
||||
}
|
||||
},
|
||||
Timber::e));
|
||||
}
|
||||
|
||||
private void performNonPagedQuery(SubtaskInfo subtasks) {
|
||||
disposable.add(
|
||||
fromCallable(() -> taskDao.fetchTasks(s -> getQuery(preferences, filter, s), subtasks))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(tasks::postValue, Timber::e));
|
||||
}
|
||||
|
||||
private void performPagedListQuery() {
|
||||
List<String> queries = getQuery(preferences, filter, new SubtaskInfo());
|
||||
if (BuildConfig.DEBUG && queries.size() != 1) {
|
||||
throw new RuntimeException("Invalid queries");
|
||||
}
|
||||
SimpleSQLiteQuery query = new SimpleSQLiteQuery(queries.get(0));
|
||||
Timber.d("paged query: %s", query.getSql());
|
||||
Factory<Integer, TaskContainer> factory = taskDao.getTaskFactory(query);
|
||||
LivePagedListBuilder<Integer, TaskContainer> builder =
|
||||
new LivePagedListBuilder<>(factory, PAGED_LIST_CONFIG);
|
||||
List<TaskContainer> current = tasks.getValue();
|
||||
if (current instanceof PagedList) {
|
||||
Object lastKey = ((PagedList<TaskContainer>) current).getLastKey();
|
||||
if (lastKey instanceof Integer) {
|
||||
builder.setInitialLoadKey((Integer) lastKey);
|
||||
}
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
builder.setFetchExecutor(
|
||||
command ->
|
||||
Completable.fromAction(
|
||||
() -> {
|
||||
assertNotMainThread();
|
||||
long start = now();
|
||||
command.run();
|
||||
Timber.d("*** paged list execution took %sms", now() - start);
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe());
|
||||
}
|
||||
internal = builder.build();
|
||||
internal.observeForever(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
disposable.dispose();
|
||||
removeObserver();
|
||||
}
|
||||
|
||||
public List<TaskContainer> getValue() {
|
||||
List<TaskContainer> value = tasks.getValue();
|
||||
return value != null ? value : Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(PagedList<TaskContainer> taskContainers) {
|
||||
tasks.setValue(taskContainers);
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package org.tasks.ui
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import androidx.paging.LivePagedListBuilder
|
||||
import androidx.paging.PagedList
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import com.todoroo.andlib.utility.AndroidUtilities
|
||||
import com.todoroo.andlib.utility.DateUtilities
|
||||
import com.todoroo.astrid.api.Filter
|
||||
import com.todoroo.astrid.dao.TaskDao
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.tasks.BuildConfig
|
||||
import org.tasks.data.SubtaskInfo
|
||||
import org.tasks.data.TaskContainer
|
||||
import org.tasks.data.TaskListQuery.getQuery
|
||||
import org.tasks.preferences.Preferences
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class TaskListViewModel : ViewModel(), Observer<PagedList<TaskContainer>> {
|
||||
@Inject lateinit var preferences: Preferences
|
||||
@Inject lateinit var taskDao: TaskDao
|
||||
|
||||
private var tasks = MutableLiveData<List<TaskContainer>>()
|
||||
private var filter: Filter? = null
|
||||
private var manualSortFilter = false
|
||||
private val disposable = CompositeDisposable()
|
||||
private var internal: LiveData<PagedList<TaskContainer>>? = null
|
||||
|
||||
fun setFilter(filter: Filter) {
|
||||
if (filter != this.filter
|
||||
|| filter.getSqlQuery() != this.filter!!.getSqlQuery()) {
|
||||
this.filter = filter
|
||||
tasks = MutableLiveData()
|
||||
invalidate()
|
||||
}
|
||||
manualSortFilter = (filter.supportsManualSort() && preferences.isManualSort
|
||||
|| filter.supportsAstridSorting() && preferences.isAstridSort)
|
||||
}
|
||||
|
||||
fun observe(owner: LifecycleOwner, observer: Observer<List<TaskContainer>>) =
|
||||
tasks.observe(owner, observer)
|
||||
|
||||
fun searchByFilter(filter: Filter?) {
|
||||
this.filter = filter
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private fun removeObserver() = internal?.removeObserver(this)
|
||||
|
||||
fun invalidate() {
|
||||
AndroidUtilities.assertMainThread()
|
||||
removeObserver()
|
||||
if (filter == null) {
|
||||
return
|
||||
}
|
||||
disposable.add(
|
||||
Single.fromCallable { taskDao.getSubtaskInfo() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ subtasks: SubtaskInfo ->
|
||||
if (manualSortFilter || !preferences.usePagedQueries()) {
|
||||
performNonPagedQuery(subtasks)
|
||||
} else {
|
||||
performPagedListQuery()
|
||||
}
|
||||
}) { t: Throwable? -> Timber.e(t) })
|
||||
}
|
||||
|
||||
private fun performNonPagedQuery(subtasks: SubtaskInfo) =
|
||||
disposable.add(
|
||||
Single.fromCallable { taskDao.fetchTasks({ s: SubtaskInfo? -> getQuery(preferences, filter!!, s!!) }, subtasks) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ value: List<TaskContainer> -> tasks.postValue(value) }) { t: Throwable? -> Timber.e(t) })
|
||||
|
||||
private fun performPagedListQuery() {
|
||||
val queries = getQuery(preferences, filter!!, SubtaskInfo())
|
||||
if (BuildConfig.DEBUG && queries.size != 1) {
|
||||
throw RuntimeException("Invalid queries")
|
||||
}
|
||||
val query = SimpleSQLiteQuery(queries[0])
|
||||
Timber.d("paged query: %s", query.sql)
|
||||
val factory = taskDao.getTaskFactory(query)
|
||||
val builder = LivePagedListBuilder(factory, PAGED_LIST_CONFIG)
|
||||
val current = tasks.value!!
|
||||
if (current is PagedList<*>) {
|
||||
val lastKey = (current as PagedList<TaskContainer>).lastKey
|
||||
if (lastKey is Int) {
|
||||
builder.setInitialLoadKey(lastKey as Int?)
|
||||
}
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
builder.setFetchExecutor { command: Runnable ->
|
||||
Completable.fromAction {
|
||||
AndroidUtilities.assertNotMainThread()
|
||||
val start = DateUtilities.now()
|
||||
command.run()
|
||||
Timber.d("*** paged list execution took %sms", DateUtilities.now() - start)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
internal = builder.build()
|
||||
internal!!.observeForever(this)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
disposable.dispose()
|
||||
removeObserver()
|
||||
}
|
||||
|
||||
val value: List<TaskContainer>
|
||||
get() = tasks.value ?: emptyList()
|
||||
|
||||
override fun onChanged(taskContainers: PagedList<TaskContainer>) {
|
||||
tasks.value = taskContainers
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val PAGED_LIST_CONFIG = PagedList.Config.Builder().setPageSize(20).build()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue