diff --git a/app/build.gradle b/app/build.gradle index e7fbcbfd..8416f500 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,7 +57,7 @@ android { buildTypes { debug { - minifyEnabled true + minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } @@ -166,13 +166,13 @@ dependencies { def nav_version = '2.3.5' def exoplayer_version = '2.14.1' - implementation 'com.google.android.material:material:1.4.0-beta01' + implementation 'com.google.android.material:material:1.4.0-rc01' implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version" implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer_version" implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version" - implementation "androidx.recyclerview:recyclerview:1.2.0" + implementation "androidx.recyclerview:recyclerview:1.2.1" implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation "androidx.viewpager2:viewpager2:1.0.0" implementation "androidx.navigation:navigation-fragment:$nav_version" @@ -183,11 +183,11 @@ dependencies { implementation 'com.google.guava:guava:27.0.1-android' - def core_version = "1.6.0-beta01" + def core_version = "1.6.0-rc01" implementation "androidx.core:core:$core_version" // Fragment - implementation "androidx.fragment:fragment-ktx:1.3.4" + implementation "androidx.fragment:fragment-ktx:1.3.5" // Lifecycle implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" @@ -203,10 +203,10 @@ dependencies { annotationProcessor "androidx.room:room-compiler:$room_version" // CameraX - def camerax_version = "1.1.0-alpha04" + def camerax_version = "1.1.0-alpha05" implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version" - implementation "androidx.camera:camera-view:1.0.0-alpha24" + implementation "androidx.camera:camera-view:1.0.0-alpha25" // EmojiCompat def emoji_compat_version = "1.1.0" @@ -238,7 +238,7 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' - githubImplementation 'io.sentry:sentry-android:4.3.0' + githubImplementation 'io.sentry:sentry-android:5.0.1' testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2' testImplementation "androidx.test.ext:junit-ktx:1.1.2" diff --git a/app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java b/app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java index e0c72194..681e92df 100644 --- a/app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java @@ -82,7 +82,7 @@ public class DirectorySelectActivity extends BaseLanguageActivity { return; } if (!"com.android.externalstorage.documents".equals(data.getData().getAuthority())) { - showErrorDialog(getString(R.string.dir_select_no_download_folder)); + showErrorDialog(getString(R.string.dir_select_no_download_folder, data.getData().getAuthority())); return; } AppExecutors.INSTANCE.getMainThread().execute(() -> { diff --git a/app/src/main/java/awais/instagrabber/adapters/DirectItemsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/DirectItemsAdapter.java index 40624082..165eddc2 100644 --- a/app/src/main/java/awais/instagrabber/adapters/DirectItemsAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/DirectItemsAdapter.java @@ -171,7 +171,7 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter { +public final class FeedStoriesAdapter extends ListAdapter { private final OnFeedStoryClickListener listener; - private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { + private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { @Override - public boolean areItemsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) { - return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId()); + public boolean areItemsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { + return oldItem.getId().equals(newItem.getId()); } @Override - public boolean areContentsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) { - return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId()) && oldItem.isFullyRead() == newItem.isFullyRead(); + public boolean areContentsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { + return oldItem.getId().equals(newItem.getId()) && oldItem.getSeen() == newItem.getSeen(); } }; @@ -41,13 +41,13 @@ public final class FeedStoriesAdapter extends ListAdapter implements Filterable { +public final class FeedStoriesListAdapter extends ListAdapter implements Filterable { private final OnFeedStoryClickListener listener; - private List list; + private List list; private final Filter filter = new Filter() { @NonNull @Override protected FilterResults performFiltering(final CharSequence filter) { final String query = TextUtils.isEmpty(filter) ? null : filter.toString().toLowerCase(); - List filteredList = list; + List filteredList = list; if (list != null && query != null) { filteredList = list.stream() - .filter(feedStoryModel -> feedStoryModel.getProfileModel() + .filter(feedStoryModel -> feedStoryModel.getUser() .getUsername() .toLowerCase() .contains(query)) @@ -45,19 +45,19 @@ public final class FeedStoriesListAdapter extends ListAdapter) results.values, true); + submitList((List) results.values, true); } }; - private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { + private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { @Override - public boolean areItemsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) { - return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId()); + public boolean areItemsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { + return oldItem.getId().equals(newItem.getId()); } @Override - public boolean areContentsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) { - return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId()) && oldItem.isFullyRead() == newItem.isFullyRead(); + public boolean areContentsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { + return oldItem.getId().equals(newItem.getId()) && oldItem.getSeen() == newItem.getSeen(); } }; @@ -71,7 +71,7 @@ public final class FeedStoriesListAdapter extends ListAdapter list, final boolean isFiltered) { + private void submitList(@Nullable final List list, final boolean isFiltered) { if (!isFiltered) { this.list = list; } @@ -79,7 +79,7 @@ public final class FeedStoriesListAdapter extends ListAdapter list) { + public void submitList(final List list) { submitList(list, false); } @@ -93,12 +93,12 @@ public final class FeedStoriesListAdapter extends ListAdapter { +public final class HighlightStoriesListAdapter extends ListAdapter { private final OnHighlightStoryClickListener listener; - private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { + private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { @Override - public boolean areItemsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) { + public boolean areItemsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { return oldItem.getId().equals(newItem.getId()); } @Override - public boolean areContentsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) { + public boolean areContentsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { return oldItem.getId().equals(newItem.getId()); } }; @@ -41,12 +41,12 @@ public final class HighlightStoriesListAdapter extends ListAdapter { +public final class HighlightsAdapter extends ListAdapter { private final OnHighlightClickListener clickListener; - private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { + private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { @Override - public boolean areItemsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) { + public boolean areItemsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { return oldItem.getId().equals(newItem.getId()); } @Override - public boolean areContentsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) { + public boolean areContentsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) { return oldItem.getId().equals(newItem.getId()); } }; @@ -42,7 +42,7 @@ public final class HighlightsAdapter extends ListAdapter clickListener.onHighlightClick(highlightModel, position)); } @@ -50,6 +50,6 @@ public final class HighlightsAdapter extends ListAdapter { - - private static final DiffUtil.ItemCallback diffCallback = new DiffUtil.ItemCallback() { - @Override - public boolean areItemsTheSame(@NonNull final MediaEntry oldItem, @NonNull final MediaEntry newItem) { - return oldItem.imageId == newItem.imageId; - } - - @Override - public boolean areContentsTheSame(@NonNull final MediaEntry oldItem, @NonNull final MediaEntry newItem) { - return oldItem.imageId == newItem.imageId; - } - }; - - private final OnItemClickListener onItemClickListener; - - public MediaItemsAdapter(final OnItemClickListener onItemClickListener) { - super(diffCallback); - this.onItemClickListener = onItemClickListener; - } - - @NonNull - @Override - public MediaItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { - final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); - final ItemMediaBinding binding = ItemMediaBinding.inflate(layoutInflater, parent, false); - return new MediaItemViewHolder(binding, onItemClickListener); - } - - @Override - public void onBindViewHolder(@NonNull final MediaItemViewHolder holder, final int position) { - holder.bind(getItem(position)); - } - - public static class MediaItemViewHolder extends RecyclerView.ViewHolder { - private static final String TAG = MediaItemViewHolder.class.getSimpleName(); - private static final int size = Utils.displayMetrics.widthPixels / 3; - - private final ItemMediaBinding binding; - private final OnItemClickListener onItemClickListener; - - public MediaItemViewHolder(@NonNull final ItemMediaBinding binding, - final OnItemClickListener onItemClickListener) { - super(binding.getRoot()); - this.binding = binding; - this.onItemClickListener = onItemClickListener; - } - - public void bind(final MediaEntry item) { - final Uri uri = Uri.fromFile(new File(item.path)); - if (onItemClickListener != null) { - itemView.setOnClickListener(v -> onItemClickListener.onItemClick(item)); - } - final BaseControllerListener controllerListener = new BaseControllerListener() { - @Override - public void onFailure(final String id, final Throwable throwable) { - Log.e(TAG, "onFailure: ", throwable); - } - }; - final ImageRequest request = ImageRequestBuilder - .newBuilderWithSource(uri) - .setLocalThumbnailPreviewsEnabled(true) - .setProgressiveRenderingEnabled(false) - .setResizeOptions(ResizeOptions.forDimensions(size, size)) - .build(); - final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder() - .setImageRequest(request) - .setControllerListener(controllerListener); - binding.item.setController(builder.build()); - if (item.isVideo && item.duration >= 0) { - final String timeString = TextUtils.millisToTimeString(item.duration); - binding.duration.setVisibility(View.VISIBLE); - binding.duration.setText(timeString); - } else { - binding.duration.setVisibility(View.GONE); - } - } - } - - public interface OnItemClickListener { - void onItemClick(MediaEntry entry); - } -} diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/FeedStoryViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/FeedStoryViewHolder.java index 7e8b526b..3e86276c 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/FeedStoryViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/FeedStoryViewHolder.java @@ -4,8 +4,8 @@ import androidx.recyclerview.widget.RecyclerView; import awais.instagrabber.adapters.FeedStoriesAdapter; import awais.instagrabber.databinding.ItemHighlightBinding; -import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.repositories.responses.User; +import awais.instagrabber.repositories.responses.stories.Story; public final class FeedStoryViewHolder extends RecyclerView.ViewHolder { @@ -16,7 +16,7 @@ public final class FeedStoryViewHolder extends RecyclerView.ViewHolder { this.binding = binding; } - public void bind(final FeedStoryModel model, + public void bind(final Story model, final int position, final FeedStoriesAdapter.OnFeedStoryClickListener listener) { if (model == null) return; @@ -28,14 +28,17 @@ public final class FeedStoryViewHolder extends RecyclerView.ViewHolder { if (listener != null) listener.onFeedStoryLongClick(model, position); return true; }); - final User profileModel = model.getProfileModel(); + final User profileModel = model.getUser(); binding.title.setText(profileModel.getUsername()); - binding.title.setAlpha(model.isFullyRead() ? 0.5F : 1.0F); + final boolean isFullyRead = + model.getSeen() != null && + model.getSeen().equals(model.getLatestReelMedia()); + binding.title.setAlpha(isFullyRead ? 0.5F : 1.0F); binding.icon.setImageURI(profileModel.getProfilePicUrl()); - binding.icon.setAlpha(model.isFullyRead() ? 0.5F : 1.0F); + binding.icon.setAlpha(isFullyRead ? 0.5F : 1.0F); - if (model.isLive()) binding.icon.setStoriesBorder(2); - else if (model.isBestie()) binding.icon.setStoriesBorder(1); + if (model.getBroadcast() != null) binding.icon.setStoriesBorder(2); + else if (model.getHasBestiesMedia()) binding.icon.setStoriesBorder(1); else binding.icon.setStoriesBorder(0); } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/HighlightViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/HighlightViewHolder.java index d9956e92..8bcb0ea6 100755 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/HighlightViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/HighlightViewHolder.java @@ -3,7 +3,7 @@ package awais.instagrabber.adapters.viewholder; import androidx.recyclerview.widget.RecyclerView; import awais.instagrabber.databinding.ItemHighlightBinding; -import awais.instagrabber.models.HighlightModel; +import awais.instagrabber.repositories.responses.stories.Story; public final class HighlightViewHolder extends RecyclerView.ViewHolder { @@ -14,10 +14,10 @@ public final class HighlightViewHolder extends RecyclerView.ViewHolder { this.binding = binding; } - public void bind(final HighlightModel model) { + public void bind(final Story model) { if (model == null) return; binding.title.setText(model.getTitle()); - binding.icon.setImageURI(model.getThumbnailUrl()); + binding.icon.setImageURI(model.getCoverMedia().getCroppedImageVersion().getUrl()); // binding.getRoot().setOnClickListener(v -> { // if (listener == null) return; // listener.onFeedStoryClick(model, position); diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/StoryListViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/StoryListViewHolder.java index a421e98c..182ef659 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/StoryListViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/StoryListViewHolder.java @@ -8,8 +8,8 @@ import awais.instagrabber.R; import awais.instagrabber.adapters.FeedStoriesListAdapter.OnFeedStoryClickListener; import awais.instagrabber.adapters.HighlightStoriesListAdapter.OnHighlightStoryClickListener; import awais.instagrabber.databinding.ItemNotificationBinding; -import awais.instagrabber.models.FeedStoryModel; -import awais.instagrabber.models.HighlightModel; +import awais.instagrabber.repositories.responses.stories.Story; +import awais.instagrabber.utils.ResponseBodyUtils; public final class StoryListViewHolder extends RecyclerView.ViewHolder { private final ItemNotificationBinding binding; @@ -19,7 +19,7 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder { this.binding = binding; } - public void bind(final FeedStoryModel model, + public void bind(final Story model, final OnFeedStoryClickListener notificationClickListener) { if (model == null) return; @@ -31,19 +31,20 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder { binding.tvDate.setText(model.getDateTime()); - binding.tvUsername.setText(model.getProfileModel().getUsername()); - binding.ivProfilePic.setImageURI(model.getProfileModel().getProfilePicUrl()); + binding.tvUsername.setText(model.getUser().getUsername()); + binding.ivProfilePic.setImageURI(model.getUser().getProfilePicUrl()); binding.ivProfilePic.setOnClickListener(v -> { if (notificationClickListener == null) return; - notificationClickListener.onProfileClick(model.getProfileModel().getUsername()); + notificationClickListener.onProfileClick(model.getUser().getUsername()); }); - if (model.getFirstStoryModel() != null) { + if (model.getItems() != null && model.getItems().size() > 0) { binding.ivPreviewPic.setVisibility(View.VISIBLE); - binding.ivPreviewPic.setImageURI(model.getFirstStoryModel().getThumbnail()); + binding.ivPreviewPic.setImageURI(ResponseBodyUtils.getThumbUrl(model.getItems().get(0))); } else binding.ivPreviewPic.setVisibility(View.INVISIBLE); - float alpha = model.isFullyRead() ? 0.5F : 1.0F; + float alpha = model.getSeen() != null && model.getSeen().equals(model.getLatestReelMedia()) + ? 0.5F : 1.0F; binding.ivProfilePic.setAlpha(alpha); binding.ivPreviewPic.setAlpha(alpha); binding.tvUsername.setAlpha(alpha); @@ -56,7 +57,7 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder { }); } - public void bind(final HighlightModel model, + public void bind(final Story model, final int position, final OnHighlightStoryClickListener notificationClickListener) { if (model == null) return; @@ -72,7 +73,7 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder { binding.ivProfilePic.setVisibility(View.GONE); binding.ivPreviewPic.setVisibility(View.VISIBLE); - binding.ivPreviewPic.setImageURI(model.getThumbnailUrl()); + binding.ivPreviewPic.setImageURI(model.getCoverImageVersion().getUrl()); itemView.setOnClickListener(v -> { if (notificationClickListener == null) return; diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaShareViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaShareViewHolder.java index 82c07ab7..78f0c8e2 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaShareViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaShareViewHolder.java @@ -65,19 +65,29 @@ public class DirectItemMediaShareViewHolder extends DirectItemViewHolder { if (media == null) return; itemView.post(() -> { setupUser(media); - setupTitle(media); setupCaption(media); }); + final int index; + final Media toDisplay; + final MediaItemType mediaType = media.getMediaType(); + switch (mediaType) { + case MEDIA_TYPE_SLIDER: + toDisplay = media.getCarouselMedia().stream() + .filter(m -> media.getCarouselShareChildMediaId() != null && + media.getCarouselShareChildMediaId().equals(m.getId())) + .findAny() + .orElse(media.getCarouselMedia().get(0)); + index = media.getCarouselMedia().indexOf(toDisplay); + break; + default: + toDisplay = media; + index = 0; + } itemView.post(() -> { - final MediaItemType mediaType = media.getMediaType(); setupTypeIndicator(mediaType); - if (mediaType == MediaItemType.MEDIA_TYPE_SLIDER) { - setupPreview(media.getCarouselMedia().get(0), messageDirection); - return; - } - setupPreview(media, messageDirection); + setupPreview(toDisplay, messageDirection); }); - itemView.setOnClickListener(v -> openMedia(media)); + itemView.setOnClickListener(v -> openMedia(media, index)); } private void setupTypeIndicator(final MediaItemType mediaType) { @@ -129,16 +139,6 @@ public class DirectItemMediaShareViewHolder extends DirectItemViewHolder { } } - private void setupTitle(@NonNull final Media media) { - final String title = media.getTitle(); - if (!TextUtils.isEmpty(title)) { - binding.title.setVisibility(View.VISIBLE); - binding.title.setText(title); - } else { - binding.title.setVisibility(View.GONE); - } - } - private void setupUser(@NonNull final Media media) { final User user = media.getUser(); if (user != null) { diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaViewHolder.java index 769548a8..d2a7a5ee 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaViewHolder.java @@ -47,7 +47,7 @@ public class DirectItemMediaViewHolder extends DirectItemViewHolder { .setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP) .build()); final Media media = directItemModel.getMedia(); - itemView.setOnClickListener(v -> openMedia(media)); + itemView.setOnClickListener(v -> openMedia(media, -1)); final MediaItemType modelMediaType = media.getMediaType(); binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO || modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemPlaceholderViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemPlaceholderViewHolder.java index 8b4f6a1b..f903e73c 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemPlaceholderViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemPlaceholderViewHolder.java @@ -1,21 +1,23 @@ package awais.instagrabber.adapters.viewholder.directmessages; +import android.view.View; + import androidx.annotation.NonNull; import androidx.recyclerview.widget.ItemTouchHelper; import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback; import awais.instagrabber.databinding.LayoutDmBaseBinding; -import awais.instagrabber.databinding.LayoutDmTextBinding; +import awais.instagrabber.databinding.LayoutDmStoryShareBinding; import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.directmessages.DirectItem; import awais.instagrabber.repositories.responses.directmessages.DirectThread; public class DirectItemPlaceholderViewHolder extends DirectItemViewHolder { - private final LayoutDmTextBinding binding; + private final LayoutDmStoryShareBinding binding; public DirectItemPlaceholderViewHolder(@NonNull final LayoutDmBaseBinding baseBinding, - final LayoutDmTextBinding binding, + final LayoutDmStoryShareBinding binding, final User currentUser, final DirectThread thread, final DirectItemCallback callback) { @@ -26,13 +28,11 @@ public class DirectItemPlaceholderViewHolder extends DirectItemViewHolder { @Override public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) { - final String text = String.format("%s: %s", directItemModel.getPlaceholder().getTitle(), directItemModel.getPlaceholder().getMessage()); - binding.tvMessage.setText(text); - } - - @Override - protected boolean showBackground() { - return true; + binding.shareInfo.setText(directItemModel.getPlaceholder().getTitle()); + binding.text.setVisibility(View.VISIBLE); + binding.text.setText(directItemModel.getPlaceholder().getMessage()); + binding.ivMediaPreview.setVisibility(View.GONE); + binding.typeIcon.setVisibility(View.GONE); } @Override diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java index 9778d046..3f8f0ed7 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java @@ -50,7 +50,7 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder { setPreview(visualMedia, messageDirection); final boolean expired = TextUtils.isEmpty(media.getId()); if (expired) return; - itemView.setOnClickListener(v -> openMedia(media)); + itemView.setOnClickListener(v -> openMedia(media, -1)); /*final boolean isExpired = visualMedia == null || (mediaModel = visualMedia.getMedia()) == null || TextUtils.isEmpty(mediaModel.getThumbUrl()) && mediaModel.getPk() < 1; diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemReelShareViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemReelShareViewHolder.java index aa1666ab..1c755881 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemReelShareViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemReelShareViewHolder.java @@ -76,7 +76,7 @@ public class DirectItemReelShareViewHolder extends DirectItemViewHolder { } if (!expired) { setPreview(media); - itemView.setOnClickListener(v -> openMedia(media)); + itemView.setOnClickListener(v -> openMedia(media, -1)); } } diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemViewHolder.java index f61c45ef..e969e183 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemViewHolder.java @@ -501,8 +501,8 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder imple callback.onURLClick(url); } - protected void openMedia(final Media media) { - callback.onMediaClick(media); + protected void openMedia(final Media media, final int index) { + callback.onMediaClick(media, index); } protected void openStory(final DirectItemStoryShare storyShare) { diff --git a/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java index 4fe91772..96643339 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java @@ -39,7 +39,7 @@ public class FeedPostFetchService implements PostFetcher.PostFetchService { return; } else if (result == null) return; nextCursor = result.getNextCursor(); - hasNextPage = result.hasNextPage(); + hasNextPage = result.getHasNextPage(); final List mediaResults = result.getFeedModels(); feedModels.addAll(mediaResults); diff --git a/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java index 87b38bb7..7b26d79b 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java @@ -35,7 +35,7 @@ public class HashtagPostFetchService implements PostFetcher.PostFetchService { public void onSuccess(final PostsFetchResponse result) { if (result == null) return; nextMaxId = result.getNextCursor(); - moreAvailable = result.hasNextPage(); + moreAvailable = result.getHasNextPage(); if (fetchListener != null) { fetchListener.onResult(result.getFeedModels()); } diff --git a/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java index 31b9f90c..11f5dce3 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java @@ -35,7 +35,7 @@ public class LocationPostFetchService implements PostFetcher.PostFetchService { public void onSuccess(final PostsFetchResponse result) { if (result == null) return; nextMaxId = result.getNextCursor(); - moreAvailable = result.hasNextPage(); + moreAvailable = result.getHasNextPage(); if (fetchListener != null) { fetchListener.onResult(result.getFeedModels()); } diff --git a/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java index 2c609dcb..9bff389e 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java @@ -36,7 +36,7 @@ public class ProfilePostFetchService implements PostFetcher.PostFetchService { public void onSuccess(final PostsFetchResponse result) { if (result == null) return; nextMaxId = result.getNextCursor(); - moreAvailable = result.hasNextPage(); + moreAvailable = result.getHasNextPage(); if (fetchListener != null) { fetchListener.onResult(result.getFeedModels()); } diff --git a/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java index a84f960a..e4650a77 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java @@ -40,7 +40,7 @@ public class SavedPostFetchService implements PostFetcher.PostFetchService { public void onSuccess(final PostsFetchResponse result) { if (result == null) return; nextMaxId = result.getNextCursor(); - moreAvailable = result.hasNextPage(); + moreAvailable = result.getHasNextPage(); if (fetchListener != null) { fetchListener.onResult(result.getFeedModels()); } diff --git a/app/src/main/java/awais/instagrabber/dialogs/MediaPickerBottomDialogFragment.java b/app/src/main/java/awais/instagrabber/dialogs/MediaPickerBottomDialogFragment.java deleted file mode 100644 index d36cb9dd..00000000 --- a/app/src/main/java/awais/instagrabber/dialogs/MediaPickerBottomDialogFragment.java +++ /dev/null @@ -1,194 +0,0 @@ -package awais.instagrabber.dialogs; - -import android.app.Dialog; -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.ViewModelProvider; -import androidx.recyclerview.widget.GridLayoutManager; - -import com.google.android.material.bottomsheet.BottomSheetDialog; -import com.google.android.material.bottomsheet.BottomSheetDialogFragment; - -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import awais.instagrabber.R; -import awais.instagrabber.adapters.MediaItemsAdapter; -import awais.instagrabber.databinding.LayoutMediaPickerBinding; -import awais.instagrabber.utils.MediaController; -import awais.instagrabber.utils.PermissionUtils; -import awais.instagrabber.utils.TextUtils; -import awais.instagrabber.viewmodels.MediaPickerViewModel; - -public class MediaPickerBottomDialogFragment extends BottomSheetDialogFragment { - private static final String TAG = MediaPickerBottomDialogFragment.class.getSimpleName(); - private static final int ATTACH_MEDIA_REQUEST_CODE = 100; - // private static final int HEIGHT_PIXELS = Utils.displayMetrics.heightPixels; - - private LayoutMediaPickerBinding binding; - private MediaPickerViewModel viewModel; - private MediaItemsAdapter mediaItemsAdapter; - private OnSelectListener onSelectListener; - // private int actionBarHeight; - // private int statusBarHeight; - - // private final BottomSheetBehavior.BottomSheetCallback bottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() { - // @Override - // public void onStateChanged(@NonNull final View bottomSheet, final int newState) { - // - // } - // - // @Override - // public void onSlide(@NonNull final View bottomSheet, final float slideOffset) { - // // Log.d(TAG, "onSlide: " + slideOffset); - // final float sheetHeight = HEIGHT_PIXELS * slideOffset; - // final Context context = getContext(); - // if (context == null) return; - // final float remaining = HEIGHT_PIXELS - sheetHeight - statusBarHeight; - // if (remaining <= actionBarHeight) { - // final ViewGroup.LayoutParams layoutParams = binding.toolbar.getLayoutParams(); - // layoutParams.height = (int) (actionBarHeight - remaining); - // binding.toolbar.requestLayout(); - // } - // } - // }; - - public static MediaPickerBottomDialogFragment newInstance() { - final Bundle args = new Bundle(); - final MediaPickerBottomDialogFragment fragment = new MediaPickerBottomDialogFragment(); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onCreate(@Nullable final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setStyle(DialogFragment.STYLE_NORMAL, R.style.ThemeOverlay_Rounded_BottomSheetDialog); - } - - @Nullable - @Override - public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { - binding = LayoutMediaPickerBinding.inflate(inflater, container, false); - viewModel = new ViewModelProvider(this).get(MediaPickerViewModel.class); - // final Context context = getContext(); - // if (context == null) return binding.getRoot(); - // actionBarHeight = Utils.getActionBarHeight(context); - // statusBarHeight = Utils.getStatusBarHeight(context); - return binding.getRoot(); - } - - @Override - public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { - init(); - // final Dialog dialog = getDialog(); - // if (dialog == null) return; - // dialog.setOnShowListener(dialog1 -> { - // final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog; - // final View bottomSheetInternal = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); - // if (bottomSheetInternal == null) return; - // final BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheetInternal); - // behavior.setState(BottomSheetBehavior.STATE_EXPANDED); - // }); - } - - @Override - public void onStart() { - super.onStart(); - final Dialog dialog = getDialog(); - if (dialog == null) return; - final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog; - final View bottomSheetInternal = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); - if (bottomSheetInternal == null) return; - bottomSheetInternal.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; - bottomSheetInternal.requestLayout(); - // final BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheetInternal); - // behavior.addBottomSheetCallback(bottomSheetCallback); - } - - @Override - public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { - if (requestCode == ATTACH_MEDIA_REQUEST_CODE) { - final Context context = getContext(); - if (context == null) return; - final boolean hasAttachMediaPerms = PermissionUtils.hasAttachMediaPerms(context); - if (hasAttachMediaPerms) { - viewModel.loadMedia(context); - } - } - } - - private void init() { - setupList(); - setupAlbumPicker(); - final Context context = getContext(); - if (context == null) return; - if (!PermissionUtils.hasAttachMediaPerms(context)) { - PermissionUtils.requestAttachMediaPerms(this, ATTACH_MEDIA_REQUEST_CODE); - return; - } - viewModel.loadMedia(context); - } - - private void setupList() { - final Context context = getContext(); - if (context == null) return; - binding.mediaList.setLayoutManager(new GridLayoutManager(context, 3)); - binding.mediaList.setHasFixedSize(true); - mediaItemsAdapter = new MediaItemsAdapter(entry -> { - if (onSelectListener == null) return; - onSelectListener.onSelect(entry); - }); - binding.mediaList.setAdapter(mediaItemsAdapter); - } - - private void setupAlbumPicker() { - final Context context = getContext(); - if (context == null) return; - final ArrayAdapter albumPickerAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item); - albumPickerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - binding.albumPicker.setAdapter(albumPickerAdapter); - binding.albumPicker.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(final AdapterView parent, final View view, final int position, final long id) { - final List albumEntries = viewModel.getAllAlbums().getValue(); - if (albumEntries == null) return; - final MediaController.AlbumEntry albumEntry = albumEntries.get(position); - mediaItemsAdapter.submitList(albumEntry.photos, () -> binding.mediaList.scrollToPosition(0)); - } - - @Override - public void onNothingSelected(final AdapterView parent) { - mediaItemsAdapter.submitList(Collections.emptyList()); - } - }); - viewModel.getAllAlbums().observe(getViewLifecycleOwner(), albums -> { - albumPickerAdapter.clear(); - albumPickerAdapter.addAll(albums.stream() - .map(albumEntry -> albumEntry.bucketName) - .filter(name -> !TextUtils.isEmpty(name)) - .collect(Collectors.toList())); - albumPickerAdapter.notifyDataSetChanged(); - if (albums.isEmpty()) return; - mediaItemsAdapter.submitList(albums.get(0).photos); - }); - } - - public void setOnSelectListener(final OnSelectListener onSelectListener) { - this.onSelectListener = onSelectListener; - } - - public interface OnSelectListener { - void onSelect(MediaController.MediaEntry entry); - } -} diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 8948b831..cd91bf96 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -2,7 +2,6 @@ package awais.instagrabber.fragments; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Rect; @@ -93,8 +92,8 @@ import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.repositories.responses.Caption; import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Media; -import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.MediaCandidate; +import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.NullSafePair; @@ -152,7 +151,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme if (context != null) { Toast.makeText(context, R.string.sending, Toast.LENGTH_SHORT).show(); } - viewModel.shareDm((RankedRecipient) result); + viewModel.shareDm((RankedRecipient) result, sliderPosition); } else if ((result instanceof Set)) { try { // Log.d(TAG, "result: " + result); @@ -161,7 +160,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme Toast.makeText(context, R.string.sending, Toast.LENGTH_SHORT).show(); } //noinspection unchecked - viewModel.shareDm((Set) result); + viewModel.shareDm((Set) result, sliderPosition); } catch (Exception e) { Log.e(TAG, "share: ", e); } @@ -294,7 +293,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme return; } final Media media = (Media) feedModelSerializable; - if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) { + if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER && sliderPosition == -1) { sliderPosition = arguments.getInt(ARG_SLIDER_POSITION, 0); } viewModel.setMedia(media); @@ -1039,6 +1038,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme final String text = "1/" + carouselMedia.size(); binding.mediaCounter.setText(text); sliderItemsAdapter.submitList(media.getCarouselMedia()); + sliderParent.setCurrentItem(sliderPosition); } private void pauseSliderPlayer() { diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java index 8bdfd548..77ef289a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java @@ -38,9 +38,9 @@ import awais.instagrabber.adapters.HighlightStoriesListAdapter.OnHighlightStoryC import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.FragmentStoryListViewerBinding; import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections; -import awais.instagrabber.models.FeedStoryModel; -import awais.instagrabber.models.HighlightModel; import awais.instagrabber.repositories.requests.StoryViewerOptions; +import awais.instagrabber.repositories.responses.stories.ArchiveResponse; +import awais.instagrabber.repositories.responses.stories.Story; import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.CoroutineUtilsKt; import awais.instagrabber.utils.TextUtils; @@ -48,7 +48,6 @@ import awais.instagrabber.viewmodels.ArchivesViewModel; import awais.instagrabber.viewmodels.FeedStoriesViewModel; import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.StoriesRepository; -import awais.instagrabber.webservices.StoriesRepository.ArchiveFetchResponse; import kotlinx.coroutines.Dispatchers; public final class StoryListViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { @@ -69,12 +68,12 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr private final OnFeedStoryClickListener clickListener = new OnFeedStoryClickListener() { @Override - public void onFeedStoryClick(final FeedStoryModel model) { + public void onFeedStoryClick(final Story model) { if (model == null) return; - final List feedStoryModels = feedStoriesViewModel.getList().getValue(); + final List feedStoryModels = feedStoriesViewModel.getList().getValue(); if (feedStoryModels == null) return; final int position = Iterables.indexOf(feedStoryModels, feedStoryModel -> feedStoryModel != null - && Objects.equals(feedStoryModel.getStoryMediaId(), model.getStoryMediaId())); + && Objects.equals(feedStoryModel.getId(), model.getId())); final NavDirections action = StoryListViewerFragmentDirections .actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forFeedStoryPosition(position)); NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action); @@ -88,7 +87,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr private final OnHighlightStoryClickListener archiveClickListener = new OnHighlightStoryClickListener() { @Override - public void onHighlightClick(final HighlightModel model, final int position) { + public void onHighlightClick(final Story model, final int position) { if (model == null) return; final NavDirections action = StoryListViewerFragmentDirections .actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forStoryArchive(position)); @@ -101,9 +100,9 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr } }; - private final ServiceCallback cb = new ServiceCallback() { + private final ServiceCallback cb = new ServiceCallback() { @Override - public void onSuccess(final ArchiveFetchResponse result) { + public void onSuccess(final ArchiveResponse result) { binding.swipeRefreshLayout.setRefreshing(false); if (result == null) { try { @@ -111,10 +110,10 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr Toast.makeText(context, R.string.empty_list, Toast.LENGTH_SHORT).show(); } catch (Exception ignored) {} } else { - endCursor = result.getNextCursor(); - final List models = archivesViewModel.getList().getValue(); - final List modelsCopy = models == null ? new ArrayList<>() : new ArrayList<>(models); - modelsCopy.addAll(result.getResult()); + endCursor = result.getMaxId(); + final List models = archivesViewModel.getList().getValue(); + final List modelsCopy = models == null ? new ArrayList<>() : new ArrayList<>(models); + modelsCopy.addAll(result.getItems()); archivesViewModel.getList().postValue(modelsCopy); } } @@ -236,7 +235,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr binding.swipeRefreshLayout.setRefreshing(true); if (type.equals("feed") && firstRefresh) { binding.swipeRefreshLayout.setRefreshing(false); - final List value = feedStoriesViewModel.getList().getValue(); + final List value = feedStoriesViewModel.getList().getValue(); if (value != null) { adapter.submitList(value); } @@ -250,9 +249,9 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr return; } //noinspection unchecked - feedStoriesViewModel.getList().postValue((List) feedStoryModels); + feedStoriesViewModel.getList().postValue((List) feedStoryModels); //noinspection unchecked - adapter.submitList((List) feedStoryModels); + adapter.submitList((List) feedStoryModels); binding.swipeRefreshLayout.setRefreshing(false); }), Dispatchers.getIO()) ); diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 4a1334d1..0786649e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -72,8 +72,6 @@ import awais.instagrabber.databinding.FragmentStoryViewerBinding; import awais.instagrabber.fragments.main.ProfileFragmentDirections; import awais.instagrabber.fragments.settings.PreferenceKeys; import awais.instagrabber.interfaces.SwipeEvent; -import awais.instagrabber.models.FeedStoryModel; -import awais.instagrabber.models.HighlightModel; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.stickers.PollModel; @@ -84,6 +82,8 @@ import awais.instagrabber.models.stickers.SwipeUpModel; import awais.instagrabber.repositories.requests.StoryViewerOptions; import awais.instagrabber.repositories.requests.StoryViewerOptions.Type; import awais.instagrabber.repositories.requests.directmessages.ThreadIdsOrUserIds; +import awais.instagrabber.repositories.responses.stories.Broadcast; +import awais.instagrabber.repositories.responses.stories.Story; import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; @@ -122,6 +122,7 @@ public class StoryViewerFragment extends Fragment { private StoriesRepository storiesRepository; private MediaRepository mediaRepository; private StoryModel currentStory; + private Broadcast live; private int slidePos; private int lastSlidePos; private String url; @@ -714,7 +715,7 @@ public class StoryViewerFragment extends Fragment { private void resetView() { final Context context = getContext(); if (context == null) return; - StoryModel live = null; + live = null; slidePos = 0; lastSlidePos = 0; if (menuDownload != null) menuDownload.setVisible(false); @@ -731,12 +732,12 @@ public class StoryViewerFragment extends Fragment { switch (type) { case HIGHLIGHT: { final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel; - final List models = highlightsViewModel.getList().getValue(); + final List models = highlightsViewModel.getList().getValue(); if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0) { Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); return; } - final HighlightModel model = models.get(currentFeedStoryIndex); + final Story model = models.get(currentFeedStoryIndex); currentStoryMediaId = model.getId(); fetchOptions = StoryViewerOptions.forHighlight(model.getId()); highlightTitle = model.getTitle(); @@ -744,25 +745,23 @@ public class StoryViewerFragment extends Fragment { } case FEED_STORY_POSITION: { final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel; - final List models = feedStoriesViewModel.getList().getValue(); + final List models = feedStoriesViewModel.getList().getValue(); if (models == null || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0) return; - final FeedStoryModel model = models.get(currentFeedStoryIndex); - currentStoryMediaId = model.getStoryMediaId(); - currentStoryUsername = model.getProfileModel().getUsername(); + final Story model = models.get(currentFeedStoryIndex); + currentStoryMediaId = model.getId(); + currentStoryUsername = model.getUser().getUsername(); fetchOptions = StoryViewerOptions.forUser(Long.parseLong(currentStoryMediaId), currentStoryUsername); - if (model.isLive()) { - live = model.getFirstStoryModel(); - } + live = model.getBroadcast(); break; } case STORY_ARCHIVE: { final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel; - final List models = archivesViewModel.getList().getValue(); + final List models = archivesViewModel.getList().getValue(); if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0) { Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); return; } - final HighlightModel model = models.get(currentFeedStoryIndex); + final Story model = models.get(currentFeedStoryIndex); currentStoryMediaId = parseStoryMediaId(model.getId()); currentStoryUsername = model.getTitle(); fetchOptions = StoryViewerOptions.forStoryArchive(model.getId()); @@ -800,6 +799,11 @@ public class StoryViewerFragment extends Fragment { return; } if (currentStoryMediaId == null) return; + if (live != null) { + currentStory = null; + refreshLive(); + return; + } final ServiceCallback> storyCallback = new ServiceCallback>() { @Override public void onSuccess(final List storyModels) { @@ -826,10 +830,6 @@ public class StoryViewerFragment extends Fragment { Log.e(TAG, "Error", t); } }; - if (live != null) { - storyCallback.onSuccess(Collections.singletonList(live)); - return; - } storiesRepository.getUserStory( fetchOptions, CoroutineUtilsKt.getContinuation((storyModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { @@ -861,6 +861,30 @@ public class StoryViewerFragment extends Fragment { } } + private synchronized void refreshLive() { + binding.storiesList.setVisibility(View.INVISIBLE); + binding.viewStoryPost.setVisibility(View.GONE); + binding.spotify.setVisibility(View.GONE); + binding.poll.setVisibility(View.GONE); + binding.answer.setVisibility(View.GONE); + binding.mention.setVisibility(View.GONE); + binding.quiz.setVisibility(View.GONE); + binding.slider.setVisibility(View.GONE); + lastSlidePos = slidePos; + releasePlayer(); + url = live.getDashPlaybackUrl(); + setupLive(); + final ActionBar actionBar = fragmentActivity.getSupportActionBar(); + actionBarSubtitle = TextUtils.epochSecondToString(live.getPublishedTime()); + if (actionBar != null) { + try { + actionBar.setSubtitle(actionBarSubtitle); + } catch (Exception e) { + Log.e(TAG, "refreshLive: ", e); + } + } + } + private synchronized void refreshStory() { if (binding.storiesList.getVisibility() == View.VISIBLE) { final List storyModels = storiesViewModel.getList().getValue(); @@ -883,42 +907,40 @@ public class StoryViewerFragment extends Fragment { url = itemType == MediaItemType.MEDIA_TYPE_IMAGE ? currentStory.getStoryUrl() : currentStory.getVideoUrl(); - if (itemType != MediaItemType.MEDIA_TYPE_LIVE) { - final String shortCode = currentStory.getTappableShortCode(); - binding.viewStoryPost.setVisibility(shortCode != null ? View.VISIBLE : View.GONE); - binding.viewStoryPost.setTag(shortCode); + final String shortCode = currentStory.getTappableShortCode(); + binding.viewStoryPost.setVisibility(shortCode != null ? View.VISIBLE : View.GONE); + binding.viewStoryPost.setTag(shortCode); - final String spotify = currentStory.getSpotify(); - binding.spotify.setVisibility(spotify != null ? View.VISIBLE : View.GONE); - binding.spotify.setTag(spotify); + final String spotify = currentStory.getSpotify(); + binding.spotify.setVisibility(spotify != null ? View.VISIBLE : View.GONE); + binding.spotify.setTag(spotify); - poll = currentStory.getPoll(); - binding.poll.setVisibility(poll != null ? View.VISIBLE : View.GONE); - binding.poll.setTag(poll); + poll = currentStory.getPoll(); + binding.poll.setVisibility(poll != null ? View.VISIBLE : View.GONE); + binding.poll.setTag(poll); - question = currentStory.getQuestion(); - binding.answer.setVisibility((question != null) ? View.VISIBLE : View.GONE); - binding.answer.setTag(question); + question = currentStory.getQuestion(); + binding.answer.setVisibility((question != null) ? View.VISIBLE : View.GONE); + binding.answer.setTag(question); - mentions = currentStory.getMentions(); - binding.mention.setVisibility((mentions != null && mentions.length > 0) ? View.VISIBLE : View.GONE); - binding.mention.setTag(mentions); + mentions = currentStory.getMentions(); + binding.mention.setVisibility((mentions != null && mentions.length > 0) ? View.VISIBLE : View.GONE); + binding.mention.setTag(mentions); - quiz = currentStory.getQuiz(); - binding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE); - binding.quiz.setTag(quiz); + quiz = currentStory.getQuiz(); + binding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE); + binding.quiz.setTag(quiz); - slider = currentStory.getSlider(); - binding.slider.setVisibility(slider != null ? View.VISIBLE : View.GONE); - binding.slider.setTag(slider); + slider = currentStory.getSlider(); + binding.slider.setVisibility(slider != null ? View.VISIBLE : View.GONE); + binding.slider.setTag(slider); - final SwipeUpModel swipeUp = currentStory.getSwipeUp(); - if (swipeUp != null) { - binding.swipeUp.setVisibility(View.VISIBLE); - binding.swipeUp.setText(swipeUp.getText()); - binding.swipeUp.setTag(swipeUp.getUrl()); - } else binding.swipeUp.setVisibility(View.GONE); - } + final SwipeUpModel swipeUp = currentStory.getSwipeUp(); + if (swipeUp != null) { + binding.swipeUp.setVisibility(View.VISIBLE); + binding.swipeUp.setText(swipeUp.getText()); + binding.swipeUp.setTag(swipeUp.getUrl()); + } else binding.swipeUp.setVisibility(View.GONE); releasePlayer(); final Type type = options.getType(); @@ -930,7 +952,6 @@ public class StoryViewerFragment extends Fragment { } } if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo(); - else if (itemType == MediaItemType.MEDIA_TYPE_LIVE) setupLive(); else setupImage(); final ActionBar actionBar = fragmentActivity.getSupportActionBar(); @@ -1202,14 +1223,14 @@ public class StoryViewerFragment extends Fragment { return; } if (settingsHelper.getBoolean(MARK_AS_SEEN) - && oldFeedStory instanceof FeedStoryModel + && oldFeedStory instanceof Story && viewModel instanceof FeedStoriesViewModel) { final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel; - final FeedStoryModel oldFeedStoryModel = (FeedStoryModel) oldFeedStory; - if (!oldFeedStoryModel.isFullyRead()) { - oldFeedStoryModel.setFullyRead(true); - final List models = feedStoriesViewModel.getList().getValue(); - final List modelsCopy = models == null ? new ArrayList<>() : new ArrayList<>(models); + final Story oldFeedStoryModel = (Story) oldFeedStory; + if (oldFeedStoryModel.getSeen() == null || !oldFeedStoryModel.getSeen().equals(oldFeedStoryModel.getLatestReelMedia())) { + oldFeedStoryModel.setSeen(oldFeedStoryModel.getLatestReelMedia()); + final List models = feedStoriesViewModel.getList().getValue(); + final List modelsCopy = models == null ? new ArrayList<>() : new ArrayList<>(models); modelsCopy.set(currentFeedStoryIndex, oldFeedStoryModel); feedStoriesViewModel.getList().postValue(models); } diff --git a/app/src/main/java/awais/instagrabber/fragments/comments/RepliesFragment.java b/app/src/main/java/awais/instagrabber/fragments/comments/RepliesFragment.java index 67c0f95c..e799e673 100644 --- a/app/src/main/java/awais/instagrabber/fragments/comments/RepliesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/comments/RepliesFragment.java @@ -174,7 +174,7 @@ public class RepliesFragment extends Fragment { } private void setupToolbar() { - binding.toolbar.setTitle("Replies"); + binding.toolbar.setTitle(R.string.title_replies); binding.toolbar.setNavigationIcon(R.drawable.ic_round_arrow_back_24); binding.toolbar.setNavigationOnClickListener(v -> { final FragmentManager fragmentManager = getParentFragmentManager(); @@ -187,7 +187,16 @@ public class RepliesFragment extends Fragment { if (context == null) return; commentsAdapter = new CommentsAdapter(currentUserId, true, - Helper.getCommentCallback(context, getViewLifecycleOwner(), getNavController(), viewModel, null)); + Helper.getCommentCallback(context, + getViewLifecycleOwner(), + getNavController(), + viewModel, + (comment, focusInput) -> { + viewModel.setReplyTo(comment); + binding.commentText.setText(String.format("@%s ", comment.getUser().getUsername())); + if (focusInput) Utils.showKeyboard(binding.commentText); + return null; + })); binding.comments.setAdapter(commentsAdapter); final Resource> listResource = viewModel.getReplyList().getValue(); commentsAdapter.submitList(listResource != null ? listResource.data : Collections.emptyList()); diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java index 72a8568b..b9aa03ef 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -8,7 +8,6 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -32,7 +31,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.view.menu.ActionMenuItemView; -import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsAnimationCompat; import androidx.core.view.WindowInsetsAnimationControlListenerCompat; @@ -97,7 +95,6 @@ import awais.instagrabber.customviews.helpers.TranslateDeferringInsetsAnimationC import awais.instagrabber.databinding.FragmentDirectMessagesThreadBinding; import awais.instagrabber.dialogs.DirectItemReactionDialogFragment; import awais.instagrabber.dialogs.GifPickerBottomDialogFragment; -import awais.instagrabber.dialogs.MediaPickerBottomDialogFragment; import awais.instagrabber.fragments.PostViewV2Fragment; import awais.instagrabber.fragments.UserSearchFragment; import awais.instagrabber.fragments.UserSearchFragmentDirections; @@ -130,6 +127,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact private static final String TAG = DirectMessageThreadFragment.class.getSimpleName(); private static final int AUDIO_RECORD_PERM_REQUEST_CODE = 1000; private static final int CAMERA_REQUEST_CODE = 200; + private static final int FILE_PICKER_REQUEST_CODE = 500; private static final String TRANSLATION_Y = "translationY"; private DirectItemsAdapter itemsAdapter; @@ -221,7 +219,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact } @Override - public void onMediaClick(final Media media) { + public void onMediaClick(final Media media, final int index) { if (media.isReelMedia()) { final String pk = media.getPk(); try { @@ -240,6 +238,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact final NavController navController = NavHostFragment.findNavController(DirectMessageThreadFragment.this); final Bundle bundle = new Bundle(); bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, index); try { navController.navigate(R.id.action_global_post_view, bundle); } catch (Exception e) { @@ -474,6 +473,24 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); + if (requestCode == FILE_PICKER_REQUEST_CODE && resultCode == Activity.RESULT_OK) { + if (data == null || data.getData() == null) { + Log.w(TAG, "data is null!"); + return; + } + final Context context = getContext(); + if (context == null) { + Log.w(TAG, "conetxt is null!"); + return; + } + final Uri uri = data.getData(); + final String mimeType = Utils.getMimeType(uri, context.getContentResolver()); + if (mimeType.startsWith("image")) { + navigateToImageEditFragment(uri); + return; + } + handleSentMessage(viewModel.sendUri(uri)); + } if (requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK) { if (data == null || data.getData() == null) { Log.w(TAG, "data is null!"); @@ -1109,17 +1126,15 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact setupInsetsCallback(); setupEmojiPicker(); binding.gallery.setOnClickListener(v -> { - final MediaPickerBottomDialogFragment mediaPicker = MediaPickerBottomDialogFragment.newInstance(); - mediaPicker.setOnSelectListener(entry -> { - mediaPicker.dismiss(); - if (!isAdded()) return; - if (!entry.isVideo) { - navigateToImageEditFragment(entry.path); - return; - } - handleSentMessage(viewModel.sendUri(entry)); + final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{ + "image/*", + "video/mp4" }); - mediaPicker.show(getChildFragmentManager(), "MediaPicker"); + startActivityForResult(intent, FILE_PICKER_REQUEST_CODE); }); binding.gif.setOnClickListener(v -> { final GifPickerBottomDialogFragment gifPicker = GifPickerBottomDialogFragment.newInstance(); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index 25a354ea..ae4e9b6b 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -1,7 +1,6 @@ package awais.instagrabber.fragments.main; import android.content.Context; -import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.util.Log; @@ -12,7 +11,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedDispatcher; @@ -43,10 +41,10 @@ import awais.instagrabber.customviews.PrimaryActionModeCallback; import awais.instagrabber.databinding.FragmentFeedBinding; import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; import awais.instagrabber.fragments.PostViewV2Fragment; -import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.repositories.requests.StoryViewerOptions; import awais.instagrabber.repositories.responses.Media; +import awais.instagrabber.repositories.responses.stories.Story; import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CoroutineUtilsKt; @@ -76,7 +74,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre private final FeedStoriesAdapter feedStoriesAdapter = new FeedStoriesAdapter( new FeedStoriesAdapter.OnFeedStoryClickListener() { @Override - public void onFeedStoryClick(FeedStoryModel model, int position) { + public void onFeedStoryClick(Story model, int position) { final NavController navController = NavHostFragment.findNavController(FeedFragment.this); if (isSafeToNavigate(navController)) { final NavDirections action = FeedFragmentDirections @@ -86,8 +84,8 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre } @Override - public void onFeedStoryLongClick(FeedStoryModel model, int position) { - navigateToProfile("@" + model.getProfileModel().getUsername()); + public void onFeedStoryLongClick(Story model, int position) { + navigateToProfile("@" + model.getUser().getUsername()); } } ); @@ -399,9 +397,9 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre } storiesFetching = false; //noinspection unchecked - feedStoriesViewModel.getList().postValue((List) feedStoryModels); + feedStoriesViewModel.getList().postValue((List) feedStoryModels); //noinspection unchecked - feedStoriesAdapter.submitList((List) feedStoryModels); + feedStoriesAdapter.submitList((List) feedStoryModels); if (storyListMenu != null) storyListMenu.setVisible(true); updateSwipeRefreshState(); }), Dispatchers.getIO()) diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java index 5a2a2de0..d79974c5 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java @@ -23,7 +23,6 @@ import java.nio.charset.StandardCharsets; import awais.instagrabber.R; import awais.instagrabber.dialogs.ConfirmDialogFragment; import awais.instagrabber.utils.AppExecutors; -import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; @@ -111,7 +110,7 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { R.string.error, "com.android.externalstorage.documents".equals(data.getData().getAuthority()) ? "Please report this error to the developers:\n\n" + sw.toString() - : getString(R.string.dir_select_no_download_folder), + : getString(R.string.dir_select_no_download_folder, data.getData().getAuthority()), R.string.ok, 0, 0 diff --git a/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt b/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt index 2878e5fc..34df42d4 100644 --- a/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt +++ b/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt @@ -70,20 +70,21 @@ object DirectMessagesManager { suspend fun createThread(userPk: Long): DirectThread = directMessagesRepository.createThread(csrfToken, viewerId, deviceUuid, listOf(userPk), null) - fun sendMedia(recipient: RankedRecipient, mediaId: String, itemType: BroadcastItemType, scope: CoroutineScope) { - sendMedia(setOf(recipient), mediaId, itemType, scope) + fun sendMedia(recipient: RankedRecipient, mediaId: String, secondId: String?, itemType: BroadcastItemType, scope: CoroutineScope) { + sendMedia(setOf(recipient), mediaId, secondId, itemType, scope) } fun sendMedia( recipients: Set, mediaId: String, + secondId: String?, itemType: BroadcastItemType, scope: CoroutineScope, ) { val threadIds = recipients.mapNotNull { it.thread?.threadId } val userIdsTemp = recipients.mapNotNull { it.user?.pk } val userIds = userIdsTemp.map { listOf(it.toString(10)) } - sendMedia(threadIds, userIds, mediaId, itemType, scope) { + sendMedia(threadIds, userIds, mediaId, secondId, itemType, scope) { inboxManager.refresh(scope) } } @@ -92,6 +93,7 @@ object DirectMessagesManager { threadIds: List, userIds: List>, mediaId: String, + secondId: String?, itemType: BroadcastItemType, scope: CoroutineScope, callback: (() -> Unit)?, @@ -107,7 +109,8 @@ object DirectMessagesManager { deviceUuid, UUID.randomUUID().toString(), ThreadIdsOrUserIds(threadIds, userIds), - mediaId + mediaId, + secondId ) if (itemType == BroadcastItemType.PROFILE) directMessagesRepository.broadcastProfile( diff --git a/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt b/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt index b1cf4bf6..b99fe3b3 100644 --- a/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt +++ b/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt @@ -39,7 +39,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import retrofit2.Call -import java.io.File import java.io.IOException import java.net.HttpURLConnection import java.util.* @@ -368,17 +367,6 @@ class ThreadManager( return data } - fun sendUri(entry: MediaController.MediaEntry, scope: CoroutineScope): LiveData> { - val data = MutableLiveData>() - val uri = Uri.fromFile(File(entry.path)) - if (!entry.isVideo) { - sendPhoto(data, uri, entry.width, entry.height, scope) - return data - } - sendVideo(data, uri, entry.size, entry.duration, entry.width, entry.height, scope) - return data - } - fun sendUri(uri: Uri, scope: CoroutineScope): LiveData> { val data = MutableLiveData>() val mimeType = Utils.getMimeType(uri, contentResolver) diff --git a/app/src/main/java/awais/instagrabber/models/FeedStoryModel.kt b/app/src/main/java/awais/instagrabber/models/FeedStoryModel.kt deleted file mode 100644 index 8040b36a..00000000 --- a/app/src/main/java/awais/instagrabber/models/FeedStoryModel.kt +++ /dev/null @@ -1,20 +0,0 @@ -package awais.instagrabber.models - -import awais.instagrabber.repositories.responses.User -import awais.instagrabber.utils.TextUtils -import java.io.Serializable -import java.util.* - -data class FeedStoryModel( - val storyMediaId: String, - val profileModel: User, - var isFullyRead: Boolean, - val timestamp: Long, - val firstStoryModel: StoryModel?, - val mediaCount: Int, - val isLive: Boolean, - val isBestie: Boolean -) : Serializable { - val dateTime: String - get() = TextUtils.epochSecondToString(timestamp) -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/models/HighlightModel.kt b/app/src/main/java/awais/instagrabber/models/HighlightModel.kt deleted file mode 100644 index 73ac96eb..00000000 --- a/app/src/main/java/awais/instagrabber/models/HighlightModel.kt +++ /dev/null @@ -1,14 +0,0 @@ -package awais.instagrabber.models - -import awais.instagrabber.utils.TextUtils - -data class HighlightModel( - val title: String? = null, - val id: String = "", - val thumbnailUrl: String = "", - val timestamp: Long = 0, - val mediaCount: Int = 0, -) { - val dateTime: String - get() = TextUtils.epochSecondToString(timestamp) -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt b/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt index 51f271f4..4d217fef 100644 --- a/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt +++ b/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt @@ -1,6 +1,8 @@ package awais.instagrabber.repositories -import awais.instagrabber.repositories.responses.StoryStickerResponse +import awais.instagrabber.repositories.responses.stories.ArchiveResponse +import awais.instagrabber.repositories.responses.stories.ReelsTrayResponse +import awais.instagrabber.repositories.responses.stories.StoryStickerResponse import retrofit2.http.* interface StoriesService { @@ -9,13 +11,13 @@ interface StoriesService { suspend fun fetch(@Path("mediaId") mediaId: Long): String @GET("/api/v1/feed/reels_tray/") - suspend fun getFeedStories(): String + suspend fun getFeedStories(): ReelsTrayResponse? @GET("/api/v1/highlights/{uid}/highlights_tray/") - suspend fun fetchHighlights(@Path("uid") uid: Long): String + suspend fun fetchHighlights(@Path("uid") uid: Long): ReelsTrayResponse? @GET("/api/v1/archive/reel/day_shells/") - suspend fun fetchArchive(@QueryMap queryParams: Map): String + suspend fun fetchArchive(@QueryMap queryParams: Map): ArchiveResponse? @GET suspend fun getUserStory(@Url url: String): String diff --git a/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/MediaShareBroadcastOptions.kt b/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/MediaShareBroadcastOptions.kt index 89b74998..c83ef73b 100644 --- a/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/MediaShareBroadcastOptions.kt +++ b/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/MediaShareBroadcastOptions.kt @@ -5,12 +5,16 @@ import awais.instagrabber.models.enums.BroadcastItemType class MediaShareBroadcastOptions( clientContext: String, threadIdsOrUserIds: ThreadIdsOrUserIds, - val mediaId: String + val mediaId: String, + val childId: String? ) : BroadcastOptions( clientContext, threadIdsOrUserIds, BroadcastItemType.MEDIA_SHARE ) { override val formMap: Map - get() = mapOf("media_id" to mediaId) + get() = listOfNotNull( + "media_id" to mediaId, + if (childId != null) "carousel_share_child_media_id" to childId else null + ).toMap() } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/HdProfilePicUrlInfo.java b/app/src/main/java/awais/instagrabber/repositories/responses/HdProfilePicUrlInfo.java deleted file mode 100644 index 86787880..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/HdProfilePicUrlInfo.java +++ /dev/null @@ -1,16 +0,0 @@ -package awais.instagrabber.repositories.responses; - -public class HdProfilePicUrlInfo { - private final String url; - private final int width, height; - - public HdProfilePicUrlInfo(final String url, final int width, final int height) { - this.url = url; - this.width = width; - this.height = height; - } - - public String getUrl() { - return url; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/ImageUrl.kt b/app/src/main/java/awais/instagrabber/repositories/responses/ImageUrl.kt new file mode 100644 index 00000000..0c2362d1 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/ImageUrl.kt @@ -0,0 +1,5 @@ +package awais.instagrabber.repositories.responses + +import java.io.Serializable + +data class ImageUrl(val url: String, private val width: Int, private val height: Int) : Serializable \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/ImageVersions2.java b/app/src/main/java/awais/instagrabber/repositories/responses/ImageVersions2.java deleted file mode 100644 index d71d8a00..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/ImageVersions2.java +++ /dev/null @@ -1,30 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.io.Serializable; -import java.util.List; -import java.util.Objects; - -public class ImageVersions2 implements Serializable { - private final List candidates; - - public ImageVersions2(final List candidates) { - this.candidates = candidates; - } - - public List getCandidates() { - return candidates; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final ImageVersions2 that = (ImageVersions2) o; - return Objects.equals(candidates, that.candidates); - } - - @Override - public int hashCode() { - return Objects.hash(candidates); - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/ImageVersions2.kt b/app/src/main/java/awais/instagrabber/repositories/responses/ImageVersions2.kt new file mode 100644 index 00000000..6bed8a10 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/ImageVersions2.kt @@ -0,0 +1,5 @@ +package awais.instagrabber.repositories.responses + +import java.io.Serializable + +data class ImageVersions2(val candidates: List) : Serializable \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/LikersResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/LikersResponse.java deleted file mode 100644 index da750b04..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/LikersResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.util.List; - -public class LikersResponse { - private final List users; - private final long userCount; - private final String status; - - public LikersResponse(final List users, final long userCount, final String status) { - this.users = users; - this.userCount = userCount; - this.status = status; - } - - public List getUsers() { - return users; - } - - public long getUserCount() { - return userCount; - } - - public String getStatus() { - return status; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/LikersResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/LikersResponse.kt new file mode 100644 index 00000000..8ea2aeb6 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/LikersResponse.kt @@ -0,0 +1,3 @@ +package awais.instagrabber.repositories.responses + +data class LikersResponse(val users: List, val userCount: Long, val status: String) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Media.kt b/app/src/main/java/awais/instagrabber/repositories/responses/Media.kt index 03d8aba2..d06e368d 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/Media.kt +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Media.kt @@ -4,7 +4,6 @@ import awais.instagrabber.models.enums.MediaItemType import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator import awais.instagrabber.utils.TextUtils import java.io.Serializable -import java.util.* data class Media( val pk: String? = null, @@ -38,7 +37,8 @@ data class Media( var isSidecarChild: Boolean = false, var hasViewerSaved: Boolean = false, private val injected: Map? = null, - val endOfFeedDemarcator: EndOfFeedDemarcator? = null + val endOfFeedDemarcator: EndOfFeedDemarcator? = null, + val carouselShareChildMediaId: String? = null // which specific child should dm show first ) : Serializable { private var dateString: String? = null diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/MediaCandidate.java b/app/src/main/java/awais/instagrabber/repositories/responses/MediaCandidate.java deleted file mode 100644 index 3a243497..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/MediaCandidate.java +++ /dev/null @@ -1,43 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.io.Serializable; -import java.util.Objects; - -public class MediaCandidate implements Serializable { - private final int width; - private final int height; - private final String url; - - public MediaCandidate(final int width, final int height, final String url) { - this.width = width; - this.height = height; - this.url = url; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public String getUrl() { - return url; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final MediaCandidate that = (MediaCandidate) o; - return width == that.width && - height == that.height && - Objects.equals(url, that.url); - } - - @Override - public int hashCode() { - return Objects.hash(width, height, url); - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/MediaCandidate.kt b/app/src/main/java/awais/instagrabber/repositories/responses/MediaCandidate.kt new file mode 100644 index 00000000..5de5ea88 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/MediaCandidate.kt @@ -0,0 +1,5 @@ +package awais.instagrabber.repositories.responses + +import java.io.Serializable + +data class MediaCandidate(val width: Int, val height: Int, val url: String) : Serializable \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/MediaInfoResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/MediaInfoResponse.java deleted file mode 100644 index 2112f48c..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/MediaInfoResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.util.List; - -public class MediaInfoResponse { - private final List items; - - public MediaInfoResponse(final List items) { - this.items = items; - } - - public List getItems() { - return items; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/MediaInfoResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/MediaInfoResponse.kt new file mode 100644 index 00000000..139d3c4a --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/MediaInfoResponse.kt @@ -0,0 +1,3 @@ +package awais.instagrabber.repositories.responses + +data class MediaInfoResponse(val items: List) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java deleted file mode 100644 index a6339e20..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java +++ /dev/null @@ -1,32 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.util.List; - -import awais.instagrabber.repositories.responses.notification.Notification; -import awais.instagrabber.repositories.responses.notification.NotificationCounts; - -public class NewsInboxResponse { - private final NotificationCounts counts; - private final List newStories; - private final List oldStories; - - public NewsInboxResponse(final NotificationCounts counts, - final List newStories, - final List oldStories) { - this.counts = counts; - this.newStories = newStories; - this.oldStories = oldStories; - } - - public NotificationCounts getCounts() { - return counts; - } - - public List getNewStories() { - return newStories; - } - - public List getOldStories() { - return oldStories; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.kt new file mode 100644 index 00000000..74c1417d --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.kt @@ -0,0 +1,10 @@ +package awais.instagrabber.repositories.responses + +import awais.instagrabber.repositories.responses.notification.Notification +import awais.instagrabber.repositories.responses.notification.NotificationCounts + +data class NewsInboxResponse( + val counts: NotificationCounts, + val newStories: List, + val oldStories: List +) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Place.java b/app/src/main/java/awais/instagrabber/repositories/responses/Place.java deleted file mode 100644 index 3f10ffd4..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/Place.java +++ /dev/null @@ -1,62 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.util.Objects; - -public class Place { - private final Location location; - // for search - private final String title; // those are repeated within location - private final String subtitle; // address - private final String slug; // browser only; for end of address - // for location info - private final String status; - - public Place(final Location location, - final String title, - final String subtitle, - final String slug, - final String status) { - this.location = location; - this.title = title; - this.subtitle = subtitle; - this.slug = slug; - this.status = status; - } - - public Location getLocation() { - return location; - } - - public String getTitle() { - return title; - } - - public String getSubtitle() { - return subtitle; - } - - public String getSlug() { - return slug; - } - - public String getStatus() { - return status; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final Place place = (Place) o; - return Objects.equals(location, place.location) && - Objects.equals(title, place.title) && - Objects.equals(subtitle, place.subtitle) && - Objects.equals(slug, place.slug) && - Objects.equals(status, place.status); - } - - @Override - public int hashCode() { - return Objects.hash(location, title, subtitle, slug, status); - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Place.kt b/app/src/main/java/awais/instagrabber/repositories/responses/Place.kt new file mode 100644 index 00000000..a0004a59 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Place.kt @@ -0,0 +1,12 @@ +package awais.instagrabber.repositories.responses + +data class Place( + val location: Location, + // for search + val title: String, // those are repeated within location + val subtitle: String?, // address + // browser only; for end of address + val slug: String?, + // for location info + val status: String? +) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/PostsFetchResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/PostsFetchResponse.java deleted file mode 100644 index c5b24016..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/PostsFetchResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.util.List; - -public class PostsFetchResponse { - private final List feedModels; - private final boolean hasNextPage; - private final String nextCursor; - - public PostsFetchResponse(final List feedModels, final boolean hasNextPage, final String nextCursor) { - this.feedModels = feedModels; - this.hasNextPage = hasNextPage; - this.nextCursor = nextCursor; - } - - public List getFeedModels() { - return feedModels; - } - - public boolean hasNextPage() { - return hasNextPage; - } - - public String getNextCursor() { - return nextCursor; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/PostsFetchResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/PostsFetchResponse.kt new file mode 100644 index 00000000..64082fce --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/PostsFetchResponse.kt @@ -0,0 +1,7 @@ +package awais.instagrabber.repositories.responses + +class PostsFetchResponse( + val feedModels: List, + val hasNextPage: Boolean, + val nextCursor: String? +) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/StoryStickerResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/StoryStickerResponse.java deleted file mode 100644 index 8ac2f4a9..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/StoryStickerResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package awais.instagrabber.repositories.responses; - -public class StoryStickerResponse { - private final String status; - - public StoryStickerResponse(final String status) { - this.status = status; - } - - public String getStatus() { - return status; - } - - @Override - public String toString() { - return "StoryStickerResponse{" + - "status='" + status + '\'' + - '}'; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/TagFeedResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/TagFeedResponse.java deleted file mode 100644 index f597beea..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/TagFeedResponse.java +++ /dev/null @@ -1,43 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.util.List; - -public class TagFeedResponse { - private final int numResults; - private final String nextMaxId; - private final boolean moreAvailable; - private final String status; - private final List items; - - public TagFeedResponse(final int numResults, - final String nextMaxId, - final boolean moreAvailable, - final String status, - final List items) { - this.numResults = numResults; - this.nextMaxId = nextMaxId; - this.moreAvailable = moreAvailable; - this.status = status; - this.items = items; - } - - public int getNumResults() { - return numResults; - } - - public String getNextMaxId() { - return nextMaxId; - } - - public boolean isMoreAvailable() { - return moreAvailable; - } - - public String getStatus() { - return status; - } - - public List getItems() { - return items; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/TagFeedResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/TagFeedResponse.kt new file mode 100644 index 00000000..d9bfb37e --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/TagFeedResponse.kt @@ -0,0 +1,9 @@ +package awais.instagrabber.repositories.responses + +class TagFeedResponse( + val numResults: Int, + val nextMaxId: String?, + val moreAvailable: Boolean, + val status: String, + val items: List +) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/User.kt b/app/src/main/java/awais/instagrabber/repositories/responses/User.kt index b46e3dab..6f465fb6 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/User.kt +++ b/app/src/main/java/awais/instagrabber/repositories/responses/User.kt @@ -27,7 +27,7 @@ data class User @JvmOverloads constructor( val externalUrl: String? = null, val usertagsCount: Long = 0, val publicEmail: String? = null, - val hdProfilePicUrlInfo: HdProfilePicUrlInfo? = null, + val hdProfilePicUrlInfo: ImageUrl? = null, val profileContext: String? = null, // "also followed by" your friends val profileContextLinksWithUserIds: List? = null, // ^ val socialContext: String? = null, // AYML diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/UserFeedResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/UserFeedResponse.java deleted file mode 100644 index bc912bed..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/UserFeedResponse.java +++ /dev/null @@ -1,43 +0,0 @@ -package awais.instagrabber.repositories.responses; - -import java.util.List; - -public class UserFeedResponse { - private final int numResults; - private final String nextMaxId; - private final boolean moreAvailable; - private final String status; - private final List items; - - public UserFeedResponse(final int numResults, - final String nextMaxId, - final boolean moreAvailable, - final String status, - final List items) { - this.numResults = numResults; - this.nextMaxId = nextMaxId; - this.moreAvailable = moreAvailable; - this.status = status; - this.items = items; - } - - public int getNumResults() { - return numResults; - } - - public String getNextMaxId() { - return nextMaxId; - } - - public boolean isMoreAvailable() { - return moreAvailable; - } - - public String getStatus() { - return status; - } - - public List getItems() { - return items; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/UserFeedResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/UserFeedResponse.kt new file mode 100644 index 00000000..9a68fa4e --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/UserFeedResponse.kt @@ -0,0 +1,9 @@ +package awais.instagrabber.repositories.responses + +class UserFeedResponse( + val numResults: Int, + val nextMaxId: String?, + val moreAvailable: Boolean, + val status: String, + val items: List +) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/WrappedMedia.java b/app/src/main/java/awais/instagrabber/repositories/responses/WrappedMedia.java deleted file mode 100644 index 2bfb1fa1..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/WrappedMedia.java +++ /dev/null @@ -1,13 +0,0 @@ -package awais.instagrabber.repositories.responses; - -public class WrappedMedia { - private final Media media; - - public WrappedMedia(final Media media) { - this.media = media; - } - - public Media getMedia() { - return media; - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/WrappedMedia.kt b/app/src/main/java/awais/instagrabber/repositories/responses/WrappedMedia.kt new file mode 100644 index 00000000..e09a20bc --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/WrappedMedia.kt @@ -0,0 +1,3 @@ +package awais.instagrabber.repositories.responses + +class WrappedMedia(val media: Media) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/ArchiveResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/ArchiveResponse.kt new file mode 100644 index 00000000..d9c990dd --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/ArchiveResponse.kt @@ -0,0 +1,9 @@ +package awais.instagrabber.repositories.responses.stories + +data class ArchiveResponse( + val numResults: Int, + val maxId: String?, + val moreAvailable: Boolean, + val status: String, + val items: List +) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/Broadcast.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/Broadcast.kt index 0037d73e..a27efbaf 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/Broadcast.kt +++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/Broadcast.kt @@ -1,10 +1,10 @@ package awais.instagrabber.repositories.responses.stories -import java.io.Serializable import awais.instagrabber.repositories.responses.User +import java.io.Serializable data class Broadcast( - val id: Long?, + val id: String?, val dashPlaybackUrl: String?, val dashAbrPlaybackUrl: String?, // adaptive quality val viewerCount: Double?, // always .0 diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/CoverMedia.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/CoverMedia.kt new file mode 100644 index 00000000..47d7a641 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/CoverMedia.kt @@ -0,0 +1,5 @@ +package awais.instagrabber.repositories.responses.stories + +import awais.instagrabber.repositories.responses.ImageUrl + +data class CoverMedia(val croppedImageVersion: ImageUrl) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/Story.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/Story.kt index 3c2312c1..b8288127 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/Story.kt +++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/Story.kt @@ -1,16 +1,31 @@ package awais.instagrabber.repositories.responses.stories -import java.io.Serializable -import awais.instagrabber.repositories.responses.Media +import awais.instagrabber.repositories.responses.ImageUrl import awais.instagrabber.repositories.responses.User +import awais.instagrabber.utils.TextUtils +import java.io.Serializable data class Story( - val id: Long?, - val latestReelMedia: Long?, // = timestamp - val seen: Long?, - val user: User?, - val muted: Boolean?, - val hasBestiesMedia: Boolean?, - val mediaCount: Int?, - val items: List? // may be null -) : Serializable \ No newline at end of file + // universal + val id: String? = null, + val latestReelMedia: Long? = null, // = timestamp + val mediaCount: Int? = null, + // for stories and highlights + var seen: Long? = null, + val user: User? = null, + // for stories + val muted: Boolean? = null, + val hasBestiesMedia: Boolean? = null, + val items: List? = null, // may be null + // for highlights + val coverMedia: CoverMedia? = null, + val title: String? = null, + // for archives + val coverImageVersion: ImageUrl? = null, + // invented fields + val broadcast: Broadcast? = null, // does not naturally occur +) : Serializable { + val dateTime: String + get() = if (latestReelMedia != null) TextUtils.epochSecondToString(latestReelMedia) else "" + // note that archives have property "timestamp" but is ignored +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt index 4fa49d3d..3b8c7787 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt +++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt @@ -1,12 +1,11 @@ package awais.instagrabber.repositories.responses.stories import awais.instagrabber.models.enums.MediaItemType -import awais.instagrabber.utils.TextUtils import awais.instagrabber.repositories.responses.ImageVersions2 -import awais.instagrabber.repositories.responses.User import awais.instagrabber.repositories.responses.MediaCandidate +import awais.instagrabber.repositories.responses.User +import awais.instagrabber.utils.TextUtils import java.io.Serializable -import java.util.* data class StoryMedia( // inherited from Media diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryStickerResponse.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryStickerResponse.kt new file mode 100644 index 00000000..9a765ec2 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryStickerResponse.kt @@ -0,0 +1,3 @@ +package awais.instagrabber.repositories.responses.stories + +data class StoryStickerResponse(val status: String?) \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt index 31157157..a9d466ba 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt @@ -1,6 +1,5 @@ package awais.instagrabber.utils -import android.Manifest import android.content.Context import android.content.DialogInterface import android.content.UriPermission @@ -38,8 +37,6 @@ object DownloadUtils { private const val DIR_TEMP = "Temp" private const val DIR_BACKUPS = "Backups" private var root: DocumentFile? = null - const val WRITE_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE - val PERMS = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) @JvmStatic @Throws(ReselectDocumentTreeException::class) fun init( @@ -49,11 +46,11 @@ object DownloadUtils { if (isEmpty(barinstaDirUri)) { throw ReselectDocumentTreeException("folder path is null or empty") } + val uri = Uri.parse(barinstaDirUri) if (!barinstaDirUri!!.startsWith("content://com.android.externalstorage.documents")) { // reselect the folder in selector view - throw ReselectDocumentTreeException(Uri.parse(barinstaDirUri)) + throw ReselectDocumentTreeException(uri) } - val uri = Uri.parse(barinstaDirUri) val existingPermissions = context.contentResolver.persistedUriPermissions if (existingPermissions.isEmpty()) { // reselect the folder in selector view @@ -150,7 +147,7 @@ object DownloadUtils { list.add(DIR_DOWNLOADS) return list } - val finalUsername = if (username!!.startsWith("@")) username.substring(1) else username + val finalUsername = if (username.startsWith("@")) username.substring(1) else username list.add(DIR_DOWNLOADS) list.add(finalUsername) return list @@ -337,7 +334,7 @@ object DownloadUtils { private fun checkPathExists(paths: List, context: Context): Boolean { if (root == null) return false - val uri = root!!.getUri() + val uri = root!!.uri var found = false var docId = DocumentsContract.getTreeDocumentId(uri) for (path in paths) { @@ -349,7 +346,7 @@ object DownloadUtils { ), null, null, null ) if (docCursor == null) return false - while (docCursor!!.moveToNext() && !found) { + while (docCursor.moveToNext() && !found) { if (path.equals(docCursor.getString(0))) { docId = docCursor.getString(1) found = true diff --git a/app/src/main/java/awais/instagrabber/utils/MediaController.java b/app/src/main/java/awais/instagrabber/utils/MediaController.java deleted file mode 100644 index cbfec5c5..00000000 --- a/app/src/main/java/awais/instagrabber/utils/MediaController.java +++ /dev/null @@ -1,386 +0,0 @@ -package awais.instagrabber.utils; - -import android.content.Context; -import android.database.Cursor; -import android.os.Build; -import android.os.Environment; -import android.provider.MediaStore; -import android.util.Log; -import android.util.SparseArray; - -import java.util.ArrayList; -import java.util.Collections; - -import awais.instagrabber.R; - -/* - * This is the source code of Telegram for Android v. 1.3.x. - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013-2018. - */ -public class MediaController { - private static final String TAG = MediaController.class.getSimpleName(); - private static final String[] PROJECTION_PHOTOS = { - MediaStore.Images.Media._ID, - MediaStore.Images.Media.BUCKET_ID, - MediaStore.Images.Media.BUCKET_DISPLAY_NAME, - MediaStore.Images.Media.DATA, - Build.VERSION.SDK_INT > 28 ? MediaStore.Images.Media.DATE_TAKEN : MediaStore.Images.Media.DATE_MODIFIED, - MediaStore.Images.Media.ORIENTATION, - MediaStore.Images.Media.WIDTH, - MediaStore.Images.Media.HEIGHT, - MediaStore.Images.Media.SIZE - }; - private static final String[] PROJECTION_VIDEO = { - MediaStore.Video.Media._ID, - MediaStore.Video.Media.BUCKET_ID, - MediaStore.Video.Media.BUCKET_DISPLAY_NAME, - MediaStore.Video.Media.DATA, - Build.VERSION.SDK_INT > 28 ? MediaStore.Video.Media.DATE_TAKEN : MediaStore.Images.Media.DATE_MODIFIED, - MediaStore.Video.Media.DURATION, - MediaStore.Video.Media.WIDTH, - MediaStore.Video.Media.HEIGHT, - MediaStore.Video.Media.SIZE - }; - - private final Context context; - private final OnLoadListener onLoadListener; - private final AppExecutors appExecutors; - - private static Runnable broadcastPhotosRunnable; - - private ArrayList allMediaAlbums; - private ArrayList allPhotoAlbums; - private AlbumEntry allPhotosAlbumEntry; - private AlbumEntry allMediaAlbumEntry; - private AlbumEntry allVideosAlbumEntry; - - public MediaController(final Context context, final OnLoadListener onLoadListener) { - this.context = context; - this.onLoadListener = onLoadListener; - appExecutors = AppExecutors.INSTANCE; - } - - public void load() { - loadGalleryAlbums(); - } - - private void loadGalleryAlbums() { - final Thread thread = new Thread(() -> { - final ArrayList mediaAlbumsSorted = new ArrayList<>(); - final ArrayList photoAlbumsSorted = new ArrayList<>(); - SparseArray mediaAlbums = new SparseArray<>(); - SparseArray photoAlbums = new SparseArray<>(); - AlbumEntry allPhotosAlbum = null; - AlbumEntry allVideosAlbum = null; - AlbumEntry allMediaAlbum = null; - String cameraFolder = null; - try { - cameraFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + "/" + "Camera/"; - } catch (Exception e) { - Log.e(TAG, "loadGalleryAlbums: ", e); - } - Integer mediaCameraAlbumId = null; - Integer photoCameraAlbumId = null; - - Cursor cursor = null; - try { - if (PermissionUtils.hasAttachMediaPerms(context)) { - cursor = MediaStore.Images.Media.query(context.getContentResolver(), - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - PROJECTION_PHOTOS, - null, - null, - (Build.VERSION.SDK_INT > 28 - ? MediaStore.Images.Media.DATE_TAKEN - : MediaStore.Images.Media.DATE_MODIFIED) + " DESC"); - if (cursor != null) { - int imageIdColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID); - int bucketIdColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID); - int bucketNameColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME); - int dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA); - int dateColumn = cursor.getColumnIndex(Build.VERSION.SDK_INT > 28 ? MediaStore.Images.Media.DATE_TAKEN - : MediaStore.Images.Media.DATE_MODIFIED); - int orientationColumn = cursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION); - int widthColumn = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH); - int heightColumn = cursor.getColumnIndex(MediaStore.Images.Media.HEIGHT); - int sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE); - - while (cursor.moveToNext()) { - String path = cursor.getString(dataColumn); - if (TextUtils.isEmpty(path)) { - continue; - } - - int imageId = cursor.getInt(imageIdColumn); - int bucketId = cursor.getInt(bucketIdColumn); - String bucketName = cursor.getString(bucketNameColumn); - long dateTaken = cursor.getLong(dateColumn); - int orientation = cursor.getInt(orientationColumn); - int width = cursor.getInt(widthColumn); - int height = cursor.getInt(heightColumn); - long size = cursor.getLong(sizeColumn); - - MediaEntry mediaEntry = new MediaEntry(bucketId, imageId, dateTaken, path, orientation, -1, false, width, height, size); - - if (allPhotosAlbum == null) { - allPhotosAlbum = new AlbumEntry(0, context.getString(R.string.all_photos), mediaEntry); - photoAlbumsSorted.add(0, allPhotosAlbum); - } - if (allMediaAlbum == null) { - allMediaAlbum = new AlbumEntry(0, context.getString(R.string.all_media), mediaEntry); - mediaAlbumsSorted.add(0, allMediaAlbum); - } - allPhotosAlbum.addPhoto(mediaEntry); - allMediaAlbum.addPhoto(mediaEntry); - - AlbumEntry albumEntry = mediaAlbums.get(bucketId); - if (albumEntry == null) { - albumEntry = new AlbumEntry(bucketId, bucketName, mediaEntry); - mediaAlbums.put(bucketId, albumEntry); - if (mediaCameraAlbumId == null && cameraFolder != null && path.startsWith(cameraFolder)) { - mediaAlbumsSorted.add(0, albumEntry); - mediaCameraAlbumId = bucketId; - } else { - mediaAlbumsSorted.add(albumEntry); - } - } - albumEntry.addPhoto(mediaEntry); - - albumEntry = photoAlbums.get(bucketId); - if (albumEntry == null) { - albumEntry = new AlbumEntry(bucketId, bucketName, mediaEntry); - photoAlbums.put(bucketId, albumEntry); - if (photoCameraAlbumId == null && cameraFolder != null && path.startsWith(cameraFolder)) { - photoAlbumsSorted.add(0, albumEntry); - photoCameraAlbumId = bucketId; - } else { - photoAlbumsSorted.add(albumEntry); - } - } - albumEntry.addPhoto(mediaEntry); - } - } - } - } catch (Throwable e) { - Log.e(TAG, "loadGalleryAlbums: ", e); - } finally { - if (cursor != null) { - try { - cursor.close(); - } catch (Exception e) { - Log.e(TAG, "loadGalleryAlbums: ", e); - } - } - } - - try { - if (PermissionUtils.hasAttachMediaPerms(context)) { - cursor = MediaStore.Images.Media.query(context.getContentResolver(), - MediaStore.Video.Media.EXTERNAL_CONTENT_URI, - PROJECTION_VIDEO, - MediaStore.Video.Media.MIME_TYPE + "=?", - new String[]{"video/mp4"}, - (Build.VERSION.SDK_INT > 28 - ? MediaStore.Video.Media.DATE_TAKEN - : MediaStore.Video.Media.DATE_MODIFIED) + " DESC"); - if (cursor != null) { - int imageIdColumn = cursor.getColumnIndex(MediaStore.Video.Media._ID); - int bucketIdColumn = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_ID); - int bucketNameColumn = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_DISPLAY_NAME); - int dataColumn = cursor.getColumnIndex(MediaStore.Video.Media.DATA); - int dateColumn = cursor.getColumnIndex(Build.VERSION.SDK_INT > 28 ? MediaStore.Video.Media.DATE_TAKEN - : MediaStore.Video.Media.DATE_MODIFIED); - int durationColumn = cursor.getColumnIndex(MediaStore.Video.Media.DURATION); - int widthColumn = cursor.getColumnIndex(MediaStore.Video.Media.WIDTH); - int heightColumn = cursor.getColumnIndex(MediaStore.Video.Media.HEIGHT); - int sizeColumn = cursor.getColumnIndex(MediaStore.Video.Media.SIZE); - - while (cursor.moveToNext()) { - String path = cursor.getString(dataColumn); - if (TextUtils.isEmpty(path)) { - continue; - } - - int imageId = cursor.getInt(imageIdColumn); - int bucketId = cursor.getInt(bucketIdColumn); - String bucketName = cursor.getString(bucketNameColumn); - long dateTaken = cursor.getLong(dateColumn); - long duration = cursor.getLong(durationColumn); - int width = cursor.getInt(widthColumn); - int height = cursor.getInt(heightColumn); - long size = cursor.getLong(sizeColumn); - - MediaEntry mediaEntry = new MediaEntry(bucketId, imageId, dateTaken, path, -1, duration, true, width, height, size); - - if (allVideosAlbum == null) { - allVideosAlbum = new AlbumEntry(0, context.getString(R.string.all_videos), mediaEntry); - allVideosAlbum.videoOnly = true; - int index = 0; - if (allMediaAlbum != null) { - index++; - } - if (allPhotosAlbum != null) { - index++; - } - mediaAlbumsSorted.add(index, allVideosAlbum); - } - if (allMediaAlbum == null) { - allMediaAlbum = new AlbumEntry(0, context.getString(R.string.all_media), mediaEntry); - mediaAlbumsSorted.add(0, allMediaAlbum); - } - allVideosAlbum.addPhoto(mediaEntry); - allMediaAlbum.addPhoto(mediaEntry); - - AlbumEntry albumEntry = mediaAlbums.get(bucketId); - if (albumEntry == null) { - albumEntry = new AlbumEntry(bucketId, bucketName, mediaEntry); - mediaAlbums.put(bucketId, albumEntry); - if (mediaCameraAlbumId == null && cameraFolder != null && path.startsWith(cameraFolder)) { - mediaAlbumsSorted.add(0, albumEntry); - mediaCameraAlbumId = bucketId; - } else { - mediaAlbumsSorted.add(albumEntry); - } - } - - albumEntry.addPhoto(mediaEntry); - } - } - } - } catch (Throwable e) { - Log.e(TAG, "loadGalleryAlbums: ", e); - } finally { - if (cursor != null) { - try { - cursor.close(); - } catch (Exception e) { - Log.e(TAG, "loadGalleryAlbums: ", e); - } - } - } - for (int a = 0; a < mediaAlbumsSorted.size(); a++) { - Collections.sort(mediaAlbumsSorted.get(a).photos, (o1, o2) -> { - if (o1.dateTaken < o2.dateTaken) { - return 1; - } else if (o1.dateTaken > o2.dateTaken) { - return -1; - } - return 0; - }); - } - broadcastNewPhotos(mediaAlbumsSorted, photoAlbumsSorted, mediaCameraAlbumId, allMediaAlbum, allPhotosAlbum, allVideosAlbum, 0); - }); - thread.setPriority(Thread.MIN_PRIORITY); - thread.start(); - } - - private void broadcastNewPhotos(final ArrayList mediaAlbumsSorted, - final ArrayList photoAlbumsSorted, - final Integer cameraAlbumIdFinal, - final AlbumEntry allMediaAlbumFinal, - final AlbumEntry allPhotosAlbumFinal, - final AlbumEntry allVideosAlbumFinal, - int delay) { - if (broadcastPhotosRunnable != null) { - appExecutors.getMainThread().cancel(broadcastPhotosRunnable); - } - appExecutors.getMainThread().execute(broadcastPhotosRunnable = () -> { - allMediaAlbums = mediaAlbumsSorted; - allPhotoAlbums = photoAlbumsSorted; - broadcastPhotosRunnable = null; - allPhotosAlbumEntry = allPhotosAlbumFinal; - allMediaAlbumEntry = allMediaAlbumFinal; - allVideosAlbumEntry = allVideosAlbumFinal; - if (onLoadListener != null) { - onLoadListener.onLoad(); - } - }, delay); - } - - public AlbumEntry getAllMediaAlbumEntry() { - return allMediaAlbumEntry; - } - - public AlbumEntry getAllPhotosAlbumEntry() { - return allPhotosAlbumEntry; - } - - public AlbumEntry getAllVideosAlbumEntry() { - return allVideosAlbumEntry; - } - - public ArrayList getAllMediaAlbums() { - return allMediaAlbums; - } - - public ArrayList getAllPhotoAlbums() { - return allPhotoAlbums; - } - - public static class AlbumEntry { - public int bucketId; - public boolean videoOnly; - public String bucketName; - public MediaEntry coverPhoto; - public ArrayList photos = new ArrayList<>(); - public SparseArray photosByIds = new SparseArray<>(); - - public AlbumEntry(int bucketId, String bucketName, MediaEntry coverPhoto) { - this.bucketId = bucketId; - this.bucketName = bucketName; - this.coverPhoto = coverPhoto; - } - - public void addPhoto(MediaEntry mediaEntry) { - photos.add(mediaEntry); - photosByIds.put(mediaEntry.imageId, mediaEntry); - } - } - - public static class MediaEntry { - public int bucketId; - public int imageId; - public long dateTaken; - public long duration; - public int width; - public int height; - public long size; - public String path; - public int orientation; - public boolean isVideo; - public boolean isMuted; - public boolean canDeleteAfter; - - public MediaEntry(int bucketId, - int imageId, - long dateTaken, - String path, - int orientation, - long duration, - boolean isVideo, - int width, - int height, - long size) { - this.bucketId = bucketId; - this.imageId = imageId; - this.dateTaken = dateTaken; - this.path = path; - this.width = width; - this.height = height; - this.size = size; - if (isVideo) { - this.duration = duration; - } else { - this.orientation = orientation; - } - this.isVideo = isVideo; - } - } - - public interface OnLoadListener { - void onLoad(); - } -} diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index 0330d6e2..a1152baf 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -28,7 +28,7 @@ import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.MediaCandidate; import awais.instagrabber.repositories.responses.User; -import awais.instagrabber.repositories.responses.MediaCandidate; +import awais.instagrabber.repositories.responses.stories.StoryMedia; public final class ResponseBodyUtils { private static final String TAG = "ResponseBodyUtils"; @@ -271,6 +271,7 @@ public final class ResponseBodyUtils { false, false, null, + null, null ); } @@ -405,27 +406,38 @@ public final class ResponseBodyUtils { return model; } - public static String getThumbUrl(final Media media) { + public static String getThumbUrl(final Object media) { return getImageCandidate(media, CandidateType.THUMBNAIL); } - public static String getImageUrl(final Media media) { + public static String getImageUrl(final Object media) { return getImageCandidate(media, CandidateType.DOWNLOAD); } - private static String getImageCandidate(final Media media, final CandidateType type) { - if (media == null) return null; - final ImageVersions2 imageVersions2 = media.getImageVersions2(); + private static String getImageCandidate(final Object rawMedia, final CandidateType type) { + final ImageVersions2 imageVersions2; + final int originalWidth, originalHeight; + if (rawMedia instanceof StoryMedia) { + imageVersions2 = ((StoryMedia) rawMedia).getImageVersions2(); + originalWidth = ((StoryMedia) rawMedia).getOriginalWidth(); + originalHeight = ((StoryMedia) rawMedia).getOriginalHeight(); + } + else if (rawMedia instanceof Media) { + imageVersions2 = ((Media) rawMedia).getImageVersions2(); + originalWidth = ((Media) rawMedia).getOriginalWidth(); + originalHeight = ((Media) rawMedia).getOriginalHeight(); + } + else return null; if (imageVersions2 == null) return null; final List candidates = imageVersions2.getCandidates(); if (candidates == null || candidates.isEmpty()) return null; - final boolean isSquare = Integer.compare(media.getOriginalWidth(), media.getOriginalHeight()) == 0; + final boolean isSquare = Integer.compare(originalWidth, originalHeight) == 0; final List sortedCandidates = candidates.stream() .sorted((c1, c2) -> Integer.compare(c2.getWidth(), c1.getWidth())) .collect(Collectors.toList()); final List filteredCandidates = sortedCandidates.stream() .filter(c -> - c.getWidth() <= media.getOriginalWidth() + c.getWidth() <= originalWidth && c.getWidth() <= type.getValue() && (isSquare || Integer .compare(c.getWidth(), c.getHeight()) != 0) diff --git a/app/src/main/java/awais/instagrabber/viewmodels/ArchivesViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/ArchivesViewModel.java index 18802826..be70eac0 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/ArchivesViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/ArchivesViewModel.java @@ -5,12 +5,12 @@ import androidx.lifecycle.ViewModel; import java.util.List; -import awais.instagrabber.models.HighlightModel; +import awais.instagrabber.repositories.responses.stories.Story; public class ArchivesViewModel extends ViewModel { - private MutableLiveData> list; + private MutableLiveData> list; - public MutableLiveData> getList() { + public MutableLiveData> getList() { if (list == null) { list = new MutableLiveData<>(); } diff --git a/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java index a8bdedeb..16a7b0d2 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java @@ -54,7 +54,7 @@ public class CommentsViewerViewModel extends ViewModel { private String postId; private String rootCursor; private boolean rootHasNext = true; - private Comment repliesParent; + private Comment repliesParent, replyTo; private String repliesCursor; private boolean repliesHasNext = true; private final CommentService commentService; @@ -153,6 +153,11 @@ public class CommentsViewerViewModel extends ViewModel { return repliesParent; } + @Nullable + public void setReplyTo(final Comment replyTo) { + this.replyTo = replyTo; + } + public LiveData>> getRootList() { return rootList; } @@ -297,6 +302,7 @@ public class CommentsViewerViewModel extends ViewModel { if (comment == null) return; if (repliesParent == null || !Objects.equals(repliesParent.getPk(), comment.getPk())) { repliesParent = comment; + replyTo = comment; prevReplies = null; prevRepliesCursor = null; prevRepliesHasNext = true; @@ -368,8 +374,8 @@ public class CommentsViewerViewModel extends ViewModel { final boolean isReply) { final MutableLiveData> data = new MutableLiveData<>(Resource.loading(null)); String replyToId = null; - if (isReply && repliesParent != null) { - replyToId = repliesParent.getPk(); + if (isReply && replyTo != null) { + replyToId = replyTo.getPk(); } if (isReply && replyToId == null) { data.postValue(Resource.error(null, null)); @@ -399,10 +405,9 @@ public class CommentsViewerViewModel extends ViewModel { final List list = getPrevList(isReply ? replyList : rootList); final ImmutableList.Builder builder = ImmutableList.builder(); if (isReply) { - // in a reply list the first comment is the parent comment - builder.add(list.get(0)) - .add(comment) - .addAll(list.subList(1, list.size())); + // replies are added to the bottom of the list to preserve chronological order + builder.addAll(list) + .add(comment); } else { builder.add(comment) .addAll(list); diff --git a/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.kt b/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.kt index 70407c06..200f4deb 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.kt +++ b/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.kt @@ -1,6 +1,5 @@ package awais.instagrabber.viewmodels -import android.R.attr import android.app.Application import android.content.ContentResolver import android.net.Uri @@ -23,7 +22,6 @@ import awais.instagrabber.utils.MediaUtils.OnInfoLoadListener import awais.instagrabber.utils.MediaUtils.VideoInfo import awais.instagrabber.utils.VoiceRecorder.VoiceRecorderCallback import awais.instagrabber.utils.VoiceRecorder.VoiceRecordingResult -import java.util.* class DirectThreadViewModel( @@ -76,10 +74,6 @@ class DirectThreadViewModel( return threadManager.sendText(text, viewModelScope) } - fun sendUri(entry: MediaController.MediaEntry): LiveData> { - return threadManager.sendUri(entry, viewModelScope) - } - fun sendUri(uri: Uri): LiveData> { return threadManager.sendUri(uri, viewModelScope) } diff --git a/app/src/main/java/awais/instagrabber/viewmodels/FeedStoriesViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/FeedStoriesViewModel.java index f4bd3b41..61118fef 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/FeedStoriesViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/FeedStoriesViewModel.java @@ -3,15 +3,14 @@ package awais.instagrabber.viewmodels; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; -import java.util.ArrayList; import java.util.List; -import awais.instagrabber.models.FeedStoryModel; +import awais.instagrabber.repositories.responses.stories.Story; public class FeedStoriesViewModel extends ViewModel { - private MutableLiveData> list; + private MutableLiveData> list; - public MutableLiveData> getList() { + public MutableLiveData> getList() { if (list == null) { list = new MutableLiveData<>(); } diff --git a/app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java index d78b9ef4..ccc8b843 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java @@ -5,12 +5,12 @@ import androidx.lifecycle.ViewModel; import java.util.List; -import awais.instagrabber.models.HighlightModel; +import awais.instagrabber.repositories.responses.stories.Story; public class HighlightsViewModel extends ViewModel { - private MutableLiveData> list; + private MutableLiveData> list; - public MutableLiveData> getList() { + public MutableLiveData> getList() { if (list == null) { list = new MutableLiveData<>(); } diff --git a/app/src/main/java/awais/instagrabber/viewmodels/MediaPickerViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/MediaPickerViewModel.java deleted file mode 100644 index 12858851..00000000 --- a/app/src/main/java/awais/instagrabber/viewmodels/MediaPickerViewModel.java +++ /dev/null @@ -1,41 +0,0 @@ -package awais.instagrabber.viewmodels; - -import android.content.Context; - -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; - -import java.util.Collections; -import java.util.List; - -import awais.instagrabber.utils.MediaController; -import awais.instagrabber.utils.MediaController.AlbumEntry; - -public class MediaPickerViewModel extends ViewModel implements MediaController.OnLoadListener { - private final MutableLiveData> allAlbums = new MutableLiveData<>(Collections.emptyList()); - - private MediaController mediaController; - - public MediaPickerViewModel() { - - } - - public void loadMedia(final Context context) { - mediaController = new MediaController(context, this); - mediaController.load(); - } - - @Override - public void onLoad() { - if (mediaController == null) { - return; - } - final List allPhotoAlbums = mediaController.getAllMediaAlbums(); - this.allAlbums.postValue(allPhotoAlbums); - } - - public LiveData> getAllAlbums() { - return allAlbums; - } -} diff --git a/app/src/main/java/awais/instagrabber/viewmodels/PostViewV2ViewModel.kt b/app/src/main/java/awais/instagrabber/viewmodels/PostViewV2ViewModel.kt index 866dc748..6cd3af04 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/PostViewV2ViewModel.kt +++ b/app/src/main/java/awais/instagrabber/viewmodels/PostViewV2ViewModel.kt @@ -331,19 +331,21 @@ class PostViewV2ViewModel : ViewModel() { return data } - fun shareDm(result: RankedRecipient) { + fun shareDm(result: RankedRecipient, child: Int) { if (messageManager == null) { messageManager = DirectMessagesManager } val mediaId = media.id ?: return - messageManager?.sendMedia(result, mediaId, BroadcastItemType.MEDIA_SHARE, viewModelScope) + val childId = if (child == -1) null else media.carouselMedia?.get(child)?.id + messageManager?.sendMedia(result, mediaId, childId, BroadcastItemType.MEDIA_SHARE, viewModelScope) } - fun shareDm(recipients: Set) { + fun shareDm(recipients: Set, child: Int) { if (messageManager == null) { messageManager = DirectMessagesManager } val mediaId = media.id ?: return - messageManager?.sendMedia(recipients, mediaId, BroadcastItemType.MEDIA_SHARE, viewModelScope) + val childId = if (child == -1) null else media.carouselMedia?.get(child)?.id + messageManager?.sendMedia(recipients, mediaId, childId, BroadcastItemType.MEDIA_SHARE, viewModelScope) } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt b/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt index e8c0fa24..2b106e30 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt +++ b/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt @@ -8,7 +8,6 @@ import awais.instagrabber.db.entities.Favorite import awais.instagrabber.db.repositories.AccountRepository import awais.instagrabber.db.repositories.FavoriteRepository import awais.instagrabber.managers.DirectMessagesManager -import awais.instagrabber.models.HighlightModel import awais.instagrabber.models.Resource import awais.instagrabber.models.StoryModel import awais.instagrabber.models.enums.BroadcastItemType @@ -18,6 +17,7 @@ import awais.instagrabber.repositories.responses.FriendshipStatus import awais.instagrabber.repositories.responses.User import awais.instagrabber.repositories.responses.UserProfileContextLink import awais.instagrabber.repositories.responses.directmessages.RankedRecipient +import awais.instagrabber.repositories.responses.stories.Story import awais.instagrabber.utils.ControlledRunner import awais.instagrabber.utils.Event import awais.instagrabber.utils.SingleRunner @@ -185,9 +185,9 @@ class ProfileFragmentViewModel( } } - private val highlightsFetchControlledRunner = ControlledRunner?>() - val userHighlights: LiveData?>> = currentUserProfileActionLiveData.switchMap { currentUserAndProfilePair -> - liveData?>>(context = viewModelScope.coroutineContext + ioDispatcher) { + private val highlightsFetchControlledRunner = ControlledRunner?>() + val userHighlights: LiveData?>> = currentUserProfileActionLiveData.switchMap { currentUserAndProfilePair -> + liveData?>>(context = viewModelScope.coroutineContext + ioDispatcher) { val (currentUserResource, profileResource, action) = currentUserAndProfilePair if (action != INIT && action != REFRESH) { return@liveData @@ -236,7 +236,7 @@ class ProfileFragmentViewModel( StoryViewerOptions.forUser(fetchedUser.pk, fetchedUser.fullName) ) - private suspend fun fetchUserHighlights(fetchedUser: User): List = storiesRepository.fetchHighlights(fetchedUser.pk) + private suspend fun fetchUserHighlights(fetchedUser: User): List = storiesRepository.fetchHighlights(fetchedUser.pk) private suspend fun checkAndUpdateFavorite(fetchedUser: User) { try { @@ -268,12 +268,12 @@ class ProfileFragmentViewModel( fun shareDm(result: RankedRecipient) { val mediaId = profile.value?.data?.pk ?: return - messageManager?.sendMedia(result, mediaId.toString(10), BroadcastItemType.PROFILE, viewModelScope) + messageManager?.sendMedia(result, mediaId.toString(10), null, BroadcastItemType.PROFILE, viewModelScope) } fun shareDm(recipients: Set) { val mediaId = profile.value?.data?.pk ?: return - messageManager?.sendMedia(recipients, mediaId.toString(10), BroadcastItemType.PROFILE, viewModelScope) + messageManager?.sendMedia(recipients, mediaId.toString(10), null, BroadcastItemType.PROFILE, viewModelScope) } fun refresh() { diff --git a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt index 4a7e124a..f21d35da 100644 --- a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt +++ b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt @@ -173,8 +173,9 @@ open class DirectMessagesRepository(private val service: DirectMessagesService) clientContext: String, threadIdsOrUserIds: ThreadIdsOrUserIds, mediaId: String, + childId: String?, ): DirectThreadBroadcastResponse = - broadcast(csrfToken, userId, deviceUuid, MediaShareBroadcastOptions(clientContext, threadIdsOrUserIds, mediaId)) + broadcast(csrfToken, userId, deviceUuid, MediaShareBroadcastOptions(clientContext, threadIdsOrUserIds, mediaId, childId)) suspend fun broadcastProfile( csrfToken: String, diff --git a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java index 1e491906..e8f6884c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java +++ b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java @@ -63,7 +63,7 @@ public class ProfileService { } callback.onSuccess(new PostsFetchResponse( body.getItems(), - body.isMoreAvailable(), + body.getMoreAvailable(), body.getNextMaxId() )); } @@ -204,7 +204,7 @@ public class ProfileService { } callback.onSuccess(new PostsFetchResponse( userFeedResponse.getItems(), - userFeedResponse.isMoreAvailable(), + userFeedResponse.getMoreAvailable(), userFeedResponse.getNextMaxId() )); } @@ -237,7 +237,7 @@ public class ProfileService { } callback.onSuccess(new PostsFetchResponse( userFeedResponse.getItems(), - userFeedResponse.isMoreAvailable(), + userFeedResponse.getMoreAvailable(), userFeedResponse.getNextMaxId() )); } diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt b/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt index 7235ace1..efe4e0e2 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt @@ -1,19 +1,15 @@ package awais.instagrabber.webservices -import android.util.Log import awais.instagrabber.fragments.settings.PreferenceKeys -import awais.instagrabber.models.FeedStoryModel -import awais.instagrabber.models.HighlightModel import awais.instagrabber.models.StoryModel import awais.instagrabber.repositories.StoriesService import awais.instagrabber.repositories.requests.StoryViewerOptions -import awais.instagrabber.repositories.responses.StoryStickerResponse -import awais.instagrabber.repositories.responses.User -import awais.instagrabber.utils.Constants +import awais.instagrabber.repositories.responses.stories.ArchiveResponse +import awais.instagrabber.repositories.responses.stories.Story +import awais.instagrabber.repositories.responses.stories.StoryStickerResponse import awais.instagrabber.utils.ResponseBodyUtils import awais.instagrabber.utils.TextUtils.isEmpty import awais.instagrabber.utils.Utils -import awais.instagrabber.utils.extensions.TAG import awais.instagrabber.webservices.RetrofitFactory.retrofit import org.json.JSONArray import org.json.JSONObject @@ -27,101 +23,42 @@ open class StoriesRepository(private val service: StoriesService) { return ResponseBodyUtils.parseStoryItem(itemJson, false, null) } - suspend fun getFeedStories(): List { + suspend fun getFeedStories(): List { val response = service.getFeedStories() - return parseStoriesBody(response) - } - - private fun parseStoriesBody(body: String): List { - val feedStoryModels: MutableList = ArrayList() - val feedStoriesReel = JSONObject(body).getJSONArray("tray") - for (i in 0 until feedStoriesReel.length()) { - val node = feedStoriesReel.getJSONObject(i) - if (node.optBoolean("hide_from_feed_unit") && Utils.settingsHelper.getBoolean(PreferenceKeys.HIDE_MUTED_REELS)) continue - val userJson = node.getJSONObject(if (node.has("user")) "user" else "owner") - try { - val user = User( - userJson.getLong("pk"), - userJson.getString("username"), - userJson.optString("full_name"), - userJson.optBoolean("is_private"), - userJson.getString("profile_pic_url"), - userJson.optBoolean("is_verified") - ) - val timestamp = node.getLong("latest_reel_media") - val fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp - val itemJson = if (node.has("items")) node.getJSONArray("items").optJSONObject(0) else null - var firstStoryModel: StoryModel? = null - if (itemJson != null) { - firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null) - } - feedStoryModels.add( - FeedStoryModel( - node.getString("id"), - user, - fullyRead, - timestamp, - firstStoryModel, - node.getInt("media_count"), - false, - node.optBoolean("has_besties_media") + val result: MutableList = mutableListOf() + if (response?.broadcasts != null) { + val length = response.broadcasts.size + for (i in 0 until length) { + val broadcast = response.broadcasts.get(i) + result.add( + Story( + broadcast.id, + broadcast.publishedTime, + 1, + 0L, + broadcast.broadcastOwner, + broadcast.muted, + false, // unclear + null, + null, + null, + null, + broadcast ) ) - } catch (e: Exception) { - Log.e(TAG, "parseStoriesBody: ", e) - } // to cover promotional reels with non-long user pk's + } } - val broadcasts = JSONObject(body).getJSONArray("broadcasts") - for (i in 0 until broadcasts.length()) { - val node = broadcasts.getJSONObject(i) - val userJson = node.getJSONObject("broadcast_owner") - val user = User( - userJson.getLong("pk"), - userJson.getString("username"), - userJson.optString("full_name"), - userJson.optBoolean("is_private"), - userJson.getString("profile_pic_url"), - userJson.optBoolean("is_verified") - ) - feedStoryModels.add( - FeedStoryModel( - node.getString("id"), - user, - false, - node.getLong("published_time"), - ResponseBodyUtils.parseBroadcastItem(node), - 1, - isLive = true, - isBestie = false - ) - ) - } - return sort(feedStoryModels) + if (response?.tray != null) result.addAll(response.tray) + return sort(result.toList()) } - open suspend fun fetchHighlights(profileId: Long): List { + open suspend fun fetchHighlights(profileId: Long): List { val response = service.fetchHighlights(profileId) - val highlightsReel = JSONObject(response).getJSONArray("tray") - val length = highlightsReel.length() - val highlightModels: MutableList = ArrayList() - for (i in 0 until length) { - val highlightNode = highlightsReel.getJSONObject(i) - highlightModels.add( - HighlightModel( - highlightNode.getString("title"), - highlightNode.getString(Constants.EXTRAS_ID), - highlightNode.getJSONObject("cover_media") - .getJSONObject("cropped_image_version") - .getString("url"), - highlightNode.getLong("latest_reel_media"), - highlightNode.getInt("media_count") - ) - ) - } + val highlightModels = response?.tray ?: listOf() return highlightModels } - suspend fun fetchArchive(maxId: String): ArchiveFetchResponse { + suspend fun fetchArchive(maxId: String): ArchiveResponse? { val form = mutableMapOf( "include_suggested_highlights" to "false", "is_in_archive_home" to "true", @@ -130,24 +67,7 @@ open class StoriesRepository(private val service: StoriesService) { if (!isEmpty(maxId)) { form["max_id"] = maxId // NOT TESTED } - val response = service.fetchArchive(form) - val data = JSONObject(response) - val highlightsReel = data.getJSONArray("items") - val length = highlightsReel.length() - val highlightModels: MutableList = ArrayList() - for (i in 0 until length) { - val highlightNode = highlightsReel.getJSONObject(i) - highlightModels.add( - HighlightModel( - null, - highlightNode.getString(Constants.EXTRAS_ID), - highlightNode.getJSONObject("cover_image_version").getString("url"), - highlightNode.getLong("latest_reel_media"), - highlightNode.getInt("media_count") - ) - ) - } - return ArchiveFetchResponse(highlightModels, data.getBoolean("more_available"), data.getString("max_id")) + return service.fetchArchive(form) } open suspend fun getUserStory(options: StoryViewerOptions): List { @@ -299,24 +219,19 @@ open class StoriesRepository(private val service: StoriesService) { return builder.toString() } - private fun sort(list: List): List { + private fun sort(list: List): List { val listCopy = ArrayList(list) listCopy.sortWith { o1, o2 -> - when (Utils.settingsHelper.getString(PreferenceKeys.STORY_SORT)) { - "1" -> return@sortWith o2.timestamp.compareTo(o1.timestamp) - "2" -> return@sortWith o1.timestamp.compareTo(o2.timestamp) + if (o1.latestReelMedia == null || o2.latestReelMedia == null) return@sortWith 0 + else when (Utils.settingsHelper.getString(PreferenceKeys.STORY_SORT)) { + "1" -> return@sortWith o2.latestReelMedia.compareTo(o1.latestReelMedia) + "2" -> return@sortWith o1.latestReelMedia.compareTo(o2.latestReelMedia) else -> return@sortWith 0 } } return listCopy } - class ArchiveFetchResponse(val result: List, val hasNextPage: Boolean, val nextCursor: String) { - fun hasNextPage(): Boolean { - return hasNextPage - } - } - companion object { @Volatile private var INSTANCE: StoriesRepository? = null diff --git a/app/src/main/java/awais/instagrabber/webservices/TagsService.java b/app/src/main/java/awais/instagrabber/webservices/TagsService.java index fa4f3dce..f207dcad 100644 --- a/app/src/main/java/awais/instagrabber/webservices/TagsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/TagsService.java @@ -122,7 +122,7 @@ public class TagsService { } callback.onSuccess(new PostsFetchResponse( body.getItems(), - body.isMoreAvailable(), + body.getMoreAvailable(), body.getNextMaxId() )); } diff --git a/app/src/main/res/color/ic_read_button_tint.xml b/app/src/main/res/color/ic_read_button_tint.xml new file mode 100644 index 00000000..a9d12381 --- /dev/null +++ b/app/src/main/res/color/ic_read_button_tint.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_check_all_24.xml b/app/src/main/res/drawable/ic_check_all_24.xml index 648f00d7..0e8dfc69 100644 --- a/app/src/main/res/drawable/ic_check_all_24.xml +++ b/app/src/main/res/drawable/ic_check_all_24.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorControlNormal"> + android:tint="@color/ic_read_button_tint"> diff --git a/app/src/main/res/layout/fragment_story_viewer.xml b/app/src/main/res/layout/fragment_story_viewer.xml index 4495cab6..cb6b66ed 100644 --- a/app/src/main/res/layout/fragment_story_viewer.xml +++ b/app/src/main/res/layout/fragment_story_viewer.xml @@ -133,7 +133,7 @@ android:id="@+id/btnBackward" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="40dp" - android:layout_height="0dp" + android:layout_height="@dimen/story_item_height" android:visibility="visible" app:icon="@drawable/exo_ic_skip_previous" app:iconGravity="textStart" @@ -157,7 +157,7 @@ android:id="@+id/btnForward" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="40dp" - android:layout_height="0dp" + android:layout_height="@dimen/story_item_height" android:visibility="visible" app:icon="@drawable/exo_ic_skip_next" app:iconGravity="textStart" diff --git a/app/src/main/res/layout/layout_dm_media_share.xml b/app/src/main/res/layout/layout_dm_media_share.xml index 6e4f74de..b59b7f17 100644 --- a/app/src/main/res/layout/layout_dm_media_share.xml +++ b/app/src/main/res/layout/layout_dm_media_share.xml @@ -76,26 +76,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="@id/title" /> - - + app:layout_constraintTop_toTopOf="@id/caption" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_media_picker.xml b/app/src/main/res/layout/layout_media_picker.xml deleted file mode 100644 index e8a314e6..00000000 --- a/app/src/main/res/layout/layout_media_picker.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4a885b06..e264fd28 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,6 +22,7 @@ Favorites Discover Comments + Replies Activity Check for updates at startup Block screenshots & app preview @@ -513,7 +514,7 @@ The previously selected folder does not exist now: Re-select the directory or select a new directory by clicking the button below. No folder selected! - Please choose a directory from your storage, not a category on the sidebar. + Please choose a directory from your storage, not a category on the sidebar.\n(%s) Success! Please wait. Starting app… Barinsta folder Top diff --git a/app/src/test/java/awais/instagrabber/common/Adapters.kt b/app/src/test/java/awais/instagrabber/common/Adapters.kt index 33b1d034..5735e342 100644 --- a/app/src/test/java/awais/instagrabber/common/Adapters.kt +++ b/app/src/test/java/awais/instagrabber/common/Adapters.kt @@ -8,6 +8,9 @@ import awais.instagrabber.models.enums.FavoriteType import awais.instagrabber.repositories.* import awais.instagrabber.repositories.responses.* import awais.instagrabber.repositories.responses.directmessages.* +import awais.instagrabber.repositories.responses.stories.ArchiveResponse +import awais.instagrabber.repositories.responses.stories.ReelsTrayResponse +import awais.instagrabber.repositories.responses.stories.StoryStickerResponse open class UserServiceAdapter : UserService { override suspend fun getUserInfo(uid: Long): WrappedUser { @@ -48,15 +51,15 @@ open class StoriesServiceAdapter : StoriesService { TODO("Not yet implemented") } - override suspend fun getFeedStories(): String { + override suspend fun getFeedStories(): ReelsTrayResponse? { TODO("Not yet implemented") } - override suspend fun fetchHighlights(uid: Long): String { + override suspend fun fetchHighlights(uid: Long): ReelsTrayResponse? { TODO("Not yet implemented") } - override suspend fun fetchArchive(queryParams: Map): String { + override suspend fun fetchArchive(queryParams: Map): ArchiveResponse? { TODO("Not yet implemented") } diff --git a/app/src/test/java/awais/instagrabber/viewmodels/ProfileFragmentViewModelTest.kt b/app/src/test/java/awais/instagrabber/viewmodels/ProfileFragmentViewModelTest.kt index 6248a8cf..165db358 100644 --- a/app/src/test/java/awais/instagrabber/viewmodels/ProfileFragmentViewModelTest.kt +++ b/app/src/test/java/awais/instagrabber/viewmodels/ProfileFragmentViewModelTest.kt @@ -9,13 +9,13 @@ import awais.instagrabber.db.datasources.FavoriteDataSource import awais.instagrabber.db.entities.Favorite import awais.instagrabber.db.repositories.FavoriteRepository import awais.instagrabber.getOrAwaitValue -import awais.instagrabber.models.HighlightModel import awais.instagrabber.models.Resource import awais.instagrabber.models.StoryModel import awais.instagrabber.models.enums.FavoriteType import awais.instagrabber.repositories.requests.StoryViewerOptions import awais.instagrabber.repositories.responses.FriendshipStatus import awais.instagrabber.repositories.responses.User +import awais.instagrabber.repositories.responses.stories.Story import awais.instagrabber.webservices.* import kotlinx.coroutines.ExperimentalCoroutinesApi import org.json.JSONException @@ -321,13 +321,13 @@ internal class ProfileFragmentViewModelTest { ) ) val testUserStories = listOf(StoryModel()) - val testUserHighlights = listOf(HighlightModel()) + val testUserHighlights = listOf(Story()) val userRepository = object : UserRepository(UserServiceAdapter()) { override suspend fun getUsernameInfo(username: String): User = testPublicUser } val storiesRepository = object : StoriesRepository(StoriesServiceAdapter()) { override suspend fun getUserStory(options: StoryViewerOptions): List = testUserStories - override suspend fun fetchHighlights(profileId: Long): List = testUserHighlights + override suspend fun fetchHighlights(profileId: Long): List = testUserHighlights } val viewModel = ProfileFragmentViewModel( state, diff --git a/build.gradle b/build.gradle index 93e0391d..e1d7b4a7 100755 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.5.0' + ext.kotlin_version = '1.5.20' repositories { google() diff --git a/gradle.properties b/gradle.properties index 8f97ac54..52f3d156 100755 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -#Tue May 04 02:33:38 JST 2021 +#Wed Jun 30 00:40:18 JST 2021 +org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" -XX:+UseParallelGC android.enableJetifier=true -android.useAndroidX=true -org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx1536M" +android.useAndroidX=true \ No newline at end of file