-
11README.md
-
18app/src/main/AndroidManifest.xml
-
99app/src/main/java/awais/instagrabber/MainHelper.java
-
4app/src/main/java/awais/instagrabber/activities/CommentsViewer.java
-
19app/src/main/java/awais/instagrabber/activities/Main.java
-
140app/src/main/java/awais/instagrabber/activities/NotificationsViewer.java
-
6app/src/main/java/awais/instagrabber/activities/PostViewer.java
-
24app/src/main/java/awais/instagrabber/activities/ProfileViewer.java
-
234app/src/main/java/awais/instagrabber/activities/SavedViewer.java
-
95app/src/main/java/awais/instagrabber/activities/StoryViewer.java
-
2app/src/main/java/awais/instagrabber/adapters/FeedAdapter.java
-
90app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java
-
76app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java
-
42app/src/main/java/awais/instagrabber/asyncs/DiscoverFetcher.java
-
1app/src/main/java/awais/instagrabber/asyncs/LocationFetcher.java
-
85app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java
-
22app/src/main/java/awais/instagrabber/asyncs/PostFetcher.java
-
22app/src/main/java/awais/instagrabber/asyncs/PostsFetcher.java
-
68app/src/main/java/awais/instagrabber/asyncs/ProfilePictureFetcher.java
-
24app/src/main/java/awais/instagrabber/asyncs/StoryStatusFetcher.java
-
62app/src/main/java/awais/instagrabber/dialogs/ProfileSettingsDialog.java
-
58app/src/main/java/awais/instagrabber/models/NotificationModel.java
-
52app/src/main/java/awais/instagrabber/models/PollModel.java
-
19app/src/main/java/awais/instagrabber/models/StoryModel.java
-
3app/src/main/java/awais/instagrabber/models/enums/DownloadMethod.java
-
1app/src/main/java/awais/instagrabber/models/enums/ItemGetType.java
-
10app/src/main/java/awais/instagrabber/models/enums/NotificationType.java
-
7app/src/main/java/awais/instagrabber/models/enums/ProfilePictureFetchMode.java
-
1app/src/main/java/awais/instagrabber/utils/Constants.java
-
1app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
-
3app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
-
80app/src/main/java/awais/instagrabber/utils/Utils.java
-
2app/src/main/java/awaisomereport/LogCollector.java
-
10app/src/main/res/drawable-anydpi/ic_bookmark.xml
-
10app/src/main/res/drawable-anydpi/ic_like.xml
-
11app/src/main/res/drawable-anydpi/ic_notif.xml
-
BINapp/src/main/res/drawable-hdpi/ic_bookmark.png
-
BINapp/src/main/res/drawable-hdpi/ic_like.png
-
BINapp/src/main/res/drawable-hdpi/ic_notif.png
-
BINapp/src/main/res/drawable-mdpi/ic_bookmark.png
-
BINapp/src/main/res/drawable-mdpi/ic_like.png
-
BINapp/src/main/res/drawable-mdpi/ic_notif.png
-
BINapp/src/main/res/drawable-xhdpi/ic_bookmark.png
-
BINapp/src/main/res/drawable-xhdpi/ic_like.png
-
BINapp/src/main/res/drawable-xhdpi/ic_notif.png
-
BINapp/src/main/res/drawable-xxhdpi/ic_bookmark.png
-
BINapp/src/main/res/drawable-xxhdpi/ic_like.png
-
BINapp/src/main/res/drawable-xxhdpi/ic_notif.png
-
BINapp/src/main/res/drawable/ic_location.png
-
55app/src/main/res/layout/activity_main.xml
-
30app/src/main/res/layout/activity_notification.xml
-
31app/src/main/res/layout/activity_saved.xml
-
41app/src/main/res/layout/activity_story_viewer.xml
-
48app/src/main/res/layout/dialog_profile_settings.xml
-
20app/src/main/res/layout/item_notification.xml
-
18app/src/main/res/layout/layout_changelog_textview.xml
-
154app/src/main/res/layout/layout_include_notif_item.xml
-
10app/src/main/res/layout/layout_include_toolbar.xml
-
8app/src/main/res/menu/menu.xml
-
9app/src/main/res/menu/saved.xml
-
5fastlane/metadata/android/full_description.txt
-
BINfastlane/metadata/android/images/phoneScreenshots/1.jpg
-
BINfastlane/metadata/android/images/phoneScreenshots/2.jpg
-
BINfastlane/metadata/android/images/phoneScreenshots/3.jpg
-
BINfastlane/metadata/android/images/phoneScreenshots/4.jpg
-
BINfastlane/metadata/android/images/phoneScreenshots/5.jpg
-
BINfastlane/metadata/android/images/phoneScreenshots/6.jpg
@ -0,0 +1,140 @@ |
|||||
|
package awais.instagrabber.activities; |
||||
|
|
||||
|
import android.content.DialogInterface; |
||||
|
import android.content.Intent; |
||||
|
import android.content.res.Resources; |
||||
|
import android.os.AsyncTask; |
||||
|
import android.os.Bundle; |
||||
|
import android.text.SpannableString; |
||||
|
import android.text.Spanned; |
||||
|
import android.text.style.RelativeSizeSpan; |
||||
|
import android.util.Log; |
||||
|
import android.view.Menu; |
||||
|
import android.view.MenuItem; |
||||
|
import android.view.View; |
||||
|
import android.view.inputmethod.InputMethodManager; |
||||
|
import android.widget.ArrayAdapter; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.appcompat.app.AlertDialog; |
||||
|
import androidx.appcompat.widget.SearchView; |
||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; |
||||
|
|
||||
|
import java.io.DataOutputStream; |
||||
|
import java.net.HttpURLConnection; |
||||
|
import java.net.URL; |
||||
|
import java.net.URLEncoder; |
||||
|
|
||||
|
import awais.instagrabber.R; |
||||
|
import awais.instagrabber.adapters.NotificationsAdapter; |
||||
|
import awais.instagrabber.asyncs.NotificationsFetcher; |
||||
|
import awais.instagrabber.databinding.ActivityNotificationBinding; |
||||
|
import awais.instagrabber.interfaces.FetchListener; |
||||
|
import awais.instagrabber.interfaces.MentionClickListener; |
||||
|
import awais.instagrabber.models.NotificationModel; |
||||
|
import awais.instagrabber.models.PostModel; |
||||
|
import awais.instagrabber.models.ProfileModel; |
||||
|
import awais.instagrabber.utils.Constants; |
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
|
||||
|
public final class NotificationsViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener { |
||||
|
private NotificationsAdapter notificationsAdapter; |
||||
|
private NotificationModel notificationModel; |
||||
|
private ActivityNotificationBinding notificationsBinding; |
||||
|
private ArrayAdapter<String> commmentDialogAdapter; |
||||
|
private String shortCode, postId, userId; |
||||
|
private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); |
||||
|
private Resources resources; |
||||
|
private InputMethodManager imm; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(@Nullable final Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
notificationsBinding = ActivityNotificationBinding.inflate(getLayoutInflater()); |
||||
|
setContentView(notificationsBinding.getRoot()); |
||||
|
notificationsBinding.swipeRefreshLayout.setOnRefreshListener(this); |
||||
|
|
||||
|
notificationsBinding.swipeRefreshLayout.setRefreshing(true); |
||||
|
setSupportActionBar(notificationsBinding.toolbar.toolbar); |
||||
|
notificationsBinding.toolbar.toolbar.setTitle(R.string.title_notifications); |
||||
|
|
||||
|
resources = getResources(); |
||||
|
|
||||
|
new NotificationsFetcher(new FetchListener<NotificationModel[]>() { |
||||
|
@Override |
||||
|
public void onResult(final NotificationModel[] notificationModels) { |
||||
|
notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener); |
||||
|
|
||||
|
notificationsBinding.rvComments.setAdapter(notificationsAdapter); |
||||
|
notificationsBinding.swipeRefreshLayout.setRefreshing(false); |
||||
|
} |
||||
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onRefresh() { |
||||
|
notificationsBinding.swipeRefreshLayout.setRefreshing(true); |
||||
|
new NotificationsFetcher(new FetchListener<NotificationModel[]>() { |
||||
|
@Override |
||||
|
public void onResult(final NotificationModel[] notificationModels) { |
||||
|
notificationsBinding.swipeRefreshLayout.setRefreshing(false); |
||||
|
|
||||
|
notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener); |
||||
|
|
||||
|
notificationsBinding.rvComments.setAdapter(notificationsAdapter); |
||||
|
} |
||||
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
||||
|
} |
||||
|
|
||||
|
final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> { |
||||
|
if (which == 0) |
||||
|
searchUsername(notificationModel.getUsername()); |
||||
|
else if (which == 1) |
||||
|
startActivity(new Intent(getApplicationContext(), PostViewer.class) |
||||
|
.putExtra(Constants.EXTRAS_POST, new PostModel(notificationModel.getShortcode()))); |
||||
|
}; |
||||
|
|
||||
|
private final View.OnClickListener clickListener = v -> { |
||||
|
final Object tag = v.getTag(); |
||||
|
if (tag instanceof NotificationModel) { |
||||
|
notificationModel = (NotificationModel) tag; |
||||
|
|
||||
|
final String username = notificationModel.getUsername(); |
||||
|
final SpannableString title = new SpannableString(username + ":\n" + notificationModel.getText()); |
||||
|
title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); |
||||
|
|
||||
|
String[] commentDialogList; |
||||
|
|
||||
|
if (notificationModel.getShortcode() != null) commentDialogList = new String[]{ |
||||
|
resources.getString(R.string.open_profile), |
||||
|
resources.getString(R.string.view_post) |
||||
|
}; |
||||
|
else commentDialogList = new String[]{ |
||||
|
resources.getString(R.string.open_profile) |
||||
|
}; |
||||
|
|
||||
|
commmentDialogAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, commentDialogList); |
||||
|
|
||||
|
new AlertDialog.Builder(this).setTitle(title) |
||||
|
.setAdapter(commmentDialogAdapter, profileDialogListener) |
||||
|
.setNeutralButton(R.string.cancel, null) |
||||
|
.show(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
private final MentionClickListener mentionClickListener = (view, text, isHashtag) -> |
||||
|
new AlertDialog.Builder(this).setTitle(text) |
||||
|
.setMessage(isHashtag ? R.string.comment_view_mention_hash_search : R.string.comment_view_mention_user_search) |
||||
|
.setNegativeButton(R.string.cancel, null).setPositiveButton(R.string.ok, |
||||
|
(dialog, which) -> searchUsername(text)).show(); |
||||
|
|
||||
|
|
||||
|
private void searchUsername(final String text) { |
||||
|
if (Main.scanHack != null) { |
||||
|
Main.scanHack.onResult(text); |
||||
|
setResult(6969); |
||||
|
finish(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,234 @@ |
|||||
|
package awais.instagrabber.activities; |
||||
|
|
||||
|
import android.content.Intent; |
||||
|
import android.content.pm.PackageManager; |
||||
|
import android.content.res.Resources; |
||||
|
import android.os.AsyncTask; |
||||
|
import android.os.Bundle; |
||||
|
import android.util.Log; |
||||
|
import android.view.Menu; |
||||
|
import android.view.MenuItem; |
||||
|
import android.view.View; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
import awais.instagrabber.BuildConfig; |
||||
|
import awais.instagrabber.R; |
||||
|
import awais.instagrabber.adapters.PostsAdapter; |
||||
|
import awais.instagrabber.asyncs.PostsFetcher; |
||||
|
import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager; |
||||
|
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; |
||||
|
import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; |
||||
|
import awais.instagrabber.databinding.ActivitySavedBinding; |
||||
|
import awais.instagrabber.interfaces.FetchListener; |
||||
|
import awais.instagrabber.interfaces.ItemGetter; |
||||
|
import awais.instagrabber.models.BasePostModel; |
||||
|
import awais.instagrabber.models.PostModel; |
||||
|
import awais.instagrabber.models.enums.DownloadMethod; |
||||
|
import awais.instagrabber.models.enums.ItemGetType; |
||||
|
import awais.instagrabber.utils.Constants; |
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
import awaisomereport.LogCollector; |
||||
|
|
||||
|
import static awais.instagrabber.utils.Constants.AUTOLOAD_POSTS; |
||||
|
import static awais.instagrabber.utils.Utils.logCollector; |
||||
|
|
||||
|
public final class SavedViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener { |
||||
|
private static AsyncTask<?, ?, ?> currentlyExecuting; |
||||
|
public static ItemGetter itemGetter; |
||||
|
private PostsAdapter postsAdapter; |
||||
|
private boolean hasNextPage, autoloadPosts; |
||||
|
//private CommentModel commentModel; |
||||
|
private ActivitySavedBinding savedBinding; |
||||
|
private String action, username, endCursor; |
||||
|
private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); |
||||
|
private RecyclerLazyLoader lazyLoader; |
||||
|
private Resources resources; |
||||
|
private ArrayList<PostModel> selectedItems = new ArrayList<>(); |
||||
|
private final ArrayList<PostModel> allItems = new ArrayList<>(); |
||||
|
private MenuItem downloadAction; |
||||
|
|
||||
|
private final FetchListener<PostModel[]> postsFetchListener = new FetchListener<PostModel[]>() { |
||||
|
@Override |
||||
|
public void onResult(final PostModel[] result) { |
||||
|
if (result != null) { |
||||
|
final int oldSize = allItems.size(); |
||||
|
allItems.addAll(Arrays.asList(result)); |
||||
|
|
||||
|
postsAdapter.notifyItemRangeInserted(oldSize, result.length); |
||||
|
|
||||
|
savedBinding.mainPosts.post(() -> { |
||||
|
savedBinding.mainPosts.setNestedScrollingEnabled(true); |
||||
|
savedBinding.mainPosts.setVisibility(View.VISIBLE); |
||||
|
}); |
||||
|
|
||||
|
final PostModel model = result[result.length - 1]; |
||||
|
if (model != null) { |
||||
|
endCursor = model.getEndCursor(); |
||||
|
|
||||
|
hasNextPage = model.hasNextPage(); |
||||
|
if (autoloadPosts && hasNextPage) |
||||
|
currentlyExecuting = new PostsFetcher(action, endCursor, this) |
||||
|
.setUsername(username).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
||||
|
else { |
||||
|
savedBinding.swipeRefreshLayout.setRefreshing(false); |
||||
|
} |
||||
|
model.setPageCursor(false, null); |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
savedBinding.swipeRefreshLayout.setRefreshing(false); |
||||
|
Toast.makeText(getApplicationContext(), R.string.empty_list, Toast.LENGTH_SHORT).show(); |
||||
|
finish(); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(@Nullable final Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
savedBinding = ActivitySavedBinding.inflate(getLayoutInflater()); |
||||
|
setContentView(savedBinding.getRoot()); |
||||
|
savedBinding.swipeRefreshLayout.setOnRefreshListener(this); |
||||
|
autoloadPosts = Utils.settingsHelper.getBoolean(AUTOLOAD_POSTS); |
||||
|
savedBinding.mainPosts.setNestedScrollingEnabled(false); |
||||
|
final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(this, Utils.convertDpToPx(110)); |
||||
|
savedBinding.mainPosts.setLayoutManager(layoutManager); |
||||
|
savedBinding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4))); |
||||
|
|
||||
|
final Intent intent = getIntent(); |
||||
|
if (intent == null || !intent.hasExtra(Constants.EXTRAS_INDEX) |
||||
|
|| Utils.isEmpty((action = intent.getStringExtra(Constants.EXTRAS_INDEX))) |
||||
|
|| !intent.hasExtra(Constants.EXTRAS_USER) |
||||
|
|| Utils.isEmpty((username = intent.getStringExtra(Constants.EXTRAS_USER)))) { |
||||
|
Utils.errorFinish(this); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
savedBinding.mainPosts.setAdapter(postsAdapter = new PostsAdapter(allItems, v -> { |
||||
|
final Object tag = v.getTag(); |
||||
|
if (tag instanceof PostModel) { |
||||
|
final PostModel postModel = (PostModel) tag; |
||||
|
|
||||
|
if (postsAdapter.isSelecting) toggleSelection(postModel); |
||||
|
else startActivity(new Intent(this, PostViewer.class) |
||||
|
.putExtra(Constants.EXTRAS_INDEX, postModel.getPosition()) |
||||
|
.putExtra(Constants.EXTRAS_POST, postModel) |
||||
|
.putExtra(Constants.EXTRAS_USER, username) |
||||
|
.putExtra(Constants.EXTRAS_TYPE, ItemGetType.SAVED_ITEMS)); |
||||
|
} |
||||
|
}, v -> { |
||||
|
final Object tag = v.getTag(); |
||||
|
if (tag instanceof PostModel) { |
||||
|
postsAdapter.isSelecting = true; |
||||
|
toggleSelection((PostModel) tag); |
||||
|
} |
||||
|
return true; |
||||
|
})); |
||||
|
savedBinding.swipeRefreshLayout.setRefreshing(true); |
||||
|
setSupportActionBar(savedBinding.toolbar.toolbar); |
||||
|
savedBinding.toolbar.toolbar.setTitle((action.charAt(0) == '$' ? R.string.saved : |
||||
|
(action.charAt(0) == '%' ? R.string.tagged : R.string.liked))); |
||||
|
savedBinding.toolbar.toolbar.setSubtitle(username); |
||||
|
|
||||
|
lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { |
||||
|
if (!autoloadPosts && hasNextPage) { |
||||
|
savedBinding.swipeRefreshLayout.setRefreshing(true); |
||||
|
stopCurrentExecutor(); |
||||
|
currentlyExecuting = new PostsFetcher(action, endCursor, postsFetchListener) |
||||
|
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
||||
|
endCursor = null; |
||||
|
} |
||||
|
}); |
||||
|
savedBinding.mainPosts.addOnScrollListener(lazyLoader); |
||||
|
|
||||
|
itemGetter = itemGetType -> { |
||||
|
if (itemGetType == ItemGetType.SAVED_ITEMS) return allItems; |
||||
|
return null; |
||||
|
}; |
||||
|
|
||||
|
new PostsFetcher(action, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean onCreateOptionsMenu(final Menu menu) { |
||||
|
getMenuInflater().inflate(R.menu.saved, menu); |
||||
|
|
||||
|
downloadAction = menu.findItem(R.id.downloadAction); |
||||
|
downloadAction.setVisible(false); |
||||
|
|
||||
|
downloadAction.setOnMenuItemClickListener(item -> { |
||||
|
if (selectedItems.size() > 0) { |
||||
|
Utils.batchDownload(this, null, DownloadMethod.DOWNLOAD_SAVED, selectedItems); |
||||
|
} |
||||
|
return true; |
||||
|
}); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public void deselectSelection(final BasePostModel postModel) { |
||||
|
if (postModel instanceof PostModel) { |
||||
|
selectedItems.remove(postModel); |
||||
|
postModel.setSelected(false); |
||||
|
if (postsAdapter != null) notifyAdapter((PostModel) postModel); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onRefresh() { |
||||
|
if (lazyLoader != null) lazyLoader.resetState(); |
||||
|
stopCurrentExecutor(); |
||||
|
allItems.clear(); |
||||
|
selectedItems.clear(); |
||||
|
if (postsAdapter != null) { |
||||
|
postsAdapter.isSelecting = false; |
||||
|
postsAdapter.notifyDataSetChanged(); |
||||
|
} |
||||
|
savedBinding.swipeRefreshLayout.setRefreshing(true); |
||||
|
new PostsFetcher(action, postsFetchListener).setUsername(username).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { |
||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults); |
||||
|
if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED && selectedItems.size() > 0) |
||||
|
Utils.batchDownload(this, null, DownloadMethod.DOWNLOAD_SAVED, selectedItems); |
||||
|
} |
||||
|
|
||||
|
public static void stopCurrentExecutor() { |
||||
|
if (currentlyExecuting != null) { |
||||
|
try { |
||||
|
currentlyExecuting.cancel(true); |
||||
|
} catch (final Exception e) { |
||||
|
if (logCollector != null) |
||||
|
logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor"); |
||||
|
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void toggleSelection(final PostModel postModel) { |
||||
|
if (postModel != null && postsAdapter != null) { |
||||
|
if (postModel.isSelected()) selectedItems.remove(postModel); |
||||
|
else selectedItems.add(postModel); |
||||
|
postModel.setSelected(!postModel.isSelected()); |
||||
|
notifyAdapter(postModel); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void notifyAdapter(final PostModel postModel) { |
||||
|
if (selectedItems.size() < 1) postsAdapter.isSelecting = false; |
||||
|
if (postModel.getPosition() < 0) postsAdapter.notifyDataSetChanged(); |
||||
|
else postsAdapter.notifyItemChanged(postModel.getPosition(), postModel); |
||||
|
|
||||
|
if (downloadAction != null) { |
||||
|
downloadAction.setVisible(postsAdapter.isSelecting); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
package awais.instagrabber.adapters; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.core.text.HtmlCompat; |
||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||
|
|
||||
|
import com.bumptech.glide.Glide; |
||||
|
import com.bumptech.glide.RequestManager; |
||||
|
import com.bumptech.glide.request.RequestOptions; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
|
||||
|
import awais.instagrabber.R; |
||||
|
import awais.instagrabber.adapters.viewholder.NotificationViewHolder; |
||||
|
import awais.instagrabber.interfaces.MentionClickListener; |
||||
|
import awais.instagrabber.models.NotificationModel; |
||||
|
import awais.instagrabber.utils.LocaleUtils; |
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
|
||||
|
public final class NotificationsAdapter extends RecyclerView.Adapter<NotificationViewHolder> { |
||||
|
private final View.OnClickListener onClickListener; |
||||
|
private final MentionClickListener mentionClickListener; |
||||
|
private final NotificationModel[] notificationModels; |
||||
|
private LayoutInflater layoutInflater; |
||||
|
|
||||
|
public NotificationsAdapter(final NotificationModel[] notificationModels, final View.OnClickListener onClickListener, |
||||
|
final MentionClickListener mentionClickListener) { |
||||
|
this.notificationModels = notificationModels; |
||||
|
this.onClickListener = onClickListener; |
||||
|
this.mentionClickListener = mentionClickListener; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public NotificationViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) { |
||||
|
final Context context = parent.getContext(); |
||||
|
if (layoutInflater == null) layoutInflater = LayoutInflater.from(context); |
||||
|
return new NotificationViewHolder(layoutInflater.inflate(R.layout.item_notification, |
||||
|
parent, false), onClickListener, mentionClickListener); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onBindViewHolder(@NonNull final NotificationViewHolder holder, final int position) { |
||||
|
final NotificationModel notificationModel = notificationModels[position]; |
||||
|
if (notificationModel != null) { |
||||
|
holder.setNotificationModel(notificationModel); |
||||
|
|
||||
|
int text = -1; |
||||
|
CharSequence subtext = null; |
||||
|
switch (notificationModel.getType()) { |
||||
|
case LIKE: |
||||
|
text = R.string.liked_notif; |
||||
|
break; |
||||
|
case COMMENT: |
||||
|
text = R.string.comment_notif; |
||||
|
subtext = notificationModel.getText(); |
||||
|
break; |
||||
|
case MENTION: |
||||
|
text = R.string.mention_notif; |
||||
|
subtext = notificationModel.getText(); |
||||
|
break; |
||||
|
case FOLLOW: |
||||
|
text = R.string.follow_notif; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
holder.setCommment(text); |
||||
|
holder.setSubCommment(subtext); |
||||
|
holder.setDate(notificationModel.getDateTime()); |
||||
|
|
||||
|
holder.setUsername(notificationModel.getUsername()); |
||||
|
|
||||
|
final RequestManager rm = Glide.with(layoutInflater.getContext()) |
||||
|
.applyDefaultRequestOptions(new RequestOptions().skipMemoryCache(true)); |
||||
|
|
||||
|
rm.load(notificationModel.getProfilePic()).into(holder.getProfilePicView()); |
||||
|
rm.load(notificationModel.getPreviewPic()).into(holder.getPreviewPicView()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getItemCount() { |
||||
|
return notificationModels == null ? 0 : notificationModels.length; |
||||
|
} |
||||
|
} |
@ -0,0 +1,76 @@ |
|||||
|
package awais.instagrabber.adapters.viewholder; |
||||
|
|
||||
|
import android.text.Spannable; |
||||
|
import android.view.View; |
||||
|
import android.widget.ImageView; |
||||
|
import android.widget.TextView; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||
|
|
||||
|
import awais.instagrabber.R; |
||||
|
import awais.instagrabber.adapters.CommentsAdapter; |
||||
|
import awais.instagrabber.customviews.RamboTextView; |
||||
|
import awais.instagrabber.interfaces.MentionClickListener; |
||||
|
import awais.instagrabber.models.NotificationModel; |
||||
|
|
||||
|
public final class NotificationViewHolder extends RecyclerView.ViewHolder { |
||||
|
private final MentionClickListener mentionClickListener; |
||||
|
private final ImageView ivProfilePic, ivPreviewPic; |
||||
|
private final TextView tvUsername, tvDate, tvComment, tvSubComment; |
||||
|
private final View container, rightContainer; |
||||
|
|
||||
|
public NotificationViewHolder(@NonNull final View itemView, final View.OnClickListener onClickListener, final MentionClickListener mentionClickListener) { |
||||
|
super(itemView); |
||||
|
|
||||
|
container = itemView.findViewById(R.id.container); |
||||
|
rightContainer = itemView.findViewById(R.id.rightContainer); |
||||
|
if (onClickListener != null) container.setOnClickListener(onClickListener); |
||||
|
|
||||
|
this.mentionClickListener = mentionClickListener; |
||||
|
|
||||
|
ivProfilePic = itemView.findViewById(R.id.ivProfilePic); |
||||
|
ivPreviewPic = itemView.findViewById(R.id.ivPreviewPic); |
||||
|
tvUsername = itemView.findViewById(R.id.tvUsername); |
||||
|
tvDate = itemView.findViewById(R.id.tvDate); |
||||
|
tvComment = itemView.findViewById(R.id.tvComment); |
||||
|
tvSubComment = itemView.findViewById(R.id.tvSubComment); |
||||
|
|
||||
|
tvUsername.setSelected(true); |
||||
|
tvDate.setSelected(true); |
||||
|
} |
||||
|
|
||||
|
public final ImageView getProfilePicView() { |
||||
|
return ivProfilePic; |
||||
|
} |
||||
|
|
||||
|
public final ImageView getPreviewPicView() { |
||||
|
return ivPreviewPic; |
||||
|
} |
||||
|
|
||||
|
public final void setNotificationModel(final NotificationModel notificationModel) { |
||||
|
if (container != null) container.setTag(notificationModel); |
||||
|
if (rightContainer != null) rightContainer.setTag(notificationModel); |
||||
|
} |
||||
|
|
||||
|
public final void setUsername(final String username) { |
||||
|
if (tvUsername != null) tvUsername.setText(username); |
||||
|
} |
||||
|
|
||||
|
public final void setDate(final String date) { |
||||
|
if (tvDate != null) tvDate.setText(date); |
||||
|
} |
||||
|
|
||||
|
public final void setCommment(final int commment) { |
||||
|
if (tvComment != null) { |
||||
|
tvComment.setText(commment); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public final void setSubCommment(final CharSequence commment) { |
||||
|
if (tvSubComment != null) { |
||||
|
tvSubComment.setText(commment, commment instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL); |
||||
|
((RamboTextView) tvSubComment).setMentionClickListener(mentionClickListener); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,85 @@ |
|||||
|
package awais.instagrabber.asyncs; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import org.json.JSONArray; |
||||
|
import org.json.JSONObject; |
||||
|
|
||||
|
import java.net.HttpURLConnection; |
||||
|
import java.net.URL; |
||||
|
|
||||
|
import awais.instagrabber.BuildConfig; |
||||
|
import awais.instagrabber.interfaces.FetchListener; |
||||
|
import awais.instagrabber.models.NotificationModel; |
||||
|
import awais.instagrabber.utils.Constants; |
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
import awaisomereport.LogCollector; |
||||
|
|
||||
|
import static awais.instagrabber.utils.Utils.logCollector; |
||||
|
|
||||
|
public final class NotificationsFetcher extends AsyncTask<Void, Void, NotificationModel[]> { |
||||
|
private final FetchListener<NotificationModel[]> fetchListener; |
||||
|
|
||||
|
public NotificationsFetcher(final FetchListener<NotificationModel[]> fetchListener) { |
||||
|
this.fetchListener = fetchListener; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected NotificationModel[] doInBackground(final Void... voids) { |
||||
|
NotificationModel[] result = null; |
||||
|
final String url = "https://www.instagram.com/accounts/activity/?__a=1"; |
||||
|
|
||||
|
try { |
||||
|
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); |
||||
|
conn.setInstanceFollowRedirects(false); |
||||
|
conn.setUseCaches(false); |
||||
|
conn.connect(); |
||||
|
|
||||
|
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { |
||||
|
JSONObject data = new JSONObject(Utils.readFromConnection(conn)) |
||||
|
.getJSONObject("graphql").getJSONObject("user").getJSONObject("activity_feed").getJSONObject("edge_web_activity_feed"); |
||||
|
|
||||
|
JSONArray media; |
||||
|
if ((media = data.optJSONArray("edges")) != null && media.length() > 0 && |
||||
|
(data = media.optJSONObject(0).optJSONObject("node")) != null) { |
||||
|
|
||||
|
final int mediaLen = media.length(); |
||||
|
|
||||
|
final NotificationModel[] models = new NotificationModel[mediaLen]; |
||||
|
for (int i = 0; i < mediaLen; ++i) { |
||||
|
data = media.optJSONObject(i).optJSONObject("node"); |
||||
|
if (Utils.getNotifType(data.getString("__typename")) == null) continue; |
||||
|
models[i] = new NotificationModel(data.getString(Constants.EXTRAS_ID), |
||||
|
data.optString("text"), // comments or mentions |
||||
|
data.getLong("timestamp"), |
||||
|
data.getJSONObject("user").getString("username"), |
||||
|
data.getJSONObject("user").getString("profile_pic_url"), |
||||
|
!data.isNull("media") ? data.getJSONObject("media").getString("shortcode") : null, |
||||
|
!data.isNull("media") ? data.getJSONObject("media").getString("thumbnail_src") : null, |
||||
|
Utils.getNotifType(data.getString("__typename"))); |
||||
|
} |
||||
|
result = models; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
conn.disconnect(); |
||||
|
} catch (final Exception e) { |
||||
|
if (logCollector != null) |
||||
|
logCollector.appendException(e, LogCollector.LogFile.ASYNC_NOTIFICATION_FETCHER, "doInBackground"); |
||||
|
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPreExecute() { |
||||
|
if (fetchListener != null) fetchListener.doBefore(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPostExecute(final NotificationModel[] result) { |
||||
|
if (fetchListener != null) fetchListener.onResult(result); |
||||
|
} |
||||
|
} |
@ -1,62 +0,0 @@ |
|||||
package awais.instagrabber.dialogs; |
|
||||
|
|
||||
import android.app.Activity; |
|
||||
import android.app.Dialog; |
|
||||
import android.content.Context; |
|
||||
import android.content.DialogInterface; |
|
||||
import android.os.Bundle; |
|
||||
import android.view.View; |
|
||||
import android.widget.AdapterView; |
|
||||
import android.widget.Spinner; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
import androidx.annotation.Nullable; |
|
||||
|
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; |
|
||||
|
|
||||
import awais.instagrabber.R; |
|
||||
|
|
||||
import static awais.instagrabber.utils.Constants.PROFILE_FETCH_MODE; |
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper; |
|
||||
|
|
||||
public final class ProfileSettingsDialog extends BottomSheetDialogFragment implements AdapterView.OnItemSelectedListener { |
|
||||
private int fetchIndex; |
|
||||
private Activity activity; |
|
||||
private Spinner spProfileFetchMode; |
|
||||
|
|
||||
@NonNull |
|
||||
@Override |
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { |
|
||||
final Dialog dialog = super.onCreateDialog(savedInstanceState); |
|
||||
|
|
||||
final Context context = getContext(); |
|
||||
activity = context instanceof Activity ? (Activity) context : getActivity(); |
|
||||
|
|
||||
final View contentView = View.inflate(activity, R.layout.dialog_profile_settings, null); |
|
||||
|
|
||||
spProfileFetchMode = contentView.findViewById(R.id.spProfileFetchMode); |
|
||||
|
|
||||
fetchIndex = Math.min(2, Math.max(0, settingsHelper.getInteger(PROFILE_FETCH_MODE))); |
|
||||
spProfileFetchMode.setSelection(fetchIndex); |
|
||||
spProfileFetchMode.setOnItemSelectedListener(this); |
|
||||
|
|
||||
dialog.setContentView(contentView); |
|
||||
|
|
||||
return dialog; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onDismiss(@NonNull final DialogInterface dialog) { |
|
||||
super.onDismiss(dialog); |
|
||||
if (activity != null && (spProfileFetchMode == null || fetchIndex != spProfileFetchMode.getSelectedItemPosition())) |
|
||||
activity.recreate(); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) { |
|
||||
settingsHelper.putInteger(PROFILE_FETCH_MODE, position); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onNothingSelected(final AdapterView<?> parent) { } |
|
||||
} |
|
@ -0,0 +1,58 @@ |
|||||
|
package awais.instagrabber.models; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
import awais.instagrabber.models.enums.NotificationType; |
||||
|
|
||||
|
public final class NotificationModel { |
||||
|
private final String id, username, profilePicUrl, shortcode, previewUrl; |
||||
|
private final NotificationType type; |
||||
|
private final CharSequence text; |
||||
|
private final long timestamp; |
||||
|
|
||||
|
public NotificationModel(final String id, final String text, final long timestamp, final String username, |
||||
|
final String profilePicUrl, final String shortcode, final String previewUrl, final NotificationType type) { |
||||
|
this.id = id; |
||||
|
this.text = Utils.hasMentions(text) ? Utils.getMentionText(text) : text; |
||||
|
this.timestamp = timestamp; |
||||
|
this.username = username; |
||||
|
this.profilePicUrl = profilePicUrl; |
||||
|
this.shortcode = shortcode; |
||||
|
this.previewUrl = previewUrl; |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public CharSequence getText() { |
||||
|
return text; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
public String getDateTime() { |
||||
|
return Utils.datetimeParser.format(new Date(timestamp * 1000L)); |
||||
|
} |
||||
|
|
||||
|
public String getUsername() { |
||||
|
return username; |
||||
|
} |
||||
|
|
||||
|
public String getProfilePic() { |
||||
|
return profilePicUrl; |
||||
|
} |
||||
|
|
||||
|
public String getShortcode() { |
||||
|
return shortcode; |
||||
|
} |
||||
|
|
||||
|
public String getPreviewPic() { |
||||
|
return previewUrl; |
||||
|
} |
||||
|
|
||||
|
public NotificationType getType() { return type; } |
||||
|
} |
@ -0,0 +1,52 @@ |
|||||
|
package awais.instagrabber.models; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
public final class PollModel implements Serializable { |
||||
|
private int leftcount, rightcount, mychoice; |
||||
|
private final String id, question, leftchoice, rightchoice; |
||||
|
|
||||
|
public PollModel(final String id, final String question, final String leftchoice, final int leftcount, |
||||
|
final String rightchoice, final int rightcount, final int mychoice) { |
||||
|
this.id = id; // only the poll id |
||||
|
this.question = question; |
||||
|
this.leftchoice = leftchoice; |
||||
|
this.leftcount = leftcount; |
||||
|
this.rightchoice = rightchoice; |
||||
|
this.rightcount = rightcount; |
||||
|
this.mychoice = mychoice; |
||||
|
} |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public String getQuestion() { |
||||
|
return question; |
||||
|
} |
||||
|
|
||||
|
public String getLeftChoice() { |
||||
|
return leftchoice; |
||||
|
} |
||||
|
|
||||
|
public int getLeftCount() { |
||||
|
return leftcount; |
||||
|
} |
||||
|
|
||||
|
public String getRightChoice() { |
||||
|
return rightchoice; |
||||
|
} |
||||
|
|
||||
|
public int getRightCount() { |
||||
|
return rightcount; |
||||
|
} |
||||
|
|
||||
|
public int getMyChoice() { return mychoice; } |
||||
|
|
||||
|
public int setMyChoice(final int choice) { |
||||
|
this.mychoice = choice; |
||||
|
if (choice == 0) this.leftcount += 1; |
||||
|
else if (choice == 1) this.rightcount += 1; |
||||
|
return choice; |
||||
|
} |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
package awais.instagrabber.models.enums; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
public enum NotificationType implements Serializable { |
||||
|
LIKE, |
||||
|
FOLLOW, |
||||
|
COMMENT, |
||||
|
MENTION |
||||
|
} |
@ -1,7 +0,0 @@ |
|||||
package awais.instagrabber.models.enums; |
|
||||
|
|
||||
public enum ProfilePictureFetchMode { |
|
||||
INSTADP, |
|
||||
INSTAFULLSIZE, |
|
||||
INSTA_STALKER, |
|
||||
} |
|
@ -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="#333333"> |
||||
|
<path |
||||
|
android:fillColor="@android:color/white" |
||||
|
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/> |
||||
|
</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="#333333"> |
||||
|
<path |
||||
|
android:fillColor="@android:color/white" |
||||
|
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/> |
||||
|
</vector> |
@ -0,0 +1,11 @@ |
|||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:width="24dp" |
||||
|
android:height="24dp" |
||||
|
android:viewportWidth="24" |
||||
|
android:viewportHeight="24" |
||||
|
android:tint="#333333" |
||||
|
android:alpha="0.6"> |
||||
|
<path |
||||
|
android:fillColor="@android:color/white" |
||||
|
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/> |
||||
|
</vector> |
After Width: 36 | Height: 36 | Size: 210 B |
After Width: 36 | Height: 36 | Size: 333 B |
After Width: 36 | Height: 36 | Size: 269 B |
After Width: 24 | Height: 24 | Size: 160 B |
After Width: 24 | Height: 24 | Size: 239 B |
After Width: 24 | Height: 24 | Size: 193 B |
After Width: 48 | Height: 48 | Size: 264 B |
After Width: 48 | Height: 48 | Size: 415 B |
After Width: 48 | Height: 48 | Size: 321 B |
After Width: 72 | Height: 72 | Size: 380 B |
After Width: 72 | Height: 72 | Size: 570 B |
After Width: 72 | Height: 72 | Size: 433 B |
Before Width: 132 | Height: 132 | Size: 8.0 KiB After Width: 132 | Height: 132 | Size: 3.8 KiB |
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="vertical" |
||||
|
tools:context=".activities.NotificationsViewer"> |
||||
|
|
||||
|
<include |
||||
|
android:id="@+id/toolbar" |
||||
|
layout="@layout/layout_include_toolbar" /> |
||||
|
|
||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout |
||||
|
android:id="@+id/swipeRefreshLayout" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent"> |
||||
|
<androidx.recyclerview.widget.RecyclerView |
||||
|
android:id="@+id/rvComments" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:clipToPadding="false" |
||||
|
android:paddingStart="8dp" |
||||
|
android:paddingLeft="8dp" |
||||
|
android:paddingEnd="8dp" |
||||
|
android:paddingRight="8dp" |
||||
|
app:layoutManager="LinearLayoutManager" |
||||
|
tools:listitem="@layout/item_notification" /> |
||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> |
||||
|
</LinearLayout> |
@ -0,0 +1,31 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="vertical" |
||||
|
tools:context=".activities.SavedViewer"> |
||||
|
|
||||
|
<include |
||||
|
android:id="@+id/toolbar" |
||||
|
layout="@layout/layout_include_toolbar" /> |
||||
|
|
||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout |
||||
|
android:id="@+id/swipeRefreshLayout" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:tag="@android:string/yes"> |
||||
|
|
||||
|
<androidx.recyclerview.widget.RecyclerView |
||||
|
android:id="@+id/mainPosts" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:clipToPadding="false" |
||||
|
android:paddingStart="8dp" |
||||
|
android:paddingLeft="8dp" |
||||
|
android:paddingEnd="8dp" |
||||
|
android:paddingRight="8dp" |
||||
|
tools:listitem="@layout/item_post" /> |
||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> |
||||
|
</LinearLayout> |
@ -1,48 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="match_parent" |
|
||||
android:orientation="vertical" |
|
||||
android:paddingBottom="10dp"> |
|
||||
|
|
||||
<androidx.appcompat.widget.AppCompatTextView |
|
||||
style="@style/TextAppearance.AppCompat.Headline" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="wrap_content" |
|
||||
android:ellipsize="end" |
|
||||
android:paddingStart="?attr/dialogPreferredPadding" |
|
||||
android:paddingLeft="?attr/dialogPreferredPadding" |
|
||||
android:paddingTop="10dp" |
|
||||
android:paddingEnd="?attr/dialogPreferredPadding" |
|
||||
android:paddingRight="?attr/dialogPreferredPadding" |
|
||||
android:paddingBottom="6dp" |
|
||||
android:singleLine="true" |
|
||||
android:text="@string/action_settings" /> |
|
||||
|
|
||||
<androidx.appcompat.widget.LinearLayoutCompat |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="wrap_content" |
|
||||
android:layout_marginStart="5dp" |
|
||||
android:layout_marginLeft="5dp" |
|
||||
android:orientation="vertical" |
|
||||
android:layout_marginBottom="24dp" |
|
||||
android:padding="5dp"> |
|
||||
|
|
||||
<androidx.appcompat.widget.AppCompatTextView |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="match_parent" |
|
||||
android:gravity="center_vertical" |
|
||||
android:padding="5dp" |
|
||||
android:text="@string/profile_endpoint" |
|
||||
android:textColor="?android:textColorPrimary" |
|
||||
android:textSize="16sp" /> |
|
||||
|
|
||||
<androidx.appcompat.widget.AppCompatSpinner |
|
||||
android:id="@+id/spProfileFetchMode" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="wrap_content" |
|
||||
android:entries="@array/profile_fetch_modes" |
|
||||
android:paddingTop="4dp" |
|
||||
android:paddingBottom="4dp" /> |
|
||||
</androidx.appcompat.widget.LinearLayoutCompat> |
|
||||
</androidx.appcompat.widget.LinearLayoutCompat> |
|
@ -0,0 +1,20 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="vertical" |
||||
|
tools:viewBindingIgnore="true"> |
||||
|
|
||||
|
<include |
||||
|
android:id="@+id/container" |
||||
|
layout="@layout/layout_include_notif_item" /> |
||||
|
|
||||
|
<View |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="1dp" |
||||
|
android:layout_gravity="bottom" |
||||
|
android:layout_marginBottom="4dp" |
||||
|
android:background="#80888888" /> |
||||
|
</LinearLayout> |
@ -1,18 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="match_parent" |
|
||||
android:clipChildren="false" |
|
||||
android:clipToPadding="false"> |
|
||||
|
|
||||
<awais.instagrabber.customviews.RamboTextView |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="wrap_content" |
|
||||
android:paddingStart="10dp" |
|
||||
android:paddingLeft="10dp" |
|
||||
android:paddingEnd="10dp" |
|
||||
android:paddingRight="10dp" |
|
||||
android:paddingBottom="24dp" |
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" |
|
||||
android:textSize="16sp" /> |
|
||||
</ScrollView> |
|
@ -0,0 +1,154 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:background="?android:selectableItemBackground" |
||||
|
android:orientation="horizontal" |
||||
|
android:paddingStart="0dp" |
||||
|
android:paddingLeft="0dp" |
||||
|
android:paddingEnd="4dp" |
||||
|
android:paddingRight="4dp"> |
||||
|
|
||||
|
<FrameLayout |
||||
|
android:layout_width="@dimen/simple_item_picture_size" |
||||
|
android:layout_height="@dimen/simple_item_picture_size" |
||||
|
android:gravity="center"> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:id="@+id/ivProfilePic" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" /> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:id="@+id/container" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="horizontal"> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="match_parent" /> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="@dimen/simple_item_picture_size_half" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="@dimen/simple_item_picture_size_half" /> |
||||
|
</LinearLayout> |
||||
|
</LinearLayout> |
||||
|
</FrameLayout> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_weight="1" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||
|
android:id="@+id/tvUsername" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="start" |
||||
|
android:layout_weight="1.0" |
||||
|
android:ellipsize="marquee" |
||||
|
android:paddingStart="8dp" |
||||
|
android:paddingLeft="8dp" |
||||
|
android:paddingTop="4dp" |
||||
|
android:paddingEnd="4dp" |
||||
|
android:paddingRight="4dp" |
||||
|
android:singleLine="true" |
||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" |
||||
|
android:textColor="?android:textColorPrimary" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="vertical" |
||||
|
android:paddingLeft="8dp" |
||||
|
android:paddingTop="4dp" |
||||
|
android:paddingRight="8dp"> |
||||
|
|
||||
|
<awais.instagrabber.customviews.RamboTextView |
||||
|
android:id="@+id/tvComment" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="start" |
||||
|
android:ellipsize="end" |
||||
|
android:linksClickable="true" |
||||
|
android:textStyle="italic" |
||||
|
android:textAppearance="@style/TextAppearance.AppCompat" /> |
||||
|
|
||||
|
<awais.instagrabber.customviews.RamboTextView |
||||
|
android:id="@+id/tvSubComment" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="start" |
||||
|
android:autoLink="web|email" |
||||
|
android:ellipsize="end" |
||||
|
android:linksClickable="true" |
||||
|
android:textAppearance="@style/TextAppearance.AppCompat" /> |
||||
|
</LinearLayout> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||
|
android:id="@+id/tvDate" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="start" |
||||
|
android:ellipsize="marquee" |
||||
|
android:gravity="right" |
||||
|
android:paddingStart="4dp" |
||||
|
android:paddingLeft="4dp" |
||||
|
android:paddingTop="4dp" |
||||
|
android:paddingEnd="8dp" |
||||
|
android:paddingRight="8dp" |
||||
|
android:singleLine="true" |
||||
|
android:textStyle="italic" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
<FrameLayout |
||||
|
android:layout_width="@dimen/simple_item_picture_size" |
||||
|
android:layout_height="@dimen/simple_item_picture_size" |
||||
|
android:gravity="center"> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:id="@+id/ivPreviewPic" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" /> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:id="@+id/rightContainer" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="horizontal"> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="match_parent" /> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="@dimen/simple_item_picture_size_half" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:layout_width="@dimen/simple_item_picture_size_half" |
||||
|
android:layout_height="@dimen/simple_item_picture_size_half" /> |
||||
|
</LinearLayout> |
||||
|
</LinearLayout> |
||||
|
</FrameLayout> |
||||
|
</LinearLayout> |
@ -0,0 +1,9 @@ |
|||||
|
<?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/downloadAction" |
||||
|
android:icon="@drawable/ic_download" |
||||
|
app:showAsAction="always|collapseActionView" /> |
||||
|
</menu> |
Before Width: 720 | Height: 1280 | Size: 137 KiB After Width: 720 | Height: 1280 | Size: 122 KiB |
Before Width: 720 | Height: 1280 | Size: 124 KiB After Width: 720 | Height: 1280 | Size: 144 KiB |
Before Width: 720 | Height: 1280 | Size: 81 KiB After Width: 720 | Height: 1280 | Size: 88 KiB |
Before Width: 720 | Height: 1280 | Size: 152 KiB After Width: 720 | Height: 1280 | Size: 81 KiB |
After Width: 720 | Height: 1280 | Size: 152 KiB |
After Width: 720 | Height: 1280 | Size: 157 KiB |