Share posts via DM. Resolves part of austinhuang0131/barinsta#537

This commit is contained in:
Ammar Githam 2021-05-23 15:57:01 +09:00
parent 0dfdc4bb41
commit 742b696d17
17 changed files with 412 additions and 64 deletions

View File

@ -14,6 +14,7 @@ import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
@ -68,8 +69,10 @@ import com.skydoves.balloon.overlay.BalloonOverlayCircle;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import awais.instagrabber.R;
import awais.instagrabber.UserSearchNavGraphDirections;
import awais.instagrabber.activities.MainActivity;
import awais.instagrabber.adapters.SliderCallbackAdapter;
import awais.instagrabber.adapters.SliderItemsAdapter;
@ -93,6 +96,7 @@ import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.VideoVersion;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.NullSafePair;
import awais.instagrabber.utils.NumberUtils;
@ -124,6 +128,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
private PopupMenu optionsPopup;
private EditTextDialogFragment editTextDialogFragment;
private boolean wasDeleted;
private MutableLiveData<Object> backStackSavedStateCollectionLiveData;
private MutableLiveData<Object> backStackSavedStateResultLiveData;
private OnDeleteListener onDeleteListener;
@Nullable
@ -131,7 +136,6 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
private LayoutPostViewBottomBinding bottom;
private View postView;
private int originalHeight;
private int originalSystemUi;
private boolean isInFullScreenMode;
private StyledPlayerView playerView;
private int playerViewOriginalHeight;
@ -145,8 +149,28 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
if (result instanceof String) {
final String collection = (String) result;
handleSaveUnsaveResourceLiveData(viewModel.toggleSave(collection, viewModel.getMedia().getHasViewerSaved()));
} else if ((result instanceof RankedRecipient)) {
// Log.d(TAG, "result: " + result);
final Context context = getContext();
if (context != null) {
Toast.makeText(context, R.string.sending, Toast.LENGTH_SHORT).show();
}
viewModel.shareDm((RankedRecipient) result);
} else if ((result instanceof Set)) {
try {
// Log.d(TAG, "result: " + result);
final Context context = getContext();
if (context != null) {
Toast.makeText(context, R.string.sending, Toast.LENGTH_SHORT).show();
}
//noinspection unchecked
viewModel.shareDm((Set<RankedRecipient>) result);
} catch (Exception e) {
Log.e(TAG, "share: ", e);
}
}
// clear result
backStackSavedStateCollectionLiveData.postValue(null);
backStackSavedStateResultLiveData.postValue(null);
};
@ -193,7 +217,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
// wasPaused = true;
if (settingsHelper.getBoolean(PreferenceKeys.PLAY_IN_BACKGROUND)) return;
final Media media = viewModel.getMedia();
if (media == null) return;
if (media == null || media.getMediaType() == null) return;
switch (media.getMediaType()) {
case MEDIA_TYPE_VIDEO:
if (videoPlayerViewHelper != null) {
@ -214,7 +238,9 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
final NavController navController = NavHostFragment.findNavController(this);
final NavBackStackEntry backStackEntry = navController.getCurrentBackStackEntry();
if (backStackEntry != null) {
backStackSavedStateResultLiveData = backStackEntry.getSavedStateHandle().getLiveData("collection");
backStackSavedStateCollectionLiveData = backStackEntry.getSavedStateHandle().getLiveData("collection");
backStackSavedStateCollectionLiveData.observe(getViewLifecycleOwner(), backStackSavedStateObserver);
backStackSavedStateResultLiveData = backStackEntry.getSavedStateHandle().getLiveData("result");
backStackSavedStateResultLiveData.observe(getViewLifecycleOwner(), backStackSavedStateObserver);
}
}
@ -224,7 +250,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
super.onDestroyView();
showSystemUI();
final Media media = viewModel.getMedia();
if (media == null) return;
if (media == null || media.getMediaType() == null) return;
switch (media.getMediaType()) {
case MEDIA_TYPE_VIDEO:
if (videoPlayerViewHelper != null) {
@ -740,14 +766,55 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
// is this necessary?
Toast.makeText(context, R.string.share_private_post, Toast.LENGTH_LONG).show();
}
final Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, "https://instagram.com/p/" + media.getCode());
startActivity(Intent.createChooser(sharingIntent,
isPrivate ? getString(R.string.share_private_post) : getString(R.string.share_public_post)));
if (viewModel.isLoggedIn()) {
final Context context = getContext();
if (context == null) return;
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle);
final PopupMenu popupMenu = new PopupMenu(themeWrapper, bottom.share);
final Menu menu = popupMenu.getMenu();
menu.add(0, R.id.share_dm, 0, R.string.share_via_dm);
menu.add(0, R.id.share, 1, R.string.share_link);
popupMenu.setOnMenuItemClickListener(item -> {
final int itemId = item.getItemId();
if (itemId == R.id.share_dm) {
final UserSearchNavGraphDirections.ActionGlobalUserSearch actionGlobalUserSearch = UserSearchFragmentDirections
.actionGlobalUserSearch()
.setTitle(getString(R.string.share))
.setActionLabel(getString(R.string.send))
.setShowGroups(true)
.setMultiple(true)
.setSearchMode(UserSearchFragment.SearchMode.RAVEN);
final NavController navController = NavHostFragment.findNavController(PostViewV2Fragment.this);
try {
navController.navigate(actionGlobalUserSearch);
} catch (Exception e) {
Log.e(TAG, "setupShare: ", e);
}
return true;
} else if (itemId == R.id.share) {
shareLink(media, isPrivate);
return true;
}
return false;
});
popupMenu.show();
return;
}
shareLink(media, isPrivate);
});
}
private void shareLink(@NonNull final Media media, final boolean isPrivate) {
final Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, "https://instagram.com/p/" + media.getCode());
startActivity(Intent.createChooser(
sharingIntent,
isPrivate ? getString(R.string.share_private_post)
: getString(R.string.share_public_post)
));
}
private void setupPostTypeLayout(final MediaItemType type) {
if (type == null) return;
switch (type) {
@ -1246,7 +1313,9 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
}
private void toggleDetails() {
final boolean hasBeenToggled = true;
// final boolean hasBeenToggled = true;
final MainActivity activity = (MainActivity) getActivity();
if (activity == null) return;
final Media media = viewModel.getMedia();
binding.getRoot().post(() -> {
TransitionManager.beginDelayedTransition(binding.getRoot());
@ -1268,8 +1337,9 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
playerView.getLayoutParams().height = fullHeight;
}
}
final BottomNavigationView bottomNavView = activity.getBottomNavView();
bottomNavView.setVisibility(View.GONE);
detailsVisible = false;
if (media.getUser() != null) {
binding.profilePic.setVisibility(View.GONE);
binding.title.setVisibility(View.GONE);
@ -1310,6 +1380,8 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
playerView = null;
}
}
final BottomNavigationView bottomNavView = activity.getBottomNavView();
bottomNavView.setVisibility(View.VISIBLE);
if (media.getUser() != null) {
binding.profilePic.setVisibility(View.VISIBLE);
binding.title.setVisibility(View.VISIBLE);
@ -1375,8 +1447,6 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
if (toolbar != null) {
toolbar.setVisibility(View.GONE);
}
final BottomNavigationView bottomNavView = activity.getBottomNavView();
bottomNavView.setVisibility(View.GONE);
binding.getRoot().setPadding(binding.getRoot().getPaddingLeft(),
binding.getRoot().getPaddingTop(),
binding.getRoot().getPaddingRight(),
@ -1404,8 +1474,6 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
if (toolbar != null) {
toolbar.setVisibility(View.VISIBLE);
}
final BottomNavigationView bottomNavView = activity.getBottomNavView();
bottomNavView.setVisibility(View.VISIBLE);
final Context context = getContext();
if (context == null) return;
binding.getRoot().setPadding(binding.getRoot().getPaddingLeft(),

View File

@ -1,16 +1,38 @@
package awais.instagrabber.managers;
import android.content.ContentResolver;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.webservices.DirectMessagesService;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class DirectMessagesManager {
private static final String TAG = DirectMessagesManager.class.getSimpleName();
@ -21,6 +43,8 @@ public final class DirectMessagesManager {
private final InboxManager inboxManager;
private final InboxManager pendingInboxManager;
private DirectMessagesService service;
public static DirectMessagesManager getInstance() {
if (instance == null) {
synchronized (LOCK) {
@ -35,26 +59,34 @@ public final class DirectMessagesManager {
private DirectMessagesManager() {
inboxManager = InboxManager.getInstance(false);
pendingInboxManager = InboxManager.getInstance(true);
final String cookie = settingsHelper.getString(Constants.COOKIE);
final long viewerId = CookieUtils.getUserIdFromCookie(cookie);
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
if (csrfToken == null) return;
service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid);
}
public void moveThreadFromPending(@NonNull final String threadId) {
final List<DirectThread> pendingThreads = pendingInboxManager.getThreads().getValue();
if (pendingThreads == null) return;
final int index = Iterables.indexOf(pendingThreads, t -> t.getThreadId().equals(threadId));
final int index = Iterables.indexOf(pendingThreads, t -> t != null && t.getThreadId().equals(threadId));
if (index < 0) return;
final DirectThread thread = pendingThreads.get(index);
final DirectItem threadFirstDirectItem = thread.getFirstDirectItem();
if (threadFirstDirectItem == null) return;
final List<DirectThread> threads = inboxManager.getThreads().getValue();
int insertIndex = 0;
for (final DirectThread tempThread : threads) {
final DirectItem firstDirectItem = tempThread.getFirstDirectItem();
if (firstDirectItem == null) continue;
final long timestamp = firstDirectItem.getTimestamp();
if (timestamp < threadFirstDirectItem.getTimestamp()) {
break;
if (threads != null) {
for (final DirectThread tempThread : threads) {
final DirectItem firstDirectItem = tempThread.getFirstDirectItem();
if (firstDirectItem == null) continue;
final long timestamp = firstDirectItem.getTimestamp();
if (timestamp < threadFirstDirectItem.getTimestamp()) {
break;
}
insertIndex++;
}
insertIndex++;
}
thread.setPending(false);
inboxManager.addThread(thread, insertIndex);
@ -78,4 +110,166 @@ public final class DirectMessagesManager {
@NonNull final ContentResolver contentResolver) {
return ThreadManager.getInstance(threadId, pending, currentUser, contentResolver);
}
public void createThread(final long userPk,
@Nullable final Function<DirectThread, Void> callback) {
if (service == null) return;
final Call<DirectThread> createThreadRequest = service.createThread(Collections.singletonList(userPk), null);
createThreadRequest.enqueue(new Callback<DirectThread>() {
@Override
public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) {
if (!response.isSuccessful()) {
if (response.errorBody() != null) {
try {
final String string = response.errorBody().string();
final String msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string);
Log.e(TAG, msg);
} catch (IOException e) {
Log.e(TAG, "onResponse: ", e);
}
return;
}
Log.e(TAG, "onResponse: request was not successful and response error body was null");
return;
}
final DirectThread thread = response.body();
if (thread == null) {
Log.e(TAG, "onResponse: thread is null");
return;
}
if (callback != null) {
callback.apply(thread);
}
}
@Override
public void onFailure(@NonNull final Call<DirectThread> call, @NonNull final Throwable t) {
}
});
}
public void sendMedia(@NonNull final Set<RankedRecipient> recipients, final String mediaId) {
final int[] resultsCount = {0};
final Function<Void, Void> callback = unused -> {
resultsCount[0]++;
if (resultsCount[0] == recipients.size()) {
inboxManager.refresh();
}
return null;
};
for (final RankedRecipient recipient : recipients) {
if (recipient == null) continue;
sendMedia(recipient, mediaId, false, callback);
}
}
public void sendMedia(@NonNull final RankedRecipient recipient, final String mediaId) {
sendMedia(recipient, mediaId, true, null);
}
private void sendMedia(@NonNull final RankedRecipient recipient,
@NonNull final String mediaId,
final boolean refreshInbox,
@Nullable final Function<Void, Void> callback) {
if (recipient.getThread() == null && recipient.getUser() != null) {
// create thread and forward
createThread(recipient.getUser().getPk(), directThread -> {
sendMedia(directThread, mediaId, unused -> {
if (refreshInbox) {
inboxManager.refresh();
}
if (callback != null) {
callback.apply(null);
}
return null;
});
return null;
});
}
if (recipient.getThread() == null) return;
// just forward
final DirectThread thread = recipient.getThread();
sendMedia(thread, mediaId, unused -> {
if (refreshInbox) {
inboxManager.refresh();
}
if (callback != null) {
callback.apply(null);
}
return null;
});
}
@NonNull
public LiveData<Resource<Object>> sendMedia(@NonNull final DirectThread thread,
@NonNull final String mediaId,
@Nullable final Function<Void, Void> callback) {
return sendMedia(thread.getThreadId(), mediaId, callback);
}
@NonNull
public LiveData<Resource<Object>> sendMedia(@NonNull final String threadId,
@NonNull final String mediaId,
@Nullable final Function<Void, Void> callback) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
final Call<DirectThreadBroadcastResponse> request = service.broadcastMediaShare(
UUID.randomUUID().toString(),
BroadcastOptions.ThreadIdOrUserIds.of(threadId),
mediaId
);
request.enqueue(new Callback<DirectThreadBroadcastResponse>() {
@Override
public void onResponse(@NonNull final Call<DirectThreadBroadcastResponse> call,
@NonNull final Response<DirectThreadBroadcastResponse> response) {
if (response.isSuccessful()) {
data.postValue(Resource.success(new Object()));
if (callback != null) {
callback.apply(null);
}
return;
}
if (response.errorBody() != null) {
try {
final String string = response.errorBody().string();
final String msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string);
Log.e(TAG, msg);
data.postValue(Resource.error(msg, null));
} catch (IOException e) {
Log.e(TAG, "onResponse: ", e);
data.postValue(Resource.error(e.getMessage(), null));
}
if (callback != null) {
callback.apply(null);
}
return;
}
final String msg = "onResponse: request was not successful and response error body was null";
Log.e(TAG, msg);
data.postValue(Resource.error(msg, null));
if (callback != null) {
callback.apply(null);
}
}
@Override
public void onFailure(@NonNull final Call<DirectThreadBroadcastResponse> call, @NonNull final Throwable t) {
Log.e(TAG, "onFailure: ", t);
data.postValue(Resource.error(t.getMessage(), null));
if (callback != null) {
callback.apply(null);
}
}
});
return data;
}
}

View File

@ -96,6 +96,7 @@ public final class ThreadManager {
private final ThreadIdOrUserIds threadIdOrUserIds;
private final User currentUser;
private final ContentResolver contentResolver;
private final DirectMessagesManager messagesManager;
private DirectMessagesService service;
private MediaService mediaService;
@ -147,7 +148,7 @@ public final class ThreadManager {
final boolean pending,
@NonNull final User currentUser,
@NonNull final ContentResolver contentResolver) {
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
messagesManager = DirectMessagesManager.getInstance();
this.inboxManager = pending ? messagesManager.getPendingInboxManager() : messagesManager.getInboxManager();
this.threadId = threadId;
this.threadIdOrUserIds = ThreadIdOrUserIds.of(threadId);
@ -821,42 +822,10 @@ public final class ThreadManager {
if (recipient == null || itemToForward == null) return;
if (recipient.getThread() == null && recipient.getUser() != null) {
// create thread and forward
final Call<DirectThread> createThreadRequest = service.createThread(Collections.singletonList(recipient.getUser().getPk()), null);
createThreadRequest.enqueue(new Callback<DirectThread>() {
@Override
public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) {
if (!response.isSuccessful()) {
if (response.errorBody() != null) {
try {
final String string = response.errorBody().string();
final String msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string);
Log.e(TAG, msg);
} catch (IOException e) {
Log.e(TAG, "onResponse: ", e);
}
return;
}
Log.e(TAG, "onResponse: request was not successful and response error body was null");
return;
}
final DirectThread thread = response.body();
if (thread == null) {
Log.e(TAG, "onResponse: thread is null");
return;
}
forward(thread, itemToForward);
}
@Override
public void onFailure(@NonNull final Call<DirectThread> call, @NonNull final Throwable t) {
}
messagesManager.createThread(recipient.getUser().getPk(), directThread -> {
forward(directThread, itemToForward);
return null;
});
return;
}
if (recipient.getThread() != null) {
// just forward
@ -870,13 +839,25 @@ public final class ThreadManager {
replyToItem.postValue(item);
}
private void forward(@NonNull final DirectThread thread, @NonNull final DirectItem itemToForward) {
@NonNull
private LiveData<Resource<Object>> forward(@NonNull final DirectThread thread, @NonNull final DirectItem itemToForward) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
if (itemToForward.getItemId() == null) {
data.postValue(Resource.error("item id is null", null));
return data;
}
final DirectItemType itemType = itemToForward.getItemType();
if (itemType == null) {
data.postValue(Resource.error("item type is null", null));
return data;
}
final String itemTypeName = itemType.getName();
if (itemTypeName == null) {
Log.e(TAG, "forward: itemTypeName was null!");
return;
data.postValue(Resource.error("itemTypeName is null", null));
return data;
}
data.postValue(Resource.loading(null));
final Call<DirectThreadBroadcastResponse> request = service.forward(thread.getThreadId(),
itemTypeName,
threadId,
@ -885,7 +866,10 @@ public final class ThreadManager {
@Override
public void onResponse(@NonNull final Call<DirectThreadBroadcastResponse> call,
@NonNull final Response<DirectThreadBroadcastResponse> response) {
if (response.isSuccessful()) return;
if (response.isSuccessful()) {
data.postValue(Resource.success(new Object()));
return;
}
if (response.errorBody() != null) {
try {
final String string = response.errorBody().string();
@ -895,19 +879,25 @@ public final class ThreadManager {
response.code(),
string);
Log.e(TAG, msg);
data.postValue(Resource.error(msg, null));
} catch (IOException e) {
Log.e(TAG, "onResponse: ", e);
data.postValue(Resource.error(e.getMessage(), null));
}
return;
}
Log.e(TAG, "onResponse: request was not successful and response error body was null");
final String msg = "onResponse: request was not successful and response error body was null";
Log.e(TAG, msg);
data.postValue(Resource.error(msg, null));
}
@Override
public void onFailure(@NonNull final Call<DirectThreadBroadcastResponse> call, @NonNull final Throwable t) {
Log.e(TAG, "onFailure: ", t);
data.postValue(Resource.error(t.getMessage(), null));
}
});
return data;
}
public LiveData<Resource<Object>> acceptRequest() {

View File

@ -8,7 +8,8 @@ public enum BroadcastItemType {
LINK("link"),
VIDEO("configure_video"),
VOICE("share_voice"),
ANIMATED_MEDIA("animated_media");
ANIMATED_MEDIA("animated_media"),
MEDIA_SHARE("media_share");
private final String value;

View File

@ -0,0 +1,18 @@
package awais.instagrabber.repositories.requests.directmessages
import awais.instagrabber.models.enums.BroadcastItemType
class MediaShareBroadcastOptions(
clientContext: String?,
threadIdOrUserIds: ThreadIdOrUserIds,
val mediaId: String
) : BroadcastOptions(
clientContext,
threadIdOrUserIds,
BroadcastItemType.MEDIA_SHARE
) {
override fun getFormMap(): Map<String, String> {
return mapOf("media_id" to mediaId)
}
}

View File

@ -11,14 +11,17 @@ import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import awais.instagrabber.R;
import awais.instagrabber.managers.DirectMessagesManager;
import awais.instagrabber.models.Resource;
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.repositories.responses.Caption;
import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.TextUtils;
@ -49,6 +52,7 @@ public class PostViewV2ViewModel extends ViewModel {
private final boolean isLoggedIn;
private Media media;
private DirectMessagesManager messageManager;
public PostViewV2ViewModel() {
final String cookie = settingsHelper.getString(Constants.COOKIE);
@ -326,4 +330,18 @@ public class PostViewV2ViewModel extends ViewModel {
});
return data;
}
public void shareDm(@NonNull final RankedRecipient result) {
if (messageManager == null) {
messageManager = DirectMessagesManager.getInstance();
}
messageManager.sendMedia(result, media.getId());
}
public void shareDm(@NonNull final Set<RankedRecipient> recipients) {
if (messageManager == null) {
messageManager = DirectMessagesManager.getInstance();
}
messageManager.sendMedia(recipients, media.getId());
}
}

View File

@ -21,6 +21,7 @@ import awais.instagrabber.repositories.requests.directmessages.AnimatedMediaBroa
import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions;
import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions.ThreadIdOrUserIds;
import awais.instagrabber.repositories.requests.directmessages.LinkBroadcastOptions;
import awais.instagrabber.repositories.requests.directmessages.MediaShareBroadcastOptions;
import awais.instagrabber.repositories.requests.directmessages.PhotoBroadcastOptions;
import awais.instagrabber.repositories.requests.directmessages.ReactionBroadcastOptions;
import awais.instagrabber.repositories.requests.directmessages.StoryReplyBroadcastOptions;
@ -190,6 +191,12 @@ public class DirectMessagesService extends BaseService {
return broadcast(new AnimatedMediaBroadcastOptions(clientContext, threadIdOrUserIds, giphyGif));
}
public Call<DirectThreadBroadcastResponse> broadcastMediaShare(@NonNull final String clientContext,
@NonNull final ThreadIdOrUserIds threadIdOrUserIds,
@NonNull final String mediaId) {
return broadcast(new MediaShareBroadcastOptions(clientContext, threadIdOrUserIds, mediaId));
}
private Call<DirectThreadBroadcastResponse> broadcast(@NonNull final BroadcastOptions broadcastOptions) {
if (TextUtils.isEmpty(broadcastOptions.getClientContext())) {
throw new IllegalArgumentException("Broadcast requires a valid client context value");

View File

@ -111,6 +111,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/discoverFragment"
android:name="awais.instagrabber.fragments.main.DiscoverFragment"

View File

@ -122,6 +122,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/feedFragment"
android:name="awais.instagrabber.fragments.main.FeedFragment"

View File

@ -81,6 +81,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/hashTagFragment"
android:name="awais.instagrabber.fragments.HashTagFragment"

View File

@ -82,6 +82,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/locationFragment"
android:name="awais.instagrabber.fragments.LocationFragment"

View File

@ -73,6 +73,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/morePreferencesFragment"
android:name="awais.instagrabber.fragments.settings.MorePreferencesFragment"

View File

@ -84,6 +84,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/storyViewerFragment"
android:name="awais.instagrabber.fragments.StoryViewerFragment"

View File

@ -98,6 +98,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/notificationsViewer"
android:name="awais.instagrabber.fragments.NotificationsViewerFragment"

View File

@ -76,6 +76,12 @@
app:argType="integer" />
</action>
<include app:graph="@navigation/user_search_nav_graph" />
<action
android:id="@+id/action_global_user_search"
app:destination="@id/user_search_nav_graph" />
<fragment
android:id="@+id/savedCollectionsFragment"
android:name="awais.instagrabber.fragments.SavedCollectionsFragment"

View File

@ -5,4 +5,5 @@
<item name="forward" type="id" />
<item name="detail" type="id" />
<item name="copy" type="id" />
<item name="share_dm" type="id" />
</resources>

View File

@ -508,4 +508,7 @@
<string name="click_to_show_full">Click to show full like count</string>
<string name="no_profile_pic_found">No profile pic found!</string>
<string name="swipe_up_confirmation">Are you sure you want to open this link?</string>
<string name="sending">Sending...</string>
<string name="share_via_dm">Share via DM</string>
<string name="share_link">Share link…</string>
</resources>