mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 06:37:30 +00:00
convert search-related backend stuff to kotlin
This commit is contained in:
parent
2dc29031cb
commit
1229992a46
@ -1,14 +1,15 @@
|
|||||||
package awais.instagrabber.repositories;
|
package awais.instagrabber.repositories
|
||||||
|
|
||||||
import java.util.Map;
|
import awais.instagrabber.repositories.responses.search.SearchResponse
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.QueryMap
|
||||||
|
import retrofit2.http.Url
|
||||||
|
|
||||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
interface SearchService {
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.http.GET;
|
|
||||||
import retrofit2.http.QueryMap;
|
|
||||||
import retrofit2.http.Url;
|
|
||||||
|
|
||||||
public interface SearchRepository {
|
|
||||||
@GET
|
@GET
|
||||||
Call<SearchResponse> search(@Url String url, @QueryMap(encoded = true) Map<String, String> queryParams);
|
suspend fun search(
|
||||||
|
@Url url: String?,
|
||||||
|
@QueryMap(encoded = true) queryParams: Map<String?, String?>?
|
||||||
|
): SearchResponse
|
||||||
}
|
}
|
@ -1,365 +1,284 @@
|
|||||||
package awais.instagrabber.viewmodels;
|
package awais.instagrabber.viewmodels
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application
|
||||||
import android.util.Log;
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.Transformations
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import awais.instagrabber.db.datasources.RecentSearchDataSource
|
||||||
|
import awais.instagrabber.db.entities.Favorite
|
||||||
|
import awais.instagrabber.db.entities.RecentSearch
|
||||||
|
import awais.instagrabber.db.entities.RecentSearch.Companion.fromSearchItem
|
||||||
|
import awais.instagrabber.db.repositories.FavoriteRepository
|
||||||
|
import awais.instagrabber.db.repositories.RecentSearchRepository
|
||||||
|
import awais.instagrabber.models.Resource
|
||||||
|
import awais.instagrabber.models.Resource.Companion.error
|
||||||
|
import awais.instagrabber.models.Resource.Companion.loading
|
||||||
|
import awais.instagrabber.models.Resource.Companion.success
|
||||||
|
import awais.instagrabber.models.enums.FavoriteType
|
||||||
|
import awais.instagrabber.repositories.responses.search.SearchItem
|
||||||
|
import awais.instagrabber.repositories.responses.search.SearchResponse
|
||||||
|
import awais.instagrabber.utils.*
|
||||||
|
import awais.instagrabber.utils.AppExecutors.mainThread
|
||||||
|
import awais.instagrabber.utils.TextUtils.isEmpty
|
||||||
|
import awais.instagrabber.webservices.SearchRepository
|
||||||
|
import com.google.common.collect.ImmutableList
|
||||||
|
import com.google.common.util.concurrent.FutureCallback
|
||||||
|
import com.google.common.util.concurrent.Futures
|
||||||
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
import java.util.*
|
||||||
|
import java.util.function.BiConsumer
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
class SearchFragmentViewModel(application: Application) : AppStateViewModel(application) {
|
||||||
import androidx.annotation.Nullable;
|
private val query = MutableLiveData<String>()
|
||||||
import androidx.lifecycle.LiveData;
|
private val topResults = MutableLiveData<Resource<List<SearchItem>?>>()
|
||||||
import androidx.lifecycle.MutableLiveData;
|
private val userResults = MutableLiveData<Resource<List<SearchItem>?>>()
|
||||||
|
private val hashtagResults = MutableLiveData<Resource<List<SearchItem>?>>()
|
||||||
|
private val locationResults = MutableLiveData<Resource<List<SearchItem>?>>()
|
||||||
|
private val searchRepository: SearchRepository by lazy { SearchRepository.getInstance() }
|
||||||
|
private val searchCallback: Debouncer.Callback<String> = object : Debouncer.Callback<String> {
|
||||||
|
override fun call(key: String) {
|
||||||
|
if (tempQuery == null) return
|
||||||
|
query.postValue(tempQuery)
|
||||||
|
}
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
override fun onError(t: Throwable) {
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
Log.e(TAG, "onError: ", t)
|
||||||
import com.google.common.util.concurrent.Futures;
|
}
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
}
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
private val searchDebouncer = Debouncer(searchCallback, 500)
|
||||||
|
private val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
|
||||||
import java.util.Collections;
|
private val isLoggedIn = !isEmpty(cookie) && getUserIdFromCookie(cookie) != 0L
|
||||||
import java.util.List;
|
private val distinctQuery = Transformations.distinctUntilChanged(query)
|
||||||
import java.util.Objects;
|
private val recentSearchRepository: RecentSearchRepository by lazy {
|
||||||
import java.util.stream.Collectors;
|
RecentSearchRepository.getInstance(RecentSearchDataSource.getInstance(application))
|
||||||
|
}
|
||||||
import awais.instagrabber.db.datasources.RecentSearchDataSource;
|
private val favoriteRepository: FavoriteRepository by lazy { FavoriteRepository.getInstance(application) }
|
||||||
import awais.instagrabber.db.entities.Favorite;
|
private var tempQuery: String? = null
|
||||||
import awais.instagrabber.db.entities.RecentSearch;
|
fun getQuery(): LiveData<String> {
|
||||||
import awais.instagrabber.db.repositories.FavoriteRepository;
|
return distinctQuery
|
||||||
import awais.instagrabber.db.repositories.RecentSearchRepository;
|
|
||||||
import awais.instagrabber.models.Resource;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
|
||||||
import awais.instagrabber.repositories.responses.search.SearchItem;
|
|
||||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
|
||||||
import awais.instagrabber.utils.AppExecutors;
|
|
||||||
import awais.instagrabber.utils.Constants;
|
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
|
||||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
|
||||||
import awais.instagrabber.utils.Debouncer;
|
|
||||||
import awais.instagrabber.utils.TextUtils;
|
|
||||||
import awais.instagrabber.webservices.SearchService;
|
|
||||||
import kotlinx.coroutines.Dispatchers;
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
import static androidx.lifecycle.Transformations.distinctUntilChanged;
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
|
||||||
|
|
||||||
public class SearchFragmentViewModel extends AppStateViewModel {
|
|
||||||
private static final String TAG = SearchFragmentViewModel.class.getSimpleName();
|
|
||||||
private static final String QUERY = "query";
|
|
||||||
|
|
||||||
private final MutableLiveData<String> query = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<Resource<List<SearchItem>>> topResults = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<Resource<List<SearchItem>>> userResults = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<Resource<List<SearchItem>>> hashtagResults = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<Resource<List<SearchItem>>> locationResults = new MutableLiveData<>();
|
|
||||||
|
|
||||||
private final SearchService searchService;
|
|
||||||
private final Debouncer<String> searchDebouncer;
|
|
||||||
private final boolean isLoggedIn;
|
|
||||||
private final LiveData<String> distinctQuery;
|
|
||||||
private final RecentSearchRepository recentSearchRepository;
|
|
||||||
private final FavoriteRepository favoriteRepository;
|
|
||||||
|
|
||||||
private String tempQuery;
|
|
||||||
|
|
||||||
public SearchFragmentViewModel(@NonNull final Application application) {
|
|
||||||
super(application);
|
|
||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
|
||||||
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) != 0;
|
|
||||||
final Debouncer.Callback<String> searchCallback = new Debouncer.Callback<String>() {
|
|
||||||
@Override
|
|
||||||
public void call(final String key) {
|
|
||||||
if (tempQuery == null) return;
|
|
||||||
query.postValue(tempQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(final Throwable t) {
|
|
||||||
Log.e(TAG, "onError: ", t);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
searchDebouncer = new Debouncer<>(searchCallback, 500);
|
|
||||||
distinctQuery = distinctUntilChanged(query);
|
|
||||||
searchService = SearchService.getInstance();
|
|
||||||
recentSearchRepository = RecentSearchRepository.getInstance(RecentSearchDataSource.getInstance(application));
|
|
||||||
favoriteRepository = FavoriteRepository.Companion.getInstance(application);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<String> getQuery() {
|
fun getTopResults(): LiveData<Resource<List<SearchItem>?>> {
|
||||||
return distinctQuery;
|
return topResults
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Resource<List<SearchItem>>> getTopResults() {
|
fun getUserResults(): LiveData<Resource<List<SearchItem>?>> {
|
||||||
return topResults;
|
return userResults
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Resource<List<SearchItem>>> getUserResults() {
|
fun getHashtagResults(): LiveData<Resource<List<SearchItem>?>> {
|
||||||
return userResults;
|
return hashtagResults
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Resource<List<SearchItem>>> getHashtagResults() {
|
fun getLocationResults(): LiveData<Resource<List<SearchItem>?>> {
|
||||||
return hashtagResults;
|
return locationResults
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Resource<List<SearchItem>>> getLocationResults() {
|
fun submitQuery(query: String?) {
|
||||||
return locationResults;
|
var localQuery = query
|
||||||
}
|
|
||||||
|
|
||||||
public void submitQuery(@Nullable final String query) {
|
|
||||||
String localQuery = query;
|
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
localQuery = "";
|
localQuery = ""
|
||||||
}
|
}
|
||||||
if (tempQuery != null && Objects.equals(localQuery.toLowerCase(), tempQuery.toLowerCase())) return;
|
if (tempQuery != null && localQuery!!.lowercase(Locale.getDefault()) == tempQuery!!.lowercase(Locale.getDefault())) return
|
||||||
tempQuery = query;
|
tempQuery = query
|
||||||
if (TextUtils.isEmpty(query)) {
|
if (isEmpty(query)) {
|
||||||
// If empty immediately post it
|
// If empty immediately post it
|
||||||
searchDebouncer.cancel(QUERY);
|
searchDebouncer.cancel(QUERY)
|
||||||
this.query.postValue("");
|
this.query.postValue("")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
searchDebouncer.call(QUERY);
|
searchDebouncer.call(QUERY)
|
||||||
}
|
}
|
||||||
|
|
||||||
public void search(@NonNull final String query,
|
fun search(
|
||||||
@NonNull final FavoriteType type) {
|
query: String,
|
||||||
final MutableLiveData<Resource<List<SearchItem>>> liveData = getLiveDataByType(type);
|
type: FavoriteType
|
||||||
if (liveData == null) return;
|
) {
|
||||||
if (TextUtils.isEmpty(query)) {
|
val liveData = getLiveDataByType(type) ?: return
|
||||||
showRecentSearchesAndFavorites(type, liveData);
|
if (isEmpty(query)) {
|
||||||
return;
|
showRecentSearchesAndFavorites(type, liveData)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (query.equals("@") || query.equals("#")) return;
|
if (query == "@" || query == "#") return
|
||||||
final String c;
|
val c: String
|
||||||
switch (type) {
|
c = when (type) {
|
||||||
case TOP:
|
FavoriteType.TOP -> "blended"
|
||||||
c = "blended";
|
FavoriteType.USER -> "user"
|
||||||
break;
|
FavoriteType.HASHTAG -> "hashtag"
|
||||||
case USER:
|
FavoriteType.LOCATION -> "place"
|
||||||
c = "user";
|
else -> return
|
||||||
break;
|
|
||||||
case HASHTAG:
|
|
||||||
c = "hashtag";
|
|
||||||
break;
|
|
||||||
case LOCATION:
|
|
||||||
c = "place";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
liveData.postValue(Resource.loading(null));
|
liveData.postValue(loading<List<SearchItem>?>(null))
|
||||||
final Call<SearchResponse> request = searchService.search(isLoggedIn, query, c);
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
request.enqueue(new Callback<SearchResponse>() {
|
try {
|
||||||
@Override
|
val response = searchRepository.search(isLoggedIn, query, c)
|
||||||
public void onResponse(@NonNull final Call<SearchResponse> call,
|
parseResponse(response, type)
|
||||||
@NonNull final Response<SearchResponse> response) {
|
|
||||||
if (!response.isSuccessful()) {
|
|
||||||
sendErrorResponse(type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final SearchResponse body = response.body();
|
|
||||||
if (body == null) {
|
|
||||||
sendErrorResponse(type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parseResponse(body, type);
|
|
||||||
}
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
@Override
|
sendErrorResponse(type)
|
||||||
public void onFailure(@NonNull final Call<SearchResponse> call,
|
|
||||||
@NonNull final Throwable t) {
|
|
||||||
Log.e(TAG, "onFailure: ", t);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showRecentSearchesAndFavorites(@NonNull final FavoriteType type,
|
private fun showRecentSearchesAndFavorites(
|
||||||
@NonNull final MutableLiveData<Resource<List<SearchItem>>> liveData) {
|
type: FavoriteType,
|
||||||
final SettableFuture<List<RecentSearch>> recentResultsFuture = SettableFuture.create();
|
liveData: MutableLiveData<Resource<List<SearchItem>?>>
|
||||||
final SettableFuture<List<Favorite>> favoritesFuture = SettableFuture.create();
|
) {
|
||||||
recentSearchRepository.getAllRecentSearches(
|
val recentResultsFuture = SettableFuture.create<List<RecentSearch>>()
|
||||||
CoroutineUtilsKt.getContinuation((recentSearches, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
val favoritesFuture = SettableFuture.create<List<Favorite>>()
|
||||||
if (throwable != null) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
Log.e(TAG, "showRecentSearchesAndFavorites: ", throwable);
|
try {
|
||||||
recentResultsFuture.set(Collections.emptyList());
|
val recentSearches = recentSearchRepository.getAllRecentSearches()
|
||||||
return;
|
recentResultsFuture.set(
|
||||||
}
|
if (type == FavoriteType.TOP) recentSearches
|
||||||
if (type != FavoriteType.TOP) {
|
else recentSearches.stream()
|
||||||
recentResultsFuture.set((List<RecentSearch>) recentSearches
|
.filter { (_, _, _, _, _, type1) -> type1 === type }
|
||||||
.stream()
|
.collect(Collectors.toList())
|
||||||
.filter(rs -> rs.getType() == type)
|
)
|
||||||
.collect(Collectors.toList())
|
}
|
||||||
);
|
catch (e: Exception) {
|
||||||
return;
|
recentResultsFuture.set(emptyList())
|
||||||
}
|
}
|
||||||
//noinspection unchecked
|
try {
|
||||||
recentResultsFuture.set((List<RecentSearch>) recentSearches);
|
val favorites = favoriteRepository.getAllFavorites()
|
||||||
}), Dispatchers.getIO())
|
favoritesFuture.set(
|
||||||
);
|
if (type == FavoriteType.TOP) favorites
|
||||||
favoriteRepository.getAllFavorites(
|
else favorites
|
||||||
CoroutineUtilsKt.getContinuation((favorites, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
.stream()
|
||||||
if (throwable != null) {
|
.filter { (_, _, type1) -> type1 === type }
|
||||||
favoritesFuture.set(Collections.emptyList());
|
.collect(Collectors.toList())
|
||||||
Log.e(TAG, "showRecentSearchesAndFavorites: ", throwable);
|
)
|
||||||
return;
|
}
|
||||||
}
|
catch (e: Exception) {
|
||||||
if (type != FavoriteType.TOP) {
|
favoritesFuture.set(emptyList())
|
||||||
favoritesFuture.set((List<Favorite>) favorites
|
}
|
||||||
.stream()
|
}
|
||||||
.filter(f -> f.getType() == type)
|
val listenableFuture = Futures.allAsList<List<*>>(recentResultsFuture, favoritesFuture)
|
||||||
.collect(Collectors.toList())
|
Futures.addCallback(listenableFuture, object : FutureCallback<List<List<*>?>?> {
|
||||||
);
|
override fun onSuccess(result: List<List<*>?>?) {
|
||||||
return;
|
if (!isEmpty(tempQuery)) return // Make sure user has not entered anything before updating results
|
||||||
}
|
|
||||||
//noinspection unchecked
|
|
||||||
favoritesFuture.set((List<Favorite>) favorites);
|
|
||||||
}), Dispatchers.getIO())
|
|
||||||
);
|
|
||||||
//noinspection UnstableApiUsage
|
|
||||||
final ListenableFuture<List<List<?>>> listenableFuture = Futures.allAsList(recentResultsFuture, favoritesFuture);
|
|
||||||
Futures.addCallback(listenableFuture, new FutureCallback<List<List<?>>>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable final List<List<?>> result) {
|
|
||||||
if (!TextUtils.isEmpty(tempQuery)) return; // Make sure user has not entered anything before updating results
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
liveData.postValue(Resource.success(Collections.emptyList()));
|
liveData.postValue(success(emptyList()))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
//noinspection unchecked
|
liveData.postValue(
|
||||||
liveData.postValue(Resource.success(
|
success(
|
||||||
ImmutableList.<SearchItem>builder()
|
ImmutableList.builder<SearchItem>()
|
||||||
.addAll(SearchItem.fromRecentSearch((List<RecentSearch>) result.get(0)))
|
.addAll(SearchItem.fromRecentSearch(result[0] as List<RecentSearch?>?))
|
||||||
.addAll(SearchItem.fromFavorite((List<Favorite>) result.get(1)))
|
.addAll(SearchItem.fromFavorite(result[1] as List<Favorite?>?))
|
||||||
.build()
|
.build()
|
||||||
));
|
)
|
||||||
} catch (Exception e) {
|
)
|
||||||
Log.e(TAG, "onSuccess: ", e);
|
} catch (e: Exception) {
|
||||||
liveData.postValue(Resource.success(Collections.emptyList()));
|
Log.e(TAG, "onSuccess: ", e)
|
||||||
|
liveData.postValue(success(emptyList()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun onFailure(t: Throwable) {
|
||||||
public void onFailure(@NonNull final Throwable t) {
|
if (!isEmpty(tempQuery)) return
|
||||||
if (!TextUtils.isEmpty(tempQuery)) return;
|
liveData.postValue(success(emptyList()))
|
||||||
liveData.postValue(Resource.success(Collections.emptyList()));
|
Log.e(TAG, "onFailure: ", t)
|
||||||
Log.e(TAG, "onFailure: ", t);
|
|
||||||
}
|
}
|
||||||
}, AppExecutors.INSTANCE.getMainThread());
|
}, mainThread)
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendErrorResponse(@NonNull final FavoriteType type) {
|
private fun sendErrorResponse(type: FavoriteType) {
|
||||||
final MutableLiveData<Resource<List<SearchItem>>> liveData = getLiveDataByType(type);
|
val liveData = getLiveDataByType(type) ?: return
|
||||||
if (liveData == null) return;
|
liveData.postValue(error(null, emptyList()))
|
||||||
liveData.postValue(Resource.error(null, Collections.emptyList()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MutableLiveData<Resource<List<SearchItem>>> getLiveDataByType(@NonNull final FavoriteType type) {
|
private fun getLiveDataByType(type: FavoriteType): MutableLiveData<Resource<List<SearchItem>?>>? {
|
||||||
final MutableLiveData<Resource<List<SearchItem>>> liveData;
|
val liveData: MutableLiveData<Resource<List<SearchItem>?>>
|
||||||
switch (type) {
|
liveData = when (type) {
|
||||||
case TOP:
|
FavoriteType.TOP -> topResults
|
||||||
liveData = topResults;
|
FavoriteType.USER -> userResults
|
||||||
break;
|
FavoriteType.HASHTAG -> hashtagResults
|
||||||
case USER:
|
FavoriteType.LOCATION -> locationResults
|
||||||
liveData = userResults;
|
else -> return null
|
||||||
break;
|
|
||||||
case HASHTAG:
|
|
||||||
liveData = hashtagResults;
|
|
||||||
break;
|
|
||||||
case LOCATION:
|
|
||||||
liveData = locationResults;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return liveData;
|
return liveData
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseResponse(@NonNull final SearchResponse body,
|
private fun parseResponse(
|
||||||
@NonNull final FavoriteType type) {
|
body: SearchResponse,
|
||||||
final MutableLiveData<Resource<List<SearchItem>>> liveData = getLiveDataByType(type);
|
type: FavoriteType
|
||||||
if (liveData == null) return;
|
) {
|
||||||
|
val liveData = getLiveDataByType(type) ?: return
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
if (body.getList() == null) {
|
if (body.list == null) {
|
||||||
liveData.postValue(Resource.success(Collections.emptyList()));
|
liveData.postValue(success(emptyList()))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (type == FavoriteType.HASHTAG || type == FavoriteType.LOCATION) {
|
if (type === FavoriteType.HASHTAG || type === FavoriteType.LOCATION) {
|
||||||
liveData.postValue(Resource.success(body.getList()
|
liveData.postValue(success(body.list
|
||||||
.stream()
|
.stream()
|
||||||
.filter(i -> i.getUser() == null)
|
.filter { i: SearchItem -> i.user == null }
|
||||||
.collect(Collectors.toList())));
|
.collect(Collectors.toList())))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
liveData.postValue(Resource.success(body.getList()));
|
liveData.postValue(success(body.list))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// anonymous
|
// anonymous
|
||||||
final List<SearchItem> list;
|
val list: List<SearchItem>?
|
||||||
switch (type) {
|
list = when (type) {
|
||||||
case TOP:
|
FavoriteType.TOP -> ImmutableList
|
||||||
list = ImmutableList
|
.builder<SearchItem>()
|
||||||
.<SearchItem>builder()
|
.addAll(body.users ?: emptyList())
|
||||||
.addAll(body.getUsers() == null ? Collections.emptyList() : body.getUsers())
|
.addAll(body.hashtags ?: emptyList())
|
||||||
.addAll(body.getHashtags() == null ? Collections.emptyList() : body.getHashtags())
|
.addAll(body.places ?: emptyList())
|
||||||
.addAll(body.getPlaces() == null ? Collections.emptyList() : body.getPlaces())
|
.build()
|
||||||
.build();
|
FavoriteType.USER -> body.users
|
||||||
break;
|
FavoriteType.HASHTAG -> body.hashtags
|
||||||
case USER:
|
FavoriteType.LOCATION -> body.places
|
||||||
list = body.getUsers();
|
else -> return
|
||||||
break;
|
|
||||||
case HASHTAG:
|
|
||||||
list = body.getHashtags();
|
|
||||||
break;
|
|
||||||
case LOCATION:
|
|
||||||
list = body.getPlaces();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
liveData.postValue(Resource.success(list));
|
liveData.postValue(success(list))
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveToRecentSearches(final SearchItem searchItem) {
|
fun saveToRecentSearches(searchItem: SearchItem?) {
|
||||||
if (searchItem == null) return;
|
if (searchItem == null) return
|
||||||
try {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
final RecentSearch recentSearch = RecentSearch.fromSearchItem(searchItem);
|
try {
|
||||||
if (recentSearch == null) return;
|
val recentSearch = fromSearchItem(searchItem)
|
||||||
recentSearchRepository.insertOrUpdateRecentSearch(
|
recentSearchRepository.insertOrUpdateRecentSearch(recentSearch!!)
|
||||||
recentSearch,
|
} catch (e: Exception) {
|
||||||
CoroutineUtilsKt.getContinuation((unit, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
Log.e(TAG, "saveToRecentSearches: ", e)
|
||||||
if (throwable != null) {
|
}
|
||||||
Log.e(TAG, "saveToRecentSearches: ", throwable);
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
// Log.d(TAG, "onSuccess: inserted recent: " + recentSearch);
|
|
||||||
}), Dispatchers.getIO())
|
|
||||||
);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "saveToRecentSearches: ", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
fun deleteRecentSearch(searchItem: SearchItem?): LiveData<Resource<Any?>>? {
|
||||||
public LiveData<Resource<Object>> deleteRecentSearch(final SearchItem searchItem) {
|
if (searchItem == null || !searchItem.isRecent) return null
|
||||||
if (searchItem == null || !searchItem.isRecent()) return null;
|
val (_, igId, _, _, _, type) = fromSearchItem(searchItem) ?: return null
|
||||||
final RecentSearch recentSearch = RecentSearch.fromSearchItem(searchItem);
|
val data = MutableLiveData<Resource<Any?>>()
|
||||||
if (recentSearch == null) return null;
|
data.postValue(loading(null))
|
||||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
data.postValue(Resource.loading(null));
|
try {
|
||||||
recentSearchRepository.deleteRecentSearchByIgIdAndType(
|
recentSearchRepository.deleteRecentSearchByIgIdAndType(igId, type)
|
||||||
recentSearch.getIgId(),
|
data.postValue(success(Any()))
|
||||||
recentSearch.getType(),
|
}
|
||||||
CoroutineUtilsKt.getContinuation((unit, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
catch (e: Exception) {
|
||||||
if (throwable != null) {
|
data.postValue(error(e.message, null))
|
||||||
Log.e(TAG, "deleteRecentSearch: ", throwable);
|
}
|
||||||
data.postValue(Resource.error("Error deleting recent item", null));
|
}
|
||||||
return;
|
return data
|
||||||
}
|
}
|
||||||
data.postValue(Resource.success(new Object()));
|
|
||||||
}), Dispatchers.getIO())
|
companion object {
|
||||||
);
|
private val TAG = SearchFragmentViewModel::class.java.simpleName
|
||||||
return data;
|
private const val QUERY = "query"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package awais.instagrabber.webservices
|
||||||
|
|
||||||
|
import awais.instagrabber.repositories.SearchService
|
||||||
|
import awais.instagrabber.repositories.responses.search.SearchResponse
|
||||||
|
import awais.instagrabber.webservices.RetrofitFactory.retrofitWeb
|
||||||
|
import com.google.common.collect.ImmutableMap
|
||||||
|
import retrofit2.Call
|
||||||
|
|
||||||
|
class SearchRepository(private val service: SearchService) {
|
||||||
|
suspend fun search(
|
||||||
|
isLoggedIn: Boolean,
|
||||||
|
query: String,
|
||||||
|
context: String
|
||||||
|
): SearchResponse {
|
||||||
|
val builder = ImmutableMap.builder<String, String>()
|
||||||
|
builder.put("query", query)
|
||||||
|
// context is one of: "blended", "user", "place", "hashtag"
|
||||||
|
// note that "place" and "hashtag" can contain ONE user result, who knows why
|
||||||
|
builder.put("context", context)
|
||||||
|
builder.put("count", "50")
|
||||||
|
return service.search(
|
||||||
|
if (isLoggedIn) "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/" else "https://www.instagram.com/web/search/topsearch/",
|
||||||
|
builder.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Volatile
|
||||||
|
private var INSTANCE: SearchRepository? = null
|
||||||
|
|
||||||
|
fun getInstance(): SearchRepository {
|
||||||
|
return INSTANCE ?: synchronized(this) {
|
||||||
|
val service: SearchService = RetrofitFactory.retrofit.create(SearchService::class.java)
|
||||||
|
SearchRepository(service).also { INSTANCE = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,43 +0,0 @@
|
|||||||
package awais.instagrabber.webservices;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
|
|
||||||
import awais.instagrabber.repositories.SearchRepository;
|
|
||||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
|
||||||
import retrofit2.Call;
|
|
||||||
|
|
||||||
public class SearchService {
|
|
||||||
private static final String TAG = "LocationService";
|
|
||||||
|
|
||||||
private final SearchRepository repository;
|
|
||||||
|
|
||||||
private static SearchService instance;
|
|
||||||
|
|
||||||
private SearchService() {
|
|
||||||
repository = RetrofitFactory.INSTANCE
|
|
||||||
.getRetrofitWeb()
|
|
||||||
.create(SearchRepository.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SearchService getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new SearchService();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Call<SearchResponse> search(final boolean isLoggedIn,
|
|
||||||
final String query,
|
|
||||||
final String context) {
|
|
||||||
final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
|
||||||
builder.put("query", query);
|
|
||||||
// context is one of: "blended", "user", "place", "hashtag"
|
|
||||||
// note that "place" and "hashtag" can contain ONE user result, who knows why
|
|
||||||
builder.put("context", context);
|
|
||||||
builder.put("count", "50");
|
|
||||||
return repository.search(isLoggedIn
|
|
||||||
? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/"
|
|
||||||
: "https://www.instagram.com/web/search/topsearch/",
|
|
||||||
builder.build());
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user