12 changed files with 673 additions and 163 deletions
-
56app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java
-
5app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java
-
467app/src/main/java/awais/instagrabber/fragments/LocationFragment.java
-
6app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java
-
15app/src/main/java/awais/instagrabber/repositories/LocationRepository.java
-
1app/src/main/java/awais/instagrabber/utils/Constants.java
-
3app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
-
213app/src/main/java/awais/instagrabber/webservices/LocationService.java
-
13app/src/main/res/layout/fragment_location.xml
-
9app/src/main/res/menu/location_menu.xml
-
9app/src/main/res/navigation/hashtag_nav_graph.xml
-
39app/src/main/res/navigation/location_nav_graph.xml
@ -0,0 +1,56 @@ |
|||||
|
package awais.instagrabber.asyncs; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import awais.instagrabber.customviews.helpers.PostFetcher; |
||||
|
import awais.instagrabber.interfaces.FetchListener; |
||||
|
import awais.instagrabber.models.FeedModel; |
||||
|
import awais.instagrabber.models.LocationModel; |
||||
|
import awais.instagrabber.webservices.LocationService; |
||||
|
import awais.instagrabber.webservices.LocationService.LocationPostsFetchResponse; |
||||
|
import awais.instagrabber.webservices.ServiceCallback; |
||||
|
|
||||
|
public class LocationPostFetchService implements PostFetcher.PostFetchService { |
||||
|
private final LocationService locationService; |
||||
|
private final LocationModel locationModel; |
||||
|
private String nextMaxId; |
||||
|
private boolean moreAvailable; |
||||
|
|
||||
|
public LocationPostFetchService(final LocationModel locationModel) { |
||||
|
this.locationModel = locationModel; |
||||
|
locationService = LocationService.getInstance(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void fetch(final FetchListener<List<FeedModel>> fetchListener) { |
||||
|
locationService.fetchPosts(locationModel.getId(), nextMaxId, new ServiceCallback<LocationPostsFetchResponse>() { |
||||
|
@Override |
||||
|
public void onSuccess(final LocationPostsFetchResponse result) { |
||||
|
if (result == null) return; |
||||
|
nextMaxId = result.getNextMaxId(); |
||||
|
moreAvailable = result.isMoreAvailable(); |
||||
|
if (fetchListener != null) { |
||||
|
fetchListener.onResult(result.getItems()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(final Throwable t) { |
||||
|
// Log.e(TAG, "onFailure: ", t); |
||||
|
if (fetchListener != null) { |
||||
|
fetchListener.onFailure(t); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void reset() { |
||||
|
nextMaxId = null; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean hasNextPage() { |
||||
|
return moreAvailable; |
||||
|
} |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
package awais.instagrabber.repositories; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
import retrofit2.Call; |
||||
|
import retrofit2.http.GET; |
||||
|
import retrofit2.http.Path; |
||||
|
import retrofit2.http.QueryMap; |
||||
|
|
||||
|
public interface LocationRepository { |
||||
|
|
||||
|
@GET("/api/v1/feed/location/{location}/") |
||||
|
Call<String> fetchPosts(@Path("location") final String locationId, |
||||
|
@QueryMap Map<String, String> queryParams); |
||||
|
} |
@ -0,0 +1,213 @@ |
|||||
|
package awais.instagrabber.webservices; |
||||
|
|
||||
|
import android.util.Log; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
|
||||
|
import com.google.common.collect.ImmutableMap; |
||||
|
|
||||
|
import org.json.JSONArray; |
||||
|
import org.json.JSONException; |
||||
|
import org.json.JSONObject; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.Objects; |
||||
|
|
||||
|
import awais.instagrabber.models.FeedModel; |
||||
|
import awais.instagrabber.repositories.LocationRepository; |
||||
|
import awais.instagrabber.utils.ResponseBodyUtils; |
||||
|
import awais.instagrabber.utils.TextUtils; |
||||
|
import retrofit2.Call; |
||||
|
import retrofit2.Callback; |
||||
|
import retrofit2.Response; |
||||
|
import retrofit2.Retrofit; |
||||
|
|
||||
|
public class LocationService extends BaseService { |
||||
|
private static final String TAG = "LocationService"; |
||||
|
|
||||
|
private final LocationRepository repository; |
||||
|
|
||||
|
private static LocationService instance; |
||||
|
|
||||
|
private LocationService() { |
||||
|
final Retrofit retrofit = getRetrofitBuilder() |
||||
|
.baseUrl("https://i.instagram.com") |
||||
|
.build(); |
||||
|
repository = retrofit.create(LocationRepository.class); |
||||
|
} |
||||
|
|
||||
|
public static LocationService getInstance() { |
||||
|
if (instance == null) { |
||||
|
instance = new LocationService(); |
||||
|
} |
||||
|
return instance; |
||||
|
} |
||||
|
|
||||
|
public void fetchPosts(@NonNull final String locationId, |
||||
|
final String maxId, |
||||
|
final ServiceCallback<LocationPostsFetchResponse> callback) { |
||||
|
final ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder(); |
||||
|
if (!TextUtils.isEmpty(maxId)) { |
||||
|
builder.put("max_id", maxId); |
||||
|
} |
||||
|
final Call<String> request = repository.fetchPosts(locationId, builder.build()); |
||||
|
request.enqueue(new Callback<String>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { |
||||
|
try { |
||||
|
if (callback == null) { |
||||
|
return; |
||||
|
} |
||||
|
final String body = response.body(); |
||||
|
if (TextUtils.isEmpty(body)) { |
||||
|
callback.onSuccess(null); |
||||
|
return; |
||||
|
} |
||||
|
final LocationPostsFetchResponse tagPostsFetchResponse = parseResponse(body); |
||||
|
callback.onSuccess(tagPostsFetchResponse); |
||||
|
} catch (JSONException e) { |
||||
|
Log.e(TAG, "onResponse", e); |
||||
|
callback.onFailure(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { |
||||
|
if (callback != null) { |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private LocationPostsFetchResponse parseResponse(@NonNull final String body) throws JSONException { |
||||
|
final JSONObject root = new JSONObject(body); |
||||
|
final boolean moreAvailable = root.optBoolean("more_available"); |
||||
|
final String nextMaxId = root.optString("next_max_id"); |
||||
|
final int numResults = root.optInt("num_results"); |
||||
|
final String status = root.optString("status"); |
||||
|
final JSONArray itemsJson = root.optJSONArray("items"); |
||||
|
final List<FeedModel> items = parseItems(itemsJson); |
||||
|
return new LocationPostsFetchResponse( |
||||
|
moreAvailable, |
||||
|
nextMaxId, |
||||
|
numResults, |
||||
|
status, |
||||
|
items |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private List<FeedModel> parseItems(final JSONArray items) throws JSONException { |
||||
|
if (items == null) { |
||||
|
return Collections.emptyList(); |
||||
|
} |
||||
|
final List<FeedModel> feedModels = new ArrayList<>(); |
||||
|
for (int i = 0; i < items.length(); i++) { |
||||
|
final JSONObject itemJson = items.optJSONObject(i); |
||||
|
if (itemJson == null) { |
||||
|
continue; |
||||
|
} |
||||
|
final FeedModel feedModel = ResponseBodyUtils.parseItem(itemJson); |
||||
|
if (feedModel != null) { |
||||
|
feedModels.add(feedModel); |
||||
|
} |
||||
|
} |
||||
|
return feedModels; |
||||
|
} |
||||
|
|
||||
|
public static class LocationPostsFetchResponse { |
||||
|
private boolean moreAvailable; |
||||
|
private String nextMaxId; |
||||
|
private int numResults; |
||||
|
private String status; |
||||
|
private List<FeedModel> items; |
||||
|
|
||||
|
public LocationPostsFetchResponse(final boolean moreAvailable, |
||||
|
final String nextMaxId, |
||||
|
final int numResults, |
||||
|
final String status, |
||||
|
final List<FeedModel> items) { |
||||
|
this.moreAvailable = moreAvailable; |
||||
|
this.nextMaxId = nextMaxId; |
||||
|
this.numResults = numResults; |
||||
|
this.status = status; |
||||
|
this.items = items; |
||||
|
} |
||||
|
|
||||
|
public boolean isMoreAvailable() { |
||||
|
return moreAvailable; |
||||
|
} |
||||
|
|
||||
|
public LocationPostsFetchResponse setMoreAvailable(final boolean moreAvailable) { |
||||
|
this.moreAvailable = moreAvailable; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public String getNextMaxId() { |
||||
|
return nextMaxId; |
||||
|
} |
||||
|
|
||||
|
public LocationPostsFetchResponse setNextMaxId(final String nextMaxId) { |
||||
|
this.nextMaxId = nextMaxId; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public int getNumResults() { |
||||
|
return numResults; |
||||
|
} |
||||
|
|
||||
|
public LocationPostsFetchResponse setNumResults(final int numResults) { |
||||
|
this.numResults = numResults; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public String getStatus() { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
public LocationPostsFetchResponse setStatus(final String status) { |
||||
|
this.status = status; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public List<FeedModel> getItems() { |
||||
|
return items; |
||||
|
} |
||||
|
|
||||
|
public LocationPostsFetchResponse setItems(final List<FeedModel> items) { |
||||
|
this.items = items; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean equals(final Object o) { |
||||
|
if (this == o) return true; |
||||
|
if (o == null || getClass() != o.getClass()) return false; |
||||
|
final LocationPostsFetchResponse that = (LocationPostsFetchResponse) o; |
||||
|
return moreAvailable == that.moreAvailable && |
||||
|
numResults == that.numResults && |
||||
|
Objects.equals(nextMaxId, that.nextMaxId) && |
||||
|
Objects.equals(status, that.status) && |
||||
|
Objects.equals(items, that.items); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int hashCode() { |
||||
|
return Objects.hash(moreAvailable, nextMaxId, numResults, status, items); |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "LocationPostsFetchResponse{" + |
||||
|
"moreAvailable=" + moreAvailable + |
||||
|
", nextMaxId='" + nextMaxId + '\'' + |
||||
|
", numResults=" + numResults + |
||||
|
", status='" + status + '\'' + |
||||
|
", items=" + items + |
||||
|
'}'; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"> |
||||
|
|
||||
|
<item |
||||
|
android:id="@+id/layout" |
||||
|
android:title="@string/layout" |
||||
|
app:showAsAction="never" /> |
||||
|
</menu> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue