mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-10-31 03:25:34 +00:00 
			
		
		
		
	Send stickers and gifs in DM
This commit is contained in:
		
							parent
							
								
									4bb77abb33
								
							
						
					
					
						commit
						6d73528387
					
				| @ -0,0 +1,107 @@ | ||||
| package awais.instagrabber.adapters; | ||||
| 
 | ||||
| import android.net.Uri; | ||||
| import android.util.Log; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.DiffUtil; | ||||
| import androidx.recyclerview.widget.ListAdapter; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import com.facebook.drawee.backends.pipeline.Fresco; | ||||
| import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; | ||||
| import com.facebook.drawee.controller.BaseControllerListener; | ||||
| import com.facebook.drawee.drawable.ScalingUtils; | ||||
| import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; | ||||
| import com.facebook.imagepipeline.common.ResizeOptions; | ||||
| import com.facebook.imagepipeline.image.ImageInfo; | ||||
| import com.facebook.imagepipeline.request.ImageRequest; | ||||
| import com.facebook.imagepipeline.request.ImageRequestBuilder; | ||||
| 
 | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| import awais.instagrabber.databinding.ItemMediaBinding; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public class GifItemsAdapter extends ListAdapter<GiphyGif, GifItemsAdapter.GifViewHolder> { | ||||
| 
 | ||||
|     private static final DiffUtil.ItemCallback<GiphyGif> diffCallback = new DiffUtil.ItemCallback<GiphyGif>() { | ||||
|         @Override | ||||
|         public boolean areItemsTheSame(@NonNull final GiphyGif oldItem, @NonNull final GiphyGif newItem) { | ||||
|             return Objects.equals(oldItem.getId(), newItem.getId()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public boolean areContentsTheSame(@NonNull final GiphyGif oldItem, @NonNull final GiphyGif newItem) { | ||||
|             return Objects.equals(oldItem.getId(), newItem.getId()); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     private final OnItemClickListener onItemClickListener; | ||||
| 
 | ||||
|     public GifItemsAdapter(final OnItemClickListener onItemClickListener) { | ||||
|         super(diffCallback); | ||||
|         this.onItemClickListener = onItemClickListener; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public GifViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { | ||||
|         final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); | ||||
|         final ItemMediaBinding binding = ItemMediaBinding.inflate(layoutInflater, parent, false); | ||||
|         return new GifViewHolder(binding, onItemClickListener); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull final GifViewHolder holder, final int position) { | ||||
|         holder.bind(getItem(position)); | ||||
|     } | ||||
| 
 | ||||
|     public static class GifViewHolder extends RecyclerView.ViewHolder { | ||||
|         private static final String TAG = GifViewHolder.class.getSimpleName(); | ||||
|         private static final int size = Utils.displayMetrics.widthPixels / 3; | ||||
| 
 | ||||
|         private final ItemMediaBinding binding; | ||||
|         private final OnItemClickListener onItemClickListener; | ||||
| 
 | ||||
|         public GifViewHolder(@NonNull final ItemMediaBinding binding, | ||||
|                              final OnItemClickListener onItemClickListener) { | ||||
|             super(binding.getRoot()); | ||||
|             this.binding = binding; | ||||
|             this.onItemClickListener = onItemClickListener; | ||||
|             binding.duration.setVisibility(View.GONE); | ||||
|             final GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(itemView.getResources()); | ||||
|             builder.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER); | ||||
|             binding.item.setHierarchy(builder.build()); | ||||
|         } | ||||
| 
 | ||||
|         public void bind(final GiphyGif item) { | ||||
|             if (onItemClickListener != null) { | ||||
|                 itemView.setOnClickListener(v -> onItemClickListener.onItemClick(item)); | ||||
|             } | ||||
|             final BaseControllerListener<ImageInfo> controllerListener = new BaseControllerListener<ImageInfo>() { | ||||
|                 @Override | ||||
|                 public void onFailure(final String id, final Throwable throwable) { | ||||
|                     Log.e(TAG, "onFailure: ", throwable); | ||||
|                 } | ||||
|             }; | ||||
|             final ImageRequest request = ImageRequestBuilder | ||||
|                     .newBuilderWithSource(Uri.parse(item.getImages().getFixedHeight().getWebp())) | ||||
|                     .setResizeOptions(ResizeOptions.forDimensions(size, size)) | ||||
|                     .build(); | ||||
|             final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder() | ||||
|                                                                   .setImageRequest(request) | ||||
|                                                                   .setAutoPlayAnimations(true) | ||||
|                                                                   .setControllerListener(controllerListener); | ||||
|             binding.item.setController(builder.build()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public interface OnItemClickListener { | ||||
|         void onItemClick(GiphyGif giphyGif); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,150 @@ | ||||
| package awais.instagrabber.dialogs; | ||||
| 
 | ||||
| import android.app.Dialog; | ||||
| import android.content.Context; | ||||
| import android.os.Bundle; | ||||
| import android.text.Editable; | ||||
| import android.util.Log; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.fragment.app.DialogFragment; | ||||
| import androidx.lifecycle.ViewModelProvider; | ||||
| import androidx.recyclerview.widget.GridLayoutManager; | ||||
| 
 | ||||
| import com.google.android.material.bottomsheet.BottomSheetDialog; | ||||
| import com.google.android.material.bottomsheet.BottomSheetDialogFragment; | ||||
| import com.google.android.material.snackbar.Snackbar; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.GifItemsAdapter; | ||||
| import awais.instagrabber.customviews.helpers.TextWatcherAdapter; | ||||
| import awais.instagrabber.databinding.LayoutGifPickerBinding; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| import awais.instagrabber.utils.Debouncer; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.viewmodels.GifPickerViewModel; | ||||
| 
 | ||||
| public class GifPickerBottomDialogFragment extends BottomSheetDialogFragment { | ||||
|     private static final String TAG = GifPickerBottomDialogFragment.class.getSimpleName(); | ||||
|     private static final int INPUT_DEBOUNCE_INTERVAL = 500; | ||||
|     private static final String INPUT_KEY = "gif_search_input"; | ||||
| 
 | ||||
|     private LayoutGifPickerBinding binding; | ||||
|     private GifPickerViewModel viewModel; | ||||
|     private GifItemsAdapter gifItemsAdapter; | ||||
|     private OnSelectListener onSelectListener; | ||||
|     private Debouncer<String> inputDebouncer; | ||||
| 
 | ||||
|     public static GifPickerBottomDialogFragment newInstance() { | ||||
|         final Bundle args = new Bundle(); | ||||
|         final GifPickerBottomDialogFragment fragment = new GifPickerBottomDialogFragment(); | ||||
|         fragment.setArguments(args); | ||||
|         return fragment; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreate(@Nullable final Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setStyle(DialogFragment.STYLE_NORMAL, R.style.ThemeOverlay_Rounded_BottomSheetDialog); | ||||
|         final Debouncer.Callback<String> callback = new Debouncer.Callback<String>() { | ||||
|             @Override | ||||
|             public void call(final String key) { | ||||
|                 final Editable text = binding.input.getText(); | ||||
|                 if (TextUtils.isEmpty(text)) { | ||||
|                     viewModel.search(null); | ||||
|                     return; | ||||
|                 } | ||||
|                 viewModel.search(text.toString().trim()); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onError(final Throwable t) { | ||||
|                 Log.e(TAG, "onError: ", t); | ||||
|             } | ||||
|         }; | ||||
|         inputDebouncer = new Debouncer<>(callback, INPUT_DEBOUNCE_INTERVAL); | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { | ||||
|         binding = LayoutGifPickerBinding.inflate(inflater, container, false); | ||||
|         viewModel = new ViewModelProvider(this).get(GifPickerViewModel.class); | ||||
|         return binding.getRoot(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         final Dialog dialog = getDialog(); | ||||
|         if (dialog == null) return; | ||||
|         final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog; | ||||
|         final View bottomSheetInternal = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); | ||||
|         if (bottomSheetInternal == null) return; | ||||
|         bottomSheetInternal.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; | ||||
|         bottomSheetInternal.requestLayout(); | ||||
|     } | ||||
| 
 | ||||
|     private void init() { | ||||
|         setupList(); | ||||
|         setupInput(); | ||||
|         setupObservers(); | ||||
|     } | ||||
| 
 | ||||
|     private void setupList() { | ||||
|         final Context context = getContext(); | ||||
|         if (context == null) return; | ||||
|         binding.gifList.setLayoutManager(new GridLayoutManager(context, 3)); | ||||
|         binding.gifList.setHasFixedSize(true); | ||||
|         gifItemsAdapter = new GifItemsAdapter(entry -> { | ||||
|             if (onSelectListener == null) return; | ||||
|             onSelectListener.onSelect(entry); | ||||
|         }); | ||||
|         binding.gifList.setAdapter(gifItemsAdapter); | ||||
|     } | ||||
| 
 | ||||
|     private void setupInput() { | ||||
|         binding.input.addTextChangedListener(new TextWatcherAdapter() { | ||||
|             @Override | ||||
|             public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { | ||||
|                 inputDebouncer.call(INPUT_KEY); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private void setupObservers() { | ||||
|         viewModel.getImages().observe(getViewLifecycleOwner(), imagesResource -> { | ||||
|             if (imagesResource == null) return; | ||||
|             switch (imagesResource.status) { | ||||
|                 case SUCCESS: | ||||
|                     gifItemsAdapter.submitList(imagesResource.data); | ||||
|                     break; | ||||
|                 case ERROR: | ||||
|                     final Context context = getContext(); | ||||
|                     if (context != null && imagesResource.message != null) { | ||||
|                         Snackbar.make(context, binding.getRoot(), imagesResource.message, Snackbar.LENGTH_LONG); | ||||
|                     } | ||||
|                     break; | ||||
|                 case LOADING: | ||||
|                     break; | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public void setOnSelectListener(final OnSelectListener onSelectListener) { | ||||
|         this.onSelectListener = onSelectListener; | ||||
|     } | ||||
| 
 | ||||
|     public interface OnSelectListener { | ||||
|         void onSelect(GiphyGif giphyGif); | ||||
|     } | ||||
| } | ||||
| @ -81,6 +81,7 @@ import awais.instagrabber.customviews.helpers.SwipeAndRestoreItemTouchHelperCall | ||||
| import awais.instagrabber.customviews.helpers.TextWatcherAdapter; | ||||
| import awais.instagrabber.databinding.FragmentDirectMessagesThreadBinding; | ||||
| import awais.instagrabber.dialogs.DirectItemReactionDialogFragment; | ||||
| import awais.instagrabber.dialogs.GifPickerBottomDialogFragment; | ||||
| import awais.instagrabber.dialogs.MediaPickerBottomDialogFragment; | ||||
| import awais.instagrabber.fragments.PostViewV2Fragment; | ||||
| import awais.instagrabber.fragments.UserSearchFragment; | ||||
| @ -737,6 +738,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact | ||||
| 
 | ||||
|     private void hideInput() { | ||||
|         binding.emojiToggle.setVisibility(View.GONE); | ||||
|         binding.gif.setVisibility(View.GONE); | ||||
|         binding.camera.setVisibility(View.GONE); | ||||
|         binding.gallery.setVisibility(View.GONE); | ||||
|         binding.input.setVisibility(View.GONE); | ||||
| @ -750,6 +752,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact | ||||
| 
 | ||||
|     private void showInput() { | ||||
|         binding.emojiToggle.setVisibility(View.VISIBLE); | ||||
|         binding.gif.setVisibility(View.VISIBLE); | ||||
|         binding.camera.setVisibility(View.VISIBLE); | ||||
|         binding.gallery.setVisibility(View.VISIBLE); | ||||
|         binding.input.setVisibility(View.VISIBLE); | ||||
| @ -788,16 +791,18 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact | ||||
|                 binding.send.setListenForRecord(true); | ||||
|                 startIconAnimation(); | ||||
|             } | ||||
|             binding.gallery.setVisibility(View.VISIBLE); | ||||
|             binding.gif.setVisibility(View.VISIBLE); | ||||
|             binding.camera.setVisibility(View.VISIBLE); | ||||
|             binding.gallery.setVisibility(View.VISIBLE); | ||||
|             return; | ||||
|         } | ||||
|         if (binding.send.isListenForRecord()) { | ||||
|             binding.send.setListenForRecord(false); | ||||
|             startIconAnimation(); | ||||
|         } | ||||
|         binding.gallery.setVisibility(View.GONE); | ||||
|         binding.gif.setVisibility(View.GONE); | ||||
|         binding.camera.setVisibility(View.GONE); | ||||
|         binding.gallery.setVisibility(View.GONE); | ||||
|     } | ||||
| 
 | ||||
|     private String getDirectItemPreviewText(final DirectItem item) { | ||||
| @ -937,8 +942,9 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact | ||||
|             public void onStart() { | ||||
|                 isRecording = true; | ||||
|                 binding.input.setHint(null); | ||||
|                 binding.gallery.setVisibility(View.GONE); | ||||
|                 binding.gif.setVisibility(View.GONE); | ||||
|                 binding.camera.setVisibility(View.GONE); | ||||
|                 binding.gallery.setVisibility(View.GONE); | ||||
|                 if (PermissionUtils.hasAudioRecordPerms(context)) { | ||||
|                     viewModel.startRecording(); | ||||
|                     return; | ||||
| @ -958,8 +964,9 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact | ||||
|             public void onFinish(final long recordTime) { | ||||
|                 Log.d(TAG, "onFinish"); | ||||
|                 binding.input.setHint("Message"); | ||||
|                 binding.gallery.setVisibility(View.VISIBLE); | ||||
|                 binding.gif.setVisibility(View.VISIBLE); | ||||
|                 binding.camera.setVisibility(View.VISIBLE); | ||||
|                 binding.gallery.setVisibility(View.VISIBLE); | ||||
|                 viewModel.stopRecording(false); | ||||
|                 isRecording = false; | ||||
|             } | ||||
| @ -971,16 +978,18 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact | ||||
|                 if (PermissionUtils.hasAudioRecordPerms(context)) { | ||||
|                     tooltip.show(binding.send); | ||||
|                 } | ||||
|                 binding.gallery.setVisibility(View.VISIBLE); | ||||
|                 binding.gif.setVisibility(View.VISIBLE); | ||||
|                 binding.camera.setVisibility(View.VISIBLE); | ||||
|                 binding.gallery.setVisibility(View.VISIBLE); | ||||
|                 viewModel.stopRecording(true); | ||||
|                 isRecording = false; | ||||
|             } | ||||
|         }); | ||||
|         binding.recordView.setOnBasketAnimationEndListener(() -> { | ||||
|             binding.input.setHint(R.string.dms_thread_message_hint); | ||||
|             binding.gallery.setVisibility(View.VISIBLE); | ||||
|             binding.gif.setVisibility(View.VISIBLE); | ||||
|             binding.camera.setVisibility(View.VISIBLE); | ||||
|             binding.gallery.setVisibility(View.VISIBLE); | ||||
|         }); | ||||
|         binding.input.addTextChangedListener(new TextWatcherAdapter() { | ||||
|             // int prevLength = 0; | ||||
| @ -1057,6 +1066,16 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact | ||||
|             mediaPicker.show(getChildFragmentManager(), "MediaPicker"); | ||||
|             hideKeyboard(true); | ||||
|         }); | ||||
|         binding.gif.setOnClickListener(v -> { | ||||
|             final GifPickerBottomDialogFragment gifPicker = GifPickerBottomDialogFragment.newInstance(); | ||||
|             gifPicker.setOnSelectListener(giphyGif -> { | ||||
|                 gifPicker.dismiss(); | ||||
|                 if (giphyGif == null) return; | ||||
|                 handleSentMessage(viewModel.sendAnimatedMedia(giphyGif)); | ||||
|             }); | ||||
|             gifPicker.show(getChildFragmentManager(), "GifPicker"); | ||||
|             hideKeyboard(true); | ||||
|         }); | ||||
|         binding.camera.setOnClickListener(v -> { | ||||
|             final Intent intent = new Intent(context, CameraActivity.class); | ||||
|             startActivityForResult(intent, CAMERA_REQUEST_CODE); | ||||
|  | ||||
| @ -53,6 +53,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectThreadDeta | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectThreadFeedResponse; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse; | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| import awais.instagrabber.utils.BitmapUtils; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| @ -641,6 +642,24 @@ public final class ThreadManager { | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     public LiveData<Resource<Object>> sendAnimatedMedia(@NonNull final GiphyGif giphyGif) { | ||||
|         final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); | ||||
|         final Long userId = getCurrentUserId(data); | ||||
|         if (userId == null) return data; | ||||
|         final String clientContext = UUID.randomUUID().toString(); | ||||
|         final DirectItem directItem = DirectItemFactory.createAnimatedMedia(userId, clientContext, giphyGif); | ||||
|         directItem.setPending(true); | ||||
|         addItems(0, Collections.singletonList(directItem)); | ||||
|         data.postValue(Resource.loading(directItem)); | ||||
|         final Call<DirectThreadBroadcastResponse> request = service.broadcastAnimatedMedia( | ||||
|                 clientContext, | ||||
|                 threadIdOrUserIds, | ||||
|                 giphyGif | ||||
|         ); | ||||
|         enqueueRequest(request, data, directItem); | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     public void sendVoice(@NonNull final MutableLiveData<Resource<Object>> data, | ||||
|                           @NonNull final Uri uri, | ||||
|                           @NonNull final List<Float> waveform, | ||||
|  | ||||
| @ -7,7 +7,8 @@ public enum BroadcastItemType { | ||||
|     IMAGE("configure_photo"), | ||||
|     LINK("link"), | ||||
|     VIDEO("configure_video"), | ||||
|     VOICE("share_voice"); | ||||
|     VOICE("share_voice"), | ||||
|     ANIMATED_MEDIA("animated_media"); | ||||
| 
 | ||||
|     private final String value; | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,14 @@ | ||||
| package awais.instagrabber.repositories; | ||||
| 
 | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGifResponse; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.http.GET; | ||||
| import retrofit2.http.Query; | ||||
| 
 | ||||
| public interface GifRepository { | ||||
| 
 | ||||
|     @GET("/api/v1/creatives/story_media_search_keyed_format/") | ||||
|     Call<GiphyGifResponse> searchGiphyGifs(@Query("request_surface") final String requestSurface, | ||||
|                                            @Query("q") final String query, | ||||
|                                            @Query("media_types") final String mediaTypes); | ||||
| } | ||||
| @ -0,0 +1,27 @@ | ||||
| package awais.instagrabber.repositories.requests.directmessages; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import awais.instagrabber.models.enums.BroadcastItemType; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| 
 | ||||
| public class AnimatedMediaBroadcastOptions extends BroadcastOptions { | ||||
| 
 | ||||
|     private final GiphyGif giphyGif; | ||||
| 
 | ||||
|     public AnimatedMediaBroadcastOptions(final String clientContext, | ||||
|                                          final ThreadIdOrUserIds threadIdOrUserIds, | ||||
|                                          final GiphyGif giphyGif) { | ||||
|         super(clientContext, threadIdOrUserIds, BroadcastItemType.ANIMATED_MEDIA); | ||||
|         this.giphyGif = giphyGif; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Map<String, String> getFormMap() { | ||||
|         final Map<String, String> form = new HashMap<>(); | ||||
|         form.put("is_sticker", String.valueOf(giphyGif.isSticker())); | ||||
|         form.put("id", giphyGif.getId()); | ||||
|         return form; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,70 @@ | ||||
| package awais.instagrabber.repositories.responses.giphy; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| public class GiphyGif { | ||||
|     private final String type; | ||||
|     private final String id; | ||||
|     private final String title; | ||||
|     private final int isSticker; | ||||
|     private final GiphyGifImages images; | ||||
| 
 | ||||
|     public GiphyGif(final String type, final String id, final String title, final int isSticker, final GiphyGifImages images) { | ||||
|         this.type = type; | ||||
|         this.id = id; | ||||
|         this.title = title; | ||||
|         this.isSticker = isSticker; | ||||
|         this.images = images; | ||||
|     } | ||||
| 
 | ||||
|     public String getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     public String getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public String getTitle() { | ||||
|         return title; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isSticker() { | ||||
|         return isSticker ==  1; | ||||
|     } | ||||
| 
 | ||||
|     public GiphyGifImages getImages() { | ||||
|         return images; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(final Object o) { | ||||
|         if (this == o) return true; | ||||
|         if (o == null || getClass() != o.getClass()) return false; | ||||
|         final GiphyGif giphyGif = (GiphyGif) o; | ||||
|         return isSticker == giphyGif.isSticker && | ||||
|                 Objects.equals(type, giphyGif.type) && | ||||
|                 Objects.equals(id, giphyGif.id) && | ||||
|                 Objects.equals(title, giphyGif.title) && | ||||
|                 Objects.equals(images, giphyGif.images); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return Objects.hash(type, id, title, isSticker, images); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "GiphyGif{" + | ||||
|                 "type='" + type + '\'' + | ||||
|                 ", id='" + id + '\'' + | ||||
|                 ", title='" + title + '\'' + | ||||
|                 ", isSticker=" + isSticker() + | ||||
|                 ", images=" + images + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| package awais.instagrabber.repositories.responses.giphy; | ||||
| 
 | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| public class GiphyGifImage { | ||||
|     private final int height; | ||||
|     private final int width; | ||||
|     private final long webpSize; | ||||
|     private final String webp; | ||||
| 
 | ||||
|     public GiphyGifImage(final int height, final int width, final long webpSize, final String webp) { | ||||
|         this.height = height; | ||||
|         this.width = width; | ||||
|         this.webpSize = webpSize; | ||||
|         this.webp = webp; | ||||
|     } | ||||
| 
 | ||||
|     public int getHeight() { | ||||
|         return height; | ||||
|     } | ||||
| 
 | ||||
|     public int getWidth() { | ||||
|         return width; | ||||
|     } | ||||
| 
 | ||||
|     public long getWebpSize() { | ||||
|         return webpSize; | ||||
|     } | ||||
| 
 | ||||
|     public String getWebp() { | ||||
|         return webp; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(final Object o) { | ||||
|         if (this == o) return true; | ||||
|         if (o == null || getClass() != o.getClass()) return false; | ||||
|         final GiphyGifImage that = (GiphyGifImage) o; | ||||
|         return height == that.height && | ||||
|                 width == that.width && | ||||
|                 webpSize == that.webpSize && | ||||
|                 Objects.equals(webp, that.webp); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return Objects.hash(height, width, webpSize, webp); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "GiphyGifImage{" + | ||||
|                 "height=" + height + | ||||
|                 ", width=" + width + | ||||
|                 ", webpSize=" + webpSize + | ||||
|                 ", webp='" + webp + '\'' + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package awais.instagrabber.repositories.responses.giphy; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| import awais.instagrabber.repositories.responses.AnimatedMediaFixedHeight; | ||||
| 
 | ||||
| public class GiphyGifImages { | ||||
|     private final AnimatedMediaFixedHeight fixedHeight; | ||||
| 
 | ||||
|     public GiphyGifImages(final AnimatedMediaFixedHeight fixedHeight) { | ||||
|         this.fixedHeight = fixedHeight; | ||||
|     } | ||||
| 
 | ||||
|     public AnimatedMediaFixedHeight getFixedHeight() { | ||||
|         return fixedHeight; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(final Object o) { | ||||
|         if (this == o) return true; | ||||
|         if (o == null || getClass() != o.getClass()) return false; | ||||
|         final GiphyGifImages that = (GiphyGifImages) o; | ||||
|         return Objects.equals(fixedHeight, that.fixedHeight); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return Objects.hash(fixedHeight); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "GiphyGifImages{" + | ||||
|                 "fixedHeight=" + fixedHeight + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,46 @@ | ||||
| package awais.instagrabber.repositories.responses.giphy; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| public class GiphyGifResponse { | ||||
|     private final GiphyGifResults results; | ||||
|     private final String status; | ||||
| 
 | ||||
|     public GiphyGifResponse(final GiphyGifResults results, final String status) { | ||||
|         this.results = results; | ||||
|         this.status = status; | ||||
|     } | ||||
| 
 | ||||
|     public GiphyGifResults getResults() { | ||||
|         return results; | ||||
|     } | ||||
| 
 | ||||
|     public String getStatus() { | ||||
|         return status; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(final Object o) { | ||||
|         if (this == o) return true; | ||||
|         if (o == null || getClass() != o.getClass()) return false; | ||||
|         final GiphyGifResponse that = (GiphyGifResponse) o; | ||||
|         return Objects.equals(results, that.results) && | ||||
|                 Objects.equals(status, that.status); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return Objects.hash(results, status); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "GiphyGifResponse{" + | ||||
|                 "results=" + results + | ||||
|                 ", status='" + status + '\'' + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| package awais.instagrabber.repositories.responses.giphy; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| public class GiphyGifResults { | ||||
|     private final List<GiphyGif> giphyGifs; | ||||
|     private final List<GiphyGif> giphy; | ||||
| 
 | ||||
|     public GiphyGifResults(final List<GiphyGif> giphyGifs, final List<GiphyGif> giphy) { | ||||
|         this.giphyGifs = giphyGifs; | ||||
|         this.giphy = giphy; | ||||
|     } | ||||
| 
 | ||||
|     public List<GiphyGif> getGiphyGifs() { | ||||
|         return giphyGifs; | ||||
|     } | ||||
| 
 | ||||
|     public List<GiphyGif> getGiphy() { | ||||
|         return giphy; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(final Object o) { | ||||
|         if (this == o) return true; | ||||
|         if (o == null || getClass() != o.getClass()) return false; | ||||
|         final GiphyGifResults that = (GiphyGifResults) o; | ||||
|         return Objects.equals(giphyGifs, that.giphyGifs) && | ||||
|                 Objects.equals(giphy, that.giphy); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return Objects.hash(giphyGifs, giphy); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "GiphyGifResults{" + | ||||
|                 "giphyGifs=" + giphyGifs + | ||||
|                 ", giphy=" + giphy + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -15,6 +15,7 @@ import awais.instagrabber.models.enums.DirectItemType; | ||||
| import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.repositories.responses.User; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectItem; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectItemAnimatedMedia; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectItemReelShare; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectItemVisualMedia; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectThread; | ||||
| @ -84,11 +85,16 @@ public final class DMUtils { | ||||
|                     message = item.getPlaceholder().getMessage(); | ||||
|                     break; | ||||
|                 case MEDIA_SHARE: | ||||
|                     subtitle = resources.getString(R.string.dms_inbox_shared_post, username != null ? username : "", | ||||
|                                                    item.getMediaShare().getUser().getUsername()); | ||||
|                     final User mediaShareUser = item.getMediaShare().getUser(); | ||||
|                     subtitle = resources.getString(R.string.dms_inbox_shared_post, | ||||
|                                                    username != null ? username : "", | ||||
|                                                    mediaShareUser == null ? "" : mediaShareUser.getUsername()); | ||||
|                     break; | ||||
|                 case ANIMATED_MEDIA: | ||||
|                     subtitle = resources.getString(R.string.dms_inbox_shared_gif, username != null ? username : ""); | ||||
|                     final DirectItemAnimatedMedia animatedMedia = item.getAnimatedMedia(); | ||||
|                     subtitle = resources.getString(animatedMedia.isSticker() ? R.string.dms_inbox_shared_sticker | ||||
|                                                                              : R.string.dms_inbox_shared_gif, | ||||
|                                                    username != null ? username : ""); | ||||
|                     break; | ||||
|                 case PROFILE: | ||||
|                     subtitle = resources | ||||
| @ -111,8 +117,10 @@ public final class DMUtils { | ||||
|                         final int format = reelType.equals("highlight_reel") | ||||
|                                            ? R.string.dms_inbox_shared_highlight | ||||
|                                            : R.string.dms_inbox_shared_story; | ||||
|                         subtitle = resources.getString(format, username != null ? username : "", | ||||
|                                                        item.getStoryShare().getMedia().getUser().getUsername()); | ||||
|                         final User storyShareMediaUser = item.getStoryShare().getMedia().getUser(); | ||||
|                         subtitle = resources.getString(format, | ||||
|                                                        username != null ? username : "", | ||||
|                                                        storyShareMediaUser == null ? "" : storyShareMediaUser.getUsername()); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
| @ -126,12 +134,16 @@ public final class DMUtils { | ||||
|                     subtitle = item.getVideoCallEvent().getDescription(); | ||||
|                     break; | ||||
|                 case CLIP: | ||||
|                     subtitle = resources.getString(R.string.dms_inbox_shared_clip, username != null ? username : "", | ||||
|                                                    item.getClip().getClip().getUser().getUsername()); | ||||
|                     final User clipUser = item.getClip().getClip().getUser(); | ||||
|                     subtitle = resources.getString(R.string.dms_inbox_shared_clip, | ||||
|                                                    username != null ? username : "", | ||||
|                                                    clipUser == null ? "" : clipUser.getUsername()); | ||||
|                     break; | ||||
|                 case FELIX_SHARE: | ||||
|                     subtitle = resources.getString(R.string.dms_inbox_shared_igtv, username != null ? username : "", | ||||
|                                                    item.getFelixShare().getVideo().getUser().getUsername()); | ||||
|                     final User felixShareVideoUser = item.getFelixShare().getVideo().getUser(); | ||||
|                     subtitle = resources.getString(R.string.dms_inbox_shared_igtv, | ||||
|                                                    username != null ? username : "", | ||||
|                                                    felixShareVideoUser == null ? "" : felixShareVideoUser.getUsername()); | ||||
|                     break; | ||||
|                 case RAVEN_MEDIA: | ||||
|                     subtitle = getRavenMediaSubtitle(item, resources, username); | ||||
|  | ||||
| @ -8,13 +8,16 @@ import java.util.UUID; | ||||
| 
 | ||||
| import awais.instagrabber.models.enums.DirectItemType; | ||||
| import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.repositories.responses.AnimatedMediaImages; | ||||
| import awais.instagrabber.repositories.responses.Audio; | ||||
| import awais.instagrabber.repositories.responses.ImageVersions2; | ||||
| import awais.instagrabber.repositories.responses.Media; | ||||
| import awais.instagrabber.repositories.responses.MediaCandidate; | ||||
| import awais.instagrabber.repositories.responses.VideoVersion; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectItem; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectItemAnimatedMedia; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectItemVoiceMedia; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| 
 | ||||
| public final class DirectItemFactory { | ||||
| 
 | ||||
| @ -213,4 +216,45 @@ public final class DirectItemFactory { | ||||
|                 0, | ||||
|                 false); | ||||
|     } | ||||
| 
 | ||||
|     public static DirectItem createAnimatedMedia(final long userId, | ||||
|                                                  final String clientContext, | ||||
|                                                  final GiphyGif giphyGif) { | ||||
|         final AnimatedMediaImages animatedImages = new AnimatedMediaImages(giphyGif.getImages().getFixedHeight()); | ||||
|         final DirectItemAnimatedMedia animateMedia = new DirectItemAnimatedMedia( | ||||
|                 giphyGif.getId(), | ||||
|                 animatedImages, | ||||
|                 false, | ||||
|                 giphyGif.isSticker() | ||||
|         ); | ||||
|         return new DirectItem( | ||||
|                 UUID.randomUUID().toString(), | ||||
|                 userId, | ||||
|                 System.currentTimeMillis() * 1000, | ||||
|                 DirectItemType.ANIMATED_MEDIA, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 clientContext, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 animateMedia, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 0, | ||||
|                 false | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -26,6 +26,7 @@ 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.RankedRecipient; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.DirectoryUtils; | ||||
| @ -219,6 +220,10 @@ public class DirectThreadViewModel extends AndroidViewModel { | ||||
|         return threadManager.unsend(item); | ||||
|     } | ||||
| 
 | ||||
|     public LiveData<Resource<Object>> sendAnimatedMedia(@NonNull final GiphyGif giphyGif) { | ||||
|         return threadManager.sendAnimatedMedia(giphyGif); | ||||
|     } | ||||
| 
 | ||||
|     public User getCurrentUser() { | ||||
|         return currentUser; | ||||
|     } | ||||
|  | ||||
| @ -0,0 +1,121 @@ | ||||
| package awais.instagrabber.viewmodels; | ||||
| 
 | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.lifecycle.LiveData; | ||||
| import androidx.lifecycle.MutableLiveData; | ||||
| import androidx.lifecycle.ViewModel; | ||||
| 
 | ||||
| import com.google.common.collect.ImmutableList; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| 
 | ||||
| import awais.instagrabber.models.Resource; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGifResponse; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGifResults; | ||||
| import awais.instagrabber.webservices.GifService; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.Callback; | ||||
| import retrofit2.Response; | ||||
| 
 | ||||
| public class GifPickerViewModel extends ViewModel { | ||||
|     private static final String TAG = GifPickerViewModel.class.getSimpleName(); | ||||
| 
 | ||||
|     private final MutableLiveData<Resource<List<GiphyGif>>> images = new MutableLiveData<>(Resource.success(Collections.emptyList())); | ||||
|     private final GifService gifService; | ||||
| 
 | ||||
|     private Call<GiphyGifResponse> searchRequest; | ||||
| 
 | ||||
|     public GifPickerViewModel() { | ||||
|         gifService = GifService.getInstance(); | ||||
|         search(null); | ||||
|     } | ||||
| 
 | ||||
|     public LiveData<Resource<List<GiphyGif>>> getImages() { | ||||
|         return images; | ||||
|     } | ||||
| 
 | ||||
|     public void search(final String query) { | ||||
|         final Resource<List<GiphyGif>> currentValue = images.getValue(); | ||||
|         if (currentValue != null && currentValue.status == Resource.Status.LOADING) { | ||||
|             cancelSearchRequest(); | ||||
|         } | ||||
|         images.postValue(Resource.loading(getCurrentImages())); | ||||
|         searchRequest = gifService.searchGiphyGifs(query, query != null); | ||||
|         searchRequest.enqueue(new Callback<GiphyGifResponse>() { | ||||
|             @Override | ||||
|             public void onResponse(@NonNull final Call<GiphyGifResponse> call, | ||||
|                                    @NonNull final Response<GiphyGifResponse> response) { | ||||
|                 if (response.isSuccessful()) { | ||||
|                     parseResponse(response); | ||||
|                     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); | ||||
|                         images.postValue(Resource.error(msg, getCurrentImages())); | ||||
|                         Log.e(TAG, msg); | ||||
|                     } catch (IOException e) { | ||||
|                         images.postValue(Resource.error(e.getMessage(), getCurrentImages())); | ||||
|                         Log.e(TAG, "onResponse: ", e); | ||||
|                     } | ||||
|                 } | ||||
|                 images.postValue(Resource.error("request was not successful and response error body was null", getCurrentImages())); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onFailure(@NonNull final Call<GiphyGifResponse> call, | ||||
|                                   @NonNull final Throwable t) { | ||||
|                 images.postValue(Resource.error(t.getMessage(), getCurrentImages())); | ||||
|                 Log.e(TAG, "enqueueRequest: onFailure: ", t); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private void parseResponse(final Response<GiphyGifResponse> response) { | ||||
|         final GiphyGifResponse giphyGifResponse = response.body(); | ||||
|         if (giphyGifResponse == null) { | ||||
|             images.postValue(Resource.error("Response body was null", getCurrentImages())); | ||||
|             return; | ||||
|         } | ||||
|         final GiphyGifResults results = giphyGifResponse.getResults(); | ||||
|         images.postValue(Resource.success( | ||||
|                 ImmutableList.<GiphyGif>builder() | ||||
|                         .addAll(results.getGiphy() == null ? Collections.emptyList() : results.getGiphy()) | ||||
|                         .addAll(results.getGiphyGifs() == null ? Collections.emptyList() : results.getGiphyGifs()) | ||||
|                         .build() | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     // @NonNull | ||||
|     // private List<GiphyGifImage> getGiphyGifImages(@NonNull final List<GiphyGif> giphy) { | ||||
|     //     return giphy.stream() | ||||
|     //                 .map(giphyGif -> { | ||||
|     //                     final GiphyGifImages images = giphyGif.getImages(); | ||||
|     //                     if (images == null) return null; | ||||
|     //                     return images.getOriginal(); | ||||
|     //                 }) | ||||
|     //                 .filter(Objects::nonNull) | ||||
|     //                 .collect(Collectors.toList()); | ||||
|     // } | ||||
| 
 | ||||
|     private List<GiphyGif> getCurrentImages() { | ||||
|         final Resource<List<GiphyGif>> value = images.getValue(); | ||||
|         return value == null ? Collections.emptyList() : value.data; | ||||
|     } | ||||
| 
 | ||||
|     public void cancelSearchRequest() { | ||||
|         if (searchRequest == null) return; | ||||
|         searchRequest.cancel(); | ||||
|     } | ||||
| } | ||||
| @ -17,6 +17,7 @@ import java.util.UUID; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| import awais.instagrabber.repositories.DirectMessagesRepository; | ||||
| import awais.instagrabber.repositories.requests.directmessages.AnimatedMediaBroadcastOptions; | ||||
| import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions; | ||||
| import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions.ThreadIdOrUserIds; | ||||
| import awais.instagrabber.repositories.requests.directmessages.LinkBroadcastOptions; | ||||
| @ -34,6 +35,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectThreadDeta | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectThreadFeedResponse; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse; | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipientsResponse; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGif; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import retrofit2.Call; | ||||
| @ -182,6 +184,11 @@ public class DirectMessagesService extends BaseService { | ||||
|         return broadcast(new ReactionBroadcastOptions(clientContext, threadIdOrUserIds, itemId, emoji, delete)); | ||||
|     } | ||||
| 
 | ||||
|     public Call<DirectThreadBroadcastResponse> broadcastAnimatedMedia(final String clientContext, | ||||
|                                                                       final ThreadIdOrUserIds threadIdOrUserIds, | ||||
|                                                                       final GiphyGif giphyGif) { | ||||
|         return broadcast(new AnimatedMediaBroadcastOptions(clientContext, threadIdOrUserIds, giphyGif)); | ||||
|     } | ||||
| 
 | ||||
|     private Call<DirectThreadBroadcastResponse> broadcast(@NonNull final BroadcastOptions broadcastOptions) { | ||||
|         if (TextUtils.isEmpty(broadcastOptions.getClientContext())) { | ||||
|  | ||||
| @ -0,0 +1,33 @@ | ||||
| package awais.instagrabber.webservices; | ||||
| 
 | ||||
| import awais.instagrabber.repositories.GifRepository; | ||||
| import awais.instagrabber.repositories.responses.giphy.GiphyGifResponse; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.Retrofit; | ||||
| 
 | ||||
| public class GifService extends BaseService { | ||||
| 
 | ||||
|     private final GifRepository repository; | ||||
| 
 | ||||
|     private static GifService instance; | ||||
| 
 | ||||
|     private GifService() { | ||||
|         final Retrofit retrofit = getRetrofitBuilder() | ||||
|                 .baseUrl("https://i.instagram.com") | ||||
|                 .build(); | ||||
|         repository = retrofit.create(GifRepository.class); | ||||
|     } | ||||
| 
 | ||||
|     public static GifService getInstance() { | ||||
|         if (instance == null) { | ||||
|             instance = new GifService(); | ||||
|         } | ||||
|         return instance; | ||||
|     } | ||||
| 
 | ||||
|     public Call<GiphyGifResponse> searchGiphyGifs(final String query, | ||||
|                                                   final boolean includeGifs) { | ||||
|         final String mediaTypes = includeGifs ? "[\"giphy_gifs\",\"giphy\"]" : "[\"giphy\"]"; | ||||
|         return repository.searchGiphyGifs("direct", query, mediaTypes); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_round_gif_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/drawable/ic_round_gif_24.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="?attr/colorControlNormal"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M12.25,9c0.41,0 0.75,0.34 0.75,0.75v4.5c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75v-4.5c0,-0.41 0.34,-0.75 0.75,-0.75zM10,9.75c0,-0.41 -0.34,-0.75 -0.75,-0.75L6,9c-0.6,0 -1,0.5 -1,1v4c0,0.5 0.4,1 1,1h3c0.6,0 1,-0.5 1,-1v-1.25c0,-0.41 -0.34,-0.75 -0.75,-0.75s-0.75,0.34 -0.75,0.75v0.75h-2v-3h2.75c0.41,0 0.75,-0.34 0.75,-0.75zM19,9.75c0,-0.41 -0.34,-0.75 -0.75,-0.75L15.5,9c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L16,13h1.25c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75L16,11.5v-1h2.25c0.41,0 0.75,-0.34 0.75,-0.75z"/> | ||||
| </vector> | ||||
| @ -120,7 +120,8 @@ | ||||
|         app:layout_constraintBottom_toBottomOf="@id/input" | ||||
|         app:layout_constraintEnd_toStartOf="@id/send" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="@id/input" /> | ||||
|         app:layout_constraintTop_toTopOf="@id/input" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <com.google.android.material.button.MaterialButton | ||||
|         android:id="@+id/emoji_toggle" | ||||
| @ -143,7 +144,8 @@ | ||||
|         app:rippleColor="@color/grey_500" | ||||
|         app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Button.Circle" | ||||
|         app:strokeColor="@color/black" | ||||
|         app:strokeWidth="1dp" /> | ||||
|         app:strokeWidth="1dp" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <awais.instagrabber.customviews.KeyNotifyingEmojiEditText | ||||
|         android:id="@+id/input" | ||||
| @ -158,16 +160,32 @@ | ||||
|         android:textColorHint="@color/grey_500" | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toStartOf="@id/camera" | ||||
|         app:layout_constraintEnd_toStartOf="@id/gif" | ||||
|         app:layout_constraintStart_toEndOf="@id/emoji_toggle" | ||||
|         app:layout_constraintTop_toBottomOf="@id/reply_preview_text" | ||||
|         app:layout_goneMarginBottom="4dp" | ||||
|         app:layout_goneMarginEnd="24dp" /> | ||||
|         app:layout_goneMarginEnd="24dp" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatImageButton | ||||
|         android:id="@+id/gif" | ||||
|         android:layout_width="32dp" | ||||
|         android:layout_height="0dp" | ||||
|         android:background="@android:color/transparent" | ||||
|         android:scaleType="fitCenter" | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintBottom_toBottomOf="@id/input_bg" | ||||
|         app:layout_constraintEnd_toStartOf="@id/camera" | ||||
|         app:layout_constraintStart_toEndOf="@id/input" | ||||
|         app:layout_constraintTop_toTopOf="@id/input" | ||||
|         app:srcCompat="@drawable/ic_round_gif_24" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatImageButton | ||||
|         android:id="@+id/camera" | ||||
|         android:layout_width="32dp" | ||||
|         android:layout_height="0dp" | ||||
|         android:layout_marginStart="4dp" | ||||
|         android:background="@android:color/transparent" | ||||
|         android:paddingStart="4dp" | ||||
|         android:paddingEnd="4dp" | ||||
| @ -175,10 +193,10 @@ | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintBottom_toBottomOf="@id/input_bg" | ||||
|         app:layout_constraintEnd_toStartOf="@id/gallery" | ||||
|         app:layout_constraintStart_toEndOf="@id/input" | ||||
|         app:layout_constraintStart_toEndOf="@id/gif" | ||||
|         app:layout_constraintTop_toTopOf="@id/input" | ||||
|         app:srcCompat="@drawable/ic_camera_24" | ||||
|         tools:visibility="gone" /> | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatImageButton | ||||
|         android:id="@+id/gallery" | ||||
| @ -196,7 +214,7 @@ | ||||
|         app:layout_constraintEnd_toStartOf="@id/send" | ||||
|         app:layout_constraintStart_toEndOf="@id/camera" | ||||
|         app:layout_constraintTop_toTopOf="@id/input" | ||||
|         tools:visibility="gone" /> | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <awais.instagrabber.customviews.RecordView | ||||
|         android:id="@+id/record_view" | ||||
| @ -214,7 +232,7 @@ | ||||
|         app:slide_to_cancel_margin_right="16dp" | ||||
|         app:slide_to_cancel_text="Slide To Cancel" | ||||
|         app:slide_to_cancel_text_color="@color/white" | ||||
|         tools:visibility="gone" /> | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <awais.instagrabber.customviews.RecordButton | ||||
|         android:id="@+id/send" | ||||
| @ -231,7 +249,8 @@ | ||||
|         app:layout_constraintBottom_toBottomOf="@id/input_bg" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@id/input_bg" | ||||
|         app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Button.Circle" /> | ||||
|         app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Button.Circle" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <awais.instagrabber.customviews.emoji.EmojiPicker | ||||
|         android:id="@+id/emoji_picker" | ||||
| @ -241,7 +260,8 @@ | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" /> | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/accept_pending_request_question" | ||||
| @ -255,7 +275,7 @@ | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintBottom_toTopOf="@id/decline" | ||||
|         app:layout_constraintTop_toBottomOf="@id/chats_barrier" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="gone" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/decline" | ||||
| @ -272,7 +292,7 @@ | ||||
|         app:layout_constraintEnd_toStartOf="@id/accept" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@id/accept_pending_request_question" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="gone" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/accept" | ||||
| @ -288,5 +308,5 @@ | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@id/decline" | ||||
|         app:layout_constraintTop_toBottomOf="@id/accept_pending_request_question" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="gone" /> | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
							
								
								
									
										70
									
								
								app/src/main/res/layout/layout_gif_picker.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								app/src/main/res/layout/layout_gif_picker.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent"> | ||||
| 
 | ||||
|     <View | ||||
|         android:id="@+id/input_bg" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="0dp" | ||||
|         android:layout_marginStart="4dp" | ||||
|         android:layout_marginEnd="4dp" | ||||
|         android:background="@drawable/bg_input" | ||||
|         app:layout_constraintBottom_toBottomOf="@id/input" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="@id/input" /> | ||||
| 
 | ||||
|     <com.google.android.material.button.MaterialButton | ||||
|         android:id="@+id/search_icon" | ||||
|         style="@style/Widget.MaterialComponents.Button.Icon.NoInsets" | ||||
|         android:layout_width="24dp" | ||||
|         android:layout_height="24dp" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginEnd="2dp" | ||||
|         android:background="@android:color/transparent" | ||||
|         android:clickable="false" | ||||
|         android:scrollbars="none" | ||||
|         app:icon="@drawable/ic_search_24" | ||||
|         app:iconGravity="textStart" | ||||
|         app:iconSize="24dp" | ||||
|         app:iconTint="@color/grey_700" | ||||
|         app:layout_constraintBottom_toBottomOf="@id/input_bg" | ||||
|         app:layout_constraintEnd_toStartOf="@id/input" | ||||
|         app:layout_constraintStart_toStartOf="@id/input_bg" | ||||
|         app:layout_constraintTop_toTopOf="@id/input" | ||||
|         app:rippleColor="@color/grey_500" | ||||
|         app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Button.Circle" | ||||
|         app:strokeColor="@color/black" | ||||
|         app:strokeWidth="1dp" /> | ||||
| 
 | ||||
|     <androidx.emoji.widget.EmojiAppCompatEditText | ||||
|         android:id="@+id/input" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="4dp" | ||||
|         android:layout_marginTop="4dp" | ||||
|         android:layout_marginEnd="20dp" | ||||
|         android:layout_marginBottom="4dp" | ||||
|         android:background="@android:color/transparent" | ||||
|         android:hint="@string/search_giphy" | ||||
|         android:paddingTop="12dp" | ||||
|         android:paddingBottom="12dp" | ||||
|         android:textColor="@color/white" | ||||
|         android:textColorHint="@color/grey_500" | ||||
|         app:layout_constraintBottom_toTopOf="@id/gif_list" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@id/search_icon" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/gif_list" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="0dp" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@id/input" /> | ||||
| 
 | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| @ -185,6 +185,7 @@ | ||||
|     <string name="dms_inbox_shared_video">%s shared a video</string> | ||||
|     <string name="dms_inbox_shared_message">%s sent a message</string> | ||||
|     <string name="dms_inbox_shared_gif">%s shared a gif</string> | ||||
|     <string name="dms_inbox_shared_sticker">%s shared a sticker</string> | ||||
|     <string name="dms_inbox_shared_profile">%s shared a profile: @%s</string> | ||||
|     <string name="dms_inbox_shared_location">%s shared a location: %s</string> | ||||
|     <string name="dms_inbox_shared_highlight">%s shared a story highlight by @%s</string> | ||||
| @ -490,4 +491,5 @@ | ||||
|     <string name="auto_refresh_every">Auto refresh every</string> | ||||
|     <string name="secs">secs</string> | ||||
|     <string name="mins">mins</string> | ||||
|     <string name="search_giphy">Search GIPHY</string> | ||||
| </resources> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user