Add Posts view to Location fragment
This commit is contained in:
parent
2931f2d3ab
commit
d9c30c99b7
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -44,7 +44,6 @@ import awais.instagrabber.customviews.PrimaryActionModeCallback;
|
|||||||
import awais.instagrabber.customviews.helpers.NestedCoordinatorLayout;
|
import awais.instagrabber.customviews.helpers.NestedCoordinatorLayout;
|
||||||
import awais.instagrabber.databinding.FragmentHashtagBinding;
|
import awais.instagrabber.databinding.FragmentHashtagBinding;
|
||||||
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
||||||
import awais.instagrabber.fragments.main.FeedFragmentDirections;
|
|
||||||
import awais.instagrabber.models.FeedModel;
|
import awais.instagrabber.models.FeedModel;
|
||||||
import awais.instagrabber.models.HashtagModel;
|
import awais.instagrabber.models.HashtagModel;
|
||||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||||
@ -183,13 +182,13 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHashtagClick(final String hashtag) {
|
public void onHashtagClick(final String hashtag) {
|
||||||
final NavDirections action = FeedFragmentDirections.actionGlobalHashTagFragment(hashtag);
|
final NavDirections action = HashTagFragmentDirections.actionGlobalHashTagFragment(hashtag);
|
||||||
NavHostFragment.findNavController(HashTagFragment.this).navigate(action);
|
NavHostFragment.findNavController(HashTagFragment.this).navigate(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocationClick(final FeedModel feedModel) {
|
public void onLocationClick(final FeedModel feedModel) {
|
||||||
final NavDirections action = FeedFragmentDirections.actionGlobalLocationFragment(feedModel.getLocationId());
|
final NavDirections action = HashTagFragmentDirections.actionGlobalLocationFragment(feedModel.getLocationId());
|
||||||
NavHostFragment.findNavController(HashTagFragment.this).navigate(action);
|
NavHostFragment.findNavController(HashTagFragment.this).navigate(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,15 @@ import android.graphics.Typeface;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.style.RelativeSizeSpan;
|
import android.text.style.RelativeSizeSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -19,12 +22,12 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.OnBackPressedCallback;
|
import androidx.activity.OnBackPressedCallback;
|
||||||
import androidx.activity.OnBackPressedDispatcher;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
import androidx.core.content.PermissionChecker;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.navigation.NavController;
|
||||||
import androidx.navigation.NavDirections;
|
import androidx.navigation.NavDirections;
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
@ -32,71 +35,64 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|||||||
import com.google.android.material.snackbar.BaseTransientBottomBar;
|
import com.google.android.material.snackbar.BaseTransientBottomBar;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.activities.MainActivity;
|
import awais.instagrabber.activities.MainActivity;
|
||||||
import awais.instagrabber.adapters.PostsAdapter;
|
import awais.instagrabber.adapters.FeedAdapterV2;
|
||||||
import awais.instagrabber.asyncs.LocationFetcher;
|
import awais.instagrabber.asyncs.LocationFetcher;
|
||||||
import awais.instagrabber.asyncs.PostsFetcher;
|
import awais.instagrabber.asyncs.LocationPostFetchService;
|
||||||
import awais.instagrabber.customviews.PrimaryActionModeCallback;
|
import awais.instagrabber.customviews.PrimaryActionModeCallback;
|
||||||
import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager;
|
|
||||||
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration;
|
|
||||||
import awais.instagrabber.customviews.helpers.NestedCoordinatorLayout;
|
import awais.instagrabber.customviews.helpers.NestedCoordinatorLayout;
|
||||||
import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
|
|
||||||
import awais.instagrabber.databinding.FragmentLocationBinding;
|
import awais.instagrabber.databinding.FragmentLocationBinding;
|
||||||
import awais.instagrabber.interfaces.FetchListener;
|
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
||||||
|
import awais.instagrabber.models.FeedModel;
|
||||||
import awais.instagrabber.models.LocationModel;
|
import awais.instagrabber.models.LocationModel;
|
||||||
import awais.instagrabber.models.PostModel;
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||||
import awais.instagrabber.models.StoryModel;
|
import awais.instagrabber.models.StoryModel;
|
||||||
import awais.instagrabber.models.enums.DownloadMethod;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
import awais.instagrabber.models.enums.FavoriteType;
|
||||||
import awais.instagrabber.models.enums.PostItemType;
|
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
import awais.instagrabber.utils.DataBox;
|
import awais.instagrabber.utils.DataBox;
|
||||||
import awais.instagrabber.utils.DownloadUtils;
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.viewmodels.PostsViewModel;
|
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.webservices.StoriesService;
|
import awais.instagrabber.webservices.StoriesService;
|
||||||
import awaisomereport.LogCollector;
|
import awaisomereport.LogCollector;
|
||||||
|
|
||||||
|
import static androidx.core.content.PermissionChecker.checkSelfPermission;
|
||||||
|
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
|
||||||
import static awais.instagrabber.utils.Utils.logCollector;
|
import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
||||||
private static final String TAG = "LocationFragment";
|
private static final String TAG = "LocationFragment";
|
||||||
|
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
|
||||||
|
|
||||||
private MainActivity fragmentActivity;
|
private MainActivity fragmentActivity;
|
||||||
private FragmentLocationBinding binding;
|
private FragmentLocationBinding binding;
|
||||||
private NestedCoordinatorLayout root;
|
private NestedCoordinatorLayout root;
|
||||||
private boolean shouldRefresh = true, hasStories = false;
|
private boolean shouldRefresh = true;
|
||||||
|
private boolean hasStories = false;
|
||||||
private String locationId;
|
private String locationId;
|
||||||
private LocationModel locationModel;
|
private LocationModel locationModel;
|
||||||
private PostsViewModel postsViewModel;
|
|
||||||
private PostsAdapter postsAdapter;
|
|
||||||
private ActionMode actionMode;
|
private ActionMode actionMode;
|
||||||
private StoriesService storiesService;
|
private StoriesService storiesService;
|
||||||
private boolean hasNextPage;
|
|
||||||
private String endCursor;
|
|
||||||
private AsyncTask<?, ?, ?> currentlyExecuting;
|
private AsyncTask<?, ?, ?> currentlyExecuting;
|
||||||
private boolean isLoggedIn;
|
private boolean isLoggedIn;
|
||||||
private boolean isPullToRefresh;
|
private boolean storiesFetching;
|
||||||
|
|
||||||
private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
|
private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
|
||||||
@Override
|
@Override
|
||||||
public void handleOnBackPressed() {
|
public void handleOnBackPressed() {
|
||||||
if (postsAdapter == null) {
|
// if (postsAdapter == null) {
|
||||||
setEnabled(false);
|
// setEnabled(false);
|
||||||
remove();
|
// remove();
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
postsAdapter.clearSelection();
|
// postsAdapter.clearSelection();
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
remove();
|
remove();
|
||||||
}
|
}
|
||||||
@ -112,45 +108,130 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
public boolean onActionItemClicked(final ActionMode mode,
|
public boolean onActionItemClicked(final ActionMode mode,
|
||||||
final MenuItem item) {
|
final MenuItem item) {
|
||||||
if (item.getItemId() == R.id.action_download) {
|
if (item.getItemId() == R.id.action_download) {
|
||||||
if (postsAdapter == null || locationId == null) {
|
// if (postsAdapter == null || locationId == null) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
final Context context = getContext();
|
// final Context context = getContext();
|
||||||
if (context == null) return false;
|
// if (context == null) return false;
|
||||||
DownloadUtils.batchDownload(context,
|
// DownloadUtils.batchDownload(context,
|
||||||
locationId,
|
// locationId,
|
||||||
DownloadMethod.DOWNLOAD_MAIN,
|
// DownloadMethod.DOWNLOAD_MAIN,
|
||||||
postsAdapter.getSelectedModels());
|
// postsAdapter.getSelectedModels());
|
||||||
checkAndResetAction();
|
// checkAndResetAction();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
private final FetchListener<List<PostModel>> postsFetchListener = new FetchListener<List<PostModel>>() {
|
// private final FetchListener<List<PostModel>> postsFetchListener = new FetchListener<List<PostModel>>() {
|
||||||
|
// @Override
|
||||||
|
// public void onResult(final List<PostModel> result) {
|
||||||
|
// binding.swipeRefreshLayout.setRefreshing(false);
|
||||||
|
// if (result == null) return;
|
||||||
|
// binding.mainPosts.post(() -> binding.mainPosts.setVisibility(View.VISIBLE));
|
||||||
|
// final List<PostModel> postModels = postsViewModel.getList().getValue();
|
||||||
|
// List<PostModel> finalList = postModels == null || postModels.isEmpty() ? new ArrayList<>()
|
||||||
|
// : new ArrayList<>(postModels);
|
||||||
|
// if (isPullToRefresh) {
|
||||||
|
// finalList = result;
|
||||||
|
// isPullToRefresh = false;
|
||||||
|
// } else {
|
||||||
|
// finalList.addAll(result);
|
||||||
|
// }
|
||||||
|
// postsViewModel.getList().postValue(finalList);
|
||||||
|
// PostModel model = null;
|
||||||
|
// if (!result.isEmpty()) {
|
||||||
|
// model = result.get(result.size() - 1);
|
||||||
|
// }
|
||||||
|
// if (model == null) return;
|
||||||
|
// endCursor = model.getEndCursor();
|
||||||
|
// hasNextPage = model.hasNextPage();
|
||||||
|
// model.setPageCursor(false, null);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
private final FeedAdapterV2.FeedItemCallback feedItemCallback = new FeedAdapterV2.FeedItemCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(final List<PostModel> result) {
|
public void onPostClick(final FeedModel feedModel, final View profilePicView, final View mainPostImage) {
|
||||||
binding.swipeRefreshLayout.setRefreshing(false);
|
openPostDialog(feedModel, profilePicView, mainPostImage, -1);
|
||||||
if (result == null) return;
|
|
||||||
binding.mainPosts.post(() -> binding.mainPosts.setVisibility(View.VISIBLE));
|
|
||||||
final List<PostModel> postModels = postsViewModel.getList().getValue();
|
|
||||||
List<PostModel> finalList = postModels == null || postModels.isEmpty() ? new ArrayList<>()
|
|
||||||
: new ArrayList<>(postModels);
|
|
||||||
if (isPullToRefresh) {
|
|
||||||
finalList = result;
|
|
||||||
isPullToRefresh = false;
|
|
||||||
} else {
|
|
||||||
finalList.addAll(result);
|
|
||||||
}
|
}
|
||||||
postsViewModel.getList().postValue(finalList);
|
|
||||||
PostModel model = null;
|
@Override
|
||||||
if (!result.isEmpty()) {
|
public void onSliderClick(final FeedModel feedModel, final int position) {
|
||||||
model = result.get(result.size() - 1);
|
openPostDialog(feedModel, null, null, position);
|
||||||
}
|
}
|
||||||
if (model == null) return;
|
|
||||||
endCursor = model.getEndCursor();
|
@Override
|
||||||
hasNextPage = model.hasNextPage();
|
public void onCommentsClick(final FeedModel feedModel) {
|
||||||
model.setPageCursor(false, null);
|
final NavDirections commentsAction = LocationFragmentDirections.actionGlobalCommentsViewerFragment(
|
||||||
|
feedModel.getShortCode(),
|
||||||
|
feedModel.getPostId(),
|
||||||
|
feedModel.getProfileModel().getId()
|
||||||
|
);
|
||||||
|
NavHostFragment.findNavController(LocationFragment.this).navigate(commentsAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDownloadClick(final FeedModel feedModel) {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) {
|
||||||
|
showDownloadDialog(feedModel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHashtagClick(final String hashtag) {
|
||||||
|
final NavDirections action = LocationFragmentDirections.actionGlobalHashTagFragment(hashtag);
|
||||||
|
NavHostFragment.findNavController(LocationFragment.this).navigate(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocationClick(final FeedModel feedModel) {
|
||||||
|
final NavDirections action = LocationFragmentDirections.actionGlobalLocationFragment(feedModel.getLocationId());
|
||||||
|
NavHostFragment.findNavController(LocationFragment.this).navigate(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMentionClick(final String mention) {
|
||||||
|
navigateToProfile(mention.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNameClick(final FeedModel feedModel, final View profilePicView) {
|
||||||
|
navigateToProfile("@" + feedModel.getProfileModel().getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProfilePicClick(final FeedModel feedModel, final View profilePicView) {
|
||||||
|
navigateToProfile("@" + feedModel.getProfileModel().getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onURLClick(final String url) {
|
||||||
|
Utils.openURL(getContext(), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEmailClick(final String emailId) {
|
||||||
|
Utils.openEmailAddress(getContext(), emailId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openPostDialog(final FeedModel feedModel,
|
||||||
|
final View profilePicView,
|
||||||
|
final View mainPostImage,
|
||||||
|
final int position) {
|
||||||
|
final PostViewV2Fragment.Builder builder = PostViewV2Fragment
|
||||||
|
.builder(feedModel);
|
||||||
|
if (position >= 0) {
|
||||||
|
builder.setPosition(position);
|
||||||
|
}
|
||||||
|
final PostViewV2Fragment fragment = builder
|
||||||
|
.setSharedProfilePicElement(profilePicView)
|
||||||
|
.setSharedMainPostElement(mainPostImage)
|
||||||
|
.build();
|
||||||
|
fragment.show(getChildFragmentManager(), "post_view");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -159,6 +240,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
fragmentActivity = (MainActivity) requireActivity();
|
fragmentActivity = (MainActivity) requireActivity();
|
||||||
storiesService = StoriesService.getInstance();
|
storiesService = StoriesService.getInstance();
|
||||||
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -185,9 +267,8 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh() {
|
public void onRefresh() {
|
||||||
isPullToRefresh = true;
|
binding.posts.refresh();
|
||||||
endCursor = null;
|
fetchStories();
|
||||||
fetchLocationModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -197,12 +278,26 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||||
super.onDestroy();
|
inflater.inflate(R.menu.topic_posts_menu, menu);
|
||||||
if (postsViewModel != null) {
|
|
||||||
postsViewModel.getList().postValue(Collections.emptyList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
||||||
|
if (item.getItemId() == R.id.layout) {
|
||||||
|
showPostsLayoutPreferences();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void onDestroy() {
|
||||||
|
// super.onDestroy();
|
||||||
|
// if (postsViewModel != null) {
|
||||||
|
// postsViewModel.getList().postValue(Collections.emptyList());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
if (getArguments() == null) return;
|
if (getArguments() == null) return;
|
||||||
@ -213,66 +308,73 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
binding.favChip.setVisibility(View.GONE);
|
binding.favChip.setVisibility(View.GONE);
|
||||||
binding.btnMap.setVisibility(View.GONE);
|
binding.btnMap.setVisibility(View.GONE);
|
||||||
setTitle();
|
setTitle();
|
||||||
setupPosts();
|
|
||||||
fetchLocationModel();
|
fetchLocationModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPosts() {
|
private void setupPosts() {
|
||||||
postsViewModel = new ViewModelProvider(this).get(PostsViewModel.class);
|
binding.posts.setViewModelStoreOwner(this)
|
||||||
final Context context = getContext();
|
.setLifeCycleOwner(this)
|
||||||
if (context == null) return;
|
.setPostFetchService(new LocationPostFetchService(locationModel))
|
||||||
final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(context, Utils.convertDpToPx(110));
|
.setLayoutPreferences(PostsLayoutPreferences.fromJson(settingsHelper.getString(Constants.PREF_LOCATION_POSTS_LAYOUT)))
|
||||||
binding.mainPosts.setLayoutManager(layoutManager);
|
.addFetchStatusChangeListener(fetching -> updateSwipeRefreshState())
|
||||||
binding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4)));
|
.setFeedItemCallback(feedItemCallback)
|
||||||
postsAdapter = new PostsAdapter((postModel, position) -> {
|
.init();
|
||||||
if (postsAdapter.isSelecting()) {
|
|
||||||
if (actionMode == null) return;
|
|
||||||
final String title = getString(R.string.number_selected, postsAdapter.getSelectedModels().size());
|
|
||||||
actionMode.setTitle(title);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (checkAndResetAction()) return;
|
|
||||||
final List<PostModel> postModels = postsViewModel.getList().getValue();
|
|
||||||
if (postModels == null || postModels.size() == 0) return;
|
|
||||||
if (postModels.get(0) == null) return;
|
|
||||||
final String postId = postModels.get(0).getPostId();
|
|
||||||
final boolean isId = postId != null && isLoggedIn;
|
|
||||||
final String[] idsOrShortCodes = new String[postModels.size()];
|
|
||||||
for (int i = 0; i < postModels.size(); i++) {
|
|
||||||
idsOrShortCodes[i] = isId ? postModels.get(i).getPostId()
|
|
||||||
: postModels.get(i).getShortCode();
|
|
||||||
}
|
|
||||||
final NavDirections action = LocationFragmentDirections.actionGlobalPostViewFragment(
|
|
||||||
position,
|
|
||||||
idsOrShortCodes,
|
|
||||||
isId);
|
|
||||||
NavHostFragment.findNavController(this).navigate(action);
|
|
||||||
}, (model, position) -> {
|
|
||||||
if (!postsAdapter.isSelecting()) {
|
|
||||||
checkAndResetAction();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (onBackPressedCallback.isEnabled()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity
|
|
||||||
.getOnBackPressedDispatcher();
|
|
||||||
onBackPressedCallback.setEnabled(true);
|
|
||||||
actionMode = fragmentActivity.startActionMode(multiSelectAction);
|
|
||||||
final String title = getString(R.string.number_selected, 1);
|
|
||||||
actionMode.setTitle(title);
|
|
||||||
onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
postsViewModel.getList().observe(fragmentActivity, postsAdapter::submitList);
|
|
||||||
binding.mainPosts.setAdapter(postsAdapter);
|
|
||||||
final RecyclerLazyLoader lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> {
|
|
||||||
if (!hasNextPage) return;
|
|
||||||
binding.swipeRefreshLayout.setRefreshing(true);
|
binding.swipeRefreshLayout.setRefreshing(true);
|
||||||
fetchPosts();
|
// postsViewModel = new ViewModelProvider(this).get(PostsViewModel.class);
|
||||||
endCursor = null;
|
// final Context context = getContext();
|
||||||
});
|
// if (context == null) return;
|
||||||
binding.mainPosts.addOnScrollListener(lazyLoader);
|
// final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(context, Utils.convertDpToPx(110));
|
||||||
|
// binding.mainPosts.setLayoutManager(layoutManager);
|
||||||
|
// binding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4)));
|
||||||
|
// postsAdapter = new PostsAdapter((postModel, position) -> {
|
||||||
|
// if (postsAdapter.isSelecting()) {
|
||||||
|
// if (actionMode == null) return;
|
||||||
|
// final String title = getString(R.string.number_selected, postsAdapter.getSelectedModels().size());
|
||||||
|
// actionMode.setTitle(title);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (checkAndResetAction()) return;
|
||||||
|
// final List<PostModel> postModels = postsViewModel.getList().getValue();
|
||||||
|
// if (postModels == null || postModels.size() == 0) return;
|
||||||
|
// if (postModels.get(0) == null) return;
|
||||||
|
// final String postId = postModels.get(0).getPostId();
|
||||||
|
// final boolean isId = postId != null && isLoggedIn;
|
||||||
|
// final String[] idsOrShortCodes = new String[postModels.size()];
|
||||||
|
// for (int i = 0; i < postModels.size(); i++) {
|
||||||
|
// idsOrShortCodes[i] = isId ? postModels.get(i).getPostId()
|
||||||
|
// : postModels.get(i).getShortCode();
|
||||||
|
// }
|
||||||
|
// final NavDirections action = LocationFragmentDirections.actionGlobalPostViewFragment(
|
||||||
|
// position,
|
||||||
|
// idsOrShortCodes,
|
||||||
|
// isId);
|
||||||
|
// NavHostFragment.findNavController(this).navigate(action);
|
||||||
|
// }, (model, position) -> {
|
||||||
|
// if (!postsAdapter.isSelecting()) {
|
||||||
|
// checkAndResetAction();
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// if (onBackPressedCallback.isEnabled()) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity
|
||||||
|
// .getOnBackPressedDispatcher();
|
||||||
|
// onBackPressedCallback.setEnabled(true);
|
||||||
|
// actionMode = fragmentActivity.startActionMode(multiSelectAction);
|
||||||
|
// final String title = getString(R.string.number_selected, 1);
|
||||||
|
// actionMode.setTitle(title);
|
||||||
|
// onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback);
|
||||||
|
// return true;
|
||||||
|
// });
|
||||||
|
// postsViewModel.getList().observe(fragmentActivity, postsAdapter::submitList);
|
||||||
|
// binding.mainPosts.setAdapter(postsAdapter);
|
||||||
|
// final RecyclerLazyLoader lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> {
|
||||||
|
// if (!hasNextPage) return;
|
||||||
|
// binding.swipeRefreshLayout.setRefreshing(true);
|
||||||
|
// fetchPosts();
|
||||||
|
// endCursor = null;
|
||||||
|
// });
|
||||||
|
// binding.mainPosts.addOnScrollListener(lazyLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchLocationModel() {
|
private void fetchLocationModel() {
|
||||||
@ -289,34 +391,15 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
}
|
}
|
||||||
setTitle();
|
setTitle();
|
||||||
setupLocationDetails();
|
setupLocationDetails();
|
||||||
fetchPosts();
|
setupPosts();
|
||||||
|
fetchStories();
|
||||||
|
// fetchPosts();
|
||||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupLocationDetails() {
|
private void setupLocationDetails() {
|
||||||
final String locationId = locationModel.getId();
|
final String locationId = locationModel.getId();
|
||||||
binding.swipeRefreshLayout.setRefreshing(true);
|
// binding.swipeRefreshLayout.setRefreshing(true);
|
||||||
if (isLoggedIn) {
|
|
||||||
storiesService.getUserStory(locationId,
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
new ServiceCallback<List<StoryModel>>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(final List<StoryModel> storyModels) {
|
|
||||||
if (storyModels != null && !storyModels.isEmpty()) {
|
|
||||||
binding.mainLocationImage.setStoriesBorder();
|
|
||||||
hasStories = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(final Throwable t) {
|
|
||||||
Log.e(TAG, "Error", t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
binding.mainLocationImage.setImageURI(locationModel.getSdProfilePic());
|
binding.mainLocationImage.setImageURI(locationModel.getSdProfilePic());
|
||||||
final String postCount = String.valueOf(locationModel.getPostCount());
|
final String postCount = String.valueOf(locationModel.getPostCount());
|
||||||
final SpannableStringBuilder span = new SpannableStringBuilder(getString(R.string.main_posts_count_inline,
|
final SpannableStringBuilder span = new SpannableStringBuilder(getString(R.string.main_posts_count_inline,
|
||||||
@ -405,18 +488,44 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
final NavDirections action = LocationFragmentDirections
|
final NavDirections action = LocationFragmentDirections
|
||||||
.actionLocationFragmentToStoryViewerFragment(-1, null, false, true, locationId, locationModel.getName());
|
.actionLocationFragmentToStoryViewerFragment(-1, null, false, true, locationId, locationModel.getName());
|
||||||
NavHostFragment.findNavController(this).navigate(action);
|
NavHostFragment.findNavController(this).navigate(action);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchPosts() {
|
private void fetchStories() {
|
||||||
stopCurrentExecutor();
|
if (isLoggedIn) {
|
||||||
currentlyExecuting = new PostsFetcher(locationModel.getId(), PostItemType.LOCATION, endCursor, postsFetchListener)
|
storiesFetching = true;
|
||||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
storiesService.getUserStory(locationId,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
new ServiceCallback<List<StoryModel>>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final List<StoryModel> storyModels) {
|
||||||
|
if (storyModels != null && !storyModels.isEmpty()) {
|
||||||
|
binding.mainLocationImage.setStoriesBorder();
|
||||||
|
hasStories = true;
|
||||||
|
}
|
||||||
|
storiesFetching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopCurrentExecutor() {
|
@Override
|
||||||
|
public void onFailure(final Throwable t) {
|
||||||
|
Log.e(TAG, "Error", t);
|
||||||
|
storiesFetching = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private void fetchPosts() {
|
||||||
|
// stopCurrentExecutor();
|
||||||
|
// currentlyExecuting = new PostsFetcher(locationModel.getId(), PostItemType.LOCATION, endCursor, postsFetchListener)
|
||||||
|
// .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void stopCurrentExecutor() {
|
||||||
if (currentlyExecuting != null) {
|
if (currentlyExecuting != null) {
|
||||||
try {
|
try {
|
||||||
currentlyExecuting.cancel(true);
|
currentlyExecuting.cancel(true);
|
||||||
@ -435,6 +544,59 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSwipeRefreshState() {
|
||||||
|
binding.swipeRefreshLayout.setRefreshing(binding.posts.isFetching() || storiesFetching);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showDownloadDialog(final FeedModel feedModel) {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
DownloadUtils.download(context, feedModel);
|
||||||
|
// switch (feedModel.getItemType()) {
|
||||||
|
// case MEDIA_TYPE_IMAGE:
|
||||||
|
// case MEDIA_TYPE_VIDEO:
|
||||||
|
// break;
|
||||||
|
// case MEDIA_TYPE_SLIDER:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// final List<ViewerPostModel> postModelsToDownload = new ArrayList<>();
|
||||||
|
// // if (!session) {
|
||||||
|
// final DialogInterface.OnClickListener clickListener = (dialog, which) -> {
|
||||||
|
// if (which == DialogInterface.BUTTON_NEGATIVE) {
|
||||||
|
// postModelsToDownload.addAll(postModels);
|
||||||
|
// } else if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||||
|
// postModelsToDownload.add(postModels.get(childPosition));
|
||||||
|
// } else {
|
||||||
|
// session = true;
|
||||||
|
// postModelsToDownload.add(postModels.get(childPosition));
|
||||||
|
// }
|
||||||
|
// if (postModelsToDownload.size() > 0) {
|
||||||
|
// DownloadUtils.batchDownload(context,
|
||||||
|
// username,
|
||||||
|
// DownloadMethod.DOWNLOAD_POST_VIEWER,
|
||||||
|
// postModelsToDownload);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// new AlertDialog.Builder(context)
|
||||||
|
// .setTitle(R.string.post_viewer_download_dialog_title)
|
||||||
|
// .setMessage(R.string.post_viewer_download_message)
|
||||||
|
// .setNeutralButton(R.string.post_viewer_download_session, clickListener)
|
||||||
|
// .setPositiveButton(R.string.post_viewer_download_current, clickListener)
|
||||||
|
// .setNegativeButton(R.string.post_viewer_download_album, clickListener).show();
|
||||||
|
// } else {
|
||||||
|
// DownloadUtils.batchDownload(context,
|
||||||
|
// username,
|
||||||
|
// DownloadMethod.DOWNLOAD_POST_VIEWER,
|
||||||
|
// Collections.singletonList(postModels.get(childPosition)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateToProfile(final String username) {
|
||||||
|
final NavController navController = NavHostFragment.findNavController(this);
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putString("username", username);
|
||||||
|
navController.navigate(R.id.action_global_profileFragment, bundle);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkAndResetAction() {
|
private boolean checkAndResetAction() {
|
||||||
if (!onBackPressedCallback.isEnabled() && actionMode == null) {
|
if (!onBackPressedCallback.isEnabled() && actionMode == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -449,4 +611,11 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showPostsLayoutPreferences() {
|
||||||
|
final PostsLayoutPreferencesDialogFragment fragment = new PostsLayoutPreferencesDialogFragment(
|
||||||
|
Constants.PREF_LOCATION_POSTS_LAYOUT,
|
||||||
|
preferences -> new Handler().postDelayed(() -> binding.posts.setLayoutPreferences(preferences), 200));
|
||||||
|
fragment.show(getChildFragmentManager(), "posts_layout_preferences");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,6 +197,12 @@ public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.O
|
|||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
fragmentActivity.setToolbar(binding.toolbar);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh() {
|
public void onRefresh() {
|
||||||
binding.posts.refresh();
|
binding.posts.refresh();
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -91,4 +91,5 @@ public final class Constants {
|
|||||||
public static final String PREF_PROFILE_POSTS_LAYOUT = "profile_posts_layout";
|
public static final String PREF_PROFILE_POSTS_LAYOUT = "profile_posts_layout";
|
||||||
public static final String PREF_TOPIC_POSTS_LAYOUT = "topic_posts_layout";
|
public static final String PREF_TOPIC_POSTS_LAYOUT = "topic_posts_layout";
|
||||||
public static final String PREF_HASHTAG_POSTS_LAYOUT = "hashtag_posts_layout";
|
public static final String PREF_HASHTAG_POSTS_LAYOUT = "hashtag_posts_layout";
|
||||||
|
public static final String PREF_LOCATION_POSTS_LAYOUT = "location_posts_layout";
|
||||||
}
|
}
|
@ -31,6 +31,7 @@ import static awais.instagrabber.utils.Constants.MUTED_VIDEOS;
|
|||||||
import static awais.instagrabber.utils.Constants.PREF_DARK_THEME;
|
import static awais.instagrabber.utils.Constants.PREF_DARK_THEME;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_HASHTAG_POSTS_LAYOUT;
|
import static awais.instagrabber.utils.Constants.PREF_HASHTAG_POSTS_LAYOUT;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_LIGHT_THEME;
|
import static awais.instagrabber.utils.Constants.PREF_LIGHT_THEME;
|
||||||
|
import static awais.instagrabber.utils.Constants.PREF_LOCATION_POSTS_LAYOUT;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_POSTS_LAYOUT;
|
import static awais.instagrabber.utils.Constants.PREF_POSTS_LAYOUT;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_PROFILE_POSTS_LAYOUT;
|
import static awais.instagrabber.utils.Constants.PREF_PROFILE_POSTS_LAYOUT;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_TOPIC_POSTS_LAYOUT;
|
import static awais.instagrabber.utils.Constants.PREF_TOPIC_POSTS_LAYOUT;
|
||||||
@ -118,7 +119,7 @@ public final class SettingsHelper {
|
|||||||
@StringDef(
|
@StringDef(
|
||||||
{APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT,
|
{APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT,
|
||||||
DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT,
|
DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT,
|
||||||
PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT})
|
PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT, PREF_LOCATION_POSTS_LAYOUT})
|
||||||
public @interface StringSettings {}
|
public @interface StringSettings {}
|
||||||
|
|
||||||
@StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
|
@StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
|
||||||
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -56,7 +56,6 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:text="@string/map"
|
android:text="@string/map"
|
||||||
app:chipBackgroundColor="@null"
|
app:chipBackgroundColor="@null"
|
||||||
app:chipIcon="@drawable/ic_outline_map_24"
|
app:chipIcon="@drawable/ic_outline_map_24"
|
||||||
@ -72,7 +71,6 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:text="@string/add_to_favorites"
|
android:text="@string/add_to_favorites"
|
||||||
app:chipBackgroundColor="@null"
|
app:chipBackgroundColor="@null"
|
||||||
app:chipIcon="@drawable/ic_outline_star_plus_24"
|
app:chipIcon="@drawable/ic_outline_star_plus_24"
|
||||||
@ -143,16 +141,15 @@
|
|||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/swipeRefreshLayout"
|
android:id="@+id/swipe_refresh_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<awais.instagrabber.customviews.PostsRecyclerView
|
||||||
android:id="@+id/mainPosts"
|
android:id="@+id/posts"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false" />
|
||||||
tools:listitem="@layout/item_post" />
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
</awais.instagrabber.customviews.helpers.NestedCoordinatorLayout>
|
</awais.instagrabber.customviews.helpers.NestedCoordinatorLayout>
|
9
app/src/main/res/menu/location_menu.xml
Normal file
9
app/src/main/res/menu/location_menu.xml
Normal file
@ -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>
|
@ -47,6 +47,15 @@
|
|||||||
app:nullable="true" />
|
app:nullable="true" />
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_locationFragment"
|
||||||
|
app:destination="@id/location_nav_graph">
|
||||||
|
<argument
|
||||||
|
android:name="locationId"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
</action>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/hashTagFragment"
|
android:id="@+id/hashTagFragment"
|
||||||
android:name="awais.instagrabber.fragments.HashTagFragment"
|
android:name="awais.instagrabber.fragments.HashTagFragment"
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
android:id="@+id/location_nav_graph"
|
android:id="@+id/location_nav_graph"
|
||||||
app:startDestination="@id/locationFragment">
|
app:startDestination="@id/locationFragment">
|
||||||
|
|
||||||
<!--<include app:graph="@navigation/post_view_nav_graph" />-->
|
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_postViewFragment"
|
android:id="@+id/action_global_postViewFragment"
|
||||||
app:destination="@id/post_view_nav_graph">
|
app:destination="@id/post_view_nav_graph">
|
||||||
@ -21,6 +19,43 @@
|
|||||||
app:argType="boolean" />
|
app:argType="boolean" />
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<include app:graph="@navigation/comments_nav_graph" />
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_commentsViewerFragment"
|
||||||
|
app:destination="@id/comments_nav_graph">
|
||||||
|
<argument
|
||||||
|
android:name="shortCode"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
<argument
|
||||||
|
android:name="postId"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
<argument
|
||||||
|
android:name="postUserId"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
</action>
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_profileFragment"
|
||||||
|
app:destination="@id/profile_nav_graph">
|
||||||
|
<argument
|
||||||
|
android:name="username"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="true" />
|
||||||
|
</action>
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_hashTagFragment"
|
||||||
|
app:destination="@id/hashtag_nav_graph">
|
||||||
|
<argument
|
||||||
|
android:name="hashtag"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
</action>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/locationFragment"
|
android:id="@+id/locationFragment"
|
||||||
android:name="awais.instagrabber.fragments.LocationFragment"
|
android:name="awais.instagrabber.fragments.LocationFragment"
|
||||||
|
Loading…
Reference in New Issue
Block a user