diff --git a/app/build.gradle b/app/build.gradle index 75bddda2..3c15763b 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,7 @@ dependencies { implementation 'org.jsoup:jsoup:1.13.1' implementation 'com.facebook.fresco:fresco:2.3.0' + implementation 'com.facebook.fresco:animated-gif:2.3.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 7e5f1829..f30bd0f1 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -40,10 +40,10 @@ import androidx.navigation.ui.NavigationUI; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.List; @@ -97,11 +97,12 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage R.id.notificationsViewer, R.id.themePreferencesFragment, R.id.favoritesFragment, - R.id.backupPreferencesFragment - // , R.id.postViewV2Fragment + R.id.backupPreferencesFragment, + R.id.directMessagesThreadFragment ); private static final Map NAV_TO_MENU_ID_MAP = new HashMap<>(); - private static final List REMOVE_COLLAPSING_TOOLBAR_SCROLL_DESTINATIONS = Collections.singletonList(R.id.commentsViewerFragment); + private static final List REMOVE_COLLAPSING_TOOLBAR_SCROLL_DESTINATIONS = ImmutableList.of(R.id.commentsViewerFragment, + R.id.directMessagesThreadFragment); private static final String FIRST_FRAGMENT_GRAPH_INDEX_KEY = "firstFragmentGraphIndex"; private ActivityMainBinding binding; diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageAnimatedMediaViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageAnimatedMediaViewHolder.java index 8f9f3f4e..17d00739 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageAnimatedMediaViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageAnimatedMediaViewHolder.java @@ -1,33 +1,64 @@ package awais.instagrabber.adapters.viewholder.directmessages; +import android.net.Uri; import android.view.View; +import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.core.util.Pair; import com.facebook.drawee.backends.pipeline.Fresco; +import com.facebook.imagepipeline.common.ResizeOptions; +import com.facebook.imagepipeline.request.ImageRequest; +import com.facebook.imagepipeline.request.ImageRequestBuilder; +import awais.instagrabber.R; import awais.instagrabber.databinding.LayoutDmAnimatedMediaBinding; import awais.instagrabber.databinding.LayoutDmBaseBinding; import awais.instagrabber.models.direct_messages.DirectItemModel; +import awais.instagrabber.utils.NumberUtils; +import awais.instagrabber.utils.Utils; public class DirectMessageAnimatedMediaViewHolder extends DirectMessageItemViewHolder { private final LayoutDmAnimatedMediaBinding binding; + private final int maxHeight; + private final int maxWidth; public DirectMessageAnimatedMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding, @NonNull final LayoutDmAnimatedMediaBinding binding, final View.OnClickListener onClickListener) { super(baseBinding, onClickListener); this.binding = binding; + maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height); + maxWidth = (int) (Utils.displayMetrics.widthPixels - Utils.convertDpToPx(64) - getItemMargin()); setItemView(binding.getRoot()); + removeElevation(); } @Override public void bindItem(final DirectItemModel directItemModel) { + final DirectItemModel.DirectItemAnimatedMediaModel animatedMediaModel = directItemModel.getAnimatedMediaModel(); + final String url = animatedMediaModel.getGifUrl(); + final Pair widthHeight = NumberUtils.calculateWidthHeight( + animatedMediaModel.getHeight(), + animatedMediaModel.getWidth(), + maxHeight, + maxWidth + ); + binding.ivAnimatedMessage.setVisibility(View.VISIBLE); + final ViewGroup.LayoutParams layoutParams = binding.ivAnimatedMessage.getLayoutParams(); + final int width = widthHeight.first != null ? widthHeight.first : 0; + final int height = widthHeight.second != null ? widthHeight.second : 0; + layoutParams.width = width; + layoutParams.height = height; + binding.ivAnimatedMessage.requestLayout(); + final ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)) + .setResizeOptions(ResizeOptions.forDimensions(width, height)) + .build(); binding.ivAnimatedMessage.setController(Fresco.newDraweeControllerBuilder() - .setUri(directItemModel.getAnimatedMediaModel().getGifUrl()) + .setImageRequest(request) .setAutoPlayAnimations(true) .build()); - binding.ivAnimatedMessage.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageItemViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageItemViewHolder.java index 747fd8ef..675b3f6d 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageItemViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageItemViewHolder.java @@ -71,6 +71,10 @@ public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolde this.binding.messageCard.addView(view); } + public int getItemMargin() { + return itemMargin; + } + public abstract void bindItem(final DirectItemModel directItemModel); @Nullable @@ -88,4 +92,8 @@ public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolde } return null; } + + protected void removeElevation() { + binding.messageCard.setCardElevation(0); + } } diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageMediaViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageMediaViewHolder.java index 8d7e0cd7..91c692c5 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageMediaViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectMessageMediaViewHolder.java @@ -26,7 +26,7 @@ public class DirectMessageMediaViewHolder extends DirectMessageItemViewHolder { super(baseBinding, onClickListener); this.binding = binding; maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height); - maxWidth = (int) (Utils.displayMetrics.widthPixels * 0.8); + maxWidth = (int) (Utils.displayMetrics.widthPixels - Utils.convertDpToPx(64) - getItemMargin()); setItemView(binding.getRoot()); } 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 3d7344f8..1cb3d474 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; @@ -26,6 +27,8 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; @@ -78,6 +81,7 @@ import awais.instagrabber.utils.Utils; public class DirectMessageThreadFragment extends Fragment { private static final String TAG = "DirectMessagesThreadFmt"; private static final int PICK_IMAGE = 100; + private static final int STORAGE_PERM_REQUEST_CODE = 8020; private AppCompatActivity fragmentActivity; private String threadId; @@ -169,8 +173,9 @@ public class DirectMessageThreadFragment extends Fragment { binding.swipeRefreshLayout.setRefreshing(false); } }; - private LinearLayout root; + private ConstraintLayout root; private boolean shouldRefresh = true; + private DirectItemModel.DirectItemMediaModel downloadMediaItem; @Override public void onCreate(@Nullable final Bundle savedInstanceState) { @@ -251,18 +256,7 @@ public class DirectMessageThreadFragment extends Fragment { break; case RAVEN_MEDIA: case MEDIA: - final ProfileModel user = getUser(directItemModel.getUserId()); - final DirectItemModel.DirectItemMediaModel selectedItem = - itemType == DirectItemType.MEDIA ? directItemModel.getMediaModel() : directItemModel.getRavenMediaModel().getMedia(); - final String url = selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO - ? selectedItem.getVideoUrl() - : selectedItem.getThumbUrl(); - if (url == null) { - Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - } else { - DownloadUtils.dmDownload(context, user.getUsername(), DownloadMethod.DOWNLOAD_DIRECT, selectedItem); - Toast.makeText(context, R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show(); - } + downloadItem(context); break; case STORY_SHARE: if (directItemModel.getReelShare() != null) { @@ -295,11 +289,13 @@ public class DirectMessageThreadFragment extends Fragment { } else if (which == 1) { sendText(null, directItemModel.getItemId(), directItemModel.isLiked()); } else if (which == 2) { - if (directItemModel == null) + if (directItemModel == null) { Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - else if (String.valueOf(directItemModel.getUserId()).equals(myId)) + } else if (String.valueOf(directItemModel.getUserId()).equals(myId)) { new ThreadAction().execute("delete", directItemModel.getItemId()); - else searchUsername(getUser(directItemModel.getUserId()).getUsername()); + } else { + searchUsername(getUser(directItemModel.getUserId()).getUsername()); + } } }; final View.OnClickListener onClickListener = v -> { @@ -365,6 +361,26 @@ public class DirectMessageThreadFragment extends Fragment { } } + private void downloadItem(final Context context) { + final ProfileModel user = getUser(directItemModel.getUserId()); + final DirectItemModel.DirectItemMediaModel selectedItem = directItemModel.getItemType() == DirectItemType.MEDIA + ? directItemModel.getMediaModel() + : directItemModel.getRavenMediaModel().getMedia(); + final String url = selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO + ? selectedItem.getVideoUrl() + : selectedItem.getThumbUrl(); + if (url == null) { + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + } else { + if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) { + DownloadUtils.dmDownload(context, user.getUsername(), selectedItem.getId(), url); + } else { + requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + } + Toast.makeText(context, R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show(); + } + } + @Override public void onResume() { super.onResume(); @@ -422,6 +438,17 @@ public class DirectMessageThreadFragment extends Fragment { if (listViewModel != null) listViewModel.getList().postValue(Collections.emptyList()); } + @Override + public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + final boolean granted = grantResults[0] == PackageManager.PERMISSION_GRANTED; + final Context context = getContext(); + if (context == null) return; + if (requestCode == STORAGE_PERM_REQUEST_CODE && granted) { + downloadItem(context); + } + } + private void sendText(final String text, final String itemId, final boolean delete) { DirectThreadBroadcaster.TextBroadcastOptions textOptions = null; DirectThreadBroadcaster.ReactionBroadcastOptions reactionOptions = null; diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index 295a7476..76c2702e 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -42,7 +42,6 @@ import awais.instagrabber.asyncs.PostFetcher; import awais.instagrabber.models.BasePostModel; import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.PostChild; -import awais.instagrabber.models.direct_messages.DirectItemModel; import awais.instagrabber.models.enums.DownloadMethod; import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.workers.DownloadWorker; @@ -169,40 +168,28 @@ public final class DownloadUtils { public static void dmDownload(@NonNull final Context context, @Nullable final String username, - final DownloadMethod method, - final DirectItemModel.DirectItemMediaModel itemsToDownload) { - if (Utils.settingsHelper == null) Utils.settingsHelper = new SettingsHelper(context); - - if (itemsToDownload == null) return; - - if (ContextCompat.checkSelfPermission(context, PERMS[0]) == PackageManager.PERMISSION_GRANTED) - dmDownloadImpl(context, username, method, itemsToDownload); - else if (context instanceof Activity) + final String modelId, + final String url) { + if (url == null) return; + if (ContextCompat.checkSelfPermission(context, PERMS[0]) == PackageManager.PERMISSION_GRANTED) { + dmDownloadImpl(context, username, modelId, url); + } else if (context instanceof Activity) { ActivityCompat.requestPermissions((Activity) context, PERMS, 8020); + } } private static void dmDownloadImpl(@NonNull final Context context, @Nullable final String username, - final DownloadMethod method, - final DirectItemModel.DirectItemMediaModel selectedItem) { - File dir = new File(Environment.getExternalStorageDirectory(), "Download"); - - if (Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) { - final String customPath = Utils.settingsHelper.getString(FOLDER_PATH); - if (!TextUtils.isEmpty(customPath)) dir = new File(customPath); - } - - if (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER) && !TextUtils.isEmpty(username)) - dir = new File(dir, username); - + final String modelId, + final String url) { + final File dir = getDownloadDir(context, username); if (dir.exists() || dir.mkdirs()) { - new DownloadAsync(context, - selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO ? selectedItem.getVideoUrl() : selectedItem.getThumbUrl(), - getDownloadSaveFileDm(dir, selectedItem), - null) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else - Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show(); + download(context, + url, + getDownloadSaveFile(dir, modelId, url).getAbsolutePath()); + return; + } + Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show(); } @NonNull @@ -229,14 +216,6 @@ public final class DownloadUtils { return new File(finalDir, fileName); } - @NonNull - private static File getDownloadSaveFileDm(final File finalDir, - @NonNull final DirectItemModel.DirectItemMediaModel model) { - final boolean isVideo = model.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO; - final String displayUrl = isVideo ? model.getVideoUrl() : model.getThumbUrl(); - return new File(finalDir, model.getId() + getFileExtensionFromUrl(displayUrl)); - } - /** * Copied from {@link MimeTypeMap#getFileExtensionFromUrl(String)}) *

diff --git a/app/src/main/java/awais/instagrabber/utils/NumberUtils.java b/app/src/main/java/awais/instagrabber/utils/NumberUtils.java index 028567f2..f387fcad 100644 --- a/app/src/main/java/awais/instagrabber/utils/NumberUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/NumberUtils.java @@ -57,13 +57,25 @@ public final class NumberUtils { @NonNull public static Pair calculateWidthHeight(final int height, final int width, final int maxHeight, final int maxWidth) { - int tempWidth = width; - int tempHeight = height > maxHeight ? maxHeight : height; - if (tempWidth > maxWidth) { - tempHeight = NumberUtils.getResultingHeight(maxWidth, height, width); - tempWidth = maxWidth; + if (width > maxWidth) { + int tempHeight = getResultingHeight(maxWidth, height, width); + int tempWidth = maxWidth; + if (tempHeight > maxHeight) { + tempWidth = getResultingWidth(maxHeight, tempHeight, tempWidth); + tempHeight = maxHeight; + } + return new Pair<>(tempWidth, tempHeight); } - return new Pair<>(tempWidth, tempHeight); + if ((height < maxHeight && width < maxWidth) || (height > maxHeight)) { + int tempWidth = getResultingWidth(maxHeight, height, width); + int tempHeight = maxHeight; + if (tempWidth > maxWidth) { + tempHeight = getResultingHeight(maxWidth, tempHeight, tempWidth); + tempWidth = maxWidth; + } + return new Pair<>(tempWidth, tempHeight); + } + return new Pair<>(width, height); } public static float roundFloat2Decimals(final float value) { diff --git a/app/src/main/res/layout/fragment_direct_messages_thread.xml b/app/src/main/res/layout/fragment_direct_messages_thread.xml index 23f34465..dc226234 100644 --- a/app/src/main/res/layout/fragment_direct_messages_thread.xml +++ b/app/src/main/res/layout/fragment_direct_messages_thread.xml @@ -1,17 +1,21 @@ - + android:layout_weight="1" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + app:layout_constraintBottom_toTopOf="@id/comment_container" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/swipeRefreshLayout"> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_dm_animated_media.xml b/app/src/main/res/layout/layout_dm_animated_media.xml index cfd28e07..407d75a0 100644 --- a/app/src/main/res/layout/layout_dm_animated_media.xml +++ b/app/src/main/res/layout/layout_dm_animated_media.xml @@ -1,5 +1,7 @@ \ No newline at end of file + android:layout_height="@dimen/dm_media_img_max_height" + app:actualImageScaleType="fitXY" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_dm_base.xml b/app/src/main/res/layout/layout_dm_base.xml index 1f265076..3b73c818 100644 --- a/app/src/main/res/layout/layout_dm_base.xml +++ b/app/src/main/res/layout/layout_dm_base.xml @@ -1,6 +1,7 @@ @@ -11,7 +12,8 @@ android:layout_height="@dimen/profile_pic_size_regular" android:layout_gravity="top|start" android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" /> + android:layout_marginEnd="4dp" + tools:background="@mipmap/ic_launcher" /> + android:textColor="?android:textColorPrimary" + tools:text="@string/app_name" /> + app:cardUseCompatPadding="true" + tools:background="@mipmap/ic_launcher" /> + android:layout_gravity="center" + app:actualImageScaleType="fitXY" />