mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-10-30 19:15:35 +00:00 
			
		
		
		
	More updated. Handle clicks. Updated comments viewer, etc
This commit is contained in:
		
							parent
							
								
									6bf59e83ad
								
							
						
					
					
						commit
						9b83c5e832
					
				
							
								
								
									
										6
									
								
								.idea/compiler.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/compiler.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="CompilerConfiguration"> | ||||
|     <bytecodeTargetLevel target="1.8" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										1
									
								
								.idea/gradle.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/gradle.xml
									
									
									
										generated
									
									
									
								
							| @ -15,6 +15,7 @@ | ||||
|           </set> | ||||
|         </option> | ||||
|         <option name="resolveModulePerSourceSet" value="false" /> | ||||
|         <option name="useQualifiedModuleNames" value="true" /> | ||||
|       </GradleProjectSettings> | ||||
|     </option> | ||||
|   </component> | ||||
|  | ||||
							
								
								
									
										2
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							| @ -40,7 +40,7 @@ | ||||
|       </value> | ||||
|     </option> | ||||
|   </component> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | ||||
|     <output url="file://$PROJECT_DIR$/build/classes" /> | ||||
|   </component> | ||||
|   <component name="ProjectType"> | ||||
|  | ||||
							
								
								
									
										8
									
								
								.idea/runConfigurations/app.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								.idea/runConfigurations/app.xml
									
									
									
										generated
									
									
									
								
							| @ -1,11 +1,12 @@ | ||||
| <component name="ProjectRunConfigurationManager"> | ||||
|   <configuration default="false" name="app" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false"> | ||||
|     <module name="app" /> | ||||
|     <module name="InstaGrabber.app" /> | ||||
|     <option name="DEPLOY" value="true" /> | ||||
|     <option name="DEPLOY_APK_FROM_BUNDLE" value="false" /> | ||||
|     <option name="DEPLOY_AS_INSTANT" value="false" /> | ||||
|     <option name="ARTIFACT_NAME" value="" /> | ||||
|     <option name="PM_INSTALL_OPTIONS" value="" /> | ||||
|     <option name="ALL_USERS" value="false" /> | ||||
|     <option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" /> | ||||
|     <option name="ACTIVITY_EXTRA_FLAGS" value="" /> | ||||
|     <option name="MODE" value="default_activity" /> | ||||
| @ -41,11 +42,16 @@ | ||||
|     </Native> | ||||
|     <Profilers> | ||||
|       <option name="ADVANCED_PROFILING_ENABLED" value="false" /> | ||||
|       <option name="STARTUP_PROFILING_ENABLED" value="false" /> | ||||
|       <option name="STARTUP_CPU_PROFILING_ENABLED" value="false" /> | ||||
|       <option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" /> | ||||
|       <option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" /> | ||||
|       <option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" /> | ||||
|     </Profilers> | ||||
|     <option name="DEEP_LINK" value="" /> | ||||
|     <option name="ACTIVITY_CLASS" value="awais.instagrabber.activities.MainActivity" /> | ||||
|     <option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" /> | ||||
|     <option name="SKIP_ACTIVITY_VALIDATION" value="false" /> | ||||
|     <method v="2"> | ||||
|       <option name="Android.Gradle.BeforeRunTask" enabled="true" /> | ||||
|     </method> | ||||
|  | ||||
| @ -39,6 +39,12 @@ android { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| configurations.all { | ||||
|     resolutionStrategy.cacheChangingModulesFor 0, 'seconds' | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|     coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10' | ||||
| 
 | ||||
| @ -62,7 +68,8 @@ dependencies { | ||||
|     implementation 'com.google.guava:guava:27.0.1-android' | ||||
| 
 | ||||
| //    implementation 'com.github.hendrawd:StorageUtil:1.1.0' | ||||
|     implementation 'com.github.armcha:AutoLinkTextViewV2:2.1.1' | ||||
| //    implementation 'com.github.armcha:AutoLinkTextViewV2:2.1.1' | ||||
|     implementation 'com.github.ammargitham:AutoLinkTextViewV2:master-SNAPSHOT' | ||||
| 
 | ||||
|     implementation 'org.jsoup:jsoup:1.13.1' | ||||
|     implementation 'com.facebook.fresco:fresco:2.3.0' | ||||
|  | ||||
| @ -2,137 +2,189 @@ package awais.instagrabber.adapters; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Filter; | ||||
| import android.widget.Filterable; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.recyclerview.widget.DiffUtil; | ||||
| import androidx.recyclerview.widget.ListAdapter; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.viewholder.CommentViewHolder; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.adapters.viewholder.comments.ChildCommentViewHolder; | ||||
| import awais.instagrabber.adapters.viewholder.comments.ParentCommentViewHolder; | ||||
| import awais.instagrabber.databinding.ItemCommentBinding; | ||||
| import awais.instagrabber.databinding.ItemCommentSmallBinding; | ||||
| import awais.instagrabber.models.CommentModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.utils.LocaleUtils; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| 
 | ||||
| public final class CommentsAdapter extends RecyclerView.Adapter<CommentViewHolder> implements Filterable { | ||||
| public final class CommentsAdapter extends ListAdapter<CommentModel, RecyclerView.ViewHolder> { | ||||
|     private static final int TYPE_PARENT = 1; | ||||
|     private static final int TYPE_CHILD = 2; | ||||
| 
 | ||||
|     private CommentModel[] filteredCommentModels; | ||||
|     private LayoutInflater layoutInflater; | ||||
|     private final Map<Integer, Integer> positionTypeMap = new HashMap<>(); | ||||
| 
 | ||||
|     private final boolean isParent; | ||||
|     private final View.OnClickListener onClickListener; | ||||
|     private final MentionClickListener mentionClickListener; | ||||
|     private final CommentModel[] commentModels; | ||||
|     private final String[] quantityStrings = new String[2]; | ||||
|     private final Filter filter = new Filter() { | ||||
|         @NonNull | ||||
|     // private final Filter filter = new Filter() { | ||||
|     //     @NonNull | ||||
|     //     @Override | ||||
|     //     protected FilterResults performFiltering(final CharSequence filter) { | ||||
|     //         final FilterResults results = new FilterResults(); | ||||
|     //         results.values = commentModels; | ||||
|     // | ||||
|     //         final int commentsLen = commentModels == null ? 0 : commentModels.size(); | ||||
|     //         if (commentModels != null && commentsLen > 0 && !TextUtils.isEmpty(filter)) { | ||||
|     //             final String query = filter.toString().toLowerCase(); | ||||
|     //             final ArrayList<CommentModel> filterList = new ArrayList<>(commentsLen); | ||||
|     // | ||||
|     //             for (final CommentModel commentModel : commentModels) { | ||||
|     //                 final String commentText = commentModel.getText().toString().toLowerCase(); | ||||
|     // | ||||
|     //                 if (commentText.contains(query)) filterList.add(commentModel); | ||||
|     //                 else { | ||||
|     //                     final List<CommentModel> childCommentModels = commentModel.getChildCommentModels(); | ||||
|     //                     if (childCommentModels != null) { | ||||
|     //                         for (final CommentModel childCommentModel : childCommentModels) { | ||||
|     //                             final String childCommentText = childCommentModel.getText().toString().toLowerCase(); | ||||
|     //                             if (childCommentText.contains(query)) filterList.add(commentModel); | ||||
|     //                         } | ||||
|     //                     } | ||||
|     //                 } | ||||
|     //             } | ||||
|     //             filterList.trimToSize(); | ||||
|     //             results.values = filterList.toArray(new CommentModel[0]); | ||||
|     //         } | ||||
|     // | ||||
|     //         return results; | ||||
|     //     } | ||||
|     // | ||||
|     //     @Override | ||||
|     //     protected void publishResults(final CharSequence constraint, @NonNull final FilterResults results) { | ||||
|     //         if (results.values instanceof List) { | ||||
|     //             //noinspection unchecked | ||||
|     //             filteredCommentModels = (List<CommentModel>) results.values; | ||||
|     //             notifyDataSetChanged(); | ||||
|     //         } | ||||
|     //     } | ||||
|     // }; | ||||
| 
 | ||||
|     private static final DiffUtil.ItemCallback<CommentModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<CommentModel>() { | ||||
|         @Override | ||||
|         protected FilterResults performFiltering(final CharSequence filter) { | ||||
|             final FilterResults results = new FilterResults(); | ||||
|             results.values = commentModels; | ||||
| 
 | ||||
|             final int commentsLen = commentModels == null ? 0 : commentModels.length; | ||||
|             if (commentModels != null && commentsLen > 0 && !TextUtils.isEmpty(filter)) { | ||||
|                 final String query = filter.toString().toLowerCase(); | ||||
|                 final ArrayList<CommentModel> filterList = new ArrayList<>(commentsLen); | ||||
| 
 | ||||
|                 for (final CommentModel commentModel : commentModels) { | ||||
|                     final String commentText = commentModel.getText().toString().toLowerCase(); | ||||
| 
 | ||||
|                     if (commentText.contains(query)) filterList.add(commentModel); | ||||
|                     else { | ||||
|                         final CommentModel[] childCommentModels = commentModel.getChildCommentModels(); | ||||
|                         if (childCommentModels != null) { | ||||
|                             for (final CommentModel childCommentModel : childCommentModels) { | ||||
|                                 final String childCommentText = childCommentModel.getText().toString().toLowerCase(); | ||||
|                                 if (childCommentText.contains(query)) filterList.add(commentModel); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 filterList.trimToSize(); | ||||
|                 results.values = filterList.toArray(new CommentModel[0]); | ||||
|             } | ||||
| 
 | ||||
|             return results; | ||||
|         public boolean areItemsTheSame(@NonNull final CommentModel oldItem, @NonNull final CommentModel newItem) { | ||||
|             return oldItem.getId().equals(newItem.getId()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         protected void publishResults(final CharSequence constraint, @NonNull final FilterResults results) { | ||||
|             if (results.values instanceof CommentModel[]) { | ||||
|                 filteredCommentModels = (CommentModel[]) results.values; | ||||
|                 notifyDataSetChanged(); | ||||
|             } | ||||
|         public boolean areContentsTheSame(@NonNull final CommentModel oldItem, @NonNull final CommentModel newItem) { | ||||
|             return oldItem.getId().equals(newItem.getId()); | ||||
|         } | ||||
|     }; | ||||
|     private final CommentCallback commentCallback; | ||||
|     private CommentModel selected; | ||||
|     private int selectedIndex; | ||||
| 
 | ||||
|     public CommentsAdapter(final CommentModel[] commentModels, | ||||
|                            final boolean isParent, | ||||
|                            final View.OnClickListener onClickListener, | ||||
|                            final MentionClickListener mentionClickListener) { | ||||
|         super(); | ||||
|         this.commentModels = this.filteredCommentModels = commentModels; | ||||
|         this.isParent = isParent; | ||||
|         this.onClickListener = onClickListener; | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Filter getFilter() { | ||||
|         return filter; | ||||
|     public CommentsAdapter(final CommentCallback commentCallback) { | ||||
|         super(DIFF_CALLBACK); | ||||
|         this.commentCallback = commentCallback; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public CommentViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) { | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) { | ||||
|         final Context context = parent.getContext(); | ||||
|         if (quantityStrings[0] == null) quantityStrings[0] = context.getString(R.string.single_like); | ||||
|         if (quantityStrings[1] == null) quantityStrings[1] = context.getString(R.string.multiple_likes); | ||||
|         if (layoutInflater == null) layoutInflater = LayoutInflater.from(context); | ||||
|         final View view = layoutInflater.inflate(isParent ? R.layout.item_comment | ||||
|                                                           : R.layout.item_comment_small, | ||||
|                                                  parent, | ||||
|                                                  false); | ||||
|         return new CommentViewHolder(view, | ||||
|                                      onClickListener, | ||||
|                                      mentionClickListener); | ||||
|         final LayoutInflater layoutInflater = LayoutInflater.from(context); | ||||
|         if (type == TYPE_PARENT) { | ||||
|             final ItemCommentBinding binding = ItemCommentBinding.inflate(layoutInflater, parent, false); | ||||
|             return new ParentCommentViewHolder(binding); | ||||
|         } | ||||
|         final ItemCommentSmallBinding binding = ItemCommentSmallBinding.inflate(layoutInflater, parent, false); | ||||
|         return new ChildCommentViewHolder(binding); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull final CommentViewHolder holder, final int position) { | ||||
|         final CommentModel commentModel = filteredCommentModels[position]; | ||||
|         if (commentModel != null) { | ||||
|             holder.setCommentModel(commentModel); | ||||
|     public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { | ||||
|         final CommentModel commentModel = getItem(position); | ||||
|         if (commentModel == null) return; | ||||
|         final int type = getItemViewType(position); | ||||
|         final boolean selected = this.selected != null && this.selected.getId().equals(commentModel.getId()); | ||||
|         if (type == TYPE_PARENT) { | ||||
|             final ParentCommentViewHolder viewHolder = (ParentCommentViewHolder) holder; | ||||
|             viewHolder.bind(commentModel, selected, commentCallback); | ||||
|             return; | ||||
|         } | ||||
|         final ChildCommentViewHolder viewHolder = (ChildCommentViewHolder) holder; | ||||
|         viewHolder.bind(commentModel, selected, commentCallback); | ||||
|     } | ||||
| 
 | ||||
|             holder.setComment(commentModel.getText()); | ||||
|             holder.setDate(commentModel.getDateTime()); | ||||
|             holder.setLiked(commentModel.getLiked()); | ||||
|     @Override | ||||
|     public void submitList(@Nullable final List<CommentModel> list) { | ||||
|         final List<CommentModel> flatList = flattenList(list); | ||||
|         super.submitList(flatList); | ||||
|     } | ||||
| 
 | ||||
|             final long likes = commentModel.getLikes(); | ||||
|             holder.setLikes(String.format(LocaleUtils.getCurrentLocale(), "%d %s", likes, quantityStrings[likes == 1 ? 0 : 1])); | ||||
|     @Override | ||||
|     public void submitList(@Nullable final List<CommentModel> list, @Nullable final Runnable commitCallback) { | ||||
|         final List<CommentModel> flatList = flattenList(list); | ||||
|         super.submitList(flatList, commitCallback); | ||||
|     } | ||||
| 
 | ||||
|             final ProfileModel profileModel = commentModel.getProfileModel(); | ||||
|             if (profileModel != null) { | ||||
|                 holder.setUsername(profileModel.getUsername()); | ||||
|                 holder.getProfilePicView().setImageURI(profileModel.getSdProfilePic()); | ||||
|             } | ||||
|             if (holder.isParent()) { | ||||
|                 final CommentModel[] childCommentModels = commentModel.getChildCommentModels(); | ||||
|                 if (childCommentModels != null && childCommentModels.length > 0) | ||||
|                     holder.setChildAdapter(new CommentsAdapter(childCommentModels, false, onClickListener, mentionClickListener)); | ||||
|                 else holder.hideChildComments(); | ||||
|     private List<CommentModel> flattenList(final List<CommentModel> list) { | ||||
|         if (list == null) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         final List<CommentModel> flatList = new ArrayList<>(); | ||||
|         int lastCommentIndex = -1; | ||||
|         for (final CommentModel parent : list) { | ||||
|             lastCommentIndex++; | ||||
|             flatList.add(parent); | ||||
|             positionTypeMap.put(lastCommentIndex, TYPE_PARENT); | ||||
|             final List<CommentModel> children = parent.getChildCommentModels(); | ||||
|             for (final CommentModel child : children) { | ||||
|                 lastCommentIndex++; | ||||
|                 flatList.add(child); | ||||
|                 positionTypeMap.put(lastCommentIndex, TYPE_CHILD); | ||||
|             } | ||||
|         } | ||||
|         return flatList; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return filteredCommentModels == null ? 0 : filteredCommentModels.length; | ||||
|     public int getItemViewType(final int position) { | ||||
|         final Integer type = positionTypeMap.get(position); | ||||
|         if (type == null) { | ||||
|             return TYPE_PARENT; | ||||
|         } | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     public void setSelected(final CommentModel commentModel) { | ||||
|         this.selected = commentModel; | ||||
|         selectedIndex = getCurrentList().indexOf(commentModel); | ||||
|         notifyItemChanged(selectedIndex); | ||||
|     } | ||||
| 
 | ||||
|     public void clearSelection() { | ||||
|         this.selected = null; | ||||
|         notifyItemChanged(selectedIndex); | ||||
|     } | ||||
| 
 | ||||
|     public CommentModel getSelected() { | ||||
|         return selected; | ||||
|     } | ||||
| 
 | ||||
|     public interface CommentCallback { | ||||
|         void onClick(final CommentModel comment); | ||||
| 
 | ||||
|         void onHashtagClick(final String hashtag); | ||||
| 
 | ||||
|         void onMentionClick(final String mention); | ||||
| 
 | ||||
|         void onURLClick(final String url); | ||||
| 
 | ||||
|         void onEmailClick(final String emailAddress); | ||||
|     } | ||||
| } | ||||
| @ -1,111 +1,111 @@ | ||||
| package awais.instagrabber.adapters; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| 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 awais.instagrabber.adapters.viewholder.feed.FeedItemViewHolder; | ||||
| import awais.instagrabber.adapters.viewholder.feed.FeedPhotoViewHolder; | ||||
| import awais.instagrabber.adapters.viewholder.feed.FeedSliderViewHolder; | ||||
| import awais.instagrabber.adapters.viewholder.feed.FeedVideoViewHolder; | ||||
| import awais.instagrabber.customviews.RamboTextView; | ||||
| import awais.instagrabber.databinding.ItemFeedPhotoBinding; | ||||
| import awais.instagrabber.databinding.ItemFeedSliderBinding; | ||||
| import awais.instagrabber.databinding.ItemFeedVideoBinding; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public final class FeedAdapter extends ListAdapter<FeedModel, FeedItemViewHolder> { | ||||
|     private static final String TAG = "FeedAdapter"; | ||||
|     private final View.OnClickListener clickListener; | ||||
|     private final MentionClickListener mentionClickListener; | ||||
|     private final View.OnLongClickListener longClickListener = v -> { | ||||
|         final Object tag; | ||||
|         if (v instanceof RamboTextView && (tag = v.getTag()) instanceof FeedModel) | ||||
|             Utils.copyText(v.getContext(), ((FeedModel) tag).getPostCaption()); | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     private static final DiffUtil.ItemCallback<FeedModel> diffCallback = new DiffUtil.ItemCallback<FeedModel>() { | ||||
|         @Override | ||||
|         public boolean areItemsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) { | ||||
|             return oldItem.getPostId().equals(newItem.getPostId()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public boolean areContentsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) { | ||||
|             return oldItem.getPostId().equals(newItem.getPostId()); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     public FeedAdapter(final View.OnClickListener clickListener, | ||||
|                        final MentionClickListener mentionClickListener) { | ||||
|         super(diffCallback); | ||||
|         // private final static String ellipsize = "… more"; | ||||
|         this.clickListener = clickListener; | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public FeedItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { | ||||
|         final Context context = parent.getContext(); | ||||
|         final LayoutInflater layoutInflater = LayoutInflater.from(context); | ||||
|         final MediaItemType type = MediaItemType.valueOf(viewType); | ||||
|         switch (type) { | ||||
|             case MEDIA_TYPE_VIDEO: { | ||||
|                 final ItemFeedVideoBinding binding = ItemFeedVideoBinding.inflate(layoutInflater, parent, false); | ||||
|                 return new FeedVideoViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
|             } | ||||
|             case MEDIA_TYPE_SLIDER: { | ||||
|                 final ItemFeedSliderBinding binding = ItemFeedSliderBinding.inflate(layoutInflater, parent, false); | ||||
|                 return new FeedSliderViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
|             } | ||||
|             case MEDIA_TYPE_IMAGE: | ||||
|             default: { | ||||
|                 final ItemFeedPhotoBinding binding = ItemFeedPhotoBinding.inflate(layoutInflater, parent, false); | ||||
|                 return new FeedPhotoViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull final FeedItemViewHolder viewHolder, final int position) { | ||||
|         final FeedModel feedModel = getItem(position); | ||||
|         if (feedModel == null) { | ||||
|             return; | ||||
|         } | ||||
|         feedModel.setPosition(position); | ||||
|         viewHolder.bind(feedModel, (feedModel1, view, postImage) -> {}); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getItemViewType(final int position) { | ||||
|         return getItem(position).getItemType().getId(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onViewAttachedToWindow(@NonNull final FeedItemViewHolder holder) { | ||||
|         super.onViewAttachedToWindow(holder); | ||||
|         // Log.d(TAG, "attached holder: " + holder); | ||||
|         if (!(holder instanceof FeedSliderViewHolder)) return; | ||||
|         final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder; | ||||
|         feedSliderViewHolder.startPlayingVideo(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onViewDetachedFromWindow(@NonNull final FeedItemViewHolder holder) { | ||||
|         super.onViewDetachedFromWindow(holder); | ||||
|         // Log.d(TAG, "detached holder: " + holder); | ||||
|         if (!(holder instanceof FeedSliderViewHolder)) return; | ||||
|         final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder; | ||||
|         feedSliderViewHolder.stopPlayingVideo(); | ||||
|     } | ||||
| } | ||||
| // package awais.instagrabber.adapters; | ||||
| // | ||||
| // import android.content.Context; | ||||
| // 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 awais.instagrabber.adapters.viewholder.feed.FeedItemViewHolder; | ||||
| // import awais.instagrabber.adapters.viewholder.feed.FeedPhotoViewHolder; | ||||
| // import awais.instagrabber.adapters.viewholder.feed.FeedSliderViewHolder; | ||||
| // import awais.instagrabber.adapters.viewholder.feed.FeedVideoViewHolder; | ||||
| // import awais.instagrabber.customviews.RamboTextView; | ||||
| // import awais.instagrabber.databinding.ItemFeedPhotoBinding; | ||||
| // import awais.instagrabber.databinding.ItemFeedSliderBinding; | ||||
| // import awais.instagrabber.databinding.ItemFeedVideoBinding; | ||||
| // import awais.instagrabber.interfaces.MentionClickListener; | ||||
| // import awais.instagrabber.models.FeedModel; | ||||
| // import awais.instagrabber.models.enums.MediaItemType; | ||||
| // import awais.instagrabber.utils.Utils; | ||||
| // | ||||
| // public final class FeedAdapter extends ListAdapter<FeedModel, FeedItemViewHolder> { | ||||
| //     private static final String TAG = "FeedAdapter"; | ||||
| //     private final View.OnClickListener clickListener; | ||||
| //     private final MentionClickListener mentionClickListener; | ||||
| //     private final View.OnLongClickListener longClickListener = v -> { | ||||
| //         final Object tag; | ||||
| //         if (v instanceof RamboTextView && (tag = v.getTag()) instanceof FeedModel) | ||||
| //             Utils.copyText(v.getContext(), ((FeedModel) tag).getPostCaption()); | ||||
| //         return true; | ||||
| //     }; | ||||
| // | ||||
| //     private static final DiffUtil.ItemCallback<FeedModel> diffCallback = new DiffUtil.ItemCallback<FeedModel>() { | ||||
| //         @Override | ||||
| //         public boolean areItemsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) { | ||||
| //             return oldItem.getPostId().equals(newItem.getPostId()); | ||||
| //         } | ||||
| // | ||||
| //         @Override | ||||
| //         public boolean areContentsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) { | ||||
| //             return oldItem.getPostId().equals(newItem.getPostId()); | ||||
| //         } | ||||
| //     }; | ||||
| // | ||||
| //     public FeedAdapter(final View.OnClickListener clickListener, | ||||
| //                        final MentionClickListener mentionClickListener) { | ||||
| //         super(diffCallback); | ||||
| //         // private final static String ellipsize = "… more"; | ||||
| //         this.clickListener = clickListener; | ||||
| //         this.mentionClickListener = mentionClickListener; | ||||
| //     } | ||||
| // | ||||
| //     @NonNull | ||||
| //     @Override | ||||
| //     public FeedItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { | ||||
| //         final Context context = parent.getContext(); | ||||
| //         final LayoutInflater layoutInflater = LayoutInflater.from(context); | ||||
| //         final MediaItemType type = MediaItemType.valueOf(viewType); | ||||
| //         switch (type) { | ||||
| //             case MEDIA_TYPE_VIDEO: { | ||||
| //                 final ItemFeedVideoBinding binding = ItemFeedVideoBinding.inflate(layoutInflater, parent, false); | ||||
| //                 return new FeedVideoViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
| //             } | ||||
| //             case MEDIA_TYPE_SLIDER: { | ||||
| //                 final ItemFeedSliderBinding binding = ItemFeedSliderBinding.inflate(layoutInflater, parent, false); | ||||
| //                 return new FeedSliderViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
| //             } | ||||
| //             case MEDIA_TYPE_IMAGE: | ||||
| //             default: { | ||||
| //                 final ItemFeedPhotoBinding binding = ItemFeedPhotoBinding.inflate(layoutInflater, parent, false); | ||||
| //                 return new FeedPhotoViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
| //             } | ||||
| //         } | ||||
| //     } | ||||
| // | ||||
| //     @Override | ||||
| //     public void onBindViewHolder(@NonNull final FeedItemViewHolder viewHolder, final int position) { | ||||
| //         final FeedModel feedModel = getItem(position); | ||||
| //         if (feedModel == null) { | ||||
| //             return; | ||||
| //         } | ||||
| //         feedModel.setPosition(position); | ||||
| //         viewHolder.bind(feedModel, (feedModel1, view, postImage) -> {}); | ||||
| //     } | ||||
| // | ||||
| //     @Override | ||||
| //     public int getItemViewType(final int position) { | ||||
| //         return getItem(position).getItemType().getId(); | ||||
| //     } | ||||
| // | ||||
| //     @Override | ||||
| //     public void onViewAttachedToWindow(@NonNull final FeedItemViewHolder holder) { | ||||
| //         super.onViewAttachedToWindow(holder); | ||||
| //         // Log.d(TAG, "attached holder: " + holder); | ||||
| //         if (!(holder instanceof FeedSliderViewHolder)) return; | ||||
| //         final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder; | ||||
| //         feedSliderViewHolder.startPlayingVideo(); | ||||
| //     } | ||||
| // | ||||
| //     @Override | ||||
| //     public void onViewDetachedFromWindow(@NonNull final FeedItemViewHolder holder) { | ||||
| //         super.onViewDetachedFromWindow(holder); | ||||
| //         // Log.d(TAG, "detached holder: " + holder); | ||||
| //         if (!(holder instanceof FeedSliderViewHolder)) return; | ||||
| //         final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder; | ||||
| //         feedSliderViewHolder.stopPlayingVideo(); | ||||
| //     } | ||||
| // } | ||||
| @ -15,32 +15,26 @@ import awais.instagrabber.adapters.viewholder.feed.FeedItemViewHolder; | ||||
| import awais.instagrabber.adapters.viewholder.feed.FeedPhotoViewHolder; | ||||
| import awais.instagrabber.adapters.viewholder.feed.FeedSliderViewHolder; | ||||
| import awais.instagrabber.adapters.viewholder.feed.FeedVideoViewHolder; | ||||
| import awais.instagrabber.customviews.RamboTextView; | ||||
| import awais.instagrabber.databinding.ItemFeedGridBinding; | ||||
| import awais.instagrabber.databinding.ItemFeedPhotoBinding; | ||||
| import awais.instagrabber.databinding.ItemFeedSliderBinding; | ||||
| import awais.instagrabber.databinding.ItemFeedVideoBinding; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.models.PostsLayoutPreferences; | ||||
| import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.ViewHolder> { | ||||
|     private static final String TAG = "FeedAdapterV2"; | ||||
| 
 | ||||
|     private PostsLayoutPreferences layoutPreferences; | ||||
|     private OnPostClickListener postClickListener; | ||||
|     private int lastAnimatedPosition; | ||||
|     private final FeedItemCallback feedItemCallback; | ||||
| 
 | ||||
|     private final View.OnClickListener clickListener; | ||||
|     private final MentionClickListener mentionClickListener; | ||||
|     private final View.OnLongClickListener longClickListener = v -> { | ||||
|         final Object tag; | ||||
|         if (v instanceof RamboTextView && (tag = v.getTag()) instanceof FeedModel) | ||||
|             Utils.copyText(v.getContext(), ((FeedModel) tag).getPostCaption()); | ||||
|         return true; | ||||
|     }; | ||||
|     // private final View.OnLongClickListener longClickListener = v -> { | ||||
|     //     final Object tag; | ||||
|     //     if (v instanceof RamboTextView && (tag = v.getTag()) instanceof FeedModel) | ||||
|     //         Utils.copyText(v.getContext(), ((FeedModel) tag).getPostCaption()); | ||||
|     //     return true; | ||||
|     // }; | ||||
| 
 | ||||
| 
 | ||||
|     private static final DiffUtil.ItemCallback<FeedModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<FeedModel>() { | ||||
| @ -56,14 +50,10 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie | ||||
|     }; | ||||
| 
 | ||||
|     public FeedAdapterV2(@NonNull final PostsLayoutPreferences layoutPreferences, | ||||
|                          final View.OnClickListener clickListener, | ||||
|                          final MentionClickListener mentionClickListener, | ||||
|                          final OnPostClickListener postClickListener) { | ||||
|                          final FeedItemCallback feedItemCallback) { | ||||
|         super(DIFF_CALLBACK); | ||||
|         this.layoutPreferences = layoutPreferences; | ||||
|         this.clickListener = clickListener; | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
|         this.postClickListener = postClickListener; | ||||
|         this.feedItemCallback = feedItemCallback; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
| @ -89,16 +79,16 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie | ||||
|         switch (MediaItemType.valueOf(viewType)) { | ||||
|             case MEDIA_TYPE_VIDEO: { | ||||
|                 final ItemFeedVideoBinding binding = ItemFeedVideoBinding.inflate(layoutInflater, parent, false); | ||||
|                 return new FeedVideoViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
|                 return new FeedVideoViewHolder(binding, feedItemCallback); | ||||
|             } | ||||
|             case MEDIA_TYPE_SLIDER: { | ||||
|                 final ItemFeedSliderBinding binding = ItemFeedSliderBinding.inflate(layoutInflater, parent, false); | ||||
|                 return new FeedSliderViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
|                 return new FeedSliderViewHolder(binding, feedItemCallback); | ||||
|             } | ||||
|             case MEDIA_TYPE_IMAGE: | ||||
|             default: { | ||||
|                 final ItemFeedPhotoBinding binding = ItemFeedPhotoBinding.inflate(layoutInflater, parent, false); | ||||
|                 return new FeedPhotoViewHolder(binding, mentionClickListener, clickListener, longClickListener); | ||||
|                 return new FeedPhotoViewHolder(binding, feedItemCallback); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -110,15 +100,13 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie | ||||
|         feedModel.setPosition(position); | ||||
|         switch (layoutPreferences.getType()) { | ||||
|             case LINEAR: | ||||
|                 ((FeedItemViewHolder) viewHolder).bind(feedModel, postClickListener); | ||||
|                 ((FeedItemViewHolder) viewHolder).bind(feedModel); | ||||
|                 break; | ||||
|             case GRID: | ||||
|             case STAGGERED_GRID: | ||||
|             default: | ||||
|                 final boolean animate = position > lastAnimatedPosition; | ||||
|                 ((FeedGridItemViewHolder) viewHolder).bind(feedModel, layoutPreferences, postClickListener, false); | ||||
|                 ((FeedGridItemViewHolder) viewHolder).bind(feedModel, layoutPreferences, feedItemCallback); | ||||
|         } | ||||
|         lastAnimatedPosition = position; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -126,19 +114,6 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie | ||||
|         return getItem(position).getItemType().getId(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onViewDetachedFromWindow(@NonNull final RecyclerView.ViewHolder viewHolder) { | ||||
|         switch (layoutPreferences.getType()) { | ||||
|             case LINEAR: | ||||
|                 ((FeedItemViewHolder) viewHolder).clearAnimation(); | ||||
|                 break; | ||||
|             case GRID: | ||||
|             case STAGGERED_GRID: | ||||
|             default: | ||||
|                 ((FeedGridItemViewHolder) viewHolder).clearAnimation(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void setLayoutPreferences(@NonNull final PostsLayoutPreferences layoutPreferences) { | ||||
|         this.layoutPreferences = layoutPreferences; | ||||
|     } | ||||
| @ -161,9 +136,31 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie | ||||
|     //     feedSliderViewHolder.stopPlayingVideo(); | ||||
|     // } | ||||
| 
 | ||||
|     public interface OnPostClickListener { | ||||
|     public interface FeedItemCallback { | ||||
|         void onPostClick(final FeedModel feedModel, | ||||
|                          final View profilePicView, | ||||
|                          final View mainPostImage); | ||||
| 
 | ||||
|         void onProfilePicClick(final FeedModel feedModel, | ||||
|                                final View profilePicView); | ||||
| 
 | ||||
|         void onNameClick(final FeedModel feedModel, | ||||
|                          final View profilePicView); | ||||
| 
 | ||||
|         void onLocationClick(final FeedModel feedModel); | ||||
| 
 | ||||
|         void onMentionClick(final String mention); | ||||
| 
 | ||||
|         void onHashtagClick(final String hashtag); | ||||
| 
 | ||||
|         void onCommentsClick(final FeedModel feedModel); | ||||
| 
 | ||||
|         void onDownloadClick(final FeedModel feedModel); | ||||
| 
 | ||||
|         void onEmailClick(final String emailId); | ||||
| 
 | ||||
|         void onURLClick(final String url); | ||||
| 
 | ||||
|         void onSliderClick(FeedModel feedModel, int position); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package awais.instagrabber.adapters; | ||||
| 
 | ||||
| import android.view.View; | ||||
| 
 | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| 
 | ||||
| public class FeedItemCallbackAdapter implements FeedAdapterV2.FeedItemCallback { | ||||
|     @Override | ||||
|     public void onPostClick(final FeedModel feedModel, final View profilePicView, final View mainPostImage) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onProfilePicClick(final FeedModel feedModel, final View profilePicView) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onNameClick(final FeedModel feedModel, final View profilePicView) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onLocationClick(final FeedModel feedModel) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onMentionClick(final String mention) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onHashtagClick(final String hashtag) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCommentsClick(final FeedModel feedModel) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onDownloadClick(final FeedModel feedModel) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onEmailClick(final String emailId) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onURLClick(final String url) {} | ||||
| 
 | ||||
|     @Override | ||||
|     public void onSliderClick(final FeedModel feedModel, final int position) {} | ||||
| } | ||||
| @ -20,6 +20,7 @@ import awais.instagrabber.models.enums.MediaItemType; | ||||
| public final class SliderItemsAdapter extends ListAdapter<PostChild, SliderItemViewHolder> { | ||||
| 
 | ||||
|     private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener; | ||||
|     private final boolean loadVideoOnItemClick; | ||||
|     private final SliderCallback sliderCallback; | ||||
|     private final awais.instagrabber.databinding.LayoutExoCustomControlsBinding controlsBinding; | ||||
| 
 | ||||
| @ -35,15 +36,13 @@ public final class SliderItemsAdapter extends ListAdapter<PostChild, SliderItemV | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     public SliderItemsAdapter() { | ||||
|         this(null, null, null); | ||||
|     } | ||||
| 
 | ||||
|     public SliderItemsAdapter(final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener, | ||||
|                               final LayoutExoCustomControlsBinding controlsBinding, | ||||
|                               final boolean loadVideoOnItemClick, | ||||
|                               final SliderCallback sliderCallback) { | ||||
|         super(DIFF_CALLBACK); | ||||
|         this.onVerticalDragListener = onVerticalDragListener; | ||||
|         this.loadVideoOnItemClick = loadVideoOnItemClick; | ||||
|         this.sliderCallback = sliderCallback; | ||||
|         this.controlsBinding = controlsBinding; | ||||
|     } | ||||
| @ -56,7 +55,7 @@ public final class SliderItemsAdapter extends ListAdapter<PostChild, SliderItemV | ||||
|         switch (mediaItemType) { | ||||
|             case MEDIA_TYPE_VIDEO: { | ||||
|                 final LayoutVideoPlayerWithThumbnailBinding binding = LayoutVideoPlayerWithThumbnailBinding.inflate(inflater, parent, false); | ||||
|                 return new SliderVideoViewHolder(binding, onVerticalDragListener, controlsBinding); | ||||
|                 return new SliderVideoViewHolder(binding, onVerticalDragListener, controlsBinding, loadVideoOnItemClick); | ||||
|             } | ||||
|             case MEDIA_TYPE_IMAGE: | ||||
|             default: | ||||
|  | ||||
| @ -1,95 +0,0 @@ | ||||
| package awais.instagrabber.adapters.viewholder; | ||||
| 
 | ||||
| import android.text.Spannable; | ||||
| import android.view.View; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import com.facebook.drawee.view.SimpleDraweeView; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.CommentsAdapter; | ||||
| import awais.instagrabber.customviews.RamboTextView; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.CommentModel; | ||||
| 
 | ||||
| public final class CommentViewHolder extends RecyclerView.ViewHolder { | ||||
|     private final MentionClickListener mentionClickListener; | ||||
|     private final RecyclerView rvChildComments; | ||||
|     private final SimpleDraweeView ivProfilePic; | ||||
|     private final TextView tvUsername; | ||||
|     private final TextView tvDate; | ||||
|     private final TextView tvComment; | ||||
|     private final TextView tvLikes; | ||||
|     private final View container; | ||||
| 
 | ||||
|     public CommentViewHolder(@NonNull final View itemView, | ||||
|                              final View.OnClickListener onClickListener, | ||||
|                              final MentionClickListener mentionClickListener) { | ||||
|         super(itemView); | ||||
| 
 | ||||
|         container = itemView.findViewById(R.id.container); | ||||
|         if (onClickListener != null) container.setOnClickListener(onClickListener); | ||||
| 
 | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
| 
 | ||||
|         ivProfilePic = itemView.findViewById(R.id.ivProfilePic); | ||||
|         tvUsername = itemView.findViewById(R.id.tvUsername); | ||||
|         tvDate = itemView.findViewById(R.id.tvDate); | ||||
|         tvLikes = itemView.findViewById(R.id.tvLikes); | ||||
|         tvComment = itemView.findViewById(R.id.tvComment); | ||||
| 
 | ||||
|         tvUsername.setSelected(true); | ||||
|         tvDate.setSelected(true); | ||||
| 
 | ||||
|         rvChildComments = itemView.findViewById(R.id.rvChildComments); | ||||
|     } | ||||
| 
 | ||||
|     public final SimpleDraweeView getProfilePicView() { | ||||
|         return ivProfilePic; | ||||
|     } | ||||
| 
 | ||||
|     public final boolean isParent() { | ||||
|         return rvChildComments != null; | ||||
|     } | ||||
| 
 | ||||
|     public final void setCommentModel(final CommentModel commentModel) { | ||||
|         if (container != null) container.setTag(commentModel); | ||||
|     } | ||||
| 
 | ||||
|     public final void setUsername(final String username) { | ||||
|         if (tvUsername != null) tvUsername.setText(username); | ||||
|     } | ||||
| 
 | ||||
|     public final void setDate(final String date) { | ||||
|         if (tvDate != null) tvDate.setText(date); | ||||
|     } | ||||
| 
 | ||||
|     public final void setLikes(final String likes) { | ||||
|         if (tvLikes != null) tvLikes.setText(likes); | ||||
|     } | ||||
| 
 | ||||
|     public final void setLiked(final boolean liked) { | ||||
|         if (liked) container.setBackgroundColor(0x40FF69B4); | ||||
|     } | ||||
| 
 | ||||
|     public final void setComment(final CharSequence comment) { | ||||
|         if (tvComment != null) { | ||||
|             tvComment.setText(comment, comment instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL); | ||||
|             ((RamboTextView) tvComment).setMentionClickListener(mentionClickListener); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public final void setChildAdapter(final CommentsAdapter adapter) { | ||||
|         if (isParent()) { | ||||
|             rvChildComments.setAdapter(adapter); | ||||
|             rvChildComments.setVisibility(View.VISIBLE); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public final void hideChildComments() { | ||||
|         if (isParent()) rvChildComments.setVisibility(View.GONE); | ||||
|     } | ||||
| } | ||||
| @ -1,11 +1,8 @@ | ||||
| package awais.instagrabber.adapters.viewholder; | ||||
| 
 | ||||
| import android.graphics.drawable.Animatable; | ||||
| import android.net.Uri; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.view.animation.Animation; | ||||
| import android.view.animation.AnimationUtils; | ||||
| 
 | ||||
| import androidx.annotation.DimenRes; | ||||
| import androidx.annotation.NonNull; | ||||
| @ -13,8 +10,6 @@ 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.imagepipeline.image.ImageInfo; | ||||
| import com.facebook.imagepipeline.request.ImageRequest; | ||||
| import com.facebook.imagepipeline.request.ImageRequestBuilder; | ||||
| 
 | ||||
| @ -42,10 +37,9 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder { | ||||
| 
 | ||||
|     public void bind(@NonNull final FeedModel feedModel, | ||||
|                      @NonNull final PostsLayoutPreferences layoutPreferences, | ||||
|                      final FeedAdapterV2.OnPostClickListener postClickListener, | ||||
|                      final boolean animate) { | ||||
|         if (postClickListener != null) { | ||||
|             itemView.setOnClickListener(v -> postClickListener.onPostClick(feedModel, binding.profilePic, binding.postImage)); | ||||
|                      final FeedAdapterV2.FeedItemCallback feedItemCallback) { | ||||
|         if (feedItemCallback != null) { | ||||
|             itemView.setOnClickListener(v -> feedItemCallback.onPostClick(feedModel, binding.profilePic, binding.postImage)); | ||||
|         } | ||||
|         itemView.setClipToOutline(layoutPreferences.getHasRoundedCorners()); | ||||
|         if (layoutPreferences.getType() == STAGGERED_GRID) { | ||||
| @ -123,25 +117,6 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder { | ||||
|         final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder() | ||||
|                                                               .setImageRequest(requestBuilder) | ||||
|                                                               .setOldController(binding.postImage.getController()); | ||||
|         if (animate) { | ||||
|             final BaseControllerListener<ImageInfo> imageListener = new BaseControllerListener<ImageInfo>() { | ||||
|                 @Override | ||||
|                 public void onFinalImageSet(final String id, final ImageInfo imageInfo, final Animatable animatable) { | ||||
|                     setAnimation(binding.getRoot()); | ||||
|                 } | ||||
|             }; | ||||
|             builder.setControllerListener(imageListener); | ||||
|         } | ||||
|         binding.postImage.setController(builder.build()); | ||||
|     } | ||||
| 
 | ||||
|     private void setAnimation(View viewToAnimate) { | ||||
|         final Animation animation = AnimationUtils.loadAnimation(viewToAnimate.getContext(), android.R.anim.fade_in); | ||||
|         animation.setDuration(300); | ||||
|         viewToAnimate.startAnimation(animation); | ||||
|     } | ||||
| 
 | ||||
|     public void clearAnimation() { | ||||
|         binding.getRoot().clearAnimation(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -22,34 +22,39 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { | ||||
|     private static final String TAG = "SliderVideoViewHolder"; | ||||
| 
 | ||||
|     private final LayoutVideoPlayerWithThumbnailBinding binding; | ||||
|     private final awais.instagrabber.databinding.LayoutExoCustomControlsBinding controlsBinding; | ||||
|     private final LayoutExoCustomControlsBinding controlsBinding; | ||||
|     private final boolean loadVideoOnItemClick; | ||||
|     private VideoPlayerViewHelper videoPlayerViewHelper; | ||||
| 
 | ||||
|     @SuppressLint("ClickableViewAccessibility") | ||||
|     public SliderVideoViewHolder(@NonNull final LayoutVideoPlayerWithThumbnailBinding binding, | ||||
|                                  final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener, | ||||
|                                  final LayoutExoCustomControlsBinding controlsBinding) { | ||||
|                                  final LayoutExoCustomControlsBinding controlsBinding, | ||||
|                                  final boolean loadVideoOnItemClick) { | ||||
|         super(binding.getRoot()); | ||||
|         this.binding = binding; | ||||
|         this.controlsBinding = controlsBinding; | ||||
|         final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent); | ||||
|         final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.playerView); | ||||
|         thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); | ||||
|         playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); | ||||
|         binding.thumbnailParent.setOnTouchListener((v, event) -> { | ||||
|             final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event); | ||||
|             if (onDragTouch) { | ||||
|                 return true; | ||||
|             } | ||||
|             return thumbnailVerticalDragHelper.onGestureTouchEvent(event); | ||||
|         }); | ||||
|         binding.playerView.setOnTouchListener((v, event) -> { | ||||
|             final boolean onDragTouch = playerVerticalDragHelper.onDragTouch(event); | ||||
|             if (onDragTouch) { | ||||
|                 return true; | ||||
|             } | ||||
|             return playerVerticalDragHelper.onGestureTouchEvent(event); | ||||
|         }); | ||||
|         this.loadVideoOnItemClick = loadVideoOnItemClick; | ||||
|         if (onVerticalDragListener != null) { | ||||
|             final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent); | ||||
|             final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.playerView); | ||||
|             thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); | ||||
|             playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); | ||||
|             binding.thumbnailParent.setOnTouchListener((v, event) -> { | ||||
|                 final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event); | ||||
|                 if (onDragTouch) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 return thumbnailVerticalDragHelper.onGestureTouchEvent(event); | ||||
|             }); | ||||
|             binding.playerView.setOnTouchListener((v, event) -> { | ||||
|                 final boolean onDragTouch = playerVerticalDragHelper.onDragTouch(event); | ||||
|                 if (onDragTouch) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 return playerVerticalDragHelper.onGestureTouchEvent(event); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void bind(@NonNull final PostChild model, | ||||
| @ -57,6 +62,14 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { | ||||
|                      final SliderItemsAdapter.SliderCallback sliderCallback) { | ||||
|         final float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f; | ||||
|         final VideoPlayerViewHelper.VideoPlayerCallback videoPlayerCallback = new VideoPlayerCallbackAdapter() { | ||||
| 
 | ||||
|             @Override | ||||
|             public void onThumbnailClick() { | ||||
|                 if (sliderCallback != null) { | ||||
|                     sliderCallback.onItemClicked(position); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onThumbnailLoaded() { | ||||
|                 if (sliderCallback != null) { | ||||
| @ -97,6 +110,7 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { | ||||
|                                                           vol, | ||||
|                                                           aspectRatio, | ||||
|                                                           model.getThumbnailUrl(), | ||||
|                                                           loadVideoOnItemClick, | ||||
|                                                           controlsBinding, | ||||
|                                                           videoPlayerCallback); | ||||
|         // binding.itemFeedBottom.btnMute.setOnClickListener(v -> { | ||||
|  | ||||
| @ -0,0 +1,93 @@ | ||||
| package awais.instagrabber.adapters.viewholder.comments; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.CommentsAdapter.CommentCallback; | ||||
| import awais.instagrabber.databinding.ItemCommentSmallBinding; | ||||
| import awais.instagrabber.models.CommentModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public final class ChildCommentViewHolder extends RecyclerView.ViewHolder { | ||||
| 
 | ||||
|     private final ItemCommentSmallBinding binding; | ||||
| 
 | ||||
|     public ChildCommentViewHolder(@NonNull final ItemCommentSmallBinding binding) { | ||||
|         super(binding.getRoot()); | ||||
|         this.binding = binding; | ||||
|     } | ||||
| 
 | ||||
|     public void bind(final CommentModel comment, | ||||
|                      final boolean selected, | ||||
|                      final CommentCallback commentCallback) { | ||||
|         if (comment == null) return; | ||||
|         if (commentCallback != null) { | ||||
|             itemView.setOnClickListener(v -> commentCallback.onClick(comment)); | ||||
|         } | ||||
|         if (selected) { | ||||
|             itemView.setBackgroundColor(itemView.getResources().getColor(R.color.comment_selected)); | ||||
|         } else { | ||||
|             itemView.setBackgroundColor(itemView.getResources().getColor(android.R.color.transparent)); | ||||
|         } | ||||
|         setupCommentText(comment, commentCallback); | ||||
|         binding.tvDate.setText(comment.getDateTime()); | ||||
|         setLiked(comment.getLiked()); | ||||
|         setLikes((int) comment.getLikes()); | ||||
|         setUser(comment); | ||||
|     } | ||||
| 
 | ||||
|     private void setupCommentText(final CommentModel comment, final CommentCallback commentCallback) { | ||||
|         binding.tvComment.clearOnURLClickListeners(); | ||||
|         binding.tvComment.clearOnHashtagClickListeners(); | ||||
|         binding.tvComment.clearOnMentionClickListeners(); | ||||
|         binding.tvComment.clearOnEmailClickListeners(); | ||||
|         binding.tvComment.setText(comment.getText()); | ||||
|         binding.tvComment.addOnHashtagListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onHashtagClick(originalText); | ||||
|         }); | ||||
|         binding.tvComment.addOnMentionClickListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onMentionClick(originalText); | ||||
| 
 | ||||
|         }); | ||||
|         binding.tvComment.addOnEmailClickListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onEmailClick(originalText); | ||||
|         }); | ||||
|         binding.tvComment.addOnURLClickListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onURLClick(originalText); | ||||
|         }); | ||||
|         binding.tvComment.setOnLongClickListener(v -> { | ||||
|             Utils.copyText(itemView.getContext(), comment.getText()); | ||||
|             return true; | ||||
|         }); | ||||
|         binding.tvComment.setOnClickListener(v -> commentCallback.onClick(comment)); | ||||
|     } | ||||
| 
 | ||||
|     private void setUser(final CommentModel comment) { | ||||
|         final ProfileModel profileModel = comment.getProfileModel(); | ||||
|         if (profileModel == null) return; | ||||
|         binding.tvUsername.setText(profileModel.getUsername()); | ||||
|         binding.ivProfilePic.setImageURI(profileModel.getSdProfilePic()); | ||||
|     } | ||||
| 
 | ||||
|     private void setLikes(final int likes) { | ||||
|         final String likesString = itemView.getResources().getQuantityString(R.plurals.likes_count, likes, likes); | ||||
|         binding.tvLikes.setText(likesString); | ||||
|     } | ||||
| 
 | ||||
|     public final void setLiked(final boolean liked) { | ||||
|         if (liked) { | ||||
|             // container.setBackgroundColor(0x40FF69B4); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,93 @@ | ||||
| package awais.instagrabber.adapters.viewholder.comments; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.CommentsAdapter.CommentCallback; | ||||
| import awais.instagrabber.databinding.ItemCommentBinding; | ||||
| import awais.instagrabber.models.CommentModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public final class ParentCommentViewHolder extends RecyclerView.ViewHolder { | ||||
| 
 | ||||
|     private final ItemCommentBinding binding; | ||||
| 
 | ||||
|     public ParentCommentViewHolder(@NonNull final ItemCommentBinding binding) { | ||||
|         super(binding.getRoot()); | ||||
|         this.binding = binding; | ||||
|     } | ||||
| 
 | ||||
|     public void bind(final CommentModel comment, | ||||
|                      final boolean selected, | ||||
|                      final CommentCallback commentCallback) { | ||||
|         if (comment == null) return; | ||||
|         if (commentCallback != null) { | ||||
|             itemView.setOnClickListener(v -> commentCallback.onClick(comment)); | ||||
|         } | ||||
|         if (selected) { | ||||
|             itemView.setBackgroundColor(itemView.getResources().getColor(R.color.comment_selected)); | ||||
|         } else { | ||||
|             itemView.setBackgroundColor(itemView.getResources().getColor(android.R.color.transparent)); | ||||
|         } | ||||
|         setupCommentText(comment, commentCallback); | ||||
|         binding.tvDate.setText(comment.getDateTime()); | ||||
|         setLiked(comment.getLiked()); | ||||
|         setLikes((int) comment.getLikes()); | ||||
|         setUser(comment); | ||||
|     } | ||||
| 
 | ||||
|     private void setupCommentText(final CommentModel comment, final CommentCallback commentCallback) { | ||||
|         binding.tvComment.clearOnURLClickListeners(); | ||||
|         binding.tvComment.clearOnHashtagClickListeners(); | ||||
|         binding.tvComment.clearOnMentionClickListeners(); | ||||
|         binding.tvComment.clearOnEmailClickListeners(); | ||||
|         binding.tvComment.setText(comment.getText()); | ||||
|         binding.tvComment.addOnHashtagListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onHashtagClick(originalText); | ||||
|         }); | ||||
|         binding.tvComment.addOnMentionClickListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onMentionClick(originalText); | ||||
| 
 | ||||
|         }); | ||||
|         binding.tvComment.addOnEmailClickListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onEmailClick(originalText); | ||||
|         }); | ||||
|         binding.tvComment.addOnURLClickListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (commentCallback == null) return; | ||||
|             commentCallback.onURLClick(originalText); | ||||
|         }); | ||||
|         binding.tvComment.setOnLongClickListener(v -> { | ||||
|             Utils.copyText(itemView.getContext(), comment.getText()); | ||||
|             return true; | ||||
|         }); | ||||
|         binding.tvComment.setOnClickListener(v -> commentCallback.onClick(comment)); | ||||
|     } | ||||
| 
 | ||||
|     private void setUser(final CommentModel comment) { | ||||
|         final ProfileModel profileModel = comment.getProfileModel(); | ||||
|         if (profileModel == null) return; | ||||
|         binding.tvUsername.setText(profileModel.getUsername()); | ||||
|         binding.ivProfilePic.setImageURI(profileModel.getSdProfilePic()); | ||||
|     } | ||||
| 
 | ||||
|     private void setLikes(final int likes) { | ||||
|         final String likesString = itemView.getResources().getQuantityString(R.plurals.likes_count, likes, likes); | ||||
|         binding.tvLikes.setText(likesString); | ||||
|     } | ||||
| 
 | ||||
|     public final void setLiked(final boolean liked) { | ||||
|         if (liked) { | ||||
|             // container.setBackgroundColor(0x40FF69B4); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,95 +1,107 @@ | ||||
| package awais.instagrabber.adapters.viewholder.feed; | ||||
| 
 | ||||
| import android.text.SpannableString; | ||||
| import android.text.Spanned; | ||||
| import android.text.method.LinkMovementMethod; | ||||
| import android.transition.TransitionManager; | ||||
| import android.view.View; | ||||
| import android.widget.RelativeLayout; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import awais.instagrabber.adapters.FeedAdapterV2; | ||||
| import awais.instagrabber.customviews.CommentMentionClickSpan; | ||||
| import awais.instagrabber.customviews.RamboTextView; | ||||
| import awais.instagrabber.databinding.ItemFeedBottomBinding; | ||||
| import awais.instagrabber.databinding.ItemFeedTopBinding; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| 
 | ||||
| import static android.text.TextUtils.TruncateAt.END; | ||||
| 
 | ||||
| public abstract class FeedItemViewHolder extends RecyclerView.ViewHolder { | ||||
|     public static final int MAX_CHARS = 255; | ||||
|     public static final int MAX_LINES_COLLAPSED = 5; | ||||
|     private final ItemFeedTopBinding topBinding; | ||||
|     private final ItemFeedBottomBinding bottomBinding; | ||||
|     private final MentionClickListener mentionClickListener; | ||||
|     private final FeedAdapterV2.FeedItemCallback feedItemCallback; | ||||
| 
 | ||||
|     public FeedItemViewHolder(@NonNull final View root, | ||||
|                               final ItemFeedTopBinding topBinding, | ||||
|                               final ItemFeedBottomBinding bottomBinding, | ||||
|                               final MentionClickListener mentionClickListener, | ||||
|                               final View.OnClickListener clickListener, | ||||
|                               final View.OnLongClickListener longClickListener) { | ||||
|                               final FeedAdapterV2.FeedItemCallback feedItemCallback) { | ||||
|         super(root); | ||||
|         this.topBinding = topBinding; | ||||
|         this.bottomBinding = bottomBinding; | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
|         // itemView.setOnClickListener(clickListener); | ||||
|         // topBinding.title.setMovementMethod(new LinkMovementMethod()); | ||||
|         // bottomBinding.btnComments.setOnClickListener(clickListener); | ||||
|         // topBinding.viewStoryPost.setOnClickListener(clickListener); | ||||
|         // topBinding.ivProfilePic.setOnClickListener(clickListener); | ||||
|         // bottomBinding.btnDownload.setOnClickListener(clickListener); | ||||
|         // bottomBinding.viewerCaption.setOnClickListener(clickListener); | ||||
|         // bottomBinding.viewerCaption.setOnLongClickListener(longClickListener); | ||||
|         // bottomBinding.viewerCaption.setMentionClickListener(mentionClickListener); | ||||
|         topBinding.title.setMovementMethod(new LinkMovementMethod()); | ||||
|         this.feedItemCallback = feedItemCallback; | ||||
|     } | ||||
| 
 | ||||
|     public void bind(final FeedModel feedModel, | ||||
|                      final FeedAdapterV2.OnPostClickListener postClickListener) { | ||||
|     public void bind(final FeedModel feedModel) { | ||||
|         if (feedModel == null) { | ||||
|             return; | ||||
|         } | ||||
|         topBinding.viewStoryPost.setTag(feedModel); | ||||
|         topBinding.ivProfilePic.setTag(feedModel); | ||||
|         bottomBinding.btnDownload.setTag(feedModel); | ||||
|         bottomBinding.viewerCaption.setTag(feedModel); | ||||
|         bottomBinding.btnComments.setTag(feedModel); | ||||
|         final ProfileModel profileModel = feedModel.getProfileModel(); | ||||
|         if (profileModel != null) { | ||||
|             topBinding.ivProfilePic.setImageURI(profileModel.getSdProfilePic()); | ||||
|             final int titleLen = profileModel.getUsername().length() + 1; | ||||
|             final SpannableString spannableString = new SpannableString("@" + profileModel.getUsername()); | ||||
|             spannableString.setSpan(new CommentMentionClickSpan(), 0, titleLen, 0); | ||||
|             topBinding.title.setText(spannableString); | ||||
|             topBinding.title.setMentionClickListener( | ||||
|                     (view, text, isHashtag, isLocation) -> mentionClickListener.onClick(null, profileModel.getUsername(), false, false)); | ||||
|         } | ||||
|         setupProfilePic(feedModel); | ||||
|         setupLocation(feedModel); | ||||
|         bottomBinding.tvPostDate.setText(feedModel.getPostDate()); | ||||
|         final long commentsCount = feedModel.getCommentsCount(); | ||||
|         bottomBinding.commentsCount.setText(String.valueOf(commentsCount)); | ||||
| 
 | ||||
|         final String locationName = feedModel.getLocationName(); | ||||
|         final String locationId = feedModel.getLocationId(); | ||||
|         setLocation(locationName, locationId); | ||||
|         CharSequence postCaption = feedModel.getPostCaption(); | ||||
|         final boolean captionEmpty = TextUtils.isEmpty(postCaption); | ||||
|         bottomBinding.viewerCaption.setVisibility(captionEmpty ? View.GONE : View.VISIBLE); | ||||
|         if (!captionEmpty) { | ||||
|             if (TextUtils.hasMentions(postCaption)) { | ||||
|                 postCaption = TextUtils.getMentionText(postCaption); | ||||
|                 feedModel.setPostCaption(postCaption); | ||||
|                 bottomBinding.viewerCaption.setText(postCaption, TextView.BufferType.SPANNABLE); | ||||
|             } else { | ||||
|                 bottomBinding.viewerCaption.setText(postCaption); | ||||
|             } | ||||
|         } | ||||
|         expandCollapseTextView(bottomBinding.viewerCaption, feedModel.getPostCaption()); | ||||
|         bindItem(feedModel, postClickListener); | ||||
|         setupComments(feedModel); | ||||
|         setupCaption(feedModel); | ||||
|         bottomBinding.btnDownload.setOnClickListener(v -> feedItemCallback.onDownloadClick(feedModel)); | ||||
|         bindItem(feedModel); | ||||
|     } | ||||
| 
 | ||||
|     private void setLocation(final String locationName, final String locationId) { | ||||
|     private void setupComments(final FeedModel feedModel) { | ||||
|         final long commentsCount = feedModel.getCommentsCount(); | ||||
|         bottomBinding.commentsCount.setText(String.valueOf(commentsCount)); | ||||
|         bottomBinding.commentsCount.setOnClickListener(v -> feedItemCallback.onCommentsClick(feedModel)); | ||||
|     } | ||||
| 
 | ||||
|     private void setupProfilePic(final FeedModel feedModel) { | ||||
|         final ProfileModel profileModel = feedModel.getProfileModel(); | ||||
|         if (profileModel != null) { | ||||
|             topBinding.ivProfilePic.setOnClickListener(v -> feedItemCallback.onProfilePicClick(feedModel, topBinding.ivProfilePic)); | ||||
|             topBinding.ivProfilePic.setImageURI(profileModel.getSdProfilePic()); | ||||
|             setupTitle(feedModel); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void setupTitle(final FeedModel feedModel) { | ||||
|         // final int titleLen = profileModel.getUsername().length() + 1; | ||||
|         // final SpannableString spannableString = new SpannableString(); | ||||
|         // spannableString.setSpan(new CommentMentionClickSpan(), 0, titleLen, 0); | ||||
|         final ProfileModel profileModel = feedModel.getProfileModel(); | ||||
|         final String title = "@" + profileModel.getUsername(); | ||||
|         topBinding.title.setText(title); | ||||
|         topBinding.title.setOnClickListener(v -> feedItemCallback.onNameClick(feedModel, topBinding.ivProfilePic)); | ||||
|     } | ||||
| 
 | ||||
|     private void setupCaption(final FeedModel feedModel) { | ||||
|         bottomBinding.viewerCaption.clearOnMentionClickListeners(); | ||||
|         bottomBinding.viewerCaption.clearOnHashtagClickListeners(); | ||||
|         bottomBinding.viewerCaption.clearOnURLClickListeners(); | ||||
|         bottomBinding.viewerCaption.clearOnEmailClickListeners(); | ||||
|         final CharSequence postCaption = feedModel.getPostCaption(); | ||||
|         final boolean captionEmpty = TextUtils.isEmpty(postCaption); | ||||
|         bottomBinding.viewerCaption.setVisibility(captionEmpty ? View.GONE : View.VISIBLE); | ||||
|         if (captionEmpty) return; | ||||
|         bottomBinding.viewerCaption.setText(postCaption); | ||||
|         bottomBinding.viewerCaption.setMaxLines(MAX_LINES_COLLAPSED); | ||||
|         bottomBinding.viewerCaption.setEllipsize(END); | ||||
|         bottomBinding.viewerCaption.setOnClickListener(v -> bottomBinding.getRoot().post(() -> { | ||||
|             TransitionManager.beginDelayedTransition(bottomBinding.getRoot()); | ||||
|             if (bottomBinding.viewerCaption.getMaxLines() == MAX_LINES_COLLAPSED) { | ||||
|                 bottomBinding.viewerCaption.setMaxLines(Integer.MAX_VALUE); | ||||
|                 bottomBinding.viewerCaption.setEllipsize(null); | ||||
|                 return; | ||||
|             } | ||||
|             bottomBinding.viewerCaption.setMaxLines(MAX_LINES_COLLAPSED); | ||||
|             bottomBinding.viewerCaption.setEllipsize(END); | ||||
|         })); | ||||
|         bottomBinding.viewerCaption.addOnMentionClickListener(autoLinkItem -> feedItemCallback.onMentionClick(autoLinkItem.getOriginalText())); | ||||
|         bottomBinding.viewerCaption.addOnHashtagListener(autoLinkItem -> feedItemCallback.onHashtagClick(autoLinkItem.getOriginalText())); | ||||
|         bottomBinding.viewerCaption.addOnEmailClickListener(autoLinkItem -> feedItemCallback.onEmailClick(autoLinkItem.getOriginalText())); | ||||
|         bottomBinding.viewerCaption.addOnURLClickListener(autoLinkItem -> feedItemCallback.onURLClick(autoLinkItem.getOriginalText())); | ||||
|     } | ||||
| 
 | ||||
|     private void setupLocation(final FeedModel feedModel) { | ||||
|         final String locationName = feedModel.getLocationName(); | ||||
|         if (TextUtils.isEmpty(locationName)) { | ||||
|             topBinding.location.setVisibility(View.GONE); | ||||
|             topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams( | ||||
| @ -101,46 +113,9 @@ public abstract class FeedItemViewHolder extends RecyclerView.ViewHolder { | ||||
|             topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams( | ||||
|                     RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT | ||||
|             )); | ||||
|             topBinding.location.setOnClickListener(v -> mentionClickListener.onClick(topBinding.location, locationId, false, true)); | ||||
|             topBinding.location.setOnClickListener(v -> feedItemCallback.onLocationClick(feedModel)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * expands or collapses {@link RamboTextView} [stg idek why i wrote this documentation] | ||||
|      * | ||||
|      * @param textView the {@link RamboTextView} view, to expand and collapse | ||||
|      * @param caption  caption | ||||
|      * @return isExpanded | ||||
|      */ | ||||
|     public static boolean expandCollapseTextView(@NonNull final RamboTextView textView, final CharSequence caption) { | ||||
|         if (TextUtils.isEmpty(caption)) return false; | ||||
| 
 | ||||
|         final TextView.BufferType bufferType = caption instanceof Spanned ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL; | ||||
| 
 | ||||
|         if (textView.isCaptionExpanded()) { | ||||
|             textView.setText(caption, bufferType); | ||||
|             // textView.setCaptionIsExpanded(false); | ||||
|             return true; | ||||
|         } | ||||
|         int i = TextUtils.indexOfChar(caption, '\r', 0); | ||||
|         if (i == -1) i = TextUtils.indexOfChar(caption, '\n', 0); | ||||
|         if (i == -1) i = MAX_CHARS; | ||||
| 
 | ||||
|         final int captionLen = caption.length(); | ||||
|         final int minTrim = Math.min(MAX_CHARS, i); | ||||
|         if (captionLen <= minTrim) return false; | ||||
| 
 | ||||
|         if (TextUtils.hasMentions(caption)) | ||||
|             textView.setText(TextUtils.getMentionText(caption), TextView.BufferType.SPANNABLE); | ||||
|         // textView.setCaptionIsExpandable(true); | ||||
|         // textView.setCaptionIsExpanded(true); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     public abstract void bindItem(final FeedModel feedModel, | ||||
|                                   final FeedAdapterV2.OnPostClickListener postClickListener); | ||||
| 
 | ||||
|     public void clearAnimation() { | ||||
|         itemView.clearAnimation(); | ||||
|     } | ||||
|     public abstract void bindItem(final FeedModel feedModel); | ||||
| } | ||||
| @ -16,7 +16,6 @@ import com.facebook.imagepipeline.request.ImageRequestBuilder; | ||||
| 
 | ||||
| import awais.instagrabber.adapters.FeedAdapterV2; | ||||
| import awais.instagrabber.databinding.ItemFeedPhotoBinding; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| 
 | ||||
| @ -24,17 +23,15 @@ public class FeedPhotoViewHolder extends FeedItemViewHolder { | ||||
|     private static final String TAG = "FeedPhotoViewHolder"; | ||||
| 
 | ||||
|     private final ItemFeedPhotoBinding binding; | ||||
|     // private final long animationDuration; | ||||
|     private final FeedAdapterV2.FeedItemCallback feedItemCallback; | ||||
| 
 | ||||
|     public FeedPhotoViewHolder(@NonNull final ItemFeedPhotoBinding binding, | ||||
|                                final MentionClickListener mentionClickListener, | ||||
|                                final View.OnClickListener clickListener, | ||||
|                                final View.OnLongClickListener longClickListener) { | ||||
|         super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, mentionClickListener, clickListener, longClickListener); | ||||
|                                final FeedAdapterV2.FeedItemCallback feedItemCallback) { | ||||
|         super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, feedItemCallback); | ||||
|         this.binding = binding; | ||||
|         // this.animationDuration = animationDuration; | ||||
|         binding.itemFeedBottom.videoViewsContainer.setVisibility(View.GONE); | ||||
|         binding.itemFeedBottom.btnMute.setVisibility(View.GONE); | ||||
|         this.feedItemCallback = feedItemCallback; | ||||
|         binding.itemFeedBottom.tvVideoViews.setVisibility(View.GONE); | ||||
|         // binding.itemFeedBottom.btnMute.setVisibility(View.GONE); | ||||
|         binding.imageViewer.setAllowTouchInterceptionWhileZoomed(false); | ||||
|         final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(itemView.getContext().getResources()) | ||||
|                 .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER) | ||||
| @ -43,85 +40,39 @@ public class FeedPhotoViewHolder extends FeedItemViewHolder { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void bindItem(final FeedModel feedModel, | ||||
|                          final FeedAdapterV2.OnPostClickListener postClickListener) { | ||||
|     public void bindItem(final FeedModel feedModel) { | ||||
|         if (feedModel == null) { | ||||
|             return; | ||||
|         } | ||||
|         setDimensions(feedModel); | ||||
|         showOrHideDetails(false); | ||||
|         final String thumbnailUrl = feedModel.getThumbnailUrl(); | ||||
|         String url = feedModel.getDisplayUrl(); | ||||
|         if (TextUtils.isEmpty(url)) url = thumbnailUrl; | ||||
|         final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)) | ||||
|                                                                .setLocalThumbnailPreviewsEnabled(true) | ||||
|                                                                .setProgressiveRenderingEnabled(true) | ||||
|                                                                .build(); | ||||
|         binding.imageViewer.setController(Fresco.newDraweeControllerBuilder() | ||||
|                                                 .setImageRequest(requestBuilder) | ||||
|                                                 .setOldController(binding.imageViewer.getController()) | ||||
|                                                 .setLowResImageRequest(ImageRequest.fromUri(thumbnailUrl)) | ||||
|                                                 .build()); | ||||
|         binding.imageViewer.setTapListener(new GestureDetector.SimpleOnGestureListener() { | ||||
|             @Override | ||||
|             public boolean onSingleTapConfirmed(final MotionEvent e) { | ||||
|                 if (postClickListener != null) { | ||||
|                     postClickListener.onPostClick(feedModel, binding.itemFeedTop.ivProfilePic, binding.imageViewer); | ||||
|                     return true; | ||||
|         binding.getRoot().post(() -> { | ||||
|             setDimensions(feedModel); | ||||
|             final String thumbnailUrl = feedModel.getThumbnailUrl(); | ||||
|             String url = feedModel.getDisplayUrl(); | ||||
|             if (TextUtils.isEmpty(url)) url = thumbnailUrl; | ||||
|             final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)) | ||||
|                                                                    // .setLocalThumbnailPreviewsEnabled(true) | ||||
|                                                                    // .setProgressiveRenderingEnabled(true) | ||||
|                                                                    .build(); | ||||
|             binding.imageViewer.setController(Fresco.newDraweeControllerBuilder() | ||||
|                                                     .setImageRequest(requestBuilder) | ||||
|                                                     .setOldController(binding.imageViewer.getController()) | ||||
|                                                     .setLowResImageRequest(ImageRequest.fromUri(thumbnailUrl)) | ||||
|                                                     .build()); | ||||
|             binding.imageViewer.setTapListener(new GestureDetector.SimpleOnGestureListener() { | ||||
|                 @Override | ||||
|                 public boolean onSingleTapConfirmed(final MotionEvent e) { | ||||
|                     if (feedItemCallback != null) { | ||||
|                         feedItemCallback.onPostClick(feedModel, binding.itemFeedTop.ivProfilePic, binding.imageViewer); | ||||
|                         return true; | ||||
|                     } | ||||
|                     return false; | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private void setDimensions(final FeedModel feedModel) { | ||||
|         // final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams(); | ||||
|         // final int deviceWidth = Utils.displayMetrics.widthPixels; | ||||
|         // final int spanWidth = deviceWidth / spanCount; | ||||
|         // final int spanHeight = NumberUtils.getResultingHeight(spanWidth, feedModel.getImageHeight(), feedModel.getImageWidth()); | ||||
|         // final int width = spanWidth == 0 ? deviceWidth : spanWidth; | ||||
|         // final int height = spanHeight == 0 ? deviceWidth + 1 : spanHeight; | ||||
|         final float aspectRatio = (float) feedModel.getImageWidth() / feedModel.getImageHeight(); | ||||
|         binding.imageViewer.setAspectRatio(aspectRatio); | ||||
|         // Log.d(TAG, "setDimensions: aspectRatio:" + aspectRatio); | ||||
|         // if (animate) { | ||||
|         //     Animation animation = AnimationUtils.expand( | ||||
|         //             binding.imageViewer, | ||||
|         //             layoutParams.width, | ||||
|         //             layoutParams.height, | ||||
|         //             width, | ||||
|         //             height, | ||||
|         //             new Animation.AnimationListener() { | ||||
|         //                 @Override | ||||
|         //                 public void onAnimationStart(final Animation animation) { | ||||
|         //                     showOrHideDetails(spanCount); | ||||
|         //                 } | ||||
|         // | ||||
|         //                 @Override | ||||
|         //                 public void onAnimationEnd(final Animation animation) { | ||||
|         //                     // showOrHideDetails(spanCount); | ||||
|         //                 } | ||||
|         // | ||||
|         //                 @Override | ||||
|         //                 public void onAnimationRepeat(final Animation animation) { | ||||
|         // | ||||
|         //                 } | ||||
|         //             }); | ||||
|         //     binding.imageViewer.startAnimation(animation); | ||||
|         // } else { | ||||
|         //     layoutParams.width = width; | ||||
|         //     layoutParams.height = height; | ||||
|         //     binding.imageViewer.requestLayout(); | ||||
|         // } | ||||
|     } | ||||
| 
 | ||||
|     private void showOrHideDetails(final boolean show) { | ||||
|         if (show) { | ||||
|             binding.itemFeedTop.getRoot().setVisibility(View.VISIBLE); | ||||
|             binding.itemFeedBottom.getRoot().setVisibility(View.VISIBLE); | ||||
|         } else { | ||||
|             binding.itemFeedTop.getRoot().setVisibility(View.GONE); | ||||
|             binding.itemFeedBottom.getRoot().setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -21,11 +21,10 @@ import com.google.android.exoplayer2.upstream.cache.SimpleCache; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.FeedAdapterV2; | ||||
| import awais.instagrabber.adapters.SliderCallbackAdapter; | ||||
| import awais.instagrabber.adapters.SliderItemsAdapter; | ||||
| import awais.instagrabber.databinding.ItemFeedSliderBinding; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.models.PostChild; | ||||
| import awais.instagrabber.models.enums.MediaItemType; | ||||
| @ -40,25 +39,20 @@ public class FeedSliderViewHolder extends FeedItemViewHolder { | ||||
|     private static final boolean shouldAutoPlay = settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS); | ||||
| 
 | ||||
|     private final ItemFeedSliderBinding binding; | ||||
|     private final FeedAdapterV2.FeedItemCallback feedItemCallback; | ||||
|     private final DefaultDataSourceFactory dataSourceFactory; | ||||
| 
 | ||||
|     private final PlayerChangeListener playerChangeListener = (position, player) -> { | ||||
|         pagerPlayer = player; | ||||
|         playerPosition = position; | ||||
|     }; | ||||
| 
 | ||||
|     private CacheDataSourceFactory cacheDataSourceFactory; | ||||
|     private SimpleExoPlayer pagerPlayer; | ||||
|     private int playerPosition = 0; | ||||
| 
 | ||||
|     public FeedSliderViewHolder(@NonNull final ItemFeedSliderBinding binding, | ||||
|                                 final MentionClickListener mentionClickListener, | ||||
|                                 final View.OnClickListener clickListener, | ||||
|                                 final View.OnLongClickListener longClickListener) { | ||||
|         super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, mentionClickListener, clickListener, longClickListener); | ||||
|                                 final FeedAdapterV2.FeedItemCallback feedItemCallback) { | ||||
|         super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, feedItemCallback); | ||||
|         this.binding = binding; | ||||
|         binding.itemFeedBottom.videoViewsContainer.setVisibility(View.GONE); | ||||
|         binding.itemFeedBottom.btnMute.setVisibility(View.GONE); | ||||
|         this.feedItemCallback = feedItemCallback; | ||||
|         binding.itemFeedBottom.tvVideoViews.setVisibility(View.GONE); | ||||
|         // binding.itemFeedBottom.btnMute.setVisibility(View.GONE); | ||||
|         final ViewGroup.LayoutParams layoutParams = binding.mediaList.getLayoutParams(); | ||||
|         layoutParams.height = Utils.displayMetrics.widthPixels + 1; | ||||
|         binding.mediaList.setLayoutParams(layoutParams); | ||||
| @ -71,31 +65,31 @@ public class FeedSliderViewHolder extends FeedItemViewHolder { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void bindItem(final FeedModel feedModel, | ||||
|                          final FeedAdapterV2.OnPostClickListener postClickListener) { | ||||
|     public void bindItem(final FeedModel feedModel) { | ||||
|         final List<PostChild> sliderItems = feedModel.getSliderItems(); | ||||
|         final int sliderItemLen = sliderItems != null ? sliderItems.size() : 0; | ||||
|         if (sliderItemLen <= 0) return; | ||||
|         final String text = "1/" + sliderItemLen; | ||||
|         binding.mediaCounter.setText(text); | ||||
|         binding.mediaList.setOffscreenPageLimit(1); | ||||
|         SliderItemsAdapter adapter = (SliderItemsAdapter) binding.mediaList.getAdapter(); | ||||
|         if (adapter == null) { | ||||
|             adapter = new SliderItemsAdapter(); | ||||
|         } | ||||
|         // adapter.setSpanCount(spanCount); | ||||
|         final SliderItemsAdapter adapter = new SliderItemsAdapter(null, null, false, new SliderCallbackAdapter() { | ||||
|             @Override | ||||
|             public void onItemClicked(final int position) { | ||||
|                 feedItemCallback.onSliderClick(feedModel, position); | ||||
|             } | ||||
|         }); | ||||
|         binding.mediaList.setAdapter(adapter); | ||||
|         binding.mediaList.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { | ||||
|             @Override | ||||
|             public void onPageSelected(final int position) { | ||||
|                 if (position >= sliderItemLen) return; | ||||
|                 final String text = (position + 1) + "/" + sliderItemLen; | ||||
|                 binding.mediaCounter.setText(text); | ||||
|                 setDimensions(binding.mediaList, sliderItems.get(position)); | ||||
|             } | ||||
|         }); | ||||
|         setDimensions(binding.mediaList, sliderItems.get(0)); | ||||
| 
 | ||||
| 
 | ||||
|         //noinspection deprecation | ||||
|         // binding.mediaList.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { | ||||
|         //     private int prevPos = 0; | ||||
|         // | ||||
| @ -149,15 +143,15 @@ public class FeedSliderViewHolder extends FeedItemViewHolder { | ||||
|             final SimpleExoPlayer player = (SimpleExoPlayer) tag; | ||||
|             final float intVol = player.getVolume() == 0f ? 1f : 0f; | ||||
|             player.setVolume(intVol); | ||||
|             binding.itemFeedBottom.btnMute.setImageResource(intVol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24); | ||||
|             Utils.sessionVolumeFull = intVol == 1f; | ||||
|             // binding.itemFeedBottom.btnMute.setImageResource(intVol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24); | ||||
|             // Utils.sessionVolumeFull = intVol == 1f; | ||||
|         }; | ||||
|         final PostChild firstItem = sliderItems.get(0); | ||||
|         if (firstItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) { | ||||
|             binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE); | ||||
|         } | ||||
|         binding.itemFeedBottom.btnMute.setImageResource(Utils.sessionVolumeFull ? R.drawable.ic_volume_off_24 : R.drawable.ic_volume_up_24); | ||||
|         binding.itemFeedBottom.btnMute.setOnClickListener(muteClickListener); | ||||
|         // final PostChild firstItem = sliderItems.get(0); | ||||
|         // if (firstItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) { | ||||
|         //     binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE); | ||||
|         // } | ||||
|         // binding.itemFeedBottom.btnMute.setImageResource(Utils.sessionVolumeFull ? R.drawable.ic_volume_off_24 : R.drawable.ic_volume_up_24); | ||||
|         // binding.itemFeedBottom.btnMute.setOnClickListener(muteClickListener); | ||||
|     } | ||||
| 
 | ||||
|     private void setDimensions(final View view, final PostChild model) { | ||||
|  | ||||
| @ -12,12 +12,10 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; | ||||
| import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory; | ||||
| import com.google.android.exoplayer2.upstream.cache.SimpleCache; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.FeedAdapterV2; | ||||
| import awais.instagrabber.customviews.VideoPlayerCallbackAdapter; | ||||
| import awais.instagrabber.customviews.VideoPlayerViewHelper; | ||||
| import awais.instagrabber.databinding.ItemFeedVideoBinding; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.NumberUtils; | ||||
| @ -29,6 +27,7 @@ public class FeedVideoViewHolder extends FeedItemViewHolder { | ||||
|     private static final String TAG = "FeedVideoViewHolder"; | ||||
| 
 | ||||
|     private final ItemFeedVideoBinding binding; | ||||
|     private final FeedAdapterV2.FeedItemCallback feedItemCallback; | ||||
|     private final Handler handler; | ||||
|     private final DefaultDataSourceFactory dataSourceFactory; | ||||
| 
 | ||||
| @ -43,12 +42,11 @@ public class FeedVideoViewHolder extends FeedItemViewHolder { | ||||
|     // }; | ||||
| 
 | ||||
|     public FeedVideoViewHolder(@NonNull final ItemFeedVideoBinding binding, | ||||
|                                final MentionClickListener mentionClickListener, | ||||
|                                final View.OnClickListener clickListener, | ||||
|                                final View.OnLongClickListener longClickListener) { | ||||
|         super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, mentionClickListener, clickListener, longClickListener); | ||||
|                                final FeedAdapterV2.FeedItemCallback feedItemCallback) { | ||||
|         super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, feedItemCallback); | ||||
|         this.binding = binding; | ||||
|         binding.itemFeedBottom.videoViewsContainer.setVisibility(View.VISIBLE); | ||||
|         this.feedItemCallback = feedItemCallback; | ||||
|         binding.itemFeedBottom.tvVideoViews.setVisibility(View.VISIBLE); | ||||
|         handler = new Handler(Looper.getMainLooper()); | ||||
|         final Context context = binding.getRoot().getContext(); | ||||
|         dataSourceFactory = new DefaultDataSourceFactory(context, "instagram"); | ||||
| @ -59,8 +57,7 @@ public class FeedVideoViewHolder extends FeedItemViewHolder { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void bindItem(final FeedModel feedModel, | ||||
|                          final FeedAdapterV2.OnPostClickListener postClickListener) { | ||||
|     public void bindItem(final FeedModel feedModel) { | ||||
|         // Log.d(TAG, "Binding post: " + feedModel.getPostId()); | ||||
|         this.feedModel = feedModel; | ||||
|         binding.itemFeedBottom.tvVideoViews.setText(String.valueOf(feedModel.getViewCount())); | ||||
| @ -70,12 +67,12 @@ public class FeedVideoViewHolder extends FeedItemViewHolder { | ||||
| 
 | ||||
|             @Override | ||||
|             public void onThumbnailClick() { | ||||
|                 postClickListener.onPostClick(feedModel, binding.itemFeedTop.ivProfilePic, binding.videoPost.thumbnail); | ||||
|                 feedItemCallback.onPostClick(feedModel, binding.itemFeedTop.ivProfilePic, binding.videoPost.thumbnail); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onPlayerViewLoaded() { | ||||
|                 binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE); | ||||
|                 // binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE); | ||||
|                 final ViewGroup.LayoutParams layoutParams = binding.videoPost.playerView.getLayoutParams(); | ||||
|                 final int requiredWidth = Utils.displayMetrics.widthPixels; | ||||
|                 final int resultingHeight = NumberUtils.getResultingHeight(requiredWidth, feedModel.getImageHeight(), feedModel.getImageWidth()); | ||||
| @ -97,19 +94,27 @@ public class FeedVideoViewHolder extends FeedItemViewHolder { | ||||
|                                                                                       vol, | ||||
|                                                                                       aspectRatio, | ||||
|                                                                                       feedModel.getThumbnailUrl(), | ||||
|                                                                                       false, | ||||
|                                                                                       null, | ||||
|                                                                                       videoPlayerCallback); | ||||
|         binding.itemFeedBottom.btnMute.setOnClickListener(v -> { | ||||
|             final float newVol = videoPlayerViewHelper.toggleMute(); | ||||
|             setMuteIcon(newVol); | ||||
|             Utils.sessionVolumeFull = newVol == 1f; | ||||
|         binding.videoPost.thumbnail.post(() -> { | ||||
|             if (feedModel.getImageHeight() > 0.8 * Utils.displayMetrics.heightPixels) { | ||||
|                 final ViewGroup.LayoutParams layoutParams = binding.videoPost.thumbnail.getLayoutParams(); | ||||
|                 layoutParams.height = (int) (0.8 * Utils.displayMetrics.heightPixels); | ||||
|                 binding.videoPost.thumbnail.requestLayout(); | ||||
|             } | ||||
|         }); | ||||
|         binding.videoPost.playerView.setOnClickListener(v -> videoPlayerViewHelper.togglePlayback()); | ||||
|         // binding.itemFeedBottom.btnMute.setOnClickListener(v -> { | ||||
|         //     final float newVol = videoPlayerViewHelper.toggleMute(); | ||||
|         //     setMuteIcon(newVol); | ||||
|         //     Utils.sessionVolumeFull = newVol == 1f; | ||||
|         // }); | ||||
|         // binding.videoPost.playerView.setOnClickListener(v -> videoPlayerViewHelper.togglePlayback()); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private void setMuteIcon(final float vol) { | ||||
|         binding.itemFeedBottom.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24); | ||||
|         // binding.itemFeedBottom.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24); | ||||
|     } | ||||
| 
 | ||||
|     public FeedModel getCurrentFeedModel() { | ||||
| @ -131,14 +136,4 @@ public class FeedVideoViewHolder extends FeedItemViewHolder { | ||||
|     //     handler.removeCallbacks(loadRunnable); | ||||
|     //     handler.postDelayed(loadRunnable, 800); | ||||
|     // } | ||||
| 
 | ||||
|     private void showOrHideDetails(final boolean show) { | ||||
|         if (show) { | ||||
|             binding.itemFeedTop.getRoot().setVisibility(View.VISIBLE); | ||||
|             binding.itemFeedBottom.getRoot().setVisibility(View.VISIBLE); | ||||
|         } else { | ||||
|             binding.itemFeedTop.getRoot().setVisibility(View.GONE); | ||||
|             binding.itemFeedBottom.getRoot().setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -12,7 +12,7 @@ import org.json.JSONObject; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import awais.instagrabber.BuildConfig; | ||||
| import awais.instagrabber.interfaces.FetchListener; | ||||
| @ -25,23 +25,20 @@ import awaisomereport.LogCollector; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Utils.logCollector; | ||||
| 
 | ||||
| public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> { | ||||
|     private final String shortCode; | ||||
|     private final FetchListener<CommentModel[]> fetchListener; | ||||
| public final class CommentsFetcher extends AsyncTask<Void, Void, List<CommentModel>> { | ||||
|     private static final String TAG = "CommentsFetcher"; | ||||
| 
 | ||||
|     /* | ||||
|      * i fucking spent the whole day on this and fixing all the fucking problems in this class. | ||||
|      * DO NO FUCK WITH THIS CODE! | ||||
|      *  -AWAiS (The Badak) @the.badak | ||||
|      */ | ||||
|     public CommentsFetcher(final String shortCode, final FetchListener<CommentModel[]> fetchListener) { | ||||
|     private final String shortCode; | ||||
|     private final FetchListener<List<CommentModel>> fetchListener; | ||||
| 
 | ||||
|     public CommentsFetcher(final String shortCode, final FetchListener<List<CommentModel>> fetchListener) { | ||||
|         this.shortCode = shortCode; | ||||
|         this.fetchListener = fetchListener; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     protected CommentModel[] doInBackground(final Void... voids) { | ||||
|     protected List<CommentModel> doInBackground(final Void... voids) { | ||||
|          /* | ||||
|         "https://www.instagram.com/graphql/query/?query_hash=97b41c52301f77ce508f55e66d17620e&variables=" + "{\"shortcode\":\"" + shortcode + "\",\"first\":50,\"after\":\"" + endCursor + "\"}"; | ||||
| 
 | ||||
| @ -50,23 +47,20 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> | ||||
| 
 | ||||
|         https://www.instagram.com/graphql/query/?query_hash=51fdd02b67508306ad4484ff574a0b62&variables={"comment_id":"18100041898085322","first":50,"after":""} | ||||
|          */ | ||||
|         final ArrayList<CommentModel> commentModels = getParentComments(); | ||||
| 
 | ||||
|         final List<CommentModel> commentModels = getParentComments(); | ||||
|         for (final CommentModel commentModel : commentModels) { | ||||
|             final CommentModel[] childCommentModels = commentModel.getChildCommentModels(); | ||||
|             final List<CommentModel> childCommentModels = commentModel.getChildCommentModels(); | ||||
|             if (childCommentModels != null) { | ||||
|                 final int childCommentsLen = childCommentModels.length; | ||||
| 
 | ||||
|                 final CommentModel lastChild = childCommentModels[childCommentsLen - 1]; | ||||
|                 final int childCommentsLen = childCommentModels.size(); | ||||
|                 final CommentModel lastChild = childCommentModels.get(childCommentsLen - 1); | ||||
|                 if (lastChild != null && lastChild.hasNextPage() && !TextUtils.isEmpty(lastChild.getEndCursor())) { | ||||
|                     final CommentModel[] remoteChildComments = getChildComments(commentModel.getId()); | ||||
|                     final List<CommentModel> remoteChildComments = getChildComments(commentModel.getId()); | ||||
|                     commentModel.setChildCommentModels(remoteChildComments); | ||||
|                     lastChild.setPageCursor(false, null); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return commentModels.toArray(new CommentModel[0]); | ||||
|         return commentModels; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -75,14 +69,13 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPostExecute(final CommentModel[] result) { | ||||
|     protected void onPostExecute(final List<CommentModel> result) { | ||||
|         if (fetchListener != null) fetchListener.onResult(result); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     private synchronized CommentModel[] getChildComments(final String commentId) { | ||||
|         final ArrayList<CommentModel> commentModels = new ArrayList<>(); | ||||
| 
 | ||||
|     private synchronized List<CommentModel> getChildComments(final String commentId) { | ||||
|         final List<CommentModel> commentModels = new ArrayList<>(); | ||||
|         String endCursor = ""; | ||||
|         while (endCursor != null) { | ||||
|             final String url = "https://www.instagram.com/graphql/query/?query_hash=51fdd02b67508306ad4484ff574a0b62&variables=" + | ||||
| @ -96,7 +89,8 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> | ||||
|                 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) break; | ||||
|                 else { | ||||
|                     final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data") | ||||
|                                                                                                  .getJSONObject("comment").getJSONObject("edge_threaded_comments"); | ||||
|                                                                                                  .getJSONObject("comment") | ||||
|                                                                                                  .getJSONObject("edge_threaded_comments"); | ||||
| 
 | ||||
|                     final JSONObject pageInfo = data.getJSONObject("page_info"); | ||||
|                     endCursor = pageInfo.getString("end_cursor"); | ||||
| @ -110,43 +104,54 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> | ||||
| 
 | ||||
|                             if (childComment != null) { | ||||
|                                 final JSONObject owner = childComment.getJSONObject("owner"); | ||||
|                                 final ProfileModel profileModel = new ProfileModel(false, false, false, | ||||
|                                         owner.getString(Constants.EXTRAS_ID), | ||||
|                                         owner.getString(Constants.EXTRAS_USERNAME), | ||||
|                                         null, null, null, | ||||
|                                         owner.getString("profile_pic_url"), | ||||
|                                         null, 0, 0, 0, false, false, false, false); | ||||
|                                 final ProfileModel profileModel = new ProfileModel(false, | ||||
|                                                                                    false, | ||||
|                                                                                    false, | ||||
|                                                                                    owner.getString(Constants.EXTRAS_ID), | ||||
|                                                                                    owner.getString(Constants.EXTRAS_USERNAME), | ||||
|                                                                                    null, | ||||
|                                                                                    null, | ||||
|                                                                                    null, | ||||
|                                                                                    owner.getString("profile_pic_url"), | ||||
|                                                                                    null, | ||||
|                                                                                    0, | ||||
|                                                                                    0, | ||||
|                                                                                    0, | ||||
|                                                                                    false, | ||||
|                                                                                    false, | ||||
|                                                                                    false, | ||||
|                                                                                    false); | ||||
| 
 | ||||
|                                 final JSONObject likedBy = childComment.optJSONObject("edge_liked_by"); | ||||
| 
 | ||||
|                                 commentModels.add(new CommentModel(childComment.getString(Constants.EXTRAS_ID), | ||||
|                                         childComment.getString("text"), | ||||
|                                         childComment.getLong("created_at"), | ||||
|                                         likedBy != null ? likedBy.optLong("count", 0) : 0, | ||||
|                                         childComment.getBoolean("viewer_has_liked"), | ||||
|                                         profileModel)); | ||||
|                                                                    childComment.getString("text"), | ||||
|                                                                    childComment.getLong("created_at"), | ||||
|                                                                    likedBy != null ? likedBy.optLong("count", 0) : 0, | ||||
|                                                                    childComment.getBoolean("viewer_has_liked"), | ||||
|                                                                    profileModel)); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 conn.disconnect(); | ||||
|             } catch (final Exception e) { | ||||
|                 if (logCollector != null) | ||||
|                     logCollector.appendException(e, LogCollector.LogFile.ASYNC_COMMENTS_FETCHER, "getChildComments", | ||||
|                             new Pair<>("commentModels.size", commentModels.size())); | ||||
|                 if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); | ||||
|                     logCollector.appendException(e, | ||||
|                                                  LogCollector.LogFile.ASYNC_COMMENTS_FETCHER, | ||||
|                                                  "getChildComments", | ||||
|                                                  new Pair<>("commentModels.size", commentModels.size())); | ||||
|                 if (BuildConfig.DEBUG) Log.e(TAG, "", e); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return commentModels.toArray(new CommentModel[0]); | ||||
|         return commentModels; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     private synchronized ArrayList<CommentModel> getParentComments() { | ||||
|         final ArrayList<CommentModel> commentModelsList = new ArrayList<>(); | ||||
| 
 | ||||
|     private synchronized List<CommentModel> getParentComments() { | ||||
|         final List<CommentModel> commentModels = new ArrayList<>(); | ||||
|         String endCursor = ""; | ||||
|         while (endCursor != null) { | ||||
|             final String url = "https://www.instagram.com/graphql/query/?query_hash=bc3296d1ce80a24b1b6e40b1e72903f5&variables=" + | ||||
| @ -160,7 +165,9 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> | ||||
|                 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) break; | ||||
|                 else { | ||||
|                     final JSONObject parentComments = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data") | ||||
|                                                                                                            .getJSONObject("shortcode_media").getJSONObject("edge_media_to_parent_comment"); | ||||
|                                                                                                            .getJSONObject("shortcode_media") | ||||
|                                                                                                            .getJSONObject( | ||||
|                                                                                                                    "edge_media_to_parent_comment"); | ||||
| 
 | ||||
|                     final JSONObject pageInfo = parentComments.getJSONObject("page_info"); | ||||
|                     endCursor = pageInfo.optString("end_cursor"); | ||||
| @ -182,31 +189,37 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> | ||||
| 
 | ||||
|                     final JSONArray comments = parentComments.getJSONArray("edges"); | ||||
|                     final int commentsLen = comments.length(); | ||||
|                     final CommentModel[] commentModels = new CommentModel[commentsLen]; | ||||
| 
 | ||||
|                     for (int i = 0; i < commentsLen; ++i) { | ||||
|                         final JSONObject comment = comments.getJSONObject(i).getJSONObject("node"); | ||||
| 
 | ||||
|                         final JSONObject owner = comment.getJSONObject("owner"); | ||||
|                         final ProfileModel profileModel = new ProfileModel(false, false, | ||||
|                                 owner.optBoolean("is_verified"), | ||||
|                                 owner.getString(Constants.EXTRAS_ID), | ||||
|                                 owner.getString(Constants.EXTRAS_USERNAME), | ||||
|                                 null, null, null, | ||||
|                                 owner.getString("profile_pic_url"), | ||||
|                                 null, 0, 0, 0, false, false, false, false); | ||||
|                         final ProfileModel profileModel = new ProfileModel(false, | ||||
|                                                                            false, | ||||
|                                                                            owner.optBoolean("is_verified"), | ||||
|                                                                            owner.getString(Constants.EXTRAS_ID), | ||||
|                                                                            owner.getString(Constants.EXTRAS_USERNAME), | ||||
|                                                                            null, | ||||
|                                                                            null, | ||||
|                                                                            null, | ||||
|                                                                            owner.getString("profile_pic_url"), | ||||
|                                                                            null, | ||||
|                                                                            0, | ||||
|                                                                            0, | ||||
|                                                                            0, | ||||
|                                                                            false, | ||||
|                                                                            false, | ||||
|                                                                            false, | ||||
|                                                                            false); | ||||
| 
 | ||||
|                         final JSONObject likedBy = comment.optJSONObject("edge_liked_by"); | ||||
|                         final String commentId = comment.getString(Constants.EXTRAS_ID); | ||||
|                         commentModels[i] = new CommentModel(commentId, | ||||
|                                 comment.getString("text"), | ||||
|                                 comment.getLong("created_at"), | ||||
|                                 likedBy != null ? likedBy.optLong("count", 0) : 0, | ||||
|                                 comment.getBoolean("viewer_has_liked"), | ||||
|                                 profileModel); | ||||
| 
 | ||||
|                         final CommentModel commentModel = new CommentModel(commentId, | ||||
|                                                                            comment.getString("text"), | ||||
|                                                                            comment.getLong("created_at"), | ||||
|                                                                            likedBy != null ? likedBy.optLong("count", 0) : 0, | ||||
|                                                                            comment.getBoolean("viewer_has_liked"), | ||||
|                                                                            profileModel); | ||||
|                         JSONObject tempJsonObject; | ||||
| 
 | ||||
|                         final JSONArray childCommentsArray; | ||||
|                         final int childCommentsLen; | ||||
|                         if ((tempJsonObject = comment.optJSONObject("edge_threaded_comments")) != null && | ||||
| @ -223,47 +236,53 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]> | ||||
|                                 hasNextPage = false; | ||||
|                             } | ||||
| 
 | ||||
|                             final CommentModel[] childCommentModels = new CommentModel[childCommentsLen]; | ||||
|                             final List<CommentModel> childCommentModels = new ArrayList<>(); | ||||
|                             for (int j = 0; j < childCommentsLen; ++j) { | ||||
|                                 final JSONObject childComment = childCommentsArray.getJSONObject(j).getJSONObject("node"); | ||||
| 
 | ||||
|                                 tempJsonObject = childComment.getJSONObject("owner"); | ||||
|                                 final ProfileModel childProfileModel = new ProfileModel(false, false, | ||||
|                                         tempJsonObject.optBoolean("is_verified"), | ||||
|                                         tempJsonObject.getString(Constants.EXTRAS_ID), | ||||
|                                         tempJsonObject.getString(Constants.EXTRAS_USERNAME), | ||||
|                                         null, null, null, | ||||
|                                         tempJsonObject.getString("profile_pic_url"), | ||||
|                                         null, 0, 0, 0, false, false, false, false); | ||||
|                                 final ProfileModel childProfileModel = new ProfileModel(false, | ||||
|                                                                                         false, | ||||
|                                                                                         tempJsonObject.optBoolean("is_verified"), | ||||
|                                                                                         tempJsonObject.getString(Constants.EXTRAS_ID), | ||||
|                                                                                         tempJsonObject.getString(Constants.EXTRAS_USERNAME), | ||||
|                                                                                         null, | ||||
|                                                                                         null, | ||||
|                                                                                         null, | ||||
|                                                                                         tempJsonObject.getString("profile_pic_url"), | ||||
|                                                                                         null, | ||||
|                                                                                         0, | ||||
|                                                                                         0, | ||||
|                                                                                         0, | ||||
|                                                                                         false, | ||||
|                                                                                         false, | ||||
|                                                                                         false, | ||||
|                                                                                         false); | ||||
| 
 | ||||
|                                 tempJsonObject = childComment.optJSONObject("edge_liked_by"); | ||||
|                                 childCommentModels[j] = new CommentModel(childComment.getString(Constants.EXTRAS_ID), | ||||
|                                         childComment.getString("text"), | ||||
|                                         childComment.getLong("created_at"), | ||||
|                                         tempJsonObject != null ? tempJsonObject.optLong("count", 0) : 0, | ||||
|                                         childComment.getBoolean("viewer_has_liked"), | ||||
|                                         childProfileModel); | ||||
|                                 childCommentModels.add(new CommentModel(childComment.getString(Constants.EXTRAS_ID), | ||||
|                                                                         childComment.getString("text"), | ||||
|                                                                         childComment.getLong("created_at"), | ||||
|                                                                         tempJsonObject != null ? tempJsonObject.optLong("count", 0) : 0, | ||||
|                                                                         childComment.getBoolean("viewer_has_liked"), | ||||
|                                                                         childProfileModel)); | ||||
|                             } | ||||
| 
 | ||||
|                             childCommentModels[childCommentsLen - 1].setPageCursor(hasNextPage, childEndCursor); | ||||
| 
 | ||||
|                             commentModels[i].setChildCommentModels(childCommentModels); | ||||
|                             childCommentModels.get(childCommentsLen - 1).setPageCursor(hasNextPage, childEndCursor); | ||||
|                             commentModel.setChildCommentModels(childCommentModels); | ||||
|                             commentModels.add(commentModel); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     Collections.addAll(commentModelsList, commentModels); | ||||
|                 } | ||||
| 
 | ||||
|                 conn.disconnect(); | ||||
|             } catch (final Exception e) { | ||||
|                 if (logCollector != null) | ||||
|                     logCollector.appendException(e, LogCollector.LogFile.ASYNC_COMMENTS_FETCHER, "getParentComments", | ||||
|                             new Pair<>("commentModelsList.size", commentModelsList.size())); | ||||
|                                                  new Pair<>("commentModelsList.size", commentModels.size())); | ||||
|                 if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return commentModelsList; | ||||
|         return commentModels; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -19,12 +19,10 @@ import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import awais.instagrabber.adapters.FeedAdapterV2; | ||||
| import awais.instagrabber.adapters.FeedAdapterV2.OnPostClickListener; | ||||
| import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; | ||||
| import awais.instagrabber.customviews.helpers.PostFetcher; | ||||
| import awais.instagrabber.customviews.helpers.RecyclerLazyLoaderAtBottom; | ||||
| import awais.instagrabber.interfaces.FetchListener; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.models.PostsLayoutPreferences; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| @ -34,12 +32,10 @@ import awais.instagrabber.viewmodels.FeedViewModel; | ||||
| public class PostsRecyclerView extends RecyclerView { | ||||
|     private static final String TAG = "PostsRecyclerView"; | ||||
| 
 | ||||
|     private StaggeredGridLayoutManager gridLayoutManager; | ||||
|     private StaggeredGridLayoutManager layoutManager; | ||||
|     private PostsLayoutPreferences layoutPreferences; | ||||
|     private PostFetcher.PostFetchService postFetchService; | ||||
|     private Transition transition; | ||||
|     private OnClickListener postViewClickListener; | ||||
|     private MentionClickListener mentionClickListener; | ||||
|     private PostFetcher postFetcher; | ||||
|     private ViewModelStoreOwner viewModelStoreOwner; | ||||
|     private FeedAdapterV2 feedAdapter; | ||||
| @ -48,7 +44,7 @@ public class PostsRecyclerView extends RecyclerView { | ||||
|     private boolean initCalled = false; | ||||
|     private GridSpacingItemDecoration gridSpacingItemDecoration; | ||||
|     private RecyclerLazyLoaderAtBottom lazyLoader; | ||||
|     private OnPostClickListener onPostClickListener; | ||||
|     private FeedAdapterV2.FeedItemCallback feedItemCallback; | ||||
| 
 | ||||
|     private final FetchListener<List<FeedModel>> fetchListener = new FetchListener<List<FeedModel>>() { | ||||
|         @Override | ||||
| @ -109,13 +105,8 @@ public class PostsRecyclerView extends RecyclerView { | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public PostsRecyclerView setOnPostClickListener(@NonNull final OnPostClickListener onPostClickListener) { | ||||
|         this.onPostClickListener = onPostClickListener; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public PostsRecyclerView setMentionClickListener(final MentionClickListener mentionClickListener) { | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
|     public PostsRecyclerView setFeedItemCallback(@NonNull final FeedAdapterV2.FeedItemCallback feedItemCallback) { | ||||
|         this.feedItemCallback = feedItemCallback; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
| @ -160,30 +151,19 @@ public class PostsRecyclerView extends RecyclerView { | ||||
| 
 | ||||
|     private void initTransition() { | ||||
|         transition = new ChangeBounds(); | ||||
|         // transition.addListener(new TransitionListenerAdapter(){ | ||||
|         //     @Override | ||||
|         //     public void onTransitionEnd(@NonNull final Transition transition) { | ||||
|         //         super.onTransitionEnd(transition); | ||||
|         //     } | ||||
|         // }); | ||||
|         transition.setDuration(300); | ||||
|     } | ||||
| 
 | ||||
|     private void initLayoutManager() { | ||||
|         gridLayoutManager = new StaggeredGridLayoutManager(layoutPreferences.getColCount(), StaggeredGridLayoutManager.VERTICAL); | ||||
|         setLayoutManager(gridLayoutManager); | ||||
|         layoutManager = new StaggeredGridLayoutManager(layoutPreferences.getColCount(), StaggeredGridLayoutManager.VERTICAL); | ||||
|         if (layoutPreferences.getHasGap()) { | ||||
|             addItemDecoration(gridSpacingItemDecoration); | ||||
|         } | ||||
|         setLayoutManager(layoutManager); | ||||
|     } | ||||
| 
 | ||||
|     private void initAdapter() { | ||||
|         feedAdapter = new FeedAdapterV2( | ||||
|                 layoutPreferences, | ||||
|                 postViewClickListener, | ||||
|                 mentionClickListener, | ||||
|                 (feedModel, view, postImage) -> { | ||||
|                     if (onPostClickListener != null) { | ||||
|                         onPostClickListener.onPostClick(feedModel, view, postImage); | ||||
|                     } | ||||
|                 }); | ||||
|         feedAdapter = new FeedAdapterV2(layoutPreferences, feedItemCallback); | ||||
|         feedAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY); | ||||
|         setAdapter(feedAdapter); | ||||
|     } | ||||
| @ -194,7 +174,8 @@ public class PostsRecyclerView extends RecyclerView { | ||||
|         postFetcher = new PostFetcher(postFetchService, fetchListener); | ||||
|         addItemDecoration(gridSpacingItemDecoration); | ||||
|         setHasFixedSize(true); | ||||
|         lazyLoader = new RecyclerLazyLoaderAtBottom(gridLayoutManager, (page) -> { | ||||
|         setNestedScrollingEnabled(true); | ||||
|         lazyLoader = new RecyclerLazyLoaderAtBottom(layoutManager, (page) -> { | ||||
|             if (postFetcher.hasMore()) { | ||||
|                 postFetcher.fetchNextPage(); | ||||
|                 dispatchFetchStatus(); | ||||
| @ -211,8 +192,23 @@ public class PostsRecyclerView extends RecyclerView { | ||||
|             feedAdapter.notifyDataSetChanged(); | ||||
|             if (!layoutPreferences.getHasGap()) { | ||||
|                 removeItemDecoration(gridSpacingItemDecoration); | ||||
|             } else { | ||||
|                 addItemDecoration(gridSpacingItemDecoration); | ||||
|             } | ||||
|             if (layoutPreferences.getType() == PostsLayoutPreferences.PostsLayoutType.LINEAR) { | ||||
|                 if (layoutManager.getSpanCount() != 1) { | ||||
|                     layoutManager.setSpanCount(1); | ||||
|                     setAdapter(null); | ||||
|                     setAdapter(feedAdapter); | ||||
|                 } | ||||
|             } else { | ||||
|                 boolean shouldRedraw = layoutManager.getSpanCount() == 1; | ||||
|                 layoutManager.setSpanCount(layoutPreferences.getColCount()); | ||||
|                 if (shouldRedraw) { | ||||
|                     setAdapter(null); | ||||
|                     setAdapter(feedAdapter); | ||||
|                 } | ||||
|             } | ||||
|             gridLayoutManager.setSpanCount(layoutPreferences.getColCount()); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,152 @@ | ||||
| package awais.instagrabber.customviews; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| 
 | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| import org.jetbrains.annotations.Nullable; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import io.github.armcha.autolink.AutoLinkItem; | ||||
| import io.github.armcha.autolink.AutoLinkTextView; | ||||
| import io.github.armcha.autolink.MODE_EMAIL; | ||||
| import io.github.armcha.autolink.MODE_HASHTAG; | ||||
| import io.github.armcha.autolink.MODE_MENTION; | ||||
| import io.github.armcha.autolink.MODE_URL; | ||||
| import io.github.armcha.autolink.Mode; | ||||
| import kotlin.Unit; | ||||
| 
 | ||||
| public class RamboTextViewV2 extends AutoLinkTextView { | ||||
|     private final List<OnMentionClickListener> onMentionClickListeners = new ArrayList<>(); | ||||
|     private final List<OnHashtagClickListener> onHashtagClickListeners = new ArrayList<>(); | ||||
|     private final List<OnURLClickListener> onURLClickListeners = new ArrayList<>(); | ||||
|     private final List<OnEmailClickListener> onEmailClickListeners = new ArrayList<>(); | ||||
| 
 | ||||
|     public RamboTextViewV2(@NotNull final Context context, | ||||
|                            @Nullable final AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     private void init() { | ||||
|         addAutoLinkMode(MODE_HASHTAG.INSTANCE, MODE_MENTION.INSTANCE, MODE_EMAIL.INSTANCE, MODE_URL.INSTANCE); | ||||
|         onAutoLinkClick(autoLinkItem -> { | ||||
|             final Mode mode = autoLinkItem.getMode(); | ||||
|             if (mode.equals(MODE_MENTION.INSTANCE)) { | ||||
|                 for (final OnMentionClickListener onMentionClickListener : onMentionClickListeners) { | ||||
|                     onMentionClickListener.onMentionClick(autoLinkItem); | ||||
|                 } | ||||
|                 return Unit.INSTANCE; | ||||
|             } | ||||
|             if (mode.equals(MODE_HASHTAG.INSTANCE)) { | ||||
|                 for (final OnHashtagClickListener onHashtagClickListener : onHashtagClickListeners) { | ||||
|                     onHashtagClickListener.onHashtagClick(autoLinkItem); | ||||
|                 } | ||||
|                 return Unit.INSTANCE; | ||||
|             } | ||||
|             if (mode.equals(MODE_URL.INSTANCE)) { | ||||
|                 for (final OnURLClickListener onURLClickListener : onURLClickListeners) { | ||||
|                     onURLClickListener.onURLClick(autoLinkItem); | ||||
|                 } | ||||
|                 return Unit.INSTANCE; | ||||
|             } | ||||
|             if (mode.equals(MODE_EMAIL.INSTANCE)) { | ||||
|                 for (final OnEmailClickListener onEmailClickListener : onEmailClickListeners) { | ||||
|                     onEmailClickListener.onEmailClick(autoLinkItem); | ||||
|                 } | ||||
|                 return Unit.INSTANCE; | ||||
|             } | ||||
|             return Unit.INSTANCE; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public void addOnMentionClickListener(final OnMentionClickListener onMentionClickListener) { | ||||
|         if (onMentionClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onMentionClickListeners.add(onMentionClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void removeOnMentionClickListener(final OnMentionClickListener onMentionClickListener) { | ||||
|         if (onMentionClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onMentionClickListeners.remove(onMentionClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void clearOnMentionClickListeners() { | ||||
|         onMentionClickListeners.clear(); | ||||
|     } | ||||
| 
 | ||||
|     public void addOnHashtagListener(final OnHashtagClickListener onHashtagClickListener) { | ||||
|         if (onHashtagClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onHashtagClickListeners.add(onHashtagClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void removeOnHashtagListener(final OnHashtagClickListener onHashtagClickListener) { | ||||
|         if (onHashtagClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onHashtagClickListeners.remove(onHashtagClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void clearOnHashtagClickListeners() { | ||||
|         onHashtagClickListeners.clear(); | ||||
|     } | ||||
| 
 | ||||
|     public void addOnURLClickListener(final OnURLClickListener onURLClickListener) { | ||||
|         if (onURLClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onURLClickListeners.add(onURLClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void removeOnURLClickListener(final OnURLClickListener onURLClickListener) { | ||||
|         if (onURLClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onURLClickListeners.remove(onURLClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void clearOnURLClickListeners() { | ||||
|         onURLClickListeners.clear(); | ||||
|     } | ||||
| 
 | ||||
|     public void addOnEmailClickListener(final OnEmailClickListener onEmailClickListener) { | ||||
|         if (onEmailClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onEmailClickListeners.add(onEmailClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void removeOnEmailClickListener(final OnEmailClickListener onEmailClickListener) { | ||||
|         if (onEmailClickListener == null) { | ||||
|             return; | ||||
|         } | ||||
|         onEmailClickListeners.remove(onEmailClickListener); | ||||
|     } | ||||
| 
 | ||||
|     public void clearOnEmailClickListeners() { | ||||
|         onEmailClickListeners.clear(); | ||||
|     } | ||||
| 
 | ||||
|     public interface OnMentionClickListener { | ||||
|         void onMentionClick(final AutoLinkItem autoLinkItem); | ||||
|     } | ||||
| 
 | ||||
|     public interface OnHashtagClickListener { | ||||
|         void onHashtagClick(final AutoLinkItem autoLinkItem); | ||||
|     } | ||||
| 
 | ||||
|     public interface OnURLClickListener { | ||||
|         void onURLClick(final AutoLinkItem autoLinkItem); | ||||
|     } | ||||
| 
 | ||||
|     public interface OnEmailClickListener { | ||||
|         void onEmailClick(final AutoLinkItem autoLinkItem); | ||||
|     } | ||||
| } | ||||
| @ -77,6 +77,7 @@ public abstract class SharedElementTransitionDialogFragment extends DialogFragme | ||||
|                             final View startView = startViews.get(key); | ||||
|                             final View destView = destViews.get(key); | ||||
|                             final ViewBounds viewBounds = viewBoundsMap.get(key); | ||||
|                             if (startView == null || destView == null || viewBounds == null) return; | ||||
|                             onEndSharedElementAnimation(startView, destView, viewBounds); | ||||
|                         } | ||||
|                     } | ||||
| @ -87,6 +88,7 @@ public abstract class SharedElementTransitionDialogFragment extends DialogFragme | ||||
|                 final View startView = startViews.get(key); | ||||
|                 final View destView = destViews.get(key); | ||||
|                 final ViewBounds viewBounds = viewBoundsMap.get(key); | ||||
|                 if (startView == null || destView == null || viewBounds == null) return; | ||||
|                 onBeforeSharedElementAnimation(startView, destView, viewBounds); | ||||
|                 setDestBounds(key); | ||||
|             } | ||||
|  | ||||
| @ -45,6 +45,7 @@ public class VideoPlayerViewHelper implements Player.EventListener { | ||||
|     private final float initialVolume; | ||||
|     private final float thumbnailAspectRatio; | ||||
|     private final String thumbnailUrl; | ||||
|     private final boolean loadPlayerOnClick; | ||||
|     private final awais.instagrabber.databinding.LayoutExoCustomControlsBinding controlsBinding; | ||||
|     private final VideoPlayerCallback videoPlayerCallback; | ||||
|     private final String videoUrl; | ||||
| @ -58,6 +59,7 @@ public class VideoPlayerViewHelper implements Player.EventListener { | ||||
|                                  final float initialVolume, | ||||
|                                  final float thumbnailAspectRatio, | ||||
|                                  final String thumbnailUrl, | ||||
|                                  final boolean loadPlayerOnClick, | ||||
|                                  final LayoutExoCustomControlsBinding controlsBinding, | ||||
|                                  final VideoPlayerCallback videoPlayerCallback) { | ||||
|         this.context = context; | ||||
| @ -65,6 +67,7 @@ public class VideoPlayerViewHelper implements Player.EventListener { | ||||
|         this.initialVolume = initialVolume; | ||||
|         this.thumbnailAspectRatio = thumbnailAspectRatio; | ||||
|         this.thumbnailUrl = thumbnailUrl; | ||||
|         this.loadPlayerOnClick = loadPlayerOnClick; | ||||
|         this.controlsBinding = controlsBinding; | ||||
|         this.videoPlayerCallback = videoPlayerCallback; | ||||
|         this.videoUrl = videoUrl; | ||||
| @ -77,7 +80,9 @@ public class VideoPlayerViewHelper implements Player.EventListener { | ||||
|             if (videoPlayerCallback != null) { | ||||
|                 videoPlayerCallback.onThumbnailClick(); | ||||
|             } | ||||
|             loadPlayer(); | ||||
|             if (loadPlayerOnClick) { | ||||
|                 loadPlayer(); | ||||
|             } | ||||
|         }); | ||||
|         setThumbnail(); | ||||
|         setupControls(); | ||||
| @ -262,38 +267,31 @@ public class VideoPlayerViewHelper implements Player.EventListener { | ||||
|         speedPopup.setOnMenuItemClickListener(item -> { | ||||
|             float nextSpeed; | ||||
|             int textResId; | ||||
|             switch (item.getItemId()) { | ||||
|                 case R.id.pt_two_five_x: | ||||
|                     nextSpeed = 0.25f; | ||||
|                     textResId = R.string.pt_two_five_x; | ||||
|                     break; | ||||
|                 case R.id.pt_five_x: | ||||
|                     nextSpeed = 0.5f; | ||||
|                     textResId = R.string.pt_five_x; | ||||
|                     break; | ||||
|                 case R.id.pt_seven_five_x: | ||||
|                     nextSpeed = 0.75f; | ||||
|                     textResId = R.string.pt_seven_five_x; | ||||
|                     break; | ||||
|                 case R.id.one_x: | ||||
|                     nextSpeed = 1f; | ||||
|                     textResId = R.string.one_x; | ||||
|                     break; | ||||
|                 case R.id.one_pt_two_five_x: | ||||
|                     nextSpeed = 1.25f; | ||||
|                     textResId = R.string.one_pt_two_five_x; | ||||
|                     break; | ||||
|                 case R.id.one_pt_five_x: | ||||
|                     nextSpeed = 1.5f; | ||||
|                     textResId = R.string.one_pt_five_x; | ||||
|                     break; | ||||
|                 case R.id.two_x: | ||||
|                     nextSpeed = 2f; | ||||
|                     textResId = R.string.two_x; | ||||
|                     break; | ||||
|                 default: | ||||
|                     nextSpeed = 1; | ||||
|                     textResId = R.string.one_x; | ||||
|             int itemId = item.getItemId(); | ||||
|             if (itemId == R.id.pt_two_five_x) { | ||||
|                 nextSpeed = 0.25f; | ||||
|                 textResId = R.string.pt_two_five_x; | ||||
|             } else if (itemId == R.id.pt_five_x) { | ||||
|                 nextSpeed = 0.5f; | ||||
|                 textResId = R.string.pt_five_x; | ||||
|             } else if (itemId == R.id.pt_seven_five_x) { | ||||
|                 nextSpeed = 0.75f; | ||||
|                 textResId = R.string.pt_seven_five_x; | ||||
|             } else if (itemId == R.id.one_x) { | ||||
|                 nextSpeed = 1f; | ||||
|                 textResId = R.string.one_x; | ||||
|             } else if (itemId == R.id.one_pt_two_five_x) { | ||||
|                 nextSpeed = 1.25f; | ||||
|                 textResId = R.string.one_pt_two_five_x; | ||||
|             } else if (itemId == R.id.one_pt_five_x) { | ||||
|                 nextSpeed = 1.5f; | ||||
|                 textResId = R.string.one_pt_five_x; | ||||
|             } else if (itemId == R.id.two_x) { | ||||
|                 nextSpeed = 2f; | ||||
|                 textResId = R.string.two_x; | ||||
|             } else { | ||||
|                 nextSpeed = 1; | ||||
|                 textResId = R.string.one_x; | ||||
|             } | ||||
|             player.setPlaybackParameters(new PlaybackParameters(nextSpeed)); | ||||
|             controlsBinding.speed.setText(textResId); | ||||
|  | ||||
| @ -82,26 +82,31 @@ public class PostsLayoutPreferencesDialogFragment extends DialogFragment { | ||||
|     } | ||||
| 
 | ||||
|     private void initLayoutToggle() { | ||||
|         binding.layoutToggle.check(getSelectedLayoutId()); | ||||
|         // binding.staggeredOrGridOptions.setVisibility(getSelectedLayoutId() != R.id.layout_linear ? View.VISIBLE : View.GONE); | ||||
|         final int selectedLayoutId = getSelectedLayoutId(); | ||||
|         binding.layoutToggle.check(selectedLayoutId); | ||||
|         if (selectedLayoutId == R.id.layout_linear) { | ||||
|             binding.staggeredOrGridOptions.setVisibility(View.GONE); | ||||
|         } | ||||
|         binding.layoutToggle.addOnButtonCheckedListener((group, checkedId, isChecked) -> { | ||||
|             if (isChecked) { | ||||
|                 switch (checkedId) { | ||||
|                     case R.id.layout_linear: | ||||
|                         preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.LINEAR); | ||||
|                         binding.staggeredOrGridOptions.setVisibility(View.GONE); | ||||
|                         break; | ||||
|                     case R.id.layout_staggered: | ||||
|                         preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.STAGGERED_GRID); | ||||
|                         binding.staggeredOrGridOptions.setVisibility(View.VISIBLE); | ||||
|                         initStaggeredOrGridOptions(); | ||||
|                         break; | ||||
|                     case R.id.layout_grid: | ||||
|                     default: | ||||
|                         preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.GRID); | ||||
|                         binding.staggeredOrGridOptions.setVisibility(View.VISIBLE); | ||||
|                         initStaggeredOrGridOptions(); | ||||
|                         break; | ||||
|                 if (checkedId == R.id.layout_linear) { | ||||
|                     preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.LINEAR); | ||||
|                     preferencesBuilder.setColCount(1); | ||||
|                     binding.staggeredOrGridOptions.setVisibility(View.GONE); | ||||
|                 } else if (checkedId == R.id.layout_staggered) { | ||||
|                     preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.STAGGERED_GRID); | ||||
|                     if (preferencesBuilder.getColCount() == 1) { | ||||
|                         preferencesBuilder.setColCount(2); | ||||
|                     } | ||||
|                     binding.staggeredOrGridOptions.setVisibility(View.VISIBLE); | ||||
|                     initStaggeredOrGridOptions(); | ||||
|                 } else { | ||||
|                     preferencesBuilder.setType(PostsLayoutPreferences.PostsLayoutType.GRID); | ||||
|                     if (preferencesBuilder.getColCount() == 1) { | ||||
|                         preferencesBuilder.setColCount(2); | ||||
|                     } | ||||
|                     binding.staggeredOrGridOptions.setVisibility(View.VISIBLE); | ||||
|                     initStaggeredOrGridOptions(); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| @ -111,14 +116,10 @@ public class PostsLayoutPreferencesDialogFragment extends DialogFragment { | ||||
|         binding.colCountToggle.check(getSelectedColCountId()); | ||||
|         binding.colCountToggle.addOnButtonCheckedListener((group, checkedId, isChecked) -> { | ||||
|             if (!isChecked) return; | ||||
|             switch (checkedId) { | ||||
|                 case R.id.col_count_two: | ||||
|                     preferencesBuilder.setColCount(2); | ||||
|                     break; | ||||
|                 case R.id.col_count_three: | ||||
|                 default: | ||||
|                     preferencesBuilder.setColCount(3); | ||||
|                     break; | ||||
|             if (checkedId == R.id.col_count_two) { | ||||
|                 preferencesBuilder.setColCount(2); | ||||
|             } else { | ||||
|                 preferencesBuilder.setColCount(3); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| @ -135,17 +136,12 @@ public class PostsLayoutPreferencesDialogFragment extends DialogFragment { | ||||
|         binding.avatarSizeToggle.setVisibility(preferencesBuilder.isAvatarVisible() ? View.VISIBLE : View.GONE); | ||||
|         binding.avatarSizeToggle.addOnButtonCheckedListener((group, checkedId, isChecked) -> { | ||||
|             if (!isChecked) return; | ||||
|             switch (checkedId) { | ||||
|                 case R.id.avatar_size_tiny: | ||||
|                     preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.TINY); | ||||
|                     break; | ||||
|                 case R.id.avatar_size_small: | ||||
|                     preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.SMALL); | ||||
|                     break; | ||||
|                 case R.id.avatar_size_regular: | ||||
|                 default: | ||||
|                     preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.REGULAR); | ||||
|                     break; | ||||
|             if (checkedId == R.id.avatar_size_tiny) { | ||||
|                 preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.TINY); | ||||
|             } else if (checkedId == R.id.avatar_size_small) { | ||||
|                 preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.SMALL); | ||||
|             } else { | ||||
|                 preferencesBuilder.setProfilePicSize(PostsLayoutPreferences.ProfilePicSize.REGULAR); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @ -12,69 +12,129 @@ import android.text.TextWatcher; | ||||
| import android.text.style.RelativeSizeSpan; | ||||
| import android.util.Log; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.view.inputmethod.InputMethodManager; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.appcompat.app.ActionBar; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| import androidx.appcompat.widget.SearchView; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.appcompat.widget.LinearLayoutCompat; | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentTransaction; | ||||
| import androidx.lifecycle.ViewModelProvider; | ||||
| import androidx.navigation.NavDirections; | ||||
| import androidx.navigation.fragment.NavHostFragment; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | ||||
| 
 | ||||
| import com.google.android.material.bottomsheet.BottomSheetDialogFragment; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.CommentsAdapter; | ||||
| import awais.instagrabber.asyncs.CommentsFetcher; | ||||
| import awais.instagrabber.databinding.FragmentCommentsBinding; | ||||
| import awais.instagrabber.dialogs.ProfilePicDialogFragment; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.CommentModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awais.instagrabber.viewmodels.CommentsViewModel; | ||||
| import awais.instagrabber.webservices.MediaService; | ||||
| import awais.instagrabber.webservices.ServiceCallback; | ||||
| 
 | ||||
| import static android.content.Context.INPUT_METHOD_SERVICE; | ||||
| 
 | ||||
| public final class CommentsViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { | ||||
| public final class CommentsViewerFragment extends BottomSheetDialogFragment implements SwipeRefreshLayout.OnRefreshListener { | ||||
|     private static final String TAG = "CommentsViewerFragment"; | ||||
| 
 | ||||
|     private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); | ||||
| 
 | ||||
|     private CommentsAdapter commentsAdapter; | ||||
|     private CommentModel commentModel; | ||||
|     private FragmentCommentsBinding binding; | ||||
|     private String shortCode; | ||||
|     private String userId; | ||||
|     private Resources resources; | ||||
|     private InputMethodManager imm; | ||||
|     private AppCompatActivity fragmentActivity; | ||||
|     private LinearLayout root; | ||||
|     private LinearLayoutCompat root; | ||||
|     private boolean shouldRefresh = true; | ||||
|     private MediaService mediaService; | ||||
|     private String postId; | ||||
|     private CommentsViewModel commentsViewModel; | ||||
| 
 | ||||
|     private final CommentsAdapter.CommentCallback commentCallback = new CommentsAdapter.CommentCallback() { | ||||
|         @Override | ||||
|         public void onClick(final CommentModel comment) { | ||||
|             onCommentClick(comment); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onHashtagClick(final String hashtag) { | ||||
|             final NavDirections action = CommentsViewerFragmentDirections.actionGlobalHashTagFragment(hashtag); | ||||
|             NavHostFragment.findNavController(CommentsViewerFragment.this).navigate(action); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onMentionClick(final String mention) { | ||||
|             openProfile(mention); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onURLClick(final String url) { | ||||
|             Utils.openURL(getContext(), url); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onEmailClick(final String emailAddress) { | ||||
|             Utils.openEmailAddress(getContext(), emailAddress); | ||||
|         } | ||||
|     }; | ||||
|     private final View.OnClickListener newCommentListener = v -> { | ||||
|         final Editable text = binding.commentText.getText(); | ||||
|         final Context context = getContext(); | ||||
|         if (context == null) return; | ||||
|         if (text == null || TextUtils.isEmpty(text.toString())) { | ||||
|             Toast.makeText(context, R.string.comment_send_empty_comment, Toast.LENGTH_SHORT).show(); | ||||
|             return; | ||||
|         } | ||||
|         final String userId = CookieUtils.getUserIdFromCookie(cookie); | ||||
|         if (userId == null) return; | ||||
|         String replyToId = null; | ||||
|         final CommentModel commentModel = commentsAdapter.getSelected(); | ||||
|         if (commentModel != null) { | ||||
|             replyToId = commentModel.getId(); | ||||
|         } | ||||
|         mediaService.comment(postId, text.toString(), userId, replyToId, CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() { | ||||
|             @Override | ||||
|             public void onSuccess(final Boolean result) { | ||||
|                 commentsAdapter.clearSelection(); | ||||
|                 binding.commentText.setText(""); | ||||
|                 if (!result) { | ||||
|                     Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                     return; | ||||
|                 } | ||||
|                 onRefresh(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onFailure(final Throwable t) { | ||||
|                 Log.e(TAG, "Error during comment", t); | ||||
|                 Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|             } | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreate(@Nullable final Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         fragmentActivity = (AppCompatActivity) getActivity(); | ||||
|         mediaService = MediaService.getInstance(); | ||||
|         setHasOptionsMenu(true); | ||||
|         // setHasOptionsMenu(true); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
| @ -85,6 +145,8 @@ public final class CommentsViewerFragment extends Fragment implements SwipeRefre | ||||
|             return root; | ||||
|         } | ||||
|         binding = FragmentCommentsBinding.inflate(getLayoutInflater()); | ||||
|         binding.swipeRefreshLayout.setEnabled(false); | ||||
|         binding.swipeRefreshLayout.setNestedScrollingEnabled(false); | ||||
|         root = binding.getRoot(); | ||||
|         return root; | ||||
|     } | ||||
| @ -96,34 +158,33 @@ public final class CommentsViewerFragment extends Fragment implements SwipeRefre | ||||
|         shouldRefresh = false; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { | ||||
|         inflater.inflate(R.menu.follow, menu); | ||||
|         menu.findItem(R.id.action_compare).setVisible(false); | ||||
|         final MenuItem menuSearch = menu.findItem(R.id.action_search); | ||||
|         final SearchView searchView = (SearchView) menuSearch.getActionView(); | ||||
|         searchView.setQueryHint(getResources().getString(R.string.action_search)); | ||||
|         searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { | ||||
|             @Override | ||||
|             public boolean onQueryTextSubmit(final String query) { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public boolean onQueryTextChange(final String query) { | ||||
|                 if (commentsAdapter != null) commentsAdapter.getFilter().filter(query); | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|     // @Override | ||||
|     // public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { | ||||
|     //     inflater.inflate(R.menu.follow, menu); | ||||
|     //     menu.findItem(R.id.action_compare).setVisible(false); | ||||
|     //     final MenuItem menuSearch = menu.findItem(R.id.action_search); | ||||
|     //     final SearchView searchView = (SearchView) menuSearch.getActionView(); | ||||
|     //     searchView.setQueryHint(getResources().getString(R.string.action_search)); | ||||
|     //     searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { | ||||
|     //         @Override | ||||
|     //         public boolean onQueryTextSubmit(final String query) { | ||||
|     //             return false; | ||||
|     //         } | ||||
|     // | ||||
|     //         @Override | ||||
|     //         public boolean onQueryTextChange(final String query) { | ||||
|     //             // if (commentsAdapter != null) commentsAdapter.getFilter().filter(query); | ||||
|     //             return true; | ||||
|     //         } | ||||
|     //     }); | ||||
|     // } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRefresh() { | ||||
|         binding.swipeRefreshLayout.setRefreshing(true); | ||||
|         new CommentsFetcher(shortCode, commentModels -> { | ||||
|             commentsViewModel.getList().postValue(commentModels); | ||||
|             binding.swipeRefreshLayout.setRefreshing(false); | ||||
|             commentsAdapter = new CommentsAdapter(commentModels, true, clickListener, mentionClickListener); | ||||
|             binding.rvComments.setAdapter(commentsAdapter); | ||||
|         }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|     } | ||||
| 
 | ||||
| @ -133,9 +194,14 @@ public final class CommentsViewerFragment extends Fragment implements SwipeRefre | ||||
|         shortCode = fragmentArgs.getShortCode(); | ||||
|         postId = fragmentArgs.getPostId(); | ||||
|         userId = fragmentArgs.getPostUserId(); | ||||
|         setTitle(); | ||||
|         // setTitle(); | ||||
|         binding.swipeRefreshLayout.setOnRefreshListener(this); | ||||
|         binding.swipeRefreshLayout.setRefreshing(true); | ||||
|         commentsViewModel = new ViewModelProvider(this).get(CommentsViewModel.class); | ||||
|         binding.rvComments.setLayoutManager(new LinearLayoutManager(getContext())); | ||||
|         commentsAdapter = new CommentsAdapter(commentCallback); | ||||
|         binding.rvComments.setAdapter(commentsAdapter); | ||||
|         commentsViewModel.getList().observe(getViewLifecycleOwner(), commentsAdapter::submitList); | ||||
|         resources = getResources(); | ||||
|         if (!TextUtils.isEmpty(cookie)) { | ||||
|             binding.commentField.setStartIconVisible(false); | ||||
| @ -155,121 +221,107 @@ public final class CommentsViewerFragment extends Fragment implements SwipeRefre | ||||
|                 public void afterTextChanged(final Editable s) {} | ||||
|             }); | ||||
|             binding.commentField.setStartIconOnClickListener(v -> { | ||||
|                 if (commentModel != null) { | ||||
|                     final View focus = binding.rvComments.findViewWithTag(commentModel); | ||||
|                     focus.setBackgroundColor(0x00000000); | ||||
|                     commentModel = null; | ||||
|                 } | ||||
|                 commentsAdapter.clearSelection(); | ||||
|                 binding.commentText.setText(""); | ||||
|             }); | ||||
|             binding.commentField.setEndIconOnClickListener(newCommentListener); | ||||
|         } | ||||
|         new CommentsFetcher(this.shortCode, commentModels -> { | ||||
|             commentsAdapter = new CommentsAdapter(commentModels, true, clickListener, mentionClickListener); | ||||
|             binding.rvComments.setAdapter(commentsAdapter); | ||||
|             binding.swipeRefreshLayout.setRefreshing(false); | ||||
|         }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|         onRefresh(); | ||||
|     } | ||||
| 
 | ||||
|     private void setTitle() { | ||||
|         final ActionBar actionBar = fragmentActivity.getSupportActionBar(); | ||||
|         if (actionBar == null) return; | ||||
|         actionBar.setTitle(R.string.title_comments); | ||||
|     // private void setTitle() { | ||||
|     //     final ActionBar actionBar = fragmentActivity.getSupportActionBar(); | ||||
|     //     if (actionBar == null) return; | ||||
|     //     actionBar.setTitle(R.string.title_comments); | ||||
|         // actionBar.setSubtitle(shortCode); | ||||
|     } | ||||
|     // } | ||||
| 
 | ||||
|     final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> { | ||||
|     private void onCommentClick(final CommentModel commentModel) { | ||||
|         final String username = commentModel.getProfileModel().getUsername(); | ||||
|         final SpannableString title = new SpannableString(username + ":\n" + commentModel.getText()); | ||||
|         title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); | ||||
| 
 | ||||
|         String[] commentDialogList; | ||||
| 
 | ||||
|         final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); | ||||
|         if (!TextUtils.isEmpty(cookie) | ||||
|                 && userIdFromCookie != null | ||||
|                 && (userIdFromCookie.equals(commentModel.getProfileModel().getId()) || userIdFromCookie.equals(userId))) { | ||||
|             commentDialogList = new String[]{ | ||||
|                     resources.getString(R.string.open_profile), | ||||
|                     resources.getString(R.string.view_pfp), | ||||
|                     resources.getString(R.string.comment_viewer_copy_user), | ||||
|                     // resources.getString(R.string.comment_viewer_copy_comment), | ||||
|                     resources.getString(R.string.comment_viewer_reply_comment), | ||||
|                     commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) | ||||
|                                             : resources.getString(R.string.comment_viewer_like_comment), | ||||
|                     resources.getString(R.string.comment_viewer_delete_comment) | ||||
|             }; | ||||
|         } else if (!TextUtils.isEmpty(cookie)) { | ||||
|             commentDialogList = new String[]{ | ||||
|                     resources.getString(R.string.open_profile), | ||||
|                     resources.getString(R.string.view_pfp), | ||||
|                     resources.getString(R.string.comment_viewer_copy_user), | ||||
|                     // resources.getString(R.string.comment_viewer_copy_comment), | ||||
|                     resources.getString(R.string.comment_viewer_reply_comment), | ||||
|                     commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) | ||||
|                                             : resources.getString(R.string.comment_viewer_like_comment), | ||||
|             }; | ||||
|         } else { | ||||
|             commentDialogList = new String[]{ | ||||
|                     resources.getString(R.string.open_profile), | ||||
|                     resources.getString(R.string.view_pfp), | ||||
|                     resources.getString(R.string.comment_viewer_copy_user), | ||||
|                     // resources.getString(R.string.comment_viewer_copy_comment) | ||||
|             }; | ||||
|         } | ||||
|         final Context context = getContext(); | ||||
|         if (context == null) return; | ||||
|         if (commentModel == null) { | ||||
|             Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|             return; | ||||
|         } | ||||
|         final ProfileModel profileModel = commentModel.getProfileModel(); | ||||
|         switch (which) { | ||||
|             case 0: // open profile | ||||
|                 openProfile(profileModel.getUsername()); | ||||
|                 break; | ||||
|             case 1: // view profile pic | ||||
|                 final FragmentManager fragmentManager = getParentFragmentManager(); | ||||
|                 final ProfilePicDialogFragment fragment = new ProfilePicDialogFragment(profileModel.getId(), | ||||
|                                                                                        profileModel.getUsername(), | ||||
|                                                                                        profileModel.getHdProfilePic()); | ||||
|                 final FragmentTransaction ft = fragmentManager.beginTransaction(); | ||||
|                 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) | ||||
|                   .add(fragment, "profilePicDialog") | ||||
|                   .commit(); | ||||
|                 break; | ||||
|             case 2: // copy username | ||||
|                 Utils.copyText(context, profileModel.getUsername()); | ||||
|                 break; | ||||
|             case 3: // copy comment | ||||
|                 Utils.copyText(context, commentModel.getText().toString()); | ||||
|                 break; | ||||
|             case 4: // reply to comment | ||||
|                 final View focus = binding.rvComments.findViewWithTag(commentModel); | ||||
|                 focus.setBackgroundColor(0x80888888); | ||||
|                 String mention = "@" + profileModel.getUsername() + " "; | ||||
|                 binding.commentText.setText(mention); | ||||
|                 binding.commentText.requestFocus(); | ||||
|                 binding.commentText.setSelection(mention.length()); | ||||
|                 binding.commentText.postDelayed(new Runnable() { | ||||
|                     @Override | ||||
|                     public void run() { | ||||
|         final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> { | ||||
|             final ProfileModel profileModel = commentModel.getProfileModel(); | ||||
|             final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); | ||||
|             switch (which) { | ||||
|                 case 0: // open profile | ||||
|                     openProfile("@" + profileModel.getUsername()); | ||||
|                     break; | ||||
|                 case 1: // view profile pic | ||||
|                     final FragmentManager fragmentManager = getParentFragmentManager(); | ||||
|                     final ProfilePicDialogFragment fragment = new ProfilePicDialogFragment(profileModel.getId(), | ||||
|                                                                                            profileModel.getUsername(), | ||||
|                                                                                            profileModel.getHdProfilePic()); | ||||
|                     final FragmentTransaction ft = fragmentManager.beginTransaction(); | ||||
|                     ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) | ||||
|                       .add(fragment, "profilePicDialog") | ||||
|                       .commit(); | ||||
|                     break; | ||||
|                 case 2: // copy username | ||||
|                     Utils.copyText(context, profileModel.getUsername()); | ||||
|                     break; | ||||
|                 // case 3: // copy comment | ||||
|                 //     Utils.copyText(context, commentModel.getText().toString()); | ||||
|                 //     break; | ||||
|                 case 3: // reply to comment | ||||
|                     // final View focus = binding.rvComments.findViewWithTag(commentModel); | ||||
|                     // focus.setBackgroundColor(0x80888888); | ||||
|                     commentsAdapter.setSelected(commentModel); | ||||
|                     String mention = "@" + profileModel.getUsername() + " "; | ||||
|                     binding.commentText.setText(mention); | ||||
|                     binding.commentText.requestFocus(); | ||||
|                     binding.commentText.setSelection(mention.length()); | ||||
|                     binding.commentText.postDelayed(() -> { | ||||
|                         imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE); | ||||
|                         if (imm == null) return; | ||||
|                         imm.showSoftInput(binding.commentText, 0); | ||||
|                     }, 200); | ||||
|                     break; | ||||
|                 case 4: // like/unlike comment | ||||
|                     if (csrfToken == null) { | ||||
|                         return; | ||||
|                     } | ||||
|                 }, 200); | ||||
|                 break; | ||||
|             case 5: // like/unlike comment | ||||
|                 if (!commentModel.getLiked()) { | ||||
|                     mediaService.commentLike(commentModel.getId(), CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() { | ||||
|                         @Override | ||||
|                         public void onSuccess(final Boolean result) { | ||||
|                             commentModel = null; | ||||
|                             if (!result) { | ||||
|                                 Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                 return; | ||||
|                             } | ||||
|                             onRefresh(); | ||||
|                         } | ||||
| 
 | ||||
|                         @Override | ||||
|                         public void onFailure(final Throwable t) { | ||||
|                             Log.e(TAG, "Error liking comment", t); | ||||
|                             Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|                         } | ||||
|                     }); | ||||
|                     return; | ||||
|                 } | ||||
|                 mediaService.commentUnlike(commentModel.getId(), CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() { | ||||
|                     @Override | ||||
|                     public void onSuccess(final Boolean result) { | ||||
|                         commentModel = null; | ||||
|                         if (!result) { | ||||
|                             Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                             return; | ||||
|                         } | ||||
|                         onRefresh(); | ||||
|                     } | ||||
| 
 | ||||
|                     @Override | ||||
|                     public void onFailure(final Throwable t) { | ||||
|                         Log.e(TAG, "Error unliking comment", t); | ||||
|                         Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|                     } | ||||
|                 }); | ||||
|                 break; | ||||
|             case 6: // delete comment | ||||
|                 final String userId = CookieUtils.getUserIdFromCookie(cookie); | ||||
|                 if (userId == null) return; | ||||
|                 mediaService.deleteComment( | ||||
|                         postId, userId, commentModel.getId(), CookieUtils.getCsrfTokenFromCookie(cookie), | ||||
|                         new ServiceCallback<Boolean>() { | ||||
|                     if (!commentModel.getLiked()) { | ||||
|                         mediaService.commentLike(commentModel.getId(), csrfToken, new ServiceCallback<Boolean>() { | ||||
|                             @Override | ||||
|                             public void onSuccess(final Boolean result) { | ||||
|                                 commentModel = null; | ||||
|                                 if (!result) { | ||||
|                                     Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                     return; | ||||
| @ -279,112 +331,62 @@ public final class CommentsViewerFragment extends Fragment implements SwipeRefre | ||||
| 
 | ||||
|                             @Override | ||||
|                             public void onFailure(final Throwable t) { | ||||
|                                 Log.e(TAG, "Error deleting comment", t); | ||||
|                                 Log.e(TAG, "Error liking comment", t); | ||||
|                                 Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|                             } | ||||
|                         }); | ||||
|                 break; | ||||
|         } | ||||
|     }; | ||||
|                         return; | ||||
|                     } | ||||
|                     mediaService.commentUnlike(commentModel.getId(), csrfToken, new ServiceCallback<Boolean>() { | ||||
|                         @Override | ||||
|                         public void onSuccess(final Boolean result) { | ||||
|                             if (!result) { | ||||
|                                 Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                 return; | ||||
|                             } | ||||
|                             onRefresh(); | ||||
|                         } | ||||
| 
 | ||||
|     private final View.OnClickListener clickListener = v -> { | ||||
|         final Object tag = v.getTag(); | ||||
|         if (tag instanceof CommentModel) { | ||||
|             commentModel = (CommentModel) tag; | ||||
|                         @Override | ||||
|                         public void onFailure(final Throwable t) { | ||||
|                             Log.e(TAG, "Error unliking comment", t); | ||||
|                             Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|                         } | ||||
|                     }); | ||||
|                     break; | ||||
|                 case 5: // delete comment | ||||
|                     final String userId = CookieUtils.getUserIdFromCookie(cookie); | ||||
|                     if (userId == null) return; | ||||
|                     mediaService.deleteComment( | ||||
|                             postId, userId, commentModel.getId(), csrfToken, | ||||
|                             new ServiceCallback<Boolean>() { | ||||
|                                 @Override | ||||
|                                 public void onSuccess(final Boolean result) { | ||||
|                                     if (!result) { | ||||
|                                         Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                         return; | ||||
|                                     } | ||||
|                                     onRefresh(); | ||||
|                                 } | ||||
| 
 | ||||
|             final String username = commentModel.getProfileModel().getUsername(); | ||||
|             final SpannableString title = new SpannableString(username + ":\n" + commentModel.getText()); | ||||
|             title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); | ||||
| 
 | ||||
|             String[] commentDialogList; | ||||
| 
 | ||||
|             final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); | ||||
|             if (!TextUtils.isEmpty(cookie) | ||||
|                     && userIdFromCookie != null | ||||
|                     && (userIdFromCookie.equals(commentModel.getProfileModel().getId()) || userIdFromCookie.equals(userId))) { | ||||
|                 commentDialogList = new String[]{ | ||||
|                         resources.getString(R.string.open_profile), | ||||
|                         resources.getString(R.string.view_pfp), | ||||
|                         resources.getString(R.string.comment_viewer_copy_user), | ||||
|                         resources.getString(R.string.comment_viewer_copy_comment), | ||||
|                         resources.getString(R.string.comment_viewer_reply_comment), | ||||
|                         commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) | ||||
|                                                 : resources.getString(R.string.comment_viewer_like_comment), | ||||
|                         resources.getString(R.string.comment_viewer_delete_comment) | ||||
|                 }; | ||||
|             } else if (!TextUtils.isEmpty(cookie)) { | ||||
|                 commentDialogList = new String[]{ | ||||
|                         resources.getString(R.string.open_profile), | ||||
|                         resources.getString(R.string.view_pfp), | ||||
|                         resources.getString(R.string.comment_viewer_copy_user), | ||||
|                         resources.getString(R.string.comment_viewer_copy_comment), | ||||
|                         resources.getString(R.string.comment_viewer_reply_comment), | ||||
|                         commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) | ||||
|                                                 : resources.getString(R.string.comment_viewer_like_comment), | ||||
|                 }; | ||||
|             } else { | ||||
|                 commentDialogList = new String[]{ | ||||
|                         resources.getString(R.string.open_profile), | ||||
|                         resources.getString(R.string.view_pfp), | ||||
|                         resources.getString(R.string.comment_viewer_copy_user), | ||||
|                         resources.getString(R.string.comment_viewer_copy_comment) | ||||
|                 }; | ||||
|                                 @Override | ||||
|                                 public void onFailure(final Throwable t) { | ||||
|                                     Log.e(TAG, "Error deleting comment", t); | ||||
|                                     Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|                                 } | ||||
|                             }); | ||||
|                     break; | ||||
|             } | ||||
|             final Context context = getContext(); | ||||
|             if (context == null) return; | ||||
|             new AlertDialog.Builder(context) | ||||
|                     .setTitle(title) | ||||
|                     .setItems(commentDialogList, profileDialogListener) | ||||
|                     .setNegativeButton(R.string.cancel, null) | ||||
|                     .show(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     private final MentionClickListener mentionClickListener = (view, text, isHashtag, isLocation) -> { | ||||
|         if (isHashtag) { | ||||
|             final NavDirections action = CommentsViewerFragmentDirections.actionGlobalHashTagFragment(text); | ||||
|             NavHostFragment.findNavController(this).navigate(action); | ||||
|             return; | ||||
|         } | ||||
|         openProfile(text); | ||||
|     }; | ||||
| 
 | ||||
|     private final View.OnClickListener newCommentListener = v -> { | ||||
|         final Editable text = binding.commentText.getText(); | ||||
|         final Context context = getContext(); | ||||
|         if (context == null) return; | ||||
|         if (text == null || TextUtils.isEmpty(text.toString())) { | ||||
|             Toast.makeText(context, R.string.comment_send_empty_comment, Toast.LENGTH_SHORT).show(); | ||||
|             return; | ||||
|         } | ||||
|         final String userId = CookieUtils.getUserIdFromCookie(cookie); | ||||
|         if (userId == null) return; | ||||
|         String replyToId = null; | ||||
|         if (commentModel != null) { | ||||
|             replyToId = commentModel.getId(); | ||||
|         } | ||||
|         mediaService.comment(postId, text.toString(), userId, replyToId, CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() { | ||||
|             @Override | ||||
|             public void onSuccess(final Boolean result) { | ||||
|                 commentModel = null; | ||||
|                 binding.commentText.setText(""); | ||||
|                 if (!result) { | ||||
|                     Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                     return; | ||||
|                 } | ||||
|                 onRefresh(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onFailure(final Throwable t) { | ||||
|                 Log.e(TAG, "Error during comment", t); | ||||
|                 Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|             } | ||||
|         }); | ||||
|     }; | ||||
|         }; | ||||
|         new AlertDialog.Builder(context) | ||||
|                 .setTitle(title) | ||||
|                 .setItems(commentDialogList, profileDialogListener) | ||||
|                 .setNegativeButton(R.string.cancel, null) | ||||
|                 .show(); | ||||
|     } | ||||
| 
 | ||||
|     private void openProfile(final String username) { | ||||
|         final NavDirections action = CommentsViewerFragmentDirections.actionGlobalProfileFragment("@" + username); | ||||
|         final NavDirections action = CommentsViewerFragmentDirections.actionGlobalProfileFragment(username); | ||||
|         NavHostFragment.findNavController(this).navigate(action); | ||||
|     } | ||||
| } | ||||
| @ -1,7 +1,6 @@ | ||||
| package awais.instagrabber.fragments; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.graphics.Typeface; | ||||
| import android.os.AsyncTask; | ||||
| import android.os.Bundle; | ||||
| @ -22,7 +21,6 @@ import androidx.activity.OnBackPressedDispatcher; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.appcompat.app.ActionBar; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.lifecycle.ViewModelProvider; | ||||
| import androidx.navigation.NavDirections; | ||||
| @ -73,6 +71,8 @@ import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { | ||||
|     private static final String TAG = "HashTagFragment"; | ||||
| 
 | ||||
|     public static final String ARG_HASHTAG = "hashtag"; | ||||
| 
 | ||||
|     private MainActivity fragmentActivity; | ||||
|     private FragmentHashtagBinding binding; | ||||
|     private NestedCoordinatorLayout root; | ||||
| @ -298,24 +298,24 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe | ||||
|         if (context == null) return; | ||||
|         if (isLoggedIn) { | ||||
|             storiesService.getUserStory(hashtagModel.getName(), | ||||
|                     null, | ||||
|                     false, | ||||
|                     true, | ||||
|                     false, | ||||
|                     new ServiceCallback<List<StoryModel>>() { | ||||
|                         @Override | ||||
|                         public void onSuccess(final List<StoryModel> storyModels) { | ||||
|                             if (storyModels != null && !storyModels.isEmpty()) { | ||||
|                                 binding.mainHashtagImage.setStoriesBorder(); | ||||
|                                 hasStories = true; | ||||
|                             } | ||||
|                         } | ||||
|                                         null, | ||||
|                                         false, | ||||
|                                         true, | ||||
|                                         false, | ||||
|                                         new ServiceCallback<List<StoryModel>>() { | ||||
|                                             @Override | ||||
|                                             public void onSuccess(final List<StoryModel> storyModels) { | ||||
|                                                 if (storyModels != null && !storyModels.isEmpty()) { | ||||
|                                                     binding.mainHashtagImage.setStoriesBorder(); | ||||
|                                                     hasStories = true; | ||||
|                                                 } | ||||
|                                             } | ||||
| 
 | ||||
|                         @Override | ||||
|                         public void onFailure(final Throwable t) { | ||||
|                             Log.e(TAG, "Error", t); | ||||
|                         } | ||||
|                     }); | ||||
|                                             @Override | ||||
|                                             public void onFailure(final Throwable t) { | ||||
|                                                 Log.e(TAG, "Error", t); | ||||
|                                             } | ||||
|                                         }); | ||||
|             binding.btnFollowTag.setVisibility(View.VISIBLE); | ||||
|             binding.btnFollowTag.setText(hashtagModel.getFollowing() ? R.string.unfollow : R.string.follow); | ||||
|             binding.btnFollowTag.setChipIconResource(hashtagModel.getFollowing() | ||||
|  | ||||
| @ -76,12 +76,9 @@ import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awais.instagrabber.webservices.MediaService; | ||||
| import awais.instagrabber.webservices.ServiceCallback; | ||||
| import io.github.armcha.autolink.MODE_EMAIL; | ||||
| import io.github.armcha.autolink.MODE_HASHTAG; | ||||
| import io.github.armcha.autolink.MODE_MENTION; | ||||
| import kotlin.Unit; | ||||
| 
 | ||||
| import static androidx.core.content.PermissionChecker.checkSelfPermission; | ||||
| import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; | ||||
| import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; | ||||
| import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| 
 | ||||
| @ -90,6 +87,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|     private static final String COOKIE = settingsHelper.getString(Constants.COOKIE); | ||||
|     private static final int DETAILS_HIDE_DELAY_MILLIS = 2000; | ||||
|     private static final String ARG_FEED_MODEL = "feedModel"; | ||||
|     private static final String ARG_SLIDER_POSITION = "position"; | ||||
|     private static final int STORAGE_PERM_REQUEST_CODE = 8020; | ||||
| 
 | ||||
|     private FeedModel feedModel; | ||||
| @ -105,6 +103,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|     private SliderItemsAdapter sliderItemsAdapter; | ||||
|     private boolean wasControlsVisible; | ||||
|     private boolean wasPaused; | ||||
|     private int captionState = BottomSheetBehavior.STATE_HIDDEN; | ||||
|     private int sliderPosition; | ||||
| 
 | ||||
|     private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener = new VerticalDragHelper.OnVerticalDragListener() { | ||||
| 
 | ||||
| @ -151,6 +151,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|         private final FeedModel feedModel; | ||||
|         private View profilePicElement; | ||||
|         private View mainPostElement; | ||||
|         private int position; | ||||
| 
 | ||||
|         public Builder setSharedProfilePicElement(final View profilePicElement) { | ||||
|             this.profilePicElement = profilePicElement; | ||||
| @ -162,8 +163,13 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public Builder setPosition(final int position) { | ||||
|             this.position = position; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public PostViewV2Fragment build() { | ||||
|             return PostViewV2Fragment.newInstance(feedModel, profilePicElement, mainPostElement); | ||||
|             return PostViewV2Fragment.newInstance(feedModel, profilePicElement, mainPostElement, position); | ||||
|         } | ||||
| 
 | ||||
|         public Builder(final FeedModel feedModel) { | ||||
| @ -171,10 +177,16 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static PostViewV2Fragment newInstance(final FeedModel feedModel, final View profilePicElement, final View mainPostElement) { | ||||
|     private static PostViewV2Fragment newInstance(final FeedModel feedModel, | ||||
|                                                   final View profilePicElement, | ||||
|                                                   final View mainPostElement, | ||||
|                                                   final int position) { | ||||
|         final PostViewV2Fragment f = new PostViewV2Fragment(profilePicElement, mainPostElement); | ||||
|         final Bundle args = new Bundle(); | ||||
|         args.putSerializable(ARG_FEED_MODEL, feedModel); | ||||
|         if (position >= 0) { | ||||
|             args.putInt(ARG_SLIDER_POSITION, position); | ||||
|         } | ||||
|         f.setArguments(args); | ||||
|         return f; | ||||
|     } | ||||
| @ -353,6 +365,9 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|             return; | ||||
|         } | ||||
|         feedModel = (FeedModel) feedModelSerializable; | ||||
|         if (feedModel.getItemType() == MediaItemType.MEDIA_TYPE_SLIDER) { | ||||
|             sliderPosition = arguments.getInt(ARG_SLIDER_POSITION, 0); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
| @ -402,6 +417,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|     public void onPause() { | ||||
|         super.onPause(); | ||||
|         wasPaused = true; | ||||
|         captionState = bottomSheetBehavior.getState(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -424,7 +440,9 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|     @Override | ||||
|     public void onSaveInstanceState(@NonNull final Bundle outState) { | ||||
|         super.onSaveInstanceState(outState); | ||||
|         Log.d(TAG, "onSaveInstanceState"); | ||||
|         if (feedModel.getItemType() == MediaItemType.MEDIA_TYPE_SLIDER) { | ||||
|             outState.putInt(ARG_SLIDER_POSITION, sliderPosition); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -505,32 +523,34 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|     } | ||||
| 
 | ||||
|     private void init() { | ||||
|         binding.getRoot().getBackground().mutate().setAlpha(0); | ||||
|         // if (getArguments() == null) return; | ||||
|         // final PostViewV2FragmentArgs fragmentArgs = PostViewV2FragmentArgs.fromBundle(getArguments()); | ||||
|         // feedModel = fragmentArgs.getFeedModel(); | ||||
|         if (!wasPaused && (sharedProfilePicElement != null || sharedMainPostElement != null)) { | ||||
|             binding.getRoot().getBackground().mutate().setAlpha(0); | ||||
|         } | ||||
|         setupProfilePic(); | ||||
|         setupTitles(); | ||||
|         setupCaption(); | ||||
|         setupCounts(); | ||||
|         setupPostTypeLayout(); | ||||
|         setupCommonActions(); | ||||
|         // binding.getRoot().setOnTouchListener(onTouchListener); | ||||
|         // final String[] idOrCodeArray = fragmentArgs.getIdOrCodeArray(); | ||||
|         // if (idOrCodeArray.length == 0) return; | ||||
|         // currentPostIndex = fragmentArgs.getIndex(); | ||||
|         // if (currentPostIndex < 0) return; | ||||
|         // if (currentPostIndex >= idOrCodeArray.length) return; | ||||
|         // idOrCodeList = Arrays.asList(idOrCodeArray); | ||||
|         // viewerPostViewModel.getList().setValue(createPlaceholderModels(idOrCodeArray.length)); | ||||
|         // isId = fragmentArgs.getIsId(); | ||||
|         // fetchPost(); | ||||
|     } | ||||
| 
 | ||||
|     private void setupCommonActions() { | ||||
|         setupLike(); | ||||
|         setupSave(); | ||||
|         setupDownload(); | ||||
|         setupComment(); | ||||
|     } | ||||
| 
 | ||||
|     private void setupComment() { | ||||
|         binding.comment.setOnClickListener(v -> { | ||||
|             final NavController navController = getNavController(); | ||||
|             if (navController == null) return; | ||||
|             final Bundle bundle = new Bundle(); | ||||
|             bundle.putString("shortCode", feedModel.getShortCode()); | ||||
|             bundle.putString("postId", feedModel.getPostId()); | ||||
|             bundle.putString("postUserId", feedModel.getProfileModel().getId()); | ||||
|             navController.navigate(R.id.action_global_commentsViewerFragment, bundle); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private void setupDownload() { | ||||
| @ -758,30 +778,26 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
| 
 | ||||
|     private void setupCaption() { | ||||
|         final CharSequence postCaption = feedModel.getPostCaption(); | ||||
|         binding.caption.addAutoLinkMode(MODE_HASHTAG.INSTANCE, MODE_MENTION.INSTANCE, MODE_EMAIL.INSTANCE); | ||||
|         binding.caption.onAutoLinkClick(autoLinkItem -> { | ||||
|             // Log.d(TAG, "setupCaption: autoLinkItem: " + autoLinkItem.getMode().getModeName() + " : " + autoLinkItem.getOriginalText()); | ||||
|             final String originalText = autoLinkItem.getOriginalText(); | ||||
|             if (autoLinkItem.getMode().equals(MODE_HASHTAG.INSTANCE)) { | ||||
|                 final NavController navController = NavHostFragment.findNavController(this); | ||||
|                 final Bundle bundle = new Bundle(); | ||||
|                 bundle.putString("hashtag", originalText); | ||||
|                 navController.navigate(R.id.action_global_hashTagFragment, bundle); | ||||
|                 return Unit.INSTANCE; | ||||
|             } | ||||
|             if (autoLinkItem.getMode().equals(MODE_MENTION.INSTANCE)) { | ||||
|                 navigateToProfile(originalText); | ||||
|                 return Unit.INSTANCE; | ||||
|             } | ||||
|             return Unit.INSTANCE; | ||||
|         binding.caption.addOnHashtagListener(autoLinkItem -> { | ||||
|             final NavController navController = NavHostFragment.findNavController(this); | ||||
|             final Bundle bundle = new Bundle(); | ||||
|             final String originalText = autoLinkItem.getOriginalText().trim(); | ||||
|             bundle.putString(ARG_HASHTAG, originalText); | ||||
|             navController.navigate(R.id.action_global_hashTagFragment, bundle); | ||||
|         }); | ||||
|         binding.caption.addOnMentionClickListener(autoLinkItem -> { | ||||
|             final String originalText = autoLinkItem.getOriginalText().trim(); | ||||
|             navigateToProfile(originalText); | ||||
|         }); | ||||
|         binding.caption.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(getContext(), autoLinkItem.getOriginalText().trim())); | ||||
|         binding.caption.addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim())); | ||||
|         binding.caption.setOnLongClickListener(v -> { | ||||
|             Utils.copyText(getContext(), postCaption); | ||||
|             Utils.copyText(context, postCaption); | ||||
|             return true; | ||||
|         }); | ||||
|         binding.caption.setText(postCaption); | ||||
|         bottomSheetBehavior = BottomSheetBehavior.from(binding.captionParent); | ||||
|         bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); | ||||
|         bottomSheetBehavior.setState(captionState); | ||||
|         bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { | ||||
|             @Override | ||||
|             public void onStateChanged(@NonNull final View bottomSheet, final int newState) {} | ||||
| @ -900,7 +916,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|         if (sharedMainPostElement != null) { | ||||
|             addSharedElement(sharedMainPostElement, binding.sliderParent); | ||||
|         } | ||||
|         sliderItemsAdapter = new SliderItemsAdapter(onVerticalDragListener, binding.playerControls, new SliderCallbackAdapter() { | ||||
|         sliderItemsAdapter = new SliderItemsAdapter(onVerticalDragListener, binding.playerControls, true, new SliderCallbackAdapter() { | ||||
|             @Override | ||||
|             public void onThumbnailLoaded(final int position) { | ||||
|                 if (position != 0) return; | ||||
| @ -926,6 +942,9 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|             } | ||||
|         }); | ||||
|         binding.sliderParent.setAdapter(sliderItemsAdapter); | ||||
|         if (sliderPosition >= 0 && sliderPosition < feedModel.getSliderItems().size()) { | ||||
|             binding.sliderParent.setCurrentItem(sliderPosition); | ||||
|         } | ||||
|         binding.sliderParent.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { | ||||
|             int prevPosition = -1; | ||||
| 
 | ||||
| @ -947,6 +966,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|             public void onPageSelected(final int position) { | ||||
|                 final int size = feedModel.getSliderItems().size(); | ||||
|                 if (position < 0 || position >= size) return; | ||||
|                 sliderPosition = position; | ||||
|                 final String text = (position + 1) + "/" + size; | ||||
|                 binding.mediaCounter.setText(text); | ||||
|                 final PostChild postChild = feedModel.getSliderItems().get(position); | ||||
| @ -1046,6 +1066,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { | ||||
|                 vol, | ||||
|                 aspectRatio, | ||||
|                 feedModel.getThumbnailUrl(), | ||||
|                 true, | ||||
|                 binding.playerControls, | ||||
|                 videoPlayerCallback); | ||||
|     } | ||||
|  | ||||
| @ -14,265 +14,159 @@ import android.view.ViewGroup; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.coordinatorlayout.widget.CoordinatorLayout; | ||||
| import androidx.core.content.PermissionChecker; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.lifecycle.ViewModelProvider; | ||||
| import androidx.navigation.NavController; | ||||
| import androidx.navigation.NavDirections; | ||||
| import androidx.navigation.fragment.NavHostFragment; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import androidx.recyclerview.widget.StaggeredGridLayoutManager; | ||||
| import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.activities.MainActivity; | ||||
| import awais.instagrabber.adapters.FeedAdapterV2; | ||||
| import awais.instagrabber.adapters.FeedStoriesAdapter; | ||||
| import awais.instagrabber.asyncs.FeedPostFetchService; | ||||
| import awais.instagrabber.customviews.helpers.VideoAwareRecyclerScroller; | ||||
| import awais.instagrabber.databinding.FragmentFeedBinding; | ||||
| import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; | ||||
| import awais.instagrabber.fragments.PostViewV2Fragment; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.models.FeedStoryModel; | ||||
| import awais.instagrabber.models.PostsLayoutPreferences; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.DownloadUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awais.instagrabber.viewmodels.FeedStoriesViewModel; | ||||
| import awais.instagrabber.webservices.ServiceCallback; | ||||
| import awais.instagrabber.webservices.StoriesService; | ||||
| 
 | ||||
| import static androidx.core.content.PermissionChecker.checkSelfPermission; | ||||
| import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; | ||||
| import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| 
 | ||||
| public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { | ||||
|     private static final String TAG = "FeedFragment"; | ||||
|     private static final double MAX_VIDEO_HEIGHT = 0.9 * Utils.displayMetrics.heightPixels; | ||||
|     private static final int RESIZED_VIDEO_HEIGHT = (int) (0.8 * Utils.displayMetrics.heightPixels); | ||||
|     private static final int STORAGE_PERM_REQUEST_CODE = 8020; | ||||
|     // private static final double MAX_VIDEO_HEIGHT = 0.9 * Utils.displayMetrics.heightPixels; | ||||
|     // private static final int RESIZED_VIDEO_HEIGHT = (int) (0.8 * Utils.displayMetrics.heightPixels); | ||||
| 
 | ||||
|     private MainActivity fragmentActivity; | ||||
|     private CoordinatorLayout root; | ||||
|     private FragmentFeedBinding binding; | ||||
|     private StoriesService storiesService; | ||||
|     private boolean feedHasNextPage = false; | ||||
|     private String feedEndCursor = null; | ||||
|     // private boolean feedHasNextPage = false; | ||||
|     // private String feedEndCursor = null; | ||||
|     // private FeedViewModel feedViewModel; | ||||
|     private VideoAwareRecyclerScroller videoAwareRecyclerScroller; | ||||
|     // private VideoAwareRecyclerScroller videoAwareRecyclerScroller; | ||||
|     private boolean shouldRefresh = true; | ||||
|     private boolean isPullToRefresh; | ||||
|     // private boolean isPullToRefresh; | ||||
|     private FeedStoriesViewModel feedStoriesViewModel; | ||||
|     private StaggeredGridLayoutManager gridLayoutManager; | ||||
|     // private StaggeredGridLayoutManager gridLayoutManager; | ||||
|     private boolean storiesFetching; | ||||
| 
 | ||||
|     private final boolean shouldAutoPlay = settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS); | ||||
|     // private final FetchListener<FeedModel[]> feedFetchListener = new FetchListener<FeedModel[]>() { | ||||
|     //     @Override | ||||
|     //     public void doBefore() { | ||||
|     //         binding.feedSwipeRefreshLayout.post(() -> binding.feedSwipeRefreshLayout.setRefreshing(true)); | ||||
|     //     } | ||||
|     // | ||||
|     //     @Override | ||||
|     //     public void onResult(final FeedModel[] result) { | ||||
|     //         if (result == null || result.length <= 0) { | ||||
|     //             binding.feedSwipeRefreshLayout.setRefreshing(false); | ||||
|     //             return; | ||||
|     // } | ||||
|     // final List<FeedModel> currentFeedModelList = feedViewModel.getList().getValue(); | ||||
|     // final Map<String, FeedModel> thumbToFeedMap = new HashMap<>(); | ||||
|     // for (final FeedModel feedModel : result) { | ||||
|     //     thumbToFeedMap.put(feedModel.getThumbnailUrl(), feedModel); | ||||
|     // } | ||||
|     // final BaseDataSubscriber<Void> subscriber = new BaseDataSubscriber<Void>() { | ||||
|     //     int success = 0; | ||||
|     //     int failed = 0; | ||||
|     // | ||||
|     //     @Override | ||||
|     //     protected void onNewResultImpl(@NonNull final DataSource<Void> dataSource) { | ||||
|     //         final Map<String, Object> extras = dataSource.getExtras(); | ||||
|     //         if (extras == null) return; | ||||
|     //         final Uri thumbUri = (Uri) extras.get("uri_source"); | ||||
|     //         if (thumbUri == null) return; | ||||
|     //         final Integer encodedWidth = (Integer) extras.get("encoded_width"); | ||||
|     //         final Integer encodedHeight = (Integer) extras.get("encoded_height"); | ||||
|     //         if (encodedWidth == null || encodedHeight == null) return; | ||||
|     //         final FeedModel feedModel = thumbToFeedMap.get(thumbUri.toString()); | ||||
|     //         if (feedModel == null) return; | ||||
|     //         int requiredWidth = Utils.displayMetrics.widthPixels; | ||||
|     //         int resultingHeight = NumberUtils | ||||
|     //                 .getResultingHeight(requiredWidth, encodedHeight, encodedWidth); | ||||
|     //         if (feedModel | ||||
|     //                 .getItemType() == MediaItemType.MEDIA_TYPE_VIDEO && resultingHeight >= MAX_VIDEO_HEIGHT) { | ||||
|     //             // If its a video and the height is too large, need to reduce the height, | ||||
|     //             // so that entire video fits on screen | ||||
|     //             resultingHeight = RESIZED_VIDEO_HEIGHT; | ||||
|     //             requiredWidth = NumberUtils.getResultingWidth(RESIZED_VIDEO_HEIGHT, | ||||
|     //                                                           resultingHeight, | ||||
|     //                                                           requiredWidth); | ||||
|     //         } | ||||
|     //         feedModel.setImageWidth(requiredWidth); | ||||
|     //         feedModel.setImageHeight(resultingHeight); | ||||
|     //         success++; | ||||
|     //         updateAdapter(); | ||||
|     //     } | ||||
|     // | ||||
|     //     @Override | ||||
|     //     protected void onFailureImpl(@NonNull final DataSource<Void> dataSource) { | ||||
|     //         failed++; | ||||
|     //         updateAdapter(); | ||||
|     //     } | ||||
|     // | ||||
|     //     public void updateAdapter() { | ||||
|     //         if (failed + success != result.length) return; | ||||
|     // | ||||
|     //     } | ||||
|     // }; | ||||
|     // for (final FeedModel feedModel : result) { | ||||
|     //     final DataSource<Void> ds = Fresco.getImagePipeline() | ||||
|     //                                       .prefetchToBitmapCache(ImageRequest.fromUri(feedModel.getThumbnailUrl()), null); | ||||
|     //     ds.subscribe(subscriber, UiThreadImmediateExecutorService.getInstance()); | ||||
|     // } | ||||
|     // List<FeedModel> finalList = currentFeedModelList == null || currentFeedModelList.isEmpty() | ||||
|     //                             ? new ArrayList<>() | ||||
|     //                             : new ArrayList<>(currentFeedModelList); | ||||
|     // final List<FeedModel> resultList = Arrays.asList(result); | ||||
|     // if (isPullToRefresh) { | ||||
|     //     finalList = resultList; | ||||
|     //     isPullToRefresh = false; | ||||
|     // } else { | ||||
|     //     finalList.addAll(resultList); | ||||
|     // } | ||||
|     // // feedViewModel.getList().postValue(finalList); | ||||
|     // final PostModel feedPostModel = result[result.length - 1]; | ||||
|     // if (feedPostModel != null) { | ||||
|     //     feedEndCursor = feedPostModel.getEndCursor(); | ||||
|     //     feedHasNextPage = feedPostModel.hasNextPage(); | ||||
|     //     feedPostModel.setPageCursor(false, null); | ||||
|     // } | ||||
|     // binding.feedSwipeRefreshLayout.setRefreshing(false); | ||||
|     // } | ||||
|     // }; | ||||
|     private final MentionClickListener mentionClickListener = (view, text, isHashtag, isLocation) -> { | ||||
|         if (isHashtag) { | ||||
|             final NavDirections action = FeedFragmentDirections.actionGlobalHashTagFragment(text); | ||||
|             NavHostFragment.findNavController(this).navigate(action); | ||||
|             return; | ||||
|     // private final boolean shouldAutoPlay = settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS); | ||||
|     private final FeedAdapterV2.FeedItemCallback feedItemCallback = new FeedAdapterV2.FeedItemCallback() { | ||||
|         @Override | ||||
|         public void onPostClick(final FeedModel feedModel, final View profilePicView, final View mainPostImage) { | ||||
|             openPostDialog(feedModel, profilePicView, mainPostImage, -1); | ||||
|         } | ||||
|         if (isLocation) { | ||||
|             final NavDirections action = FeedFragmentDirections.actionGlobalLocationFragment(text); | ||||
|             NavHostFragment.findNavController(this).navigate(action); | ||||
|             return; | ||||
| 
 | ||||
|         @Override | ||||
|         public void onSliderClick(final FeedModel feedModel, final int position) { | ||||
|             openPostDialog(feedModel, null, null, position); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onCommentsClick(final FeedModel feedModel) { | ||||
|             final NavDirections commentsAction = FeedFragmentDirections.actionGlobalCommentsViewerFragment( | ||||
|                     feedModel.getShortCode(), | ||||
|                     feedModel.getPostId(), | ||||
|                     feedModel.getProfileModel().getId() | ||||
|             ); | ||||
|             NavHostFragment.findNavController(FeedFragment.this).navigate(commentsAction); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onDownloadClick(final FeedModel feedModel) { | ||||
|             final Context context = getContext(); | ||||
|             if (context == null) return; | ||||
|             if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { | ||||
|                 showDownloadDialog(feedModel); | ||||
|                 return; | ||||
|             } | ||||
|             requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onHashtagClick(final String hashtag) { | ||||
|             final NavDirections action = FeedFragmentDirections.actionGlobalHashTagFragment(hashtag); | ||||
|             NavHostFragment.findNavController(FeedFragment.this).navigate(action); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onLocationClick(final FeedModel feedModel) { | ||||
|             final NavDirections action = FeedFragmentDirections.actionGlobalLocationFragment(feedModel.getLocationId()); | ||||
|             NavHostFragment.findNavController(FeedFragment.this).navigate(action); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onMentionClick(final String mention) { | ||||
|             navigateToProfile(mention.trim()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onNameClick(final FeedModel feedModel, final View profilePicView) { | ||||
|             navigateToProfile("@" + feedModel.getProfileModel().getUsername()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onProfilePicClick(final FeedModel feedModel, final View profilePicView) { | ||||
|             navigateToProfile("@" + feedModel.getProfileModel().getUsername()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onURLClick(final String url) { | ||||
|             Utils.openURL(getContext(), url); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onEmailClick(final String emailId) { | ||||
|             Utils.openEmailAddress(getContext(), emailId); | ||||
|         } | ||||
| 
 | ||||
|         private void openPostDialog(final FeedModel feedModel, | ||||
|                                     final View profilePicView, | ||||
|                                     final View mainPostImage, | ||||
|                                     final int position) { | ||||
|             final PostViewV2Fragment.Builder builder = PostViewV2Fragment | ||||
|                     .builder(feedModel); | ||||
|             if (position >= 0) { | ||||
|                 builder.setPosition(position); | ||||
|             } | ||||
|             final PostViewV2Fragment fragment = builder | ||||
|                     .setSharedProfilePicElement(profilePicView) | ||||
|                     .setSharedMainPostElement(mainPostImage) | ||||
|                     .build(); | ||||
|             fragment.show(getChildFragmentManager(), "post_view"); | ||||
|         } | ||||
|         final NavDirections action = FeedFragmentDirections.actionGlobalProfileFragment("@" + text); | ||||
|         NavHostFragment.findNavController(this).navigate(action); | ||||
|     }; | ||||
|     private final View.OnClickListener postViewClickListener = v -> { | ||||
|         // gridLayoutManager.setSpanCount(1); | ||||
|         // final Object tag = v.getTag(); | ||||
|         // if (!(tag instanceof FeedModel)) return; | ||||
|         // | ||||
|         // final FeedModel feedModel = (FeedModel) tag; | ||||
|         // if (v instanceof RamboTextView) { | ||||
|         //     if (feedModel.isMentionClicked()) feedModel.toggleCaption(); | ||||
|         //     feedModel.setMentionClicked(false); | ||||
|         //     if (!FeedItemViewHolder.expandCollapseTextView((RamboTextView) v, feedModel.getPostCaption())) | ||||
|         //         feedModel.toggleCaption(); | ||||
|         //     return; | ||||
|         // } | ||||
|         // | ||||
|         // final int id = v.getId(); | ||||
|         // switch (id) { | ||||
|         //     case R.id.btnComments: | ||||
|         //         final NavDirections commentsAction = FeedFragmentDirections.actionGlobalCommentsViewerFragment( | ||||
|         //                 feedModel.getShortCode(), | ||||
|         //                 feedModel.getPostId(), | ||||
|         //                 feedModel.getProfileModel().getId() | ||||
|         //         ); | ||||
|         //         NavHostFragment.findNavController(this).navigate(commentsAction); | ||||
|         //         break; | ||||
|         //     // case R.id.viewStoryPost: | ||||
|         //     //     final List<FeedModel> feedModels = feedViewModel.getList().getValue(); | ||||
|         //     //     if (feedModels == null || feedModels.size() == 0) return; | ||||
|         //     //     if (feedModels.get(0) == null) return; | ||||
|         //     //     final String postId = feedModels.get(0).getPostId(); | ||||
|         //     //     final boolean isId = postId != null; | ||||
|         //     //     final String[] idsOrShortCodes = new String[feedModels.size()]; | ||||
|         //     //     for (int i = 0; i < feedModels.size(); i++) { | ||||
|         //     //         idsOrShortCodes[i] = isId ? feedModels.get(i).getPostId() | ||||
|         //     //                                   : feedModels.get(i).getShortCode(); | ||||
|         //     //     } | ||||
|         //     //     final NavDirections action = FeedFragmentDirections.actionGlobalPostViewFragment( | ||||
|         //     //             feedModel.getPosition(), | ||||
|         //     //             idsOrShortCodes, | ||||
|         //     //             isId); | ||||
|         //     //     NavHostFragment.findNavController(this).navigate(action); | ||||
|         //     //     break; | ||||
|         //     case R.id.btnDownload: | ||||
|         //         ProfileModel profileModel = feedModel.getProfileModel(); | ||||
|         //         final String username = profileModel != null ? profileModel.getUsername() : null; | ||||
|         // | ||||
|         //         final ViewerPostModel[] sliderItems = feedModel.getSliderItems(); | ||||
|         // | ||||
|         //         final Context context = getContext(); | ||||
|         //         if (context == null) return; | ||||
|         //         if (feedModel | ||||
|         //                 .getItemType() != MediaItemType.MEDIA_TYPE_SLIDER || sliderItems == null || sliderItems.length == 1) | ||||
|         //             DownloadUtils.batchDownload(context, | ||||
|         //                                         username, | ||||
|         //                                         DownloadMethod.DOWNLOAD_FEED, | ||||
|         //                                         Collections.singletonList(feedModel)); | ||||
|         //         else { | ||||
|         //             final ArrayList<BasePostModel> postModels = new ArrayList<>(); | ||||
|         //             final DialogInterface.OnClickListener clickListener1 = (dialog, which) -> { | ||||
|         //                 postModels.clear(); | ||||
|         // | ||||
|         //                 final boolean breakWhenFoundSelected = which == DialogInterface.BUTTON_POSITIVE; | ||||
|         // | ||||
|         //                 for (final ViewerPostModel sliderItem : sliderItems) { | ||||
|         //                     if (sliderItem != null) { | ||||
|         //                         if (!breakWhenFoundSelected) postModels.add(sliderItem); | ||||
|         //                         else if (sliderItem.isSelected()) { | ||||
|         //                             postModels.add(sliderItem); | ||||
|         //                             break; | ||||
|         //                         } | ||||
|         //                     } | ||||
|         //                 } | ||||
|         // | ||||
|         //                 // shows 0 items on first item of viewpager cause onPageSelected hasn't been called yet | ||||
|         //                 if (breakWhenFoundSelected && postModels.size() == 0) { | ||||
|         //                     postModels.add(sliderItems[0]); | ||||
|         //                 } | ||||
|         //                 if (postModels.size() > 0) { | ||||
|         //                     DownloadUtils.batchDownload(context, | ||||
|         //                                                 username, | ||||
|         //                                                 DownloadMethod.DOWNLOAD_FEED, | ||||
|         //                                                 postModels); | ||||
|         //                 } | ||||
|         //             }; | ||||
|         // | ||||
|         //             new AlertDialog.Builder(context) | ||||
|         //                     .setTitle(R.string.post_viewer_download_dialog_title) | ||||
|         //                     .setPositiveButton(R.string.post_viewer_download_current, clickListener1) | ||||
|         //                     .setNegativeButton(R.string.post_viewer_download_album, clickListener1) | ||||
|         //                     .show(); | ||||
|         //         } | ||||
|         //         break; | ||||
|         // | ||||
|         //     case R.id.ivProfilePic: | ||||
|         //         profileModel = feedModel.getProfileModel(); | ||||
|         //         if (profileModel != null) mentionClickListener.onClick(null, profileModel.getUsername(), false, false); | ||||
|         //         break; | ||||
|         //     default: | ||||
|         //         break; | ||||
|         // } | ||||
|     }; | ||||
| 
 | ||||
|     private void navigateToProfile(final String username) { | ||||
|         final NavController navController = NavHostFragment.findNavController(this); | ||||
|         final Bundle bundle = new Bundle(); | ||||
|         bundle.putString("username", username); | ||||
|         navController.navigate(R.id.action_global_profileFragment, bundle); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreate(@Nullable final Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         fragmentActivity = (MainActivity) requireActivity(); | ||||
|         storiesService = StoriesService.getInstance(); | ||||
|         // feedService = FeedService.getInstance(); | ||||
|         // final TransitionInflater inflater = TransitionInflater.from(getContext()); | ||||
|         // setExitTransition(inflater.inflateTransition(android.R.transition.move)); | ||||
|         setHasOptionsMenu(true); | ||||
|     } | ||||
| 
 | ||||
| @ -316,74 +210,44 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre | ||||
|     @Override | ||||
|     public void onPause() { | ||||
|         super.onPause(); | ||||
|         if (videoAwareRecyclerScroller != null) { | ||||
|             videoAwareRecyclerScroller.stopPlaying(); | ||||
|         } | ||||
|         // if (videoAwareRecyclerScroller != null) { | ||||
|         //     videoAwareRecyclerScroller.stopPlaying(); | ||||
|         // } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onResume() { | ||||
|         super.onResume(); | ||||
|         binding.feedSwipeRefreshLayout.setRefreshing(false); | ||||
|         if (videoAwareRecyclerScroller != null && shouldAutoPlay) { | ||||
|             videoAwareRecyclerScroller.startPlaying(); | ||||
|         } | ||||
|         // if (videoAwareRecyclerScroller != null && shouldAutoPlay) { | ||||
|         //     videoAwareRecyclerScroller.startPlaying(); | ||||
|         // } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRefresh() { | ||||
|         isPullToRefresh = true; | ||||
|         feedEndCursor = null; | ||||
|         // isPullToRefresh = true; | ||||
|         // feedEndCursor = null; | ||||
|         binding.feedRecyclerView.refresh(); | ||||
|         fetchStories(); | ||||
|     } | ||||
| 
 | ||||
|     private void setupFeed() { | ||||
|         // feedViewModel = new ViewModelProvider(fragmentActivity).get(FeedViewModel.class); | ||||
|         final Context context = getContext(); | ||||
|         if (context == null) return; | ||||
|         // final PostFetcher.PostFetchService feedPostsFetchService = new PostFetcher.PostFetchService() { | ||||
|         //     @Override | ||||
|         //     public void fetch(final int page, final FetchListener<List<FeedModel>> fetchListener) { | ||||
|         //         new FeedFetcher(feedEndCursor, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|         //     } | ||||
|         // }; | ||||
|         binding.feedRecyclerView.setViewModelStoreOwner(this) | ||||
|                                 .setLifeCycleOwner(this) | ||||
|                                 .setPostFetchService(new FeedPostFetchService()) | ||||
|                                 .setLayoutPreferences(PostsLayoutPreferences.fromJson(settingsHelper.getString(Constants.PREF_POSTS_LAYOUT))) | ||||
|                                 .addFetchStatusChangeListener(fetching -> updateSwipeRefreshState()) | ||||
|                                 .setOnPostClickListener((feedModel, profilePicView, mainPostImage) -> { | ||||
|                                     final PostViewV2Fragment fragment = PostViewV2Fragment | ||||
|                                             .builder(feedModel) | ||||
|                                             .setSharedProfilePicElement(profilePicView) | ||||
|                                             .setSharedMainPostElement(mainPostImage) | ||||
|                                             .build(); | ||||
|                                     fragment.show(getChildFragmentManager(), "post_view"); | ||||
|                                 }) | ||||
|                                 .setFeedItemCallback(feedItemCallback) | ||||
|                                 .init(); | ||||
|         binding.feedSwipeRefreshLayout.setRefreshing(true); | ||||
|         // final LinearLayoutManager layoutManager = new LinearLayoutManager(context); | ||||
|         // binding.feedRecyclerView.setLayoutManager(gridLayoutManager); | ||||
|         // feedAdapter = new FeedAdapterV2(spanCount[0], postViewClickListener, mentionClickListener, feedModel -> { | ||||
|         //     final ChangeBounds transition = new ChangeBounds(); | ||||
|         //     transition.setDuration(200); | ||||
|         //     TransitionManager.beginDelayedTransition(binding.feedRecyclerView, transition); | ||||
|         //     spanCount[0] = spanCount[0] - 1; | ||||
|         //     if (spanCount[0] == 0) { | ||||
|         //         spanCount[0] = 3; | ||||
|         //     } | ||||
|         //     gridLayoutManager.setSpanCount(spanCount[0]); | ||||
|         // }); | ||||
|         // feedAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY); | ||||
|         // binding.feedRecyclerView.setAdapter(feedAdapter); | ||||
|         // feedViewModel.getList().observe(fragmentActivity, feedAdapter::submitList); | ||||
|         // if (shouldAutoPlay) { | ||||
|         //     videoAwareRecyclerScroller = new VideoAwareRecyclerScroller(); | ||||
|         //     binding.feedRecyclerView.addOnScrollListener(videoAwareRecyclerScroller); | ||||
|         // } | ||||
|         // fetchFeed(); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private void updateSwipeRefreshState() { | ||||
| @ -424,6 +288,48 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private void showDownloadDialog(final FeedModel feedModel) { | ||||
|         final Context context = getContext(); | ||||
|         if (context == null) return; | ||||
|         DownloadUtils.download(context, feedModel); | ||||
|         // switch (feedModel.getItemType()) { | ||||
|         //     case MEDIA_TYPE_IMAGE: | ||||
|         //     case MEDIA_TYPE_VIDEO: | ||||
|         //         break; | ||||
|         //     case MEDIA_TYPE_SLIDER: | ||||
|         //         break; | ||||
|         // } | ||||
|         // final List<ViewerPostModel> postModelsToDownload = new ArrayList<>(); | ||||
|         // // if (!session) { | ||||
|         // final DialogInterface.OnClickListener clickListener = (dialog, which) -> { | ||||
|         //     if (which == DialogInterface.BUTTON_NEGATIVE) { | ||||
|         //         postModelsToDownload.addAll(postModels); | ||||
|         //     } else if (which == DialogInterface.BUTTON_POSITIVE) { | ||||
|         //         postModelsToDownload.add(postModels.get(childPosition)); | ||||
|         //     } else { | ||||
|         //         session = true; | ||||
|         //         postModelsToDownload.add(postModels.get(childPosition)); | ||||
|         //     } | ||||
|         //     if (postModelsToDownload.size() > 0) { | ||||
|         //         DownloadUtils.batchDownload(context, | ||||
|         //                                     username, | ||||
|         //                                     DownloadMethod.DOWNLOAD_POST_VIEWER, | ||||
|         //                                     postModelsToDownload); | ||||
|         //     } | ||||
|         // }; | ||||
|         // new AlertDialog.Builder(context) | ||||
|         //         .setTitle(R.string.post_viewer_download_dialog_title) | ||||
|         //         .setMessage(R.string.post_viewer_download_message) | ||||
|         //         .setNeutralButton(R.string.post_viewer_download_session, clickListener) | ||||
|         //         .setPositiveButton(R.string.post_viewer_download_current, clickListener) | ||||
|         //         .setNegativeButton(R.string.post_viewer_download_album, clickListener).show(); | ||||
|         // } else { | ||||
|         //     DownloadUtils.batchDownload(context, | ||||
|         //                                 username, | ||||
|         //                                 DownloadMethod.DOWNLOAD_POST_VIEWER, | ||||
|         //                                 Collections.singletonList(postModels.get(childPosition))); | ||||
|     } | ||||
| 
 | ||||
|     private void showPostsLayoutPreferences() { | ||||
|         final PostsLayoutPreferencesDialogFragment fragment = new PostsLayoutPreferencesDialogFragment(preferences -> new Handler() | ||||
|                 .postDelayed(() -> binding.feedRecyclerView.setLayoutPreferences(preferences), 200)); | ||||
|  | ||||
| @ -420,7 +420,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe | ||||
| 
 | ||||
|     private void fetchProfileDetails() { | ||||
|         if (TextUtils.isEmpty(username)) return; | ||||
|         new ProfileFetcher(username.substring(1), profileModel -> { | ||||
|         new ProfileFetcher(username.trim().substring(1), profileModel -> { | ||||
|             if (getContext() == null) return; | ||||
|             this.profileModel = profileModel; | ||||
|             // final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); | ||||
|  | ||||
| @ -3,23 +3,29 @@ package awais.instagrabber.models; | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public final class CommentModel { | ||||
| public class CommentModel { | ||||
|     private final ProfileModel profileModel; | ||||
|     private final String id; | ||||
|     private final CharSequence text; | ||||
|     private final long likes, timestamp; | ||||
|     private CommentModel[] childCommentModels; | ||||
|     private boolean hasNextPage, liked; | ||||
|     private final String text; | ||||
|     private final long likes; | ||||
|     private final long timestamp; | ||||
|     private List<CommentModel> childCommentModels; | ||||
|     private final boolean liked; | ||||
|     private boolean hasNextPage; | ||||
|     private String endCursor; | ||||
| 
 | ||||
|     public CommentModel(final String id, final String text, final long timestamp, final long likes, final boolean liked, | ||||
|     public CommentModel(final String id, | ||||
|                         final String text, | ||||
|                         final long timestamp, | ||||
|                         final long likes, | ||||
|                         final boolean liked, | ||||
|                         final ProfileModel profileModel) { | ||||
|         this.id = id; | ||||
|         this.text = TextUtils.hasMentions(text) ? TextUtils.getMentionText(text) : text; | ||||
|         this.text = text; | ||||
|         this.likes = likes; | ||||
|         this.liked = liked; | ||||
|         this.timestamp = timestamp; | ||||
| @ -30,7 +36,7 @@ public final class CommentModel { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public CharSequence getText() { | ||||
|     public String getText() { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
| @ -51,11 +57,11 @@ public final class CommentModel { | ||||
|         return profileModel; | ||||
|     } | ||||
| 
 | ||||
|     public CommentModel[] getChildCommentModels() { | ||||
|     public List<CommentModel> getChildCommentModels() { | ||||
|         return childCommentModels; | ||||
|     } | ||||
| 
 | ||||
|     public void setChildCommentModels(final CommentModel[] childCommentModels) { | ||||
|     public void setChildCommentModels(final List<CommentModel> childCommentModels) { | ||||
|         this.childCommentModels = childCommentModels; | ||||
|     } | ||||
| 
 | ||||
| @ -72,21 +78,21 @@ public final class CommentModel { | ||||
|         return endCursor; | ||||
|     } | ||||
| 
 | ||||
| //    @NonNull | ||||
| //    @Override | ||||
| //    public String toString() { | ||||
| //        try { | ||||
| //            final JSONObject object = new JSONObject(); | ||||
| //            object.put(Constants.EXTRAS_ID, id); | ||||
| //            object.put("text", text); | ||||
| //            object.put(Constants.EXTRAS_NAME, profileModel != null ? profileModel.getUsername() : ""); | ||||
| //            if (childCommentModels != null) object.put("childComments", childCommentModels); | ||||
| //            return object.toString(); | ||||
| //        } catch (Exception e) { | ||||
| //            return "{\"id\":\"" + id + "\", \"text\":\"" + text | ||||
| //                     //(text != null ? text.replaceAll("\"", "\\\\\"") : "") | ||||
| //                    + "\", \"name\":\"" + (profileModel != null ? profileModel.getUsername() : "") + | ||||
| //                    (childCommentModels != null ? "\", \"childComments\":" + childCommentModels.length : "\"") + '}'; | ||||
| //        } | ||||
| //    } | ||||
|     //    @NonNull | ||||
|     //    @Override | ||||
|     //    public String toString() { | ||||
|     //        try { | ||||
|     //            final JSONObject object = new JSONObject(); | ||||
|     //            object.put(Constants.EXTRAS_ID, id); | ||||
|     //            object.put("text", text); | ||||
|     //            object.put(Constants.EXTRAS_NAME, profileModel != null ? profileModel.getUsername() : ""); | ||||
|     //            if (childCommentModels != null) object.put("childComments", childCommentModels); | ||||
|     //            return object.toString(); | ||||
|     //        } catch (Exception e) { | ||||
|     //            return "{\"id\":\"" + id + "\", \"text\":\"" + text | ||||
|     //                     //(text != null ? text.replaceAll("\"", "\\\\\"") : "") | ||||
|     //                    + "\", \"name\":\"" + (profileModel != null ? profileModel.getUsername() : "") + | ||||
|     //                    (childCommentModels != null ? "\", \"childComments\":" + childCommentModels.length : "\"") + '}'; | ||||
|     //        } | ||||
|     //    } | ||||
| } | ||||
| @ -5,6 +5,7 @@ import android.content.ClipData; | ||||
| import android.content.ClipboardManager; | ||||
| import android.content.ContentResolver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.res.Resources; | ||||
| import android.net.Uri; | ||||
| import android.util.DisplayMetrics; | ||||
| @ -158,4 +159,23 @@ public final class Utils { | ||||
|         } | ||||
|         return statusBarHeight; | ||||
|     } | ||||
| 
 | ||||
|     public static void openURL(final Context context, final String url) { | ||||
|         if (context == null || TextUtils.isEmpty(url)) { | ||||
|             return; | ||||
|         } | ||||
|         final Intent i = new Intent(Intent.ACTION_VIEW); | ||||
|         i.setData(Uri.parse(url)); | ||||
|         context.startActivity(i); | ||||
|     } | ||||
| 
 | ||||
|     public static void openEmailAddress(final Context context, final String emailAddress) { | ||||
|         if (context == null || TextUtils.isEmpty(emailAddress)) { | ||||
|             return; | ||||
|         } | ||||
|         Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + emailAddress)); | ||||
|         emailIntent.putExtra(Intent.EXTRA_SUBJECT, ""); | ||||
|         emailIntent.putExtra(Intent.EXTRA_TEXT, ""); | ||||
|         context.startActivity(emailIntent); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,19 @@ | ||||
| package awais.instagrabber.viewmodels; | ||||
| 
 | ||||
| import androidx.lifecycle.MutableLiveData; | ||||
| import androidx.lifecycle.ViewModel; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import awais.instagrabber.models.CommentModel; | ||||
| 
 | ||||
| public class CommentsViewModel extends ViewModel { | ||||
|     private MutableLiveData<List<CommentModel>> list; | ||||
| 
 | ||||
|     public MutableLiveData<List<CommentModel>> getList() { | ||||
|         if (list == null) { | ||||
|             list = new MutableLiveData<>(); | ||||
|         } | ||||
|         return list; | ||||
|     } | ||||
| } | ||||
| @ -134,34 +134,34 @@ public class DownloadWorker extends Worker { | ||||
|                 boolean deletedIPTC = false; | ||||
|                 while ((count = bis.read(buffer, 0, 0x2000)) != -1) { | ||||
|                     totalRead = totalRead + count; | ||||
|                     if (!deletedIPTC) { | ||||
|                         int iptcStart = -1; | ||||
|                         int fbmdStart = -1; | ||||
|                         int fbmdBytesLen = -1; | ||||
|                         for (int i = 0; i < buffer.length; ++i) { | ||||
|                             if (buffer[i] == (byte) 0xFF && buffer[i + 1] == (byte) 0xED) | ||||
|                                 iptcStart = i; | ||||
|                             else if (buffer[i] == (byte) 'F' && buffer[i + 1] == (byte) 'B' | ||||
|                                     && buffer[i + 2] == (byte) 'M' && buffer[i + 3] == (byte) 'D') { | ||||
|                                 fbmdStart = i; | ||||
|                                 fbmdBytesLen = buffer[i - 10] << 24 | (buffer[i - 9] & 0xFF) << 16 | | ||||
|                                         (buffer[i - 8] & 0xFF) << 8 | (buffer[i - 7] & 0xFF) | | ||||
|                                         (buffer[i - 6] & 0xFF); | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                         if (iptcStart != -1 && fbmdStart != -1 && fbmdBytesLen != -1) { | ||||
|                             final int fbmdDataLen = (iptcStart + (fbmdStart - iptcStart) + (fbmdBytesLen - iptcStart)) - 4; | ||||
|                             fos.write(buffer, 0, iptcStart); | ||||
|                             fos.write(buffer, fbmdDataLen + iptcStart, count - fbmdDataLen - iptcStart); | ||||
|                             // setProgressAsync(new Data.Builder().putString(URL, url) | ||||
|                             //                                    .putFloat(PROGRESS, totalRead * 100f / fileSize) | ||||
|                             //                                    .build()); | ||||
|                             updateDownloadProgress(notificationId, position, total, totalRead * 100f / fileSize); | ||||
|                             deletedIPTC = true; | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
|                     // if (!deletedIPTC) { | ||||
|                     //     int iptcStart = -1; | ||||
|                     //     int fbmdStart = -1; | ||||
|                     //     int fbmdBytesLen = -1; | ||||
|                     //     for (int i = 0; i < buffer.length; ++i) { | ||||
|                     //         if (buffer[i] == (byte) 0xFF && buffer[i + 1] == (byte) 0xED) | ||||
|                     //             iptcStart = i; | ||||
|                     //         else if (buffer[i] == (byte) 'F' && buffer[i + 1] == (byte) 'B' | ||||
|                     //                 && buffer[i + 2] == (byte) 'M' && buffer[i + 3] == (byte) 'D') { | ||||
|                     //             fbmdStart = i; | ||||
|                     //             fbmdBytesLen = buffer[i - 10] << 24 | (buffer[i - 9] & 0xFF) << 16 | | ||||
|                     //                     (buffer[i - 8] & 0xFF) << 8 | (buffer[i - 7] & 0xFF) | | ||||
|                     //                     (buffer[i - 6] & 0xFF); | ||||
|                     //             break; | ||||
|                     //         } | ||||
|                     //     } | ||||
|                     //     if (iptcStart != -1 && fbmdStart != -1 && fbmdBytesLen != -1) { | ||||
|                     //         final int fbmdDataLen = (iptcStart + (fbmdStart - iptcStart) + (fbmdBytesLen - iptcStart)) - 4; | ||||
|                     //         fos.write(buffer, 0, iptcStart); | ||||
|                     //         fos.write(buffer, fbmdDataLen + iptcStart, count - fbmdDataLen - iptcStart); | ||||
|                     //         // setProgressAsync(new Data.Builder().putString(URL, url) | ||||
|                     //         //                                    .putFloat(PROGRESS, totalRead * 100f / fileSize) | ||||
|                     //         //                                    .build()); | ||||
|                     //         updateDownloadProgress(notificationId, position, total, totalRead * 100f / fileSize); | ||||
|                     //         deletedIPTC = true; | ||||
|                     //         continue; | ||||
|                     //     } | ||||
|                     // } | ||||
|                     fos.write(buffer, 0, count); | ||||
|                     // setProgressAsync(new Data.Builder().putString(URL, url) | ||||
|                     //                                    .putFloat(PROGRESS, totalRead * 100f / fileSize) | ||||
|  | ||||
| @ -132,7 +132,7 @@ | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:background="@null"> | ||||
| 
 | ||||
|                 <io.github.armcha.autolink.AutoLinkTextView | ||||
|                 <awais.instagrabber.customviews.RamboTextViewV2 | ||||
|                     android:id="@+id/caption" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
| @ -253,12 +253,32 @@ | ||||
|         app:iconSize="16dp" | ||||
|         app:iconTint="@color/white" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toStartOf="@id/player_controls_toggle" | ||||
|         app:layout_constraintEnd_toStartOf="@id/comment" | ||||
|         app:layout_constraintStart_toEndOf="@id/caption_toggle" | ||||
|         app:layout_constraintTop_toTopOf="@id/caption_toggle" | ||||
|         app:rippleColor="@color/grey_300" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <com.google.android.material.button.MaterialButton | ||||
|         android:id="@+id/comment" | ||||
|         style="@style/Widget.MaterialComponents.Button.TextButton" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="@string/comment" | ||||
|         android:textAppearance="@style/TextAppearance.MaterialComponents.Caption" | ||||
|         android:textColor="@color/white" | ||||
|         android:visibility="visible" | ||||
|         app:icon="@drawable/ic_outline_comments_24" | ||||
|         app:iconGravity="top" | ||||
|         app:iconSize="16dp" | ||||
|         app:iconTint="@color/white" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toStartOf="@id/player_controls_toggle" | ||||
|         app:layout_constraintStart_toEndOf="@id/like" | ||||
|         app:layout_constraintTop_toTopOf="@id/caption_toggle" | ||||
|         app:rippleColor="@color/grey_300" | ||||
|         tools:visibility="visible" /> | ||||
| 
 | ||||
|     <com.google.android.material.button.MaterialButton | ||||
|         android:id="@+id/player_controls_toggle" | ||||
|         style="@style/Widget.MaterialComponents.Button.TextButton" | ||||
| @ -274,7 +294,7 @@ | ||||
|         app:iconTint="@color/white" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toStartOf="@id/save" | ||||
|         app:layout_constraintStart_toEndOf="@id/like" | ||||
|         app:layout_constraintStart_toEndOf="@id/comment" | ||||
|         app:layout_constraintTop_toTopOf="@id/caption_toggle" | ||||
|         app:rippleColor="@color/grey_300" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| <androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
| @ -17,13 +17,11 @@ | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:clipToPadding="false" | ||||
|             app:layoutManager="LinearLayoutManager" | ||||
|             tools:listitem="@layout/item_comment" /> | ||||
|     </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | ||||
| 
 | ||||
|     <com.google.android.material.textfield.TextInputLayout | ||||
|         android:id="@+id/commentField" | ||||
|         style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_margin="4dp" | ||||
| @ -45,4 +43,4 @@ | ||||
|             android:scrollHorizontally="false" /> | ||||
| 
 | ||||
|     </com.google.android.material.textfield.TextInputLayout> | ||||
| </LinearLayout> | ||||
| </androidx.appcompat.widget.LinearLayoutCompat> | ||||
| @ -38,9 +38,9 @@ | ||||
|             tools:listitem="@layout/item_feed_photo" /> | ||||
|     </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | ||||
| 
 | ||||
|     <androidx.fragment.app.FragmentContainerView | ||||
|         android:id="@+id/frag_container" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         app:layout_behavior="@string/appbar_scrolling_view_behavior" /> | ||||
|     <!--<androidx.fragment.app.FragmentContainerView--> | ||||
|     <!--    android:id="@+id/frag_container"--> | ||||
|     <!--    android:layout_width="match_parent"--> | ||||
|     <!--    android:layout_height="match_parent"--> | ||||
|     <!--    app:layout_behavior="@string/appbar_scrolling_view_behavior" />--> | ||||
| </awais.instagrabber.customviews.helpers.NestedCoordinatorLayout> | ||||
| @ -1,118 +1,117 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:id="@+id/container" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:orientation="vertical" | ||||
|     tools:viewBindingIgnore="true"> | ||||
|     android:background="?android:selectableItemBackground" | ||||
|     android:clickable="true" | ||||
|     android:focusable="true" | ||||
|     android:orientation="horizontal" | ||||
|     android:padding="8dp"> | ||||
| 
 | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:id="@+id/container" | ||||
|         android:layout_width="match_parent" | ||||
|     <com.facebook.drawee.view.SimpleDraweeView | ||||
|         android:id="@+id/ivProfilePic" | ||||
|         android:layout_width="@dimen/simple_item_picture_size" | ||||
|         android:layout_height="@dimen/simple_item_picture_size" | ||||
|         android:padding="4dp" | ||||
|         app:actualImageScaleType="centerCrop" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         app:roundAsCircle="true" | ||||
|         tools:background="@mipmap/ic_launcher" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/tvUsername" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:background="?android:selectableItemBackground" | ||||
|         android:orientation="horizontal"> | ||||
|         android:ellipsize="marquee" | ||||
|         android:paddingStart="4dp" | ||||
|         android:paddingTop="2dp" | ||||
|         android:paddingEnd="4dp" | ||||
|         android:paddingBottom="2dp" | ||||
|         android:singleLine="true" | ||||
|         android:textAppearance="@style/TextAppearance.AppCompat.Medium" | ||||
|         android:textColor="?android:textColorPrimary" | ||||
|         android:textStyle="bold" | ||||
|         app:layout_constraintBottom_toTopOf="@id/tvComment" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@id/ivProfilePic" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         tools:text="username" /> | ||||
| 
 | ||||
|         <com.facebook.drawee.view.SimpleDraweeView | ||||
|             android:id="@+id/ivProfilePic" | ||||
|             android:layout_width="@dimen/simple_item_picture_size" | ||||
|             android:layout_height="@dimen/simple_item_picture_size" | ||||
|             android:padding="4dp" | ||||
|             app:actualImageScaleType="centerCrop" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" | ||||
|             app:roundAsCircle="true" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvUsername" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:ellipsize="marquee" | ||||
|             android:paddingStart="4dp" | ||||
|             android:paddingTop="2dp" | ||||
|             android:paddingEnd="4dp" | ||||
|             android:paddingBottom="2dp" | ||||
|             android:singleLine="true" | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat.Medium" | ||||
|             android:textColor="?android:textColorPrimary" | ||||
|             android:textStyle="bold" | ||||
|             app:layout_constraintBottom_toTopOf="@id/tvComment" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toEndOf="@id/ivProfilePic" | ||||
|             app:layout_constraintTop_toTopOf="parent" | ||||
|             tools:text="username" /> | ||||
| 
 | ||||
|         <awais.instagrabber.customviews.RamboTextView | ||||
|             android:id="@+id/tvComment" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:autoLink="web|email" | ||||
|             android:ellipsize="end" | ||||
|             android:linksClickable="true" | ||||
|             android:paddingStart="4dp" | ||||
|             android:paddingTop="2dp" | ||||
|             android:paddingEnd="4dp" | ||||
|             android:paddingBottom="2dp" | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat" | ||||
|             app:layout_constraintBottom_toTopOf="@id/tvLikes" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.0" | ||||
|             app:layout_constraintStart_toEndOf="@id/ivProfilePic" | ||||
|             app:layout_constraintTop_toBottomOf="@id/tvUsername" | ||||
|             tools:text="comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment " /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvLikes" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_weight="1" | ||||
|             android:gravity="center_vertical" | ||||
|             android:paddingStart="4dp" | ||||
|             android:paddingTop="2dp" | ||||
|             android:paddingEnd="4dp" | ||||
|             android:paddingBottom="2dp" | ||||
|             android:singleLine="true" | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toStartOf="@id/tvDate" | ||||
|             app:layout_constraintStart_toEndOf="@id/ivProfilePic" | ||||
|             app:layout_constraintTop_toBottomOf="@id/tvComment" | ||||
|             tools:text="likes" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvDate" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:ellipsize="marquee" | ||||
|             android:gravity="end" | ||||
|             android:singleLine="true" | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|             android:textStyle="italic" | ||||
|             app:layout_constraintBaseline_toBaselineOf="@id/tvLikes" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toEndOf="@id/tvLikes" | ||||
|             app:layout_constraintTop_toBottomOf="@id/tvComment" | ||||
|             tools:text="long date................................" /> | ||||
|     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/rvChildComments" | ||||
|         android:layout_width="match_parent" | ||||
|     <awais.instagrabber.customviews.RamboTextViewV2 | ||||
|         android:id="@+id/tvComment" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="40dp" | ||||
|         android:layout_marginLeft="40dp" | ||||
|         app:layoutManager="LinearLayoutManager" | ||||
|         tools:itemCount="5" | ||||
|         tools:listitem="@layout/item_comment_small" /> | ||||
|         android:autoLink="web|email" | ||||
|         android:ellipsize="end" | ||||
|         android:linksClickable="true" | ||||
|         android:paddingStart="4dp" | ||||
|         android:paddingTop="2dp" | ||||
|         android:paddingEnd="4dp" | ||||
|         android:paddingBottom="2dp" | ||||
|         android:textAppearance="@style/TextAppearance.AppCompat" | ||||
|         app:layout_constraintBottom_toTopOf="@id/tvLikes" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintHorizontal_bias="0.0" | ||||
|         app:layout_constraintStart_toEndOf="@id/ivProfilePic" | ||||
|         app:layout_constraintTop_toBottomOf="@id/tvUsername" | ||||
|         tools:text="comment comment comment comment comment comment comment comment comment comment comment comment | ||||
|         comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment" /> | ||||
| 
 | ||||
|     <View | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="1dp" | ||||
|         android:layout_gravity="bottom" | ||||
|         android:layout_marginStart="4dp" | ||||
|         android:layout_marginEnd="4dp" | ||||
|         android:layout_marginBottom="4dp" | ||||
|         android:background="#32888888" /> | ||||
| </LinearLayout> | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/tvLikes" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_weight="1" | ||||
|         android:gravity="center_vertical" | ||||
|         android:paddingStart="4dp" | ||||
|         android:paddingTop="2dp" | ||||
|         android:paddingEnd="4dp" | ||||
|         android:paddingBottom="2dp" | ||||
|         android:scrollbars="none" | ||||
|         android:singleLine="true" | ||||
|         android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toStartOf="@id/tvDate" | ||||
|         app:layout_constraintStart_toEndOf="@id/ivProfilePic" | ||||
|         app:layout_constraintTop_toBottomOf="@id/tvComment" | ||||
|         tools:text="likes" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/tvDate" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:ellipsize="marquee" | ||||
|         android:gravity="end" | ||||
|         android:singleLine="true" | ||||
|         android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|         android:textStyle="italic" | ||||
|         app:layout_constraintBaseline_toBaselineOf="@id/tvLikes" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@id/tvLikes" | ||||
|         app:layout_constraintTop_toBottomOf="@id/tvComment" | ||||
|         tools:text="long date................................" /> | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| 
 | ||||
|     <!--<androidx.recyclerview.widget.RecyclerView--> | ||||
|     <!--    android:id="@+id/rvChildComments"--> | ||||
|     <!--    android:layout_width="match_parent"--> | ||||
|     <!--    android:layout_height="wrap_content"--> | ||||
|     <!--    android:layout_marginStart="40dp"--> | ||||
|     <!--    android:layout_marginLeft="40dp"--> | ||||
|     <!--    app:layoutManager="LinearLayoutManager"--> | ||||
|     <!--    tools:itemCount="5"--> | ||||
|     <!--    tools:listitem="@layout/item_comment_small" />--> | ||||
| 
 | ||||
|     <!--<View--> | ||||
|     <!--    android:layout_width="match_parent"--> | ||||
|     <!--    android:layout_height="1dp"--> | ||||
|     <!--    android:layout_gravity="bottom"--> | ||||
|     <!--    android:layout_marginStart="4dp"--> | ||||
|     <!--    android:layout_marginEnd="4dp"--> | ||||
|     <!--    android:layout_marginBottom="4dp"--> | ||||
|     <!--    android:background="#32888888" />--> | ||||
| @ -5,6 +5,9 @@ | ||||
|     android:id="@+id/container" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:paddingStart="40dp" | ||||
|     android:paddingTop="8dp" | ||||
|     android:paddingEnd="8dp" | ||||
|     android:paddingBottom="2dp"> | ||||
| 
 | ||||
|     <com.facebook.drawee.view.SimpleDraweeView | ||||
| @ -15,7 +18,8 @@ | ||||
|         app:layout_constraintEnd_toStartOf="@id/tvUsername" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         app:roundAsCircle="true" /> | ||||
|         app:roundAsCircle="true" | ||||
|         tools:background="@mipmap/ic_launcher" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/tvUsername" | ||||
| @ -36,7 +40,7 @@ | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         tools:text="username" /> | ||||
| 
 | ||||
|     <awais.instagrabber.customviews.RamboTextView | ||||
|     <awais.instagrabber.customviews.RamboTextViewV2 | ||||
|         android:id="@+id/tvComment" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
| @ -55,17 +59,20 @@ | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@id/ivProfilePic" | ||||
|         app:layout_constraintTop_toBottomOf="@id/tvUsername" | ||||
|         tools:text="comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment " /> | ||||
|         tools:text="comment comment comment comment comment comment comment comment | ||||
|         comment comment comment comment comment comment comment comment comment comment comment comment comment comment | ||||
|         comment comment comment comment comment comment " /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         android:id="@+id/tvLikes" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="0dp" | ||||
|         android:singleLine="true" | ||||
|         android:paddingStart="4dp" | ||||
|         android:paddingTop="2dp" | ||||
|         android:paddingEnd="4dp" | ||||
|         android:paddingBottom="2dp" | ||||
|         android:scrollbars="none" | ||||
|         android:singleLine="true" | ||||
|         android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toStartOf="@id/tvDate" | ||||
|  | ||||
| @ -37,29 +37,13 @@ | ||||
|                 tools:text="690000" /> | ||||
|         </LinearLayout> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:id="@+id/videoViewsContainer" | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvVideoViews" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="match_parent" | ||||
|             android:gravity="center" | ||||
|             android:orientation="horizontal" | ||||
|             android:visibility="gone"> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageView | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:padding="4dp" | ||||
|                 app:srcCompat="@drawable/ic_outline_views_24" | ||||
|                 app:tint="?android:textColorPrimary" /> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatTextView | ||||
|                 android:id="@+id/tvVideoViews" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:gravity="center_vertical" | ||||
|                 android:textAppearance="?attr/textAppearanceButton" | ||||
|                 tools:text="690000" /> | ||||
|         </LinearLayout> | ||||
|             android:gravity="center_vertical" | ||||
|             android:textAppearance="?attr/textAppearanceCaption" | ||||
|             tools:text="690000 views" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvPostDate" | ||||
| @ -70,17 +54,18 @@ | ||||
|             android:maxLines="1" | ||||
|             android:padding="8dp" | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|             tools:text="690000" /> | ||||
|             tools:text="2020-01-01 12:00:00" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatImageView | ||||
|             android:id="@+id/btnMute" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="match_parent" | ||||
|             android:background="?selectableItemBackgroundBorderless" | ||||
|             android:padding="4dp" | ||||
|             android:visibility="gone" | ||||
|             app:srcCompat="@drawable/ic_volume_up_24" | ||||
|             app:tint="?android:textColorPrimary" /> | ||||
|         <!--<androidx.appcompat.widget.AppCompatImageView--> | ||||
|         <!--    android:id="@+id/btnMute"--> | ||||
|         <!--    android:layout_width="wrap_content"--> | ||||
|         <!--    android:layout_height="match_parent"--> | ||||
|         <!--    android:background="?selectableItemBackgroundBorderless"--> | ||||
|         <!--    android:padding="4dp"--> | ||||
|         <!--    android:visibility="gone"--> | ||||
|         <!--    app:srcCompat="@drawable/ic_volume_up_24"--> | ||||
|         <!--    app:tint="?android:textColorPrimary"--> | ||||
|         <!--    tools:visibility="visible" />--> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatImageView | ||||
|             android:id="@+id/btnDownload" | ||||
| @ -92,34 +77,21 @@ | ||||
|             app:tint="?android:textColorPrimary" /> | ||||
|     </LinearLayout> | ||||
| 
 | ||||
|     <ScrollView | ||||
|     <awais.instagrabber.customviews.RamboTextViewV2 | ||||
|         android:id="@+id/viewerCaption" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="0dp" | ||||
|         android:layout_weight="1" | ||||
|         android:isScrollContainer="true" | ||||
|         android:scrollbars="vertical" | ||||
|         android:scrollHorizontally="false"> | ||||
| 
 | ||||
|         <FrameLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:background="?android:selectableItemBackground" | ||||
|             android:clickable="true" | ||||
|             android:focusable="true"> | ||||
| 
 | ||||
|             <awais.instagrabber.customviews.RamboTextView | ||||
|                 android:id="@+id/viewerCaption" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:background="?android:selectableItemBackground" | ||||
|                 android:clipToPadding="false" | ||||
|                 android:paddingStart="8dp" | ||||
|                 android:paddingLeft="8dp" | ||||
|                 android:paddingEnd="8dp" | ||||
|                 android:paddingRight="8dp" | ||||
|                 android:paddingBottom="8dp" | ||||
|                 android:textAppearance="@style/TextAppearance.AppCompat.Body1" | ||||
|                 tools:text="BOTTOM TEXT" /> | ||||
|         </FrameLayout> | ||||
|     </ScrollView> | ||||
|         android:layout_height="wrap_content" | ||||
|         android:background="?android:selectableItemBackground" | ||||
|         android:clickable="true" | ||||
|         android:clipToPadding="false" | ||||
|         android:ellipsize="end" | ||||
|         android:focusable="true" | ||||
|         android:maxLines="5" | ||||
|         android:paddingStart="8dp" | ||||
|         android:paddingLeft="8dp" | ||||
|         android:paddingEnd="8dp" | ||||
|         android:paddingRight="8dp" | ||||
|         android:paddingBottom="8dp" | ||||
|         android:textAppearance="@style/TextAppearance.AppCompat.Body1" | ||||
|         tools:text="Bottom text with hashtags etc." /> | ||||
| </LinearLayout> | ||||
| @ -7,8 +7,7 @@ | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/item_feed_top" | ||||
|         layout="@layout/item_feed_top" | ||||
|         android:visibility="gone" /> | ||||
|         layout="@layout/item_feed_top" /> | ||||
| 
 | ||||
|     <awais.instagrabber.customviews.drawee.ZoomableDraweeView | ||||
|         android:id="@+id/imageViewer" | ||||
| @ -22,6 +21,5 @@ | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/item_feed_bottom" | ||||
|         layout="@layout/item_feed_bottom" | ||||
|         android:visibility="gone" /> | ||||
|         layout="@layout/item_feed_bottom" /> | ||||
| </LinearLayout> | ||||
| @ -8,8 +8,7 @@ | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/item_feed_top" | ||||
|         layout="@layout/item_feed_top" | ||||
|         android:visibility="gone" /> | ||||
|         layout="@layout/item_feed_top" /> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|         android:layout_width="match_parent" | ||||
| @ -42,6 +41,5 @@ | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/item_feed_bottom" | ||||
|         layout="@layout/item_feed_bottom" | ||||
|         android:visibility="gone" /> | ||||
|         layout="@layout/item_feed_bottom" /> | ||||
| </LinearLayout> | ||||
| @ -30,7 +30,7 @@ | ||||
|         android:paddingRight="8dp" | ||||
|         android:weightSum="2"> | ||||
| 
 | ||||
|         <awais.instagrabber.customviews.RamboTextView | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/title" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
| @ -38,7 +38,7 @@ | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat.Medium" | ||||
|             tools:text="username" /> | ||||
| 
 | ||||
|         <awais.instagrabber.customviews.RamboTextView | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/location" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
| @ -50,12 +50,12 @@ | ||||
|             tools:text="location" /> | ||||
|     </RelativeLayout> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatImageView | ||||
|         android:id="@+id/viewStoryPost" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="match_parent" | ||||
|         android:layout_gravity="center" | ||||
|         android:background="?selectableItemBackgroundBorderless" | ||||
|         app:srcCompat="@drawable/ic_open_in_new_24" | ||||
|         app:tint="?android:textColorPrimary" /> | ||||
|     <!--<androidx.appcompat.widget.AppCompatImageView--> | ||||
|     <!--    android:id="@+id/viewStoryPost"--> | ||||
|     <!--    android:layout_width="wrap_content"--> | ||||
|     <!--    android:layout_height="match_parent"--> | ||||
|     <!--    android:layout_gravity="center"--> | ||||
|     <!--    android:background="?selectableItemBackgroundBorderless"--> | ||||
|     <!--    app:srcCompat="@drawable/ic_open_in_new_24"--> | ||||
|     <!--    app:tint="?android:textColorPrimary" />--> | ||||
| </LinearLayout> | ||||
| @ -7,8 +7,7 @@ | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/item_feed_top" | ||||
|         layout="@layout/item_feed_top" | ||||
|         android:visibility="gone" /> | ||||
|         layout="@layout/item_feed_top" /> | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/video_post" | ||||
| @ -16,6 +15,5 @@ | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/item_feed_bottom" | ||||
|         layout="@layout/item_feed_bottom" | ||||
|         android:visibility="gone" /> | ||||
|         layout="@layout/item_feed_bottom" /> | ||||
| </LinearLayout> | ||||
| @ -15,7 +15,7 @@ | ||||
|             android:id="@+id/thumbnail" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             app:actualImageScaleType="fitCenter" | ||||
|             app:actualImageScaleType="centerCrop" | ||||
|             app:viewAspectRatio="1" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatImageView | ||||
|  | ||||
| @ -27,7 +27,7 @@ | ||||
|             app:nullable="true" /> | ||||
|     </action> | ||||
| 
 | ||||
|     <fragment | ||||
|     <dialog | ||||
|         android:id="@+id/commentsViewerFragment" | ||||
|         android:name="awais.instagrabber.fragments.CommentsViewerFragment" | ||||
|         android:label="Comments" | ||||
| @ -44,7 +44,7 @@ | ||||
|             android:name="postUserId" | ||||
|             app:argType="string" | ||||
|             app:nullable="false" /> | ||||
|     </fragment> | ||||
|     </dialog> | ||||
| 
 | ||||
|     <action | ||||
|         android:id="@+id/action_global_commentsViewerFragment" | ||||
|  | ||||
| @ -30,6 +30,8 @@ | ||||
| 
 | ||||
|     <color name="dm_profile_button_color">#efefef</color> | ||||
| 
 | ||||
|     <color name="comment_selected">#888888</color> | ||||
| 
 | ||||
|     <color name="white">#FFFFFF</color> | ||||
| 
 | ||||
|     <color name="black">#000000</color> | ||||
|  | ||||
| @ -9,8 +9,6 @@ | ||||
|     <string name="action_fdroid" translatable="false">F-Droid</string> | ||||
|     <string name="action_search">Search username…</string> | ||||
|     <string name="action_compare">Compare</string> | ||||
|     <string name="single_like">like</string> | ||||
|     <string name="multiple_likes">likes</string> | ||||
|     <string name="clipboard_error">Error copying text</string> | ||||
|     <string name="clipboard_copied">Copied to clipboard!</string> | ||||
|     <string name="report">Report</string> | ||||
| @ -325,6 +323,7 @@ | ||||
|     <string name="downloading">Downloading…</string> | ||||
|     <string name="downloader_downloading_child">Download item %d of %d</string> | ||||
|     <string name="delete">Delete</string> | ||||
|     <string name="comment">Comment</string> | ||||
|     <plurals name="likes_count"> | ||||
|         <item quantity="one">%d like</item> | ||||
|         <item quantity="other">%d likes</item> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user