Austin Huang
4 years ago
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
20 changed files with 579 additions and 15 deletions
-
97app/src/main/java/awais/instagrabber/adapters/FeedStoriesListAdapter.java
-
53app/src/main/java/awais/instagrabber/adapters/HighlightStoriesListAdapter.java
-
69app/src/main/java/awais/instagrabber/adapters/viewholder/StoryListViewHolder.java
-
108app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java
-
7app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java
-
5app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java
-
25app/src/main/java/awais/instagrabber/models/FeedStoryModel.java
-
20app/src/main/java/awais/instagrabber/models/HighlightModel.java
-
9app/src/main/java/awais/instagrabber/models/StoryModel.java
-
3app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java
-
2app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java
-
65app/src/main/java/awais/instagrabber/webservices/StoriesService.java
-
10app/src/main/res/drawable/ic_archive.xml
-
10app/src/main/res/drawable/ic_story_list.xml
-
15app/src/main/res/layout/fragment_story_list_viewer.xml
-
5app/src/main/res/menu/feed_menu.xml
-
11app/src/main/res/navigation/feed_nav_graph.xml
-
10app/src/main/res/navigation/more_nav_graph.xml
-
68app/src/main/res/navigation/story_list_nav_graph.xml
-
2app/src/main/res/values/strings.xml
@ -0,0 +1,97 @@ |
|||
package awais.instagrabber.adapters; |
|||
|
|||
import android.view.LayoutInflater; |
|||
import android.view.ViewGroup; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.recyclerview.widget.DiffUtil; |
|||
import androidx.recyclerview.widget.ListAdapter; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
import awais.instagrabber.adapters.viewholder.StoryListViewHolder; |
|||
import awais.instagrabber.databinding.ItemNotificationBinding; |
|||
import awais.instagrabber.models.FeedStoryModel; |
|||
import awais.instagrabber.utils.Constants; |
|||
import awais.instagrabber.utils.Utils; |
|||
|
|||
public final class FeedStoriesListAdapter extends ListAdapter<FeedStoryModel, StoryListViewHolder> { |
|||
private final OnFeedStoryClickListener listener; |
|||
|
|||
private static final DiffUtil.ItemCallback<FeedStoryModel> diffCallback = new DiffUtil.ItemCallback<FeedStoryModel>() { |
|||
@Override |
|||
public boolean areItemsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) { |
|||
return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId()); |
|||
} |
|||
|
|||
@Override |
|||
public boolean areContentsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) { |
|||
return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId()) && oldItem.isFullyRead().equals(newItem.isFullyRead()); |
|||
} |
|||
}; |
|||
|
|||
public FeedStoriesListAdapter(final OnFeedStoryClickListener listener) { |
|||
super(diffCallback); |
|||
this.listener = listener; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public StoryListViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { |
|||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); |
|||
final ItemNotificationBinding binding = ItemNotificationBinding.inflate(layoutInflater, parent, false); |
|||
return new StoryListViewHolder(binding); |
|||
} |
|||
|
|||
@Override |
|||
public void onBindViewHolder(@NonNull final StoryListViewHolder holder, final int position) { |
|||
final FeedStoryModel model = getItem(position); |
|||
holder.bind(model, listener); |
|||
} |
|||
|
|||
@Override |
|||
public void submitList(@Nullable final List<FeedStoryModel> list, @Nullable final Runnable commitCallback) { |
|||
if (list == null) { |
|||
super.submitList(null, commitCallback); |
|||
return; |
|||
} |
|||
super.submitList(sort(list), commitCallback); |
|||
} |
|||
|
|||
@Override |
|||
public void submitList(@Nullable final List<FeedStoryModel> list) { |
|||
if (list == null) { |
|||
super.submitList(null); |
|||
return; |
|||
} |
|||
super.submitList(sort(list)); |
|||
} |
|||
|
|||
private List<FeedStoryModel> sort(final List<FeedStoryModel> list) { |
|||
final List<FeedStoryModel> listCopy = new ArrayList<>(list); |
|||
Collections.sort(listCopy, (o1, o2) -> { |
|||
int result; |
|||
switch (Utils.settingsHelper.getString(Constants.STORY_SORT)) { |
|||
case "1": |
|||
result = o1.getTimestamp() > o2.getTimestamp() ? -1 : (o1.getTimestamp() == o2.getTimestamp() ? 0 : 1); |
|||
break; |
|||
case "2": |
|||
result = o1.getTimestamp() > o2.getTimestamp() ? 1 : (o1.getTimestamp() == o2.getTimestamp() ? 0 : -1); |
|||
break; |
|||
default: |
|||
result = 0; |
|||
} |
|||
return result; |
|||
}); |
|||
return listCopy; |
|||
} |
|||
|
|||
public interface OnFeedStoryClickListener { |
|||
void onFeedStoryClick(final FeedStoryModel model); |
|||
|
|||
void onProfileClick(final String username); |
|||
} |
|||
} |
@ -0,0 +1,53 @@ |
|||
package awais.instagrabber.adapters; |
|||
|
|||
import android.view.LayoutInflater; |
|||
import android.view.ViewGroup; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.recyclerview.widget.DiffUtil; |
|||
import androidx.recyclerview.widget.ListAdapter; |
|||
|
|||
import awais.instagrabber.adapters.viewholder.StoryListViewHolder; |
|||
import awais.instagrabber.databinding.ItemNotificationBinding; |
|||
import awais.instagrabber.models.HighlightModel; |
|||
|
|||
public final class HighlightStoriesListAdapter extends ListAdapter<HighlightModel, StoryListViewHolder> { |
|||
private final OnHighlightStoryClickListener listener; |
|||
|
|||
private static final DiffUtil.ItemCallback<HighlightModel> diffCallback = new DiffUtil.ItemCallback<HighlightModel>() { |
|||
@Override |
|||
public boolean areItemsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) { |
|||
return oldItem.getId().equals(newItem.getId()); |
|||
} |
|||
|
|||
@Override |
|||
public boolean areContentsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) { |
|||
return oldItem.getId().equals(newItem.getId()); |
|||
} |
|||
}; |
|||
|
|||
public HighlightStoriesListAdapter(final OnHighlightStoryClickListener listener) { |
|||
super(diffCallback); |
|||
this.listener = listener; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public StoryListViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { |
|||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); |
|||
final ItemNotificationBinding binding = ItemNotificationBinding.inflate(layoutInflater, parent, false); |
|||
return new StoryListViewHolder(binding); |
|||
} |
|||
|
|||
@Override |
|||
public void onBindViewHolder(@NonNull final StoryListViewHolder holder, final int position) { |
|||
final HighlightModel model = getItem(position); |
|||
holder.bind(model, listener); |
|||
} |
|||
|
|||
public interface OnHighlightStoryClickListener { |
|||
void onHighlightClick(HighlightModel model); |
|||
|
|||
void onProfileClick(String username); |
|||
} |
|||
} |
@ -0,0 +1,69 @@ |
|||
package awais.instagrabber.adapters.viewholder; |
|||
|
|||
import android.text.TextUtils; |
|||
import android.view.View; |
|||
|
|||
import androidx.recyclerview.widget.RecyclerView; |
|||
|
|||
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; |
|||
|
|||
public final class StoryListViewHolder extends RecyclerView.ViewHolder { |
|||
private final ItemNotificationBinding binding; |
|||
|
|||
public StoryListViewHolder(final ItemNotificationBinding binding) { |
|||
super(binding.getRoot()); |
|||
this.binding = binding; |
|||
} |
|||
|
|||
public void bind(final FeedStoryModel model, |
|||
final OnFeedStoryClickListener notificationClickListener) { |
|||
if (model == null) return; |
|||
binding.tvComment.setVisibility(View.GONE); |
|||
binding.tvSubComment.setVisibility(View.GONE); |
|||
|
|||
binding.tvDate.setText(model.getDateTime()); |
|||
|
|||
binding.tvUsername.setText(model.getProfileModel().getUsername()); |
|||
binding.ivProfilePic.setImageURI(model.getProfileModel().getSdProfilePic()); |
|||
binding.ivProfilePic.setOnClickListener(v -> { |
|||
if (notificationClickListener == null) return; |
|||
notificationClickListener.onProfileClick(model.getProfileModel().getUsername()); |
|||
}); |
|||
|
|||
binding.ivPreviewPic.setVisibility(View.VISIBLE); |
|||
binding.ivPreviewPic.setImageURI(model.getFirstStoryModel().getThumbnail()); |
|||
binding.ivPreviewPic.setOnClickListener(v -> { |
|||
if (notificationClickListener == null) return; |
|||
notificationClickListener.onFeedStoryClick(model); |
|||
}); |
|||
|
|||
itemView.setOnClickListener(v -> { |
|||
if (notificationClickListener == null) return; |
|||
notificationClickListener.onFeedStoryClick(model); |
|||
}); |
|||
} |
|||
|
|||
public void bind(final HighlightModel model, |
|||
final OnHighlightStoryClickListener notificationClickListener) { |
|||
if (model == null) return; |
|||
binding.tvComment.setVisibility(View.GONE); |
|||
binding.tvSubComment.setVisibility(View.GONE); |
|||
|
|||
binding.tvUsername.setText(model.getDateTime()); |
|||
|
|||
binding.ivProfilePic.setVisibility(View.GONE); |
|||
|
|||
binding.ivPreviewPic.setVisibility(View.VISIBLE); |
|||
binding.ivPreviewPic.setImageURI(model.getThumbnailUrl()); |
|||
|
|||
itemView.setOnClickListener(v -> { |
|||
if (notificationClickListener == null) return; |
|||
notificationClickListener.onHighlightClick(model); |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,108 @@ |
|||
package awais.instagrabber.fragments; |
|||
|
|||
import android.content.Context; |
|||
import android.os.Bundle; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.fragment.app.Fragment; |
|||
import androidx.lifecycle.ViewModelProvider; |
|||
import androidx.navigation.NavDirections; |
|||
import androidx.navigation.fragment.NavHostFragment; |
|||
import androidx.recyclerview.widget.LinearLayoutManager; |
|||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; |
|||
|
|||
import awais.instagrabber.adapters.FeedStoriesListAdapter; |
|||
import awais.instagrabber.adapters.FeedStoriesListAdapter.OnFeedStoryClickListener; |
|||
import awais.instagrabber.databinding.FragmentStoryListViewerBinding; |
|||
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections; |
|||
import awais.instagrabber.models.FeedStoryModel; |
|||
import awais.instagrabber.utils.Constants; |
|||
import awais.instagrabber.viewmodels.StoriesViewModel; |
|||
import awais.instagrabber.webservices.StoriesService; |
|||
|
|||
import static awais.instagrabber.utils.Utils.settingsHelper; |
|||
|
|||
public final class StoryListViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { |
|||
private static final String TAG = "StoryListViewerFragment"; |
|||
|
|||
private FragmentStoryListViewerBinding binding; |
|||
private SwipeRefreshLayout root; |
|||
private boolean shouldRefresh = true; |
|||
private StoriesViewModel storiesViewModel; |
|||
private StoriesService storiesService; |
|||
private Context context; |
|||
private String type; |
|||
|
|||
private final OnFeedStoryClickListener clickListener = new OnFeedStoryClickListener() { |
|||
@Override |
|||
public void onFeedStoryClick(final FeedStoryModel model) { |
|||
if (model == null) return; |
|||
// final NavDirections action = StoryListNavGraphDirections.actionStoryListFragmentToStoryViewerFragment(position, null, false, false, null, null); |
|||
// NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action); |
|||
} |
|||
|
|||
@Override |
|||
public void onProfileClick(final String username) { |
|||
openProfile(username); |
|||
} |
|||
}; |
|||
|
|||
@Override |
|||
public void onCreate(@Nullable final Bundle savedInstanceState) { |
|||
super.onCreate(savedInstanceState); |
|||
context = getContext(); |
|||
if (context == null) return; |
|||
storiesService = StoriesService.getInstance(); |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { |
|||
if (root != null) { |
|||
shouldRefresh = false; |
|||
return root; |
|||
} |
|||
binding = FragmentStoryListViewerBinding.inflate(getLayoutInflater()); |
|||
root = binding.getRoot(); |
|||
return root; |
|||
} |
|||
|
|||
@Override |
|||
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { |
|||
if (!shouldRefresh) return; |
|||
init(); |
|||
shouldRefresh = false; |
|||
} |
|||
|
|||
private void init() { |
|||
final Context context = getContext(); |
|||
if (getArguments() == null) return; |
|||
final StoryListViewerFragmentArgs fragmentArgs = StoryListViewerFragmentArgs.fromBundle(getArguments()); |
|||
type = fragmentArgs.getType(); |
|||
binding.swipeRefreshLayout.setOnRefreshListener(this); |
|||
storiesViewModel = new ViewModelProvider(this).get(StoriesViewModel.class); |
|||
// final NotificationsAdapter adapter = new NotificationsAdapter(clickListener, mentionClickListener); |
|||
binding.rvStories.setLayoutManager(new LinearLayoutManager(context)); |
|||
// binding.rvStories.setAdapter(adapter); |
|||
// storiesViewModel.getList().observe(getViewLifecycleOwner(), adapter::submitList); |
|||
onRefresh(); |
|||
} |
|||
|
|||
@Override |
|||
public void onRefresh() { |
|||
binding.swipeRefreshLayout.setRefreshing(true); |
|||
|
|||
binding.swipeRefreshLayout.setRefreshing(false); |
|||
// storiesViewModel.getList().postValue(); |
|||
} |
|||
|
|||
private void openProfile(final String username) { |
|||
final NavDirections action = MorePreferencesFragmentDirections |
|||
.actionGlobalProfileFragment("@" + username); |
|||
NavHostFragment.findNavController(this).navigate(action); |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24" |
|||
android:tint="?attr/colorControlNormal"> |
|||
<path |
|||
android:fillColor="@android:color/white" |
|||
android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/> |
|||
</vector> |
@ -0,0 +1,10 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24" |
|||
android:tint="?attr/colorControlNormal"> |
|||
<path |
|||
android:fillColor="@android:color/white" |
|||
android:pathData="M13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM11,4.07L11,2.05c-2.01,0.2 -3.84,1 -5.32,2.21L7.1,5.69c1.11,-0.86 2.44,-1.44 3.9,-1.62zM5.69,7.1L4.26,5.68C3.05,7.16 2.25,8.99 2.05,11h2.02c0.18,-1.46 0.76,-2.79 1.62,-3.9zM4.07,13L2.05,13c0.2,2.01 1,3.84 2.21,5.32l1.43,-1.43c-0.86,-1.1 -1.44,-2.43 -1.62,-3.89zM5.68,19.74C7.16,20.95 9,21.75 11,21.95v-2.02c-1.46,-0.18 -2.79,-0.76 -3.9,-1.62l-1.42,1.43zM22,12c0,5.16 -3.92,9.42 -8.95,9.95v-2.02C16.97,19.41 20,16.05 20,12s-3.03,-7.41 -6.95,-7.93L13.05,2.05C18.08,2.58 22,6.84 22,12z"/> |
|||
</vector> |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:id="@+id/swipeRefreshLayout" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
tools:context=".fragments.StoryListViewerFragment"> |
|||
|
|||
<androidx.recyclerview.widget.RecyclerView |
|||
android:id="@+id/rvStories" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:clipToPadding="false" |
|||
tools:listitem="@layout/item_notification" /> |
|||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> |
@ -1,6 +1,11 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto"> |
|||
<item |
|||
android:id="@+id/storyList" |
|||
android:icon="@drawable/ic_story_list" |
|||
android:title="@string/feed_stories" |
|||
app:showAsAction="always" /> |
|||
<item |
|||
android:id="@+id/layout" |
|||
android:title="@string/layout" |
|||
|
@ -0,0 +1,68 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<navigation xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:id="@+id/story_list_nav_graph" |
|||
app:startDestination="@id/storyListViewerFragment"> |
|||
|
|||
<action |
|||
android:id="@+id/action_global_profileFragment" |
|||
app:destination="@id/profile_nav_graph"> |
|||
<argument |
|||
android:name="username" |
|||
app:argType="string" |
|||
app:nullable="true" /> |
|||
</action> |
|||
|
|||
<fragment |
|||
android:id="@+id/storyListViewerFragment" |
|||
android:name="awais.instagrabber.fragments.StoryListViewerFragment" |
|||
android:label="Stories" |
|||
tools:layout="@layout/fragment_story_list_viewer"> |
|||
<argument |
|||
android:name="type" |
|||
app:argType="string" |
|||
app:nullable="false" /> |
|||
<action |
|||
android:id="@+id/action_storyListFragment_to_storyViewerFragment" |
|||
app:destination="@id/storyViewerFragment" /> |
|||
</fragment> |
|||
|
|||
<action |
|||
android:id="@+id/action_global_storyListViewerFragment" |
|||
app:destination="@id/storyListViewerFragment"> |
|||
<argument |
|||
android:name="type" |
|||
app:argType="string" |
|||
app:nullable="false" /> |
|||
</action> |
|||
|
|||
<fragment |
|||
android:id="@+id/storyViewerFragment" |
|||
android:name="awais.instagrabber.fragments.StoryViewerFragment" |
|||
android:label="StoryViewerFragment" |
|||
tools:layout="@layout/fragment_story_viewer"> |
|||
<argument |
|||
android:name="feedStoryIndex" |
|||
app:argType="integer" |
|||
app:nullable="false" /> |
|||
<argument |
|||
android:name="highlight" |
|||
app:argType="string" |
|||
app:nullable="true" /> |
|||
<argument |
|||
android:name="isHashtag" |
|||
app:argType="boolean" /> |
|||
<argument |
|||
android:name="isLoc" |
|||
app:argType="boolean" /> |
|||
<argument |
|||
android:name="profileId" |
|||
app:argType="string" |
|||
app:nullable="true" /> |
|||
<argument |
|||
android:name="username" |
|||
app:argType="string" |
|||
app:nullable="true" /> |
|||
</fragment> |
|||
</navigation> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue