Ammar Githam
4 years ago
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