session-android/src/org/thoughtcrime/securesms/search/SearchViewModel.java
Greyson Parrelli 9f04c28bfd Implemented conversation search.
You can now search for messages within a specific conversation.
2019-02-14 20:19:01 -08:00

125 lines
3.4 KiB
Java

package org.thoughtcrime.securesms.search;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProvider;
import android.database.ContentObserver;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import org.thoughtcrime.securesms.search.model.SearchResult;
import org.thoughtcrime.securesms.util.Debouncer;
import org.thoughtcrime.securesms.util.Util;
/**
* A {@link ViewModel} for handling all the business logic and interactions that take place inside
* of the {@link SearchFragment}.
*
* This class should be view- and Android-agnostic, and therefore should contain no references to
* things like {@link android.content.Context}, {@link android.view.View},
* {@link android.support.v4.app.Fragment}, etc.
*/
class SearchViewModel extends ViewModel {
private final ObservingLiveData searchResult;
private final SearchRepository searchRepository;
private final Debouncer debouncer;
private String lastQuery;
private SearchViewModel(@NonNull SearchRepository searchRepository) {
this.searchResult = new ObservingLiveData();
this.searchRepository = searchRepository;
this.debouncer = new Debouncer(500);
searchResult.registerContentObserver(new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
if (!TextUtils.isEmpty(getLastQuery())) {
searchRepository.query(getLastQuery(), searchResult::postValue);
}
}
});
}
LiveData<SearchResult> getSearchResult() {
return searchResult;
}
void updateQuery(String query) {
lastQuery = query;
debouncer.publish(() -> searchRepository.query(query, result -> {
Util.runOnMain(() -> {
if (query.equals(lastQuery)) {
searchResult.setValue(result);
} else {
result.close();
}
});
}));
}
@NonNull
String getLastQuery() {
return lastQuery == null ? "" : lastQuery;
}
@Override
protected void onCleared() {
debouncer.clear();
searchResult.close();
}
/**
* Ensures that the previous {@link SearchResult} is always closed whenever we set a new one.
*/
private static class ObservingLiveData extends MutableLiveData<SearchResult> {
private ContentObserver observer;
@Override
public void setValue(SearchResult value) {
SearchResult previous = getValue();
if (previous != null) {
previous.unregisterContentObserver(observer);
previous.close();
}
value.registerContentObserver(observer);
super.setValue(value);
}
void close() {
SearchResult value = getValue();
if (value != null) {
value.unregisterContentObserver(observer);
value.close();
}
}
void registerContentObserver(@NonNull ContentObserver observer) {
this.observer = observer;
}
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {
private final SearchRepository searchRepository;
public Factory(@NonNull SearchRepository searchRepository) {
this.searchRepository = searchRepository;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return modelClass.cast(new SearchViewModel(searchRepository));
}
}
}