diff --git a/.all-contributorsrc b/.all-contributorsrc index cd865d08..7a9958b9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -79,6 +79,25 @@ "code" ] }, + { + "login": "stamatiap", + "name": "Stamatia Papageorgiou", + "avatar_url": "https://avatars.githubusercontent.com/u/57223967?v=4", + "profile": "https://github.com/stamatiap", + "contributions": [ + "code", + "translation" + ] + }, + { + "login": "The-EDev", + "name": "Farook Al-Sammarraie", + "avatar_url": "https://avatars.githubusercontent.com/u/60552923?v=4", + "profile": "https://github.com/The-EDev", + "contributions": [ + "code" + ] + }, { "login": "Zopieux", "name": "Alexandre Macabies", diff --git a/.github/workflows/github_nightly_release.yml b/.github/workflows/github_nightly_release.yml index 8edb6a63..bddf63b5 100644 --- a/.github/workflows/github_nightly_release.yml +++ b/.github/workflows/github_nightly_release.yml @@ -15,10 +15,11 @@ jobs: uses: actions/checkout@v2 - name: set up JDK 1.8 - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: - java-version: 1.8 - + distribution: 'zulu' + java-version: '8' + - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/.github/workflows/github_pre_release.yml b/.github/workflows/github_pre_release.yml index 9700fdfc..42d8e481 100644 --- a/.github/workflows/github_pre_release.yml +++ b/.github/workflows/github_pre_release.yml @@ -16,9 +16,10 @@ jobs: uses: actions/checkout@v2 - name: set up JDK 1.8 - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: - java-version: 1.8 + distribution: 'zulu' + java-version: '8' - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/README.md b/README.md index d1301419..15999d16 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) [![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE) [![GitHub stars](https://img.shields.io/github/stars/austinhuang0131/instagrabber.svg?style=social&label=Star)](https://GitHub.com/austinhuang0131/barinsta/stargazers/) -[![All Contributors](https://img.shields.io/badge/all_contributors-42-orange.svg)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-44-orange.svg)](#contributors) Instagram client; previously known as InstaGrabber. @@ -63,49 +63,53 @@ Prominent contributors are listed here in the [all-contributors](https://allcont
Pablo RodrΓ­guez

πŸ’» +
Stamatia Papageorgiou

πŸ’» 🌍 +
Farook Al-Sammarraie

πŸ’»
Alexandre Macabies

πŸ’»
Stefan Najdovski

🎨 🌍
CrazyMarvin

πŸ’΅ -
Kevin Thomas

πŸ’΅ -
Shadowspear123

πŸ“ πŸ› πŸ€” πŸ’¬ +
Kevin Thomas

πŸ’΅ +
Shadowspear123

πŸ“ πŸ› πŸ€” πŸ’¬
Ricardo

πŸ› 🌍
Akrai

πŸ€” 🌍
avtkal

🌍
CΓ©zar Augusto

🌍 -
Dimitris T

🌍 -
farzadx

🌍 +
Dimitris T

🌍 +
farzadx

🌍
Fatih AydΔ±n

🌍
fouze555

🌍
Galang23

🌍
Initdebugs

🌍 -
Jakub Janek

🌍 -
GenosseFlosse

🌍 +
Jakub Janek

🌍 +
GenosseFlosse

🌍
kernoeb

🌍
MoaufmKlo

🌍
nalinalini

🌍
peterge1998

🌍 -
PierreM0

🌍 -
Pyrobauve

🌍 +
PierreM0

🌍 +
Pyrobauve

🌍
RAMAR-RAR

🌍
rohang02

🌍
retiolus

🌍
rikishi0071

🌍 -
Alexey Peschany

🌍 -
Sitavi

🌍 +
Alexey Peschany

🌍 +
Sitavi

🌍
Still Hsu

🌍
Ten_Lego

🌍
wagnim

🌍
wokija

🌍 + +
ysakamoto

🌍
ZDVokoun

🌍 @@ -121,7 +125,7 @@ This app's predecessor, InstaGrabber, was originally made by [@AwaisKing](https: Barinsta Copyright (C) 2020-2021 Austin Huang - Ammar Githam + Ammar Githam This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/app/src/main/java/awais/instagrabber/adapters/FeedStoriesListAdapter.java b/app/src/main/java/awais/instagrabber/adapters/FeedStoriesListAdapter.java index 9d7401e0..146904d0 100755 --- a/app/src/main/java/awais/instagrabber/adapters/FeedStoriesListAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/FeedStoriesListAdapter.java @@ -23,23 +23,29 @@ public final class FeedStoriesListAdapter extends ListAdapter list; private final Filter filter = new Filter() { - @Nullable + @NonNull @Override protected FilterResults performFiltering(final CharSequence filter) { - final boolean isFilterEmpty = TextUtils.isEmpty(filter); - final String query = isFilterEmpty ? null : filter.toString().toLowerCase(); - - for (FeedStoryModel item : list) { - if (isFilterEmpty) item.setShown(true); - else item.setShown(item.getProfileModel().getUsername().toLowerCase().contains(query)); + final String query = TextUtils.isEmpty(filter) ? null : filter.toString().toLowerCase(); + List filteredList = list; + if (list != null && query != null) { + filteredList = list.stream() + .filter(feedStoryModel -> feedStoryModel.getProfileModel() + .getUsername() + .toLowerCase() + .contains(query)) + .collect(Collectors.toList()); } - return null; + final FilterResults filterResults = new FilterResults(); + filterResults.count = filteredList != null ? filteredList.size() : 0; + filterResults.values = filteredList; + return filterResults; } @Override protected void publishResults(final CharSequence constraint, final FilterResults results) { - submitList(list); - notifyDataSetChanged(); + //noinspection unchecked + submitList((List) results.values, true); } }; @@ -65,10 +71,16 @@ public final class FeedStoriesListAdapter extends ListAdapter list, final boolean isFiltered) { + if (!isFiltered) { + this.list = list; + } + super.submitList(list); + } + @Override public void submitList(final List list) { - super.submitList(list.stream().filter(i -> i.isShown()).collect(Collectors.toList())); - this.list = list; + submitList(list, false); } @NonNull @@ -82,11 +94,11 @@ public final class FeedStoriesListAdapter extends ListAdapter { if (notificationClickListener == null) return; - notificationClickListener.onFeedStoryClick(model, position); + notificationClickListener.onFeedStoryClick(model); }); } diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 65315e35..35249824 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -18,6 +18,7 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.widget.Toast; import androidx.annotation.NonNull; @@ -29,6 +30,7 @@ import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.Toolbar; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.PermissionChecker; +import androidx.core.view.WindowCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.LiveData; @@ -100,7 +102,6 @@ import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_SHOWN_COUNT_TOOLTIP; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; -import static awais.instagrabber.utils.Utils.getAttrValue; import static awais.instagrabber.utils.Utils.settingsHelper; public class PostViewV2Fragment extends Fragment implements EditTextDialogFragment.EditTextDialogFragmentCallback { @@ -131,6 +132,9 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme private boolean isInFullScreenMode; private StyledPlayerView playerView; private int playerViewOriginalHeight; + private Drawable originalRootBackground; + private ColorStateList originalLikeColorStateList; + private ColorStateList originalSaveColorStateList; private final Observer backStackSavedStateObserver = result -> { if (result == null) return; @@ -141,7 +145,6 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme // clear result backStackSavedStateResultLiveData.postValue(null); }; - private Drawable originalRootBackground; public void setOnDeleteListener(final OnDeleteListener onDeleteListener) { if (onDeleteListener == null) return; @@ -441,6 +444,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme } private void setupLike() { + originalLikeColorStateList = bottom.like.getIconTint(); final boolean likableMedia = viewModel.hasPk() /*&& viewModel.getMedia().isCommentLikesEnabled()*/; if (!likableMedia) { bottom.like.setVisibility(View.GONE); @@ -503,25 +507,25 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme private void setLikedResources(final boolean liked) { final int iconResource; - final int tintResource; + final ColorStateList tintColorStateList; final Context context = getContext(); if (context == null) return; final Resources resources = context.getResources(); if (resources == null) return; if (liked) { iconResource = R.drawable.ic_like; - tintResource = resources.getColor(R.color.red_600); - // textResId = R.string.unlike_without_count; + tintColorStateList = ColorStateList.valueOf(resources.getColor(R.color.red_600)); } else { iconResource = R.drawable.ic_not_liked; - tintResource = getAttrValue(context, R.attr.colorPrimary); - // textResId = R.string.like_without_count; + tintColorStateList = originalLikeColorStateList != null ? originalLikeColorStateList + : ColorStateList.valueOf(resources.getColor(R.color.white)); } bottom.like.setIconResource(iconResource); - bottom.like.setIconTint(ColorStateList.valueOf(tintResource)); + bottom.like.setIconTint(tintColorStateList); } private void setupSave() { + originalSaveColorStateList = bottom.save.getIconTint(); if (!viewModel.isLoggedIn() || !viewModel.hasPk() || !viewModel.getMedia().canViewerSave()) { bottom.save.setVisibility(View.GONE); return; @@ -574,22 +578,21 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme private void setSavedResources(final boolean saved) { final int iconResource; - final int tintResource; + final ColorStateList tintColorStateList; final Context context = getContext(); if (context == null) return; final Resources resources = context.getResources(); if (resources == null) return; if (saved) { iconResource = R.drawable.ic_bookmark; - tintResource = resources.getColor(R.color.blue_700); - // textResId = R.string.saved; + tintColorStateList = ColorStateList.valueOf(resources.getColor(R.color.blue_700)); } else { iconResource = R.drawable.ic_round_bookmark_border_24; - tintResource = getAttrValue(context, R.attr.colorPrimary); - // textResId = R.string.save; + tintColorStateList = originalSaveColorStateList != null ? originalSaveColorStateList + : ColorStateList.valueOf(resources.getColor(R.color.white)); } bottom.save.setIconResource(iconResource); - bottom.save.setIconTint(ColorStateList.valueOf(tintResource)); + bottom.save.setIconTint(tintColorStateList); } private void setupProfilePic(final User user) { @@ -1427,8 +1430,10 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme if (toolbar != null) { toolbar.setVisibility(View.VISIBLE); } - final View decorView = activity.getWindow().getDecorView(); + final Window window = activity.getWindow(); + final View decorView = window.getDecorView(); decorView.setSystemUiVisibility(originalSystemUi); + WindowCompat.setDecorFitsSystemWindows(window, false); isInFullScreenMode = false; } diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java index f4bf129a..f8bdfb81 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java @@ -23,9 +23,12 @@ import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import com.google.common.collect.Iterables; + import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import awais.instagrabber.R; import awais.instagrabber.adapters.FeedStoriesListAdapter; @@ -58,15 +61,17 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr private StoriesService storiesService; private Context context; private String type; - private String currentQuery; private String endCursor = null; private FeedStoriesListAdapter adapter; - private MenuItem menuSearch; private final OnFeedStoryClickListener clickListener = new OnFeedStoryClickListener() { @Override - public void onFeedStoryClick(final FeedStoryModel model, final int position) { + public void onFeedStoryClick(final FeedStoryModel model) { if (model == null) return; + 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())); final NavDirections action = StoryListViewerFragmentDirections .actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forFeedStoryPosition(position)); NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action); @@ -153,7 +158,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr @Override public void onCreateOptionsMenu(@NonNull final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.search, menu); - menuSearch = menu.findItem(R.id.action_search); + final MenuItem menuSearch = menu.findItem(R.id.action_search); final SearchView searchView = (SearchView) menuSearch.getActionView(); searchView.setQueryHint(getResources().getString(R.string.action_search)); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @@ -166,7 +171,6 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr @Override public boolean onQueryTextChange(final String query) { if (adapter != null) { - currentQuery = query; adapter.getFilter().filter(query); } return true; diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 1372eb59..5cc6887b 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -119,6 +119,7 @@ public class StoryViewerFragment extends Fragment { private View root; private FragmentStoryViewerBinding binding; private String currentStoryUsername; + private String highlightTitle; private StoriesAdapter storiesAdapter; private SwipeEvent swipeEvent; private GestureDetectorCompat gestureDetector; @@ -274,7 +275,9 @@ public class StoryViewerFragment extends Fragment { @Override public void onPause() { super.onPause(); - releasePlayer(); + if (player != null) { + player.pause(); + } } @Override @@ -724,7 +727,7 @@ public class StoryViewerFragment extends Fragment { final HighlightModel model = models.get(currentFeedStoryIndex); currentStoryMediaId = model.getId(); fetchOptions = StoryViewerOptions.forHighlight(model.getId()); - currentStoryUsername = model.getTitle(); + highlightTitle = model.getTitle(); break; } case FEED_STORY_POSITION: { @@ -824,8 +827,8 @@ public class StoryViewerFragment extends Fragment { if (type == Type.HIGHLIGHT) { final ActionBar actionBar = fragmentActivity.getSupportActionBar(); if (actionBar != null) { - actionBarTitle = options.getName(); - actionBar.setTitle(options.getName()); + actionBarTitle = highlightTitle; + actionBar.setTitle(highlightTitle); } } else if (hasUsername) { currentStoryUsername = currentStoryUsername.replace("@", ""); diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java index 60a7482e..d8a98087 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java @@ -16,6 +16,7 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.view.menu.ActionMenuItemView; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; @@ -27,6 +28,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.badge.BadgeDrawable; import com.google.android.material.badge.BadgeUtils; +import com.google.android.material.internal.ToolbarUtils; import com.google.android.material.snackbar.Snackbar; import java.util.List; @@ -102,7 +104,9 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh super.onPause(); unregisterReceiver(); isPendingRequestTotalBadgeAttached = false; - if (pendingRequestTotalBadgeDrawable != null) { + @SuppressLint("RestrictedApi") final ActionMenuItemView menuItemView = ToolbarUtils + .getActionMenuItemView(fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); + if (pendingRequestTotalBadgeDrawable != null && menuItemView != null) { BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); pendingRequestTotalBadgeDrawable = null; } @@ -217,7 +221,11 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh pendingRequestTotalBadgeDrawable = BadgeDrawable.create(context); } if (count == null || count == 0) { - BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); + @SuppressLint("RestrictedApi") final ActionMenuItemView menuItemView = ToolbarUtils + .getActionMenuItemView(fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); + if (menuItemView != null) { + BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); + } isPendingRequestTotalBadgeAttached = false; pendingRequestTotalBadgeDrawable.setNumber(0); pendingRequestsMenuItem.setVisible(false); 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 99d72a57..eb97b60f 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -31,6 +31,7 @@ import androidx.activity.OnBackPressedDispatcher; 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; @@ -56,6 +57,7 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; import com.google.android.material.badge.BadgeDrawable; import com.google.android.material.badge.BadgeUtils; +import com.google.android.material.internal.ToolbarUtils; import com.google.android.material.snackbar.Snackbar; import com.google.common.collect.ImmutableList; @@ -554,7 +556,11 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact } isPendingRequestCountBadgeAttached = false; if (pendingRequestCountBadgeDrawable != null) { - BadgeUtils.detachBadgeDrawable(pendingRequestCountBadgeDrawable, fragmentActivity.getToolbar(), R.id.info); + @SuppressLint("RestrictedApi") final ActionMenuItemView menuItemView = ToolbarUtils + .getActionMenuItemView(fragmentActivity.getToolbar(), R.id.info); + if (menuItemView != null) { + BadgeUtils.detachBadgeDrawable(pendingRequestCountBadgeDrawable, fragmentActivity.getToolbar(), R.id.info); + } pendingRequestCountBadgeDrawable = null; } } @@ -838,7 +844,11 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact pendingRequestCountBadgeDrawable = BadgeDrawable.create(context); } if (count == null || count == 0) { - BadgeUtils.detachBadgeDrawable(pendingRequestCountBadgeDrawable, fragmentActivity.getToolbar(), R.id.info); + @SuppressLint("RestrictedApi") final ActionMenuItemView menuItemView = ToolbarUtils + .getActionMenuItemView(fragmentActivity.getToolbar(), R.id.info); + if (menuItemView != null) { + BadgeUtils.detachBadgeDrawable(pendingRequestCountBadgeDrawable, fragmentActivity.getToolbar(), R.id.info); + } isPendingRequestCountBadgeAttached = false; pendingRequestCountBadgeDrawable.setNumber(0); return; @@ -1107,7 +1117,9 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact if (!isAdded()) return; if (!entry.isVideo) { navigateToImageEditFragment(entry.path); + return; } + handleSentMessage(viewModel.sendUri(entry)); }); mediaPicker.show(getChildFragmentManager(), "MediaPicker"); }); 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 ea54ceca..d22b5a51 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -337,6 +337,12 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre return super.onOptionsItemSelected(item); } + @Override + public void onResume() { + super.onResume(); + binding.getRoot().postDelayed(feedStoriesAdapter::notifyDataSetChanged, 1000); + } + @Override public void onRefresh() { binding.feedRecyclerView.refresh(); @@ -418,15 +424,16 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre } private void fetchStories() { + if (storiesFetching) return; // final String cookie = settingsHelper.getString(Constants.COOKIE); storiesFetching = true; updateSwipeRefreshState(); storiesService.getFeedStories(new ServiceCallback>() { @Override public void onSuccess(final List result) { + storiesFetching = false; feedStoriesViewModel.getList().postValue(result); feedStoriesAdapter.submitList(result); - storiesFetching = false; if (storyListMenu != null) storyListMenu.setVisible(true); updateSwipeRefreshState(); } @@ -451,8 +458,10 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre } public void scrollToTop() { - binding.feedRecyclerView.smoothScrollToPosition(0); - // binding.storiesContainer.setExpanded(true); + if (binding != null) { + binding.feedRecyclerView.smoothScrollToPosition(0); + // binding.storiesContainer.setExpanded(true); + } } private boolean isSafeToNavigate(final NavController navController) { diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 5e40818f..45564d61 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -408,7 +408,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } chainingMenuItem = menu.findItem(R.id.chaining); if (chainingMenuItem != null) { - chainingMenuItem.setVisible(isNotMe); + chainingMenuItem.setVisible(isNotMe && profileModel.hasChaining()); } } @@ -528,7 +528,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe @Override public void onRefresh() { - profileDetailsBinding.countsBarrier.getRoot().setVisibility(View.GONE); + profileDetailsBinding.countsDivider.getRoot().setVisibility(View.GONE); profileDetailsBinding.mainProfileImage.setVisibility(View.INVISIBLE); fetchProfileDetails(); } @@ -663,18 +663,22 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe Toast.makeText(context, R.string.error_loading_profile, Toast.LENGTH_SHORT).show(); return; } - if (!postsSetupDone) { - setupPosts(); - } else { - binding.postsRecyclerView.refresh(); + final long profileId = profileModel.getPk(); + if (!isReallyPrivate()) { + if (!postsSetupDone) { + setupPosts(); + } + else { + binding.postsRecyclerView.refresh(); + } + if (isLoggedIn) { + fetchStoryAndHighlights(profileId); + } } profileDetailsBinding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE); profileDetailsBinding.isPrivate.setVisibility(profileModel.isPrivate() ? View.VISIBLE : View.GONE); - final long profileId = profileModel.getPk(); - if (isLoggedIn) { - fetchStoryAndHighlights(profileId); - } + setupButtons(profileId); final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); favoriteRepository.getFavorite(profileModel.getUsername(), FavoriteType.USER, new RepositoryCallback() { @@ -746,7 +750,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe profileDetailsBinding.mainProfileImage.setImageURI(profileModel.getProfilePicUrl()); profileDetailsBinding.mainProfileImage.setVisibility(View.VISIBLE); - profileDetailsBinding.countsBarrier.getRoot().setVisibility(View.VISIBLE); + profileDetailsBinding.countsDivider.getRoot().setVisibility(View.VISIBLE); final long followersCount = profileModel.getFollowerCount(); final long followingCount = profileModel.getFollowingCount(); @@ -907,6 +911,8 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe binding.privatePage1.setImageResource(R.drawable.lock); binding.privatePage2.setText(R.string.priv_acc); binding.privatePage.setVisibility(View.VISIBLE); + binding.privatePage1.setVisibility(View.VISIBLE); + binding.privatePage2.setVisibility(View.VISIBLE); binding.postsRecyclerView.setVisibility(View.GONE); binding.swipeRefreshLayout.setRefreshing(false); } @@ -972,7 +978,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe mutePostsMenuItem.setTitle(profileModel.getFriendshipStatus().isMuting() ? R.string.unmute_posts : R.string.mute_posts); } if (chainingMenuItem != null) { - chainingMenuItem.setVisible(true); + chainingMenuItem.setVisible(profileModel.hasChaining()); } } } diff --git a/app/src/main/java/awais/instagrabber/models/FeedStoryModel.java b/app/src/main/java/awais/instagrabber/models/FeedStoryModel.java index 04595093..b87091e5 100755 --- a/app/src/main/java/awais/instagrabber/models/FeedStoryModel.java +++ b/app/src/main/java/awais/instagrabber/models/FeedStoryModel.java @@ -16,11 +16,15 @@ public final class FeedStoryModel implements Serializable { private final boolean isLive, isBestie; private final long timestamp; private final int mediaCount; - private boolean isShown = true; - public FeedStoryModel(final String storyMediaId, final User profileModel, final boolean fullyRead, - final long timestamp, final StoryModel firstStoryModel, final int mediaCount, - final boolean isLive, final boolean isBestie) { + public FeedStoryModel(final String storyMediaId, + final User profileModel, + final boolean fullyRead, + final long timestamp, + final StoryModel firstStoryModel, + final int mediaCount, + final boolean isLive, + final boolean isBestie) { this.storyMediaId = storyMediaId; this.profileModel = profileModel; this.fullyRead = fullyRead; @@ -52,10 +56,6 @@ public final class FeedStoryModel implements Serializable { return profileModel; } - // public void setFirstStoryModel(final StoryModel firstStoryModel) { - // this.firstStoryModel = firstStoryModel; - // } - public StoryModel getFirstStoryModel() { return firstStoryModel; } @@ -75,12 +75,4 @@ public final class FeedStoryModel implements Serializable { public boolean isBestie() { return isBestie; } - - public boolean isShown() { - return isShown; - } - - public void setShown(final boolean shown) { - isShown = shown; - } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/User.java b/app/src/main/java/awais/instagrabber/repositories/responses/User.java index b2f2a0b2..0d707f72 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/User.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/User.java @@ -17,6 +17,7 @@ public class User implements Serializable { private final boolean isUnpublished; private final boolean isFavorite; private final boolean isDirectappInstalled; + private final boolean hasChaining; private final String reelAutoArchive; private final String allowedCommenterType; private final long mediaCount; @@ -28,11 +29,10 @@ public class User implements Serializable { private final long usertagsCount; private final String publicEmail; private final HdProfilePicUrlInfo hdProfilePicUrlInfo; - private final String profileContext; - private final List profileContextLinksWithUserIds; - private final String socialContext; - // if a DM member is a Facebook user, this is present - private final String interopMessagingUserFbid; + private final String profileContext; // "also followed by" your friends + private final List profileContextLinksWithUserIds; // ^ + private final String socialContext; // AYML + private final String interopMessagingUserFbid; // in DMs only: Facebook user ID public User(final long pk, final String username, @@ -46,6 +46,7 @@ public class User implements Serializable { final boolean isUnpublished, final boolean isFavorite, final boolean isDirectappInstalled, + final boolean hasChaining, final String reelAutoArchive, final String allowedCommenterType, final long mediaCount, @@ -73,6 +74,7 @@ public class User implements Serializable { this.isUnpublished = isUnpublished; this.isFavorite = isFavorite; this.isDirectappInstalled = isDirectappInstalled; + this.hasChaining = hasChaining; this.reelAutoArchive = reelAutoArchive; this.allowedCommenterType = allowedCommenterType; this.mediaCount = mediaCount; @@ -90,6 +92,53 @@ public class User implements Serializable { this.interopMessagingUserFbid = interopMessagingUserFbid; } + public User(final long pk, + final String username, + final String fullName, + final boolean isPrivate, + final String profilePicUrl, + final boolean isVerified) { + this.pk = pk; + this.username = username; + this.fullName = fullName; + this.isPrivate = isPrivate; + this.profilePicUrl = profilePicUrl; + this.profilePicId = null; + this.friendshipStatus = new FriendshipStatus( + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ); + this.isVerified = isVerified; + this.hasAnonymousProfilePicture = false; + this.isUnpublished = false; + this.isFavorite = false; + this.isDirectappInstalled = false; + this.hasChaining = false; + this.reelAutoArchive = null; + this.allowedCommenterType = null; + this.mediaCount = 0; + this.followerCount = 0; + this.followingCount = 0; + this.followingTagCount = 0; + this.biography = null; + this.externalUrl = null; + this.usertagsCount = 0; + this.publicEmail = null; + this.hdProfilePicUrlInfo = null; + this.profileContext = null; + this.profileContextLinksWithUserIds = null; + this.socialContext = null; + this.interopMessagingUserFbid = null; + } + public long getPk() { return pk; } @@ -149,6 +198,10 @@ public class User implements Serializable { return isDirectappInstalled; } + public boolean hasChaining() { + return hasChaining; + } + public String getReelAutoArchive() { return reelAutoArchive; } @@ -237,7 +290,7 @@ public class User implements Serializable { @Override public int hashCode() { return Objects.hash(pk, username, fullName, isPrivate, profilePicUrl, profilePicId, friendshipStatus, isVerified, hasAnonymousProfilePicture, - isUnpublished, isFavorite, isDirectappInstalled, reelAutoArchive, allowedCommenterType, mediaCount, followerCount, - followingCount, followingTagCount, biography, externalUrl, usertagsCount, publicEmail); + isUnpublished, isFavorite, isDirectappInstalled, hasChaining, reelAutoArchive, allowedCommenterType, mediaCount, + followerCount, followingCount, followingTagCount, biography, externalUrl, usertagsCount, publicEmail); } } diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java index f99c7dfd..9f56b765 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java @@ -191,9 +191,7 @@ public class SearchItem { recentSearch.getName(), false, recentSearch.getPicUrl(), - null, null, false, false, false, false, false, - null, null, 0, 0, 0, 0, null, null, - 0, null, null, null, null, null, null + false ); } @@ -205,9 +203,7 @@ public class SearchItem { favorite.getDisplayName(), false, favorite.getPicUrl(), - null, null, false, false, false, false, false, - null, null, 0, 0, 0, 0, null, null, - 0, null, null, null, null, null, null + false ); } diff --git a/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java b/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java index a6bccbfd..bc0f3cb4 100644 --- a/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java +++ b/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java @@ -63,7 +63,7 @@ public class NavigationExtensions { selectedItemTag = graphIdToTagMap.get(bottomNavigationView.getSelectedItemId()); final String firstFragmentTag = graphIdToTagMap.get(firstFragmentGraphId); isOnFirstFragment = selectedItemTag != null && selectedItemTag.equals(firstFragmentTag); - bottomNavigationView.setOnNavigationItemSelectedListener(item -> { + bottomNavigationView.setOnItemSelectedListener(item -> { if (fragmentManager.isStateSaved()) { return false; } @@ -169,7 +169,7 @@ public class NavigationExtensions { private static void setupItemReselected(final BottomNavigationView bottomNavigationView, final SparseArray graphIdToTagMap, final FragmentManager fragmentManager) { - bottomNavigationView.setOnNavigationItemReselectedListener(item -> { + bottomNavigationView.setOnItemReselectedListener(item -> { final String newlySelectedItemTag = graphIdToTagMap.get(item.getItemId()); final Fragment fragmentByTag = fragmentManager.findFragmentByTag(newlySelectedItemTag); if (fragmentByTag == null) { diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index b3968fdd..f205b04f 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -767,11 +767,7 @@ public final class ResponseBodyUtils { owner.optString("full_name"), false, owner.optString("profile_pic_url"), - null, - friendshipStatus, - owner.optBoolean("is_verified"), - false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, - null, null, null, null); + owner.optBoolean("is_verified")); } final String id = feedItem.getString(Constants.EXTRAS_ID); VideoVersion videoVersion = null; diff --git a/app/src/main/java/awais/instagrabber/utils/ViewUtils.java b/app/src/main/java/awais/instagrabber/utils/ViewUtils.java index 3e371045..c2c91e61 100644 --- a/app/src/main/java/awais/instagrabber/utils/ViewUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ViewUtils.java @@ -104,7 +104,6 @@ public final class ViewUtils { } else { hiddenSuppressLayout($this$suppressLayoutCompat, suppress); } - } private static boolean tryHiddenSuppressLayout = true; @@ -118,6 +117,5 @@ public final class ViewUtils { tryHiddenSuppressLayout = false; } } - } } diff --git a/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java index 109b6fea..ab42e84d 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java @@ -238,11 +238,7 @@ public class CommentsViewerViewModel extends ViewModel { null, false, owner.getString("profile_pic_url"), - null, - new FriendshipStatus(false, false, false, false, false, false, false, false, false, false), - owner.optBoolean("is_verified"), - false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, null, null, - null, null); + owner.optBoolean("is_verified")); final JSONObject likedBy = commentJsonObject.optJSONObject("edge_liked_by"); final String commentId = commentJsonObject.getString("id"); final JSONObject childCommentsJsonObject = commentJsonObject.optJSONObject("edge_threaded_comments"); diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index eef7af9a..ddb6da6b 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -34,7 +34,6 @@ import retrofit2.Response; public class GraphQLService extends BaseService { private static final String TAG = "GraphQLService"; - // private static final boolean loadFromMock = false; private final GraphQLRepository repository; @@ -230,39 +229,7 @@ public class GraphQLService extends BaseService { userObject.optString("full_name"), userObject.optBoolean("is_private"), userObject.getString("profile_pic_url"), - null, - new FriendshipStatus( - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ), - userObject.optBoolean("is_verified"), - false, - false, - false, - false, - null, - null, - 0, - 0, - 0, - 0, - null, - null, - 0, - null, - null, - null, - null, - null, - null + userObject.optBoolean("is_verified") )); // userModels.add(new ProfileModel(userObject.optBoolean("is_private"), // false, @@ -357,6 +324,7 @@ public class GraphQLService extends BaseService { false, false, false, + false, null, null, timelineMedia.getLong("count"), diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index 169f630a..96e9bc7d 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -143,39 +143,7 @@ public class StoriesService extends BaseService { userJson.optString("full_name"), userJson.optBoolean("is_private"), userJson.getString("profile_pic_url"), - null, - new FriendshipStatus( - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ), - userJson.optBoolean("is_verified"), - false, - false, - false, - false, - null, - null, - 0, - 0, - 0, - 0, - null, - null, - 0, - null, - null, - null, - null, - null, - null + userJson.optBoolean("is_verified") ); final long timestamp = node.getLong("latest_reel_media"); final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp; @@ -210,39 +178,7 @@ public class StoriesService extends BaseService { userJson.optString("full_name"), userJson.optBoolean("is_private"), userJson.getString("profile_pic_url"), - null, - new FriendshipStatus( - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ), - userJson.optBoolean("is_verified"), - false, - false, - false, - false, - null, - null, - 0, - 0, - 0, - 0, - null, - null, - 0, - null, - null, - null, - null, - null, - null + userJson.optBoolean("is_verified") ); feedStoryModels.add(new FeedStoryModel( node.getString("id"), diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 051dd0aa..48b36bfd 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -38,7 +38,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" - android:layout_marginTop="@dimen/private_page_margins" android:gravity="center" android:orientation="vertical" android:visibility="gone" @@ -48,6 +47,8 @@ android:id="@+id/privatePage1" android:layout_width="@dimen/private_page_size" android:layout_height="@dimen/private_page_size" + android:visibility="gone" + tools:visibility="visible" app:srcCompat="@drawable/lock" /> diff --git a/app/src/main/res/layout/item_feed_top.xml b/app/src/main/res/layout/item_feed_top.xml index 7aac41b5..61b49c31 100755 --- a/app/src/main/res/layout/item_feed_top.xml +++ b/app/src/main/res/layout/item_feed_top.xml @@ -43,7 +43,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/title" + android:ellipsize="end" android:gravity="center_vertical" + android:maxLines="1" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" android:textSize="15sp" android:visibility="visible" diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index d7f5bdd8..61cec0ff 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -15,10 +15,11 @@ android:transitionName="profile_pic" android:visibility="invisible" app:actualImageScaleType="centerCrop" - app:layout_constraintBottom_toBottomOf="@id/btnTagged" + app:layout_constraintBottom_toTopOf="@id/top_barrier" app:layout_constraintEnd_toStartOf="@id/btnFollow" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0" tools:foreground="@mipmap/ic_launcher" tools:visibility="visible" /> @@ -112,7 +113,7 @@ app:chipBackgroundColor="@null" app:chipIcon="@drawable/ic_outline_person_pin_24" app:chipIconTint="@color/deep_orange_800" - app:layout_constraintBottom_toTopOf="@+id/mainFullName" + app:layout_constraintBottom_toTopOf="@+id/top_barrier" app:layout_constraintStart_toEndOf="@id/mainProfileImage" app:layout_constraintTop_toBottomOf="@id/fav_chip" app:rippleColor="@color/deep_orange_400" @@ -128,12 +129,18 @@ app:chipBackgroundColor="@null" app:chipIcon="@drawable/ic_round_send_24" app:chipIconTint="@color/green" - app:layout_constraintBottom_toTopOf="@+id/mainFullName" + app:layout_constraintBottom_toTopOf="@+id/top_barrier" app:layout_constraintStart_toEndOf="@id/btnTagged" app:layout_constraintTop_toBottomOf="@id/fav_chip" app:rippleColor="@color/green" tools:visibility="visible" /> + + @@ -233,6 +237,7 @@ android:paddingBottom="4dp" android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:visibility="gone" + app:layout_constraintBottom_toTopOf="@id/profileContext" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/mainBiography" @@ -254,7 +259,7 @@ android:textSize="12sp" android:textStyle="italic" android:visibility="gone" - app:layout_constraintBottom_toTopOf="@id/counts_barrier" + app:layout_constraintBottom_toTopOf="@id/counts_divider" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/mainUrl" @@ -262,11 +267,12 @@ tools:visibility="visible" /> @color/text_color_light #FF5500 - #FFFFFFFF + @color/white #FFBB00 - #FF000000 + @color/black #efefef diff --git a/app/src/main/res/xml/header_list_scene.xml b/app/src/main/res/xml/header_list_scene.xml index 389b7cb1..f4a76d88 100644 --- a/app/src/main/res/xml/header_list_scene.xml +++ b/app/src/main/res/xml/header_list_scene.xml @@ -9,6 +9,13 @@ motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> +