Add delete option in post view. Fixes 1 part of https://github.com/austinhuang0131/barinsta/issues/289
This commit is contained in:
parent
7b578e0462
commit
839e30a4e5
@ -24,7 +24,6 @@ import android.util.Log;
|
|||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -132,8 +131,10 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
|||||||
private PostViewV2ViewModel viewModel;
|
private PostViewV2ViewModel viewModel;
|
||||||
private PopupMenu optionsPopup;
|
private PopupMenu optionsPopup;
|
||||||
private EditTextDialogFragment editTextDialogFragment;
|
private EditTextDialogFragment editTextDialogFragment;
|
||||||
|
private boolean wasDeleted;
|
||||||
private MutableLiveData<Object> backStackSavedStateResultLiveData;
|
private MutableLiveData<Object> backStackSavedStateResultLiveData;
|
||||||
|
private OnDeleteListener onDeleteListener;
|
||||||
|
|
||||||
private final Observer<Object> backStackSavedStateObserver = result -> {
|
private final Observer<Object> backStackSavedStateObserver = result -> {
|
||||||
if (result == null) return;
|
if (result == null) return;
|
||||||
if (result instanceof String) {
|
if (result instanceof String) {
|
||||||
@ -196,6 +197,15 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
|||||||
this.onShowListener = onShowListener;
|
this.onShowListener = onShowListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOnDeleteListener(final OnDeleteListener onDeleteListener) {
|
||||||
|
if (onDeleteListener == null) return;
|
||||||
|
this.onDeleteListener = onDeleteListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnDeleteListener {
|
||||||
|
void onDelete();
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private final Media feedModel;
|
private final Media feedModel;
|
||||||
private View profilePicElement;
|
private View profilePicElement;
|
||||||
@ -540,7 +550,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
|||||||
viewModel.getSaved().observe(getViewLifecycleOwner(), this::setSavedResources);
|
viewModel.getSaved().observe(getViewLifecycleOwner(), this::setSavedResources);
|
||||||
viewModel.getOptions().observe(getViewLifecycleOwner(), options -> binding.getRoot().post(() -> {
|
viewModel.getOptions().observe(getViewLifecycleOwner(), options -> binding.getRoot().post(() -> {
|
||||||
setupOptions(options != null && !options.isEmpty());
|
setupOptions(options != null && !options.isEmpty());
|
||||||
createOptionsPopupMenu(options);
|
createOptionsPopupMenu();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,30 +1385,73 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createOptionsPopupMenu(final List<Integer> options) {
|
private void createOptionsPopupMenu() {
|
||||||
if (options == null) return;
|
|
||||||
if (optionsPopup == null) {
|
if (optionsPopup == null) {
|
||||||
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle);
|
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle);
|
||||||
optionsPopup = new PopupMenu(themeWrapper, binding.options);
|
optionsPopup = new PopupMenu(themeWrapper, binding.options);
|
||||||
|
} else {
|
||||||
|
optionsPopup.getMenu().clear();
|
||||||
}
|
}
|
||||||
optionsPopup.getMenuInflater().inflate(R.menu.post_view_menu, optionsPopup.getMenu());
|
optionsPopup.getMenuInflater().inflate(R.menu.post_view_menu, optionsPopup.getMenu());
|
||||||
final Menu menu = optionsPopup.getMenu();
|
// final Menu menu = optionsPopup.getMenu();
|
||||||
final int size = menu.size();
|
// final int size = menu.size();
|
||||||
for (int i = 0; i < size; i++) {
|
// for (int i = 0; i < size; i++) {
|
||||||
final MenuItem item = menu.getItem(i);
|
// final MenuItem item = menu.getItem(i);
|
||||||
if (item == null) continue;
|
// if (item == null) continue;
|
||||||
if (options.contains(item.getItemId())) continue;
|
// if (options.contains(item.getItemId())) continue;
|
||||||
menu.removeItem(item.getItemId());
|
// menu.removeItem(item.getItemId());
|
||||||
}
|
// }
|
||||||
optionsPopup.setOnMenuItemClickListener(item -> {
|
optionsPopup.setOnMenuItemClickListener(item -> {
|
||||||
int itemId = item.getItemId();
|
int itemId = item.getItemId();
|
||||||
if (itemId == R.id.edit_caption) {
|
if (itemId == R.id.edit_caption) {
|
||||||
showCaptionEditDialog();
|
showCaptionEditDialog();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (itemId == R.id.delete) {
|
||||||
|
item.setEnabled(false);
|
||||||
|
final LiveData<Resource<Object>> resourceLiveData = viewModel.delete();
|
||||||
|
handleDeleteResource(resourceLiveData, item);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleDeleteResource(final LiveData<Resource<Object>> resourceLiveData, final MenuItem item) {
|
||||||
|
if (resourceLiveData == null) return;
|
||||||
|
resourceLiveData.observe(getViewLifecycleOwner(), new Observer<Resource<Object>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(final Resource<Object> resource) {
|
||||||
|
try {
|
||||||
|
switch (resource.status) {
|
||||||
|
case SUCCESS:
|
||||||
|
wasDeleted = true;
|
||||||
|
if (onDeleteListener != null) {
|
||||||
|
onDeleteListener.onDelete();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
if (item != null) {
|
||||||
|
item.setEnabled(true);
|
||||||
|
}
|
||||||
|
final Snackbar snackbar = Snackbar.make(binding.getRoot(),
|
||||||
|
R.string.delete_unsuccessful,
|
||||||
|
Snackbar.LENGTH_INDEFINITE);
|
||||||
|
snackbar.setAction(R.string.ok, null);
|
||||||
|
snackbar.show();
|
||||||
|
break;
|
||||||
|
case LOADING:
|
||||||
|
if (item != null) {
|
||||||
|
item.setEnabled(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
resourceLiveData.removeObserver(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void showCaptionEditDialog() {
|
private void showCaptionEditDialog() {
|
||||||
final Caption caption = viewModel.getCaption().getValue();
|
final Caption caption = viewModel.getCaption().getValue();
|
||||||
final String captionText = caption != null ? caption.getText() : null;
|
final String captionText = caption != null ? caption.getText() : null;
|
||||||
@ -1561,4 +1614,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
|||||||
}
|
}
|
||||||
return navController;
|
return navController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean wasDeleted() {
|
||||||
|
return wasDeleted;
|
||||||
|
}
|
||||||
}
|
}
|
@ -258,7 +258,12 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
builder.setSharedProfilePicElement(profilePicView)
|
builder.setSharedProfilePicElement(profilePicView)
|
||||||
.setSharedMainPostElement(mainPostImage);
|
.setSharedMainPostElement(mainPostImage);
|
||||||
}
|
}
|
||||||
builder.build().show(getChildFragmentManager(), "post_view");
|
final PostViewV2Fragment postViewV2Fragment = builder.build();
|
||||||
|
postViewV2Fragment.setOnDeleteListener(() -> {
|
||||||
|
postViewV2Fragment.dismiss();
|
||||||
|
binding.postsRecyclerView.refresh();
|
||||||
|
});
|
||||||
|
postViewV2Fragment.show(getChildFragmentManager(), "post_view");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() {
|
private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() {
|
||||||
@ -1086,7 +1091,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
|
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
|
||||||
profileDetailsBinding.btnDM.setEnabled(true);
|
profileDetailsBinding.btnDM.setEnabled(true);
|
||||||
}).execute();
|
}).execute();
|
||||||
});
|
});
|
||||||
profileDetailsBinding.mainProfileImage.setOnClickListener(v -> {
|
profileDetailsBinding.mainProfileImage.setOnClickListener(v -> {
|
||||||
if (!hasStories) {
|
if (!hasStories) {
|
||||||
// show profile pic
|
// show profile pic
|
||||||
@ -1160,7 +1165,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateSwipeRefreshState() {
|
private void updateSwipeRefreshState() {
|
||||||
Log.d("austin_debug", "usrs: "+binding.postsRecyclerView.isFetching());
|
Log.d("austin_debug", "usrs: " + binding.postsRecyclerView.isFetching());
|
||||||
binding.swipeRefreshLayout.setRefreshing(binding.postsRecyclerView.isFetching());
|
binding.swipeRefreshLayout.setRefreshing(binding.postsRecyclerView.isFetching());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import retrofit2.http.GET;
|
|||||||
import retrofit2.http.Header;
|
import retrofit2.http.Header;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
import retrofit2.http.Path;
|
import retrofit2.http.Path;
|
||||||
|
import retrofit2.http.Query;
|
||||||
import retrofit2.http.QueryMap;
|
import retrofit2.http.QueryMap;
|
||||||
|
|
||||||
public interface MediaRepository {
|
public interface MediaRepository {
|
||||||
@ -60,4 +61,15 @@ public interface MediaRepository {
|
|||||||
Call<String> uploadFinish(@Header("retry_context") final String retryContext,
|
Call<String> uploadFinish(@Header("retry_context") final String retryContext,
|
||||||
@QueryMap Map<String, String> queryParams,
|
@QueryMap Map<String, String> queryParams,
|
||||||
@FieldMap final Map<String, String> signedForm);
|
@FieldMap final Map<String, String> signedForm);
|
||||||
|
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/api/v1/media/{mediaId}/delete/")
|
||||||
|
Call<String> delete(@Path("mediaId") final String mediaId,
|
||||||
|
@Query("media_type") final String mediaType,
|
||||||
|
@FieldMap final Map<String, String> signedForm);
|
||||||
|
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/api/v1/media/{mediaId}/archive/")
|
||||||
|
Call<String> archive(@Path("mediaId") final String mediaId,
|
||||||
|
@FieldMap final Map<String, String> signedForm);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,9 @@ import awais.instagrabber.utils.CookieUtils;
|
|||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.webservices.MediaService;
|
import awais.instagrabber.webservices.MediaService;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
@ -75,6 +78,7 @@ public class PostViewV2ViewModel extends ViewModel {
|
|||||||
final ImmutableList.Builder<Integer> builder = ImmutableList.builder();
|
final ImmutableList.Builder<Integer> builder = ImmutableList.builder();
|
||||||
if (isLoggedIn && media.getUser() != null && media.getUser().getPk() == viewerId) {
|
if (isLoggedIn && media.getUser() != null && media.getUser().getPk() == viewerId) {
|
||||||
builder.add(R.id.edit_caption);
|
builder.add(R.id.edit_caption);
|
||||||
|
builder.add(R.id.delete);
|
||||||
}
|
}
|
||||||
options.postValue(builder.build());
|
options.postValue(builder.build());
|
||||||
}
|
}
|
||||||
@ -290,4 +294,36 @@ public class PostViewV2ViewModel extends ViewModel {
|
|||||||
public void setViewCount(final Long viewCount) {
|
public void setViewCount(final Long viewCount) {
|
||||||
this.viewCount.postValue(viewCount);
|
this.viewCount.postValue(viewCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<Resource<Object>> delete() {
|
||||||
|
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||||
|
data.postValue(Resource.loading(null));
|
||||||
|
final Call<String> request = mediaService.delete(media.getId(), media.getMediaType());
|
||||||
|
if (request == null) {
|
||||||
|
data.postValue(Resource.success(new Object()));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
request.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
data.postValue(Resource.error(R.string.generic_null_response, null));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String body = response.body();
|
||||||
|
if (body == null) {
|
||||||
|
data.postValue(Resource.error(R.string.generic_null_response, null));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.postValue(Resource.success(new Object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||||
|
Log.e(TAG, "onFailure: ", t);
|
||||||
|
data.postValue(Resource.error(t.getMessage(), null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import android.util.Log;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@ -17,6 +18,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import awais.instagrabber.models.enums.MediaItemType;
|
||||||
import awais.instagrabber.repositories.MediaRepository;
|
import awais.instagrabber.repositories.MediaRepository;
|
||||||
import awais.instagrabber.repositories.requests.UploadFinishOptions;
|
import awais.instagrabber.repositories.requests.UploadFinishOptions;
|
||||||
import awais.instagrabber.repositories.responses.LikersResponse;
|
import awais.instagrabber.repositories.responses.LikersResponse;
|
||||||
@ -33,6 +35,9 @@ import retrofit2.Retrofit;
|
|||||||
|
|
||||||
public class MediaService extends BaseService {
|
public class MediaService extends BaseService {
|
||||||
private static final String TAG = "MediaService";
|
private static final String TAG = "MediaService";
|
||||||
|
private static final List<MediaItemType> DELETABLE_ITEMS_TYPES = ImmutableList.of(MediaItemType.MEDIA_TYPE_IMAGE,
|
||||||
|
MediaItemType.MEDIA_TYPE_VIDEO,
|
||||||
|
MediaItemType.MEDIA_TYPE_SLIDER);
|
||||||
|
|
||||||
private final MediaRepository repository;
|
private final MediaRepository repository;
|
||||||
private final String deviceUuid, csrfToken;
|
private final String deviceUuid, csrfToken;
|
||||||
@ -444,4 +449,31 @@ public class MediaService extends BaseService {
|
|||||||
final Map<String, String> signedForm = Utils.sign(formBuilder.build());
|
final Map<String, String> signedForm = Utils.sign(formBuilder.build());
|
||||||
return repository.uploadFinish(MediaUploadHelper.getRetryContextString(), queryMap, signedForm);
|
return repository.uploadFinish(MediaUploadHelper.getRetryContextString(), queryMap, signedForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Call<String> delete(@NonNull final String postId,
|
||||||
|
@NonNull final MediaItemType type) {
|
||||||
|
if (!DELETABLE_ITEMS_TYPES.contains(type)) return null;
|
||||||
|
final Map<String, Object> form = new HashMap<>();
|
||||||
|
form.put("_csrftoken", csrfToken);
|
||||||
|
form.put("_uid", userId);
|
||||||
|
form.put("_uuid", deviceUuid);
|
||||||
|
form.put("igtv_feed_preview", "false");
|
||||||
|
form.put("media_id", postId);
|
||||||
|
final Map<String, String> signedForm = Utils.sign(form);
|
||||||
|
final String mediaType;
|
||||||
|
switch (type) {
|
||||||
|
case MEDIA_TYPE_IMAGE:
|
||||||
|
mediaType = "PHOTO";
|
||||||
|
break;
|
||||||
|
case MEDIA_TYPE_VIDEO:
|
||||||
|
mediaType = "VIDEO";
|
||||||
|
break;
|
||||||
|
case MEDIA_TYPE_SLIDER:
|
||||||
|
mediaType = "CAROUSEL";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return repository.delete(postId, mediaType, signedForm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,7 @@
|
|||||||
<item
|
<item
|
||||||
android:id="@+id/edit_caption"
|
android:id="@+id/edit_caption"
|
||||||
android:title="@string/edit_caption" />
|
android:title="@string/edit_caption" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/delete"
|
||||||
|
android:title="@string/delete" />
|
||||||
</menu>
|
</menu>
|
@ -467,4 +467,5 @@
|
|||||||
<string name="generic_not_ok_response">Response status is not ok!</string>
|
<string name="generic_not_ok_response">Response status is not ok!</string>
|
||||||
<string name="generic_failed_request">Request failed!</string>
|
<string name="generic_failed_request">Request failed!</string>
|
||||||
<string name="marked_as_seen">Marked as seen</string>
|
<string name="marked_as_seen">Marked as seen</string>
|
||||||
|
<string name="delete_unsuccessful">Delete unsuccessful</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user