mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-11-04 05:25:35 +00:00 
			
		
		
		
	Convert comment viewer activity to fragment and update layouts
This commit is contained in:
		
							parent
							
								
									7807fe7f59
								
							
						
					
					
						commit
						c64ae3a101
					
				@ -141,14 +141,14 @@
 | 
			
		||||
        <!--        android:value=".activities.MainActivity" />-->
 | 
			
		||||
        <!--</activity>-->
 | 
			
		||||
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".activities.CommentsViewer"
 | 
			
		||||
            android:parentActivityName=".activities.PostViewer">
 | 
			
		||||
        <!--<activity-->
 | 
			
		||||
        <!--    android:name=".activities.CommentsViewerFragment"-->
 | 
			
		||||
        <!--    android:parentActivityName=".activities.PostViewer">-->
 | 
			
		||||
 | 
			
		||||
            <meta-data
 | 
			
		||||
                android:name="android.support.PARENT_ACTIVITY"
 | 
			
		||||
                android:value=".activities.PostViewer" />
 | 
			
		||||
        </activity>
 | 
			
		||||
        <!--    <meta-data-->
 | 
			
		||||
        <!--        android:name="android.support.PARENT_ACTIVITY"-->
 | 
			
		||||
        <!--        android:value=".activities.PostViewer" />-->
 | 
			
		||||
        <!--</activity>-->
 | 
			
		||||
 | 
			
		||||
        <!--<activity-->
 | 
			
		||||
        <!--    android:name=".activities.StoryViewer"-->
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.activities.CommentsViewer;
 | 
			
		||||
import awais.instagrabber.activities.CommentsViewerFragment;
 | 
			
		||||
import awais.instagrabber.activities.FollowViewer;
 | 
			
		||||
import awais.instagrabber.activities.MainActivityBackup;
 | 
			
		||||
import awais.instagrabber.activities.PostViewer;
 | 
			
		||||
@ -604,7 +604,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
 | 
			
		||||
                final int id = v.getId();
 | 
			
		||||
                switch (id) {
 | 
			
		||||
                    case R.id.btnComments:
 | 
			
		||||
                        mainActivity.startActivityForResult(new Intent(mainActivity, CommentsViewer.class)
 | 
			
		||||
                        mainActivity.startActivityForResult(new Intent(mainActivity, CommentsViewerFragment.class)
 | 
			
		||||
                                                                    .putExtra(Constants.EXTRAS_SHORTCODE, feedModel.getShortCode())
 | 
			
		||||
                                                                    .putExtra(Constants.EXTRAS_POST, feedModel.getPostId())
 | 
			
		||||
                                                                    .putExtra(Constants.EXTRAS_USER, feedModel.getProfileModel().getId()), 6969);
 | 
			
		||||
 | 
			
		||||
@ -1,302 +0,0 @@
 | 
			
		||||
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.CommentsAdapter;
 | 
			
		||||
import awais.instagrabber.asyncs.CommentsFetcher;
 | 
			
		||||
import awais.instagrabber.databinding.ActivityCommentsBinding;
 | 
			
		||||
import awais.instagrabber.interfaces.FetchListener;
 | 
			
		||||
import awais.instagrabber.interfaces.MentionClickListener;
 | 
			
		||||
import awais.instagrabber.models.CommentModel;
 | 
			
		||||
import awais.instagrabber.models.ProfileModel;
 | 
			
		||||
import awais.instagrabber.utils.Constants;
 | 
			
		||||
import awais.instagrabber.utils.Utils;
 | 
			
		||||
 | 
			
		||||
public final class CommentsViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
 | 
			
		||||
    private CommentsAdapter commentsAdapter;
 | 
			
		||||
    private CommentModel commentModel;
 | 
			
		||||
    private ActivityCommentsBinding commentsBinding;
 | 
			
		||||
    private ArrayAdapter<String> commmentDialogAdapter;
 | 
			
		||||
    private String shortCode, postId, userId;
 | 
			
		||||
    private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
 | 
			
		||||
    private Resources resources;
 | 
			
		||||
    private InputMethodManager imm;
 | 
			
		||||
    private View focus;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(@Nullable final Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        commentsBinding = ActivityCommentsBinding.inflate(getLayoutInflater());
 | 
			
		||||
        setContentView(commentsBinding.getRoot());
 | 
			
		||||
        commentsBinding.swipeRefreshLayout.setOnRefreshListener(this);
 | 
			
		||||
 | 
			
		||||
        final Intent intent = getIntent();
 | 
			
		||||
        if (intent == null || !intent.hasExtra(Constants.EXTRAS_SHORTCODE)
 | 
			
		||||
                || Utils.isEmpty((shortCode = intent.getStringExtra(Constants.EXTRAS_SHORTCODE)))
 | 
			
		||||
                || !intent.hasExtra(Constants.EXTRAS_POST)
 | 
			
		||||
                || Utils.isEmpty((postId = intent.getStringExtra(Constants.EXTRAS_POST)))
 | 
			
		||||
                || !intent.hasExtra(Constants.EXTRAS_USER)
 | 
			
		||||
                || Utils.isEmpty((userId = intent.getStringExtra(Constants.EXTRAS_USER)))) {
 | 
			
		||||
            Utils.errorFinish(this);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        commentsBinding.swipeRefreshLayout.setRefreshing(true);
 | 
			
		||||
        setSupportActionBar(commentsBinding.toolbar.toolbar);
 | 
			
		||||
        commentsBinding.toolbar.toolbar.setTitle(R.string.title_comments);
 | 
			
		||||
        commentsBinding.toolbar.toolbar.setSubtitle(shortCode);
 | 
			
		||||
 | 
			
		||||
        resources = getResources();
 | 
			
		||||
 | 
			
		||||
        if (!Utils.isEmpty(cookie)) {
 | 
			
		||||
            commentsBinding.commentText.setVisibility(View.VISIBLE);
 | 
			
		||||
            commentsBinding.commentSend.setVisibility(View.VISIBLE);
 | 
			
		||||
 | 
			
		||||
            commentsBinding.commentSend.setOnClickListener(newCommentListener);
 | 
			
		||||
            commentsBinding.commentCancelParent.setOnClickListener(newCommentListener);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        new CommentsFetcher(shortCode, new FetchListener<CommentModel[]>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResult(final CommentModel[] commentModels) {
 | 
			
		||||
                commentsAdapter = new CommentsAdapter(commentModels, true, clickListener, mentionClickListener);
 | 
			
		||||
 | 
			
		||||
                commentsBinding.rvComments.setAdapter(commentsAdapter);
 | 
			
		||||
                commentsBinding.swipeRefreshLayout.setRefreshing(false);
 | 
			
		||||
            }
 | 
			
		||||
        }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onRefresh() {
 | 
			
		||||
        commentsBinding.swipeRefreshLayout.setRefreshing(true);
 | 
			
		||||
        new CommentsFetcher(shortCode, new FetchListener<CommentModel[]>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResult(final CommentModel[] commentModels) {
 | 
			
		||||
                commentsBinding.swipeRefreshLayout.setRefreshing(false);
 | 
			
		||||
 | 
			
		||||
                commentsAdapter = new CommentsAdapter(commentModels, true, clickListener, mentionClickListener);
 | 
			
		||||
 | 
			
		||||
                commentsBinding.rvComments.setAdapter(commentsAdapter);
 | 
			
		||||
            }
 | 
			
		||||
        }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
 | 
			
		||||
        final ProfileModel profileModel = commentModel.getProfileModel();
 | 
			
		||||
 | 
			
		||||
        if (which == 0) {
 | 
			
		||||
            searchUsername(profileModel.getUsername());
 | 
			
		||||
        } else if (which == 1) {
 | 
			
		||||
            startActivity(new Intent(this, ProfilePicViewer.class).putExtra(Constants.EXTRAS_PROFILE, profileModel));
 | 
			
		||||
        } else if (which == 2) {
 | 
			
		||||
            Utils.copyText(this, profileModel.getUsername());
 | 
			
		||||
        } else if (which == 3) {
 | 
			
		||||
            Utils.copyText(this, commentModel.getText().toString());
 | 
			
		||||
        } else if (which == 4) {
 | 
			
		||||
            if (commentModel == null) {
 | 
			
		||||
                Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                focus = commentsBinding.rvComments.findViewWithTag(commentModel);
 | 
			
		||||
                focus.setBackgroundColor(0x80888888);
 | 
			
		||||
                commentsBinding.commentCancelParent.setVisibility(View.VISIBLE);
 | 
			
		||||
                String mention = "@" + profileModel.getUsername() + " ";
 | 
			
		||||
                commentsBinding.commentText.setText(mention);
 | 
			
		||||
                commentsBinding.commentText.requestFocus();
 | 
			
		||||
                commentsBinding.commentText.setSelection(mention.length());
 | 
			
		||||
                commentsBinding.commentText.postDelayed(new Runnable() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void run() {
 | 
			
		||||
                        imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE);
 | 
			
		||||
                        imm.showSoftInput(commentsBinding.commentText, 0);
 | 
			
		||||
                    }
 | 
			
		||||
                }, 200);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (which == 5) {
 | 
			
		||||
            new CommentAction().execute((commentModel.getLiked() ? "unlike/" : "like/")+commentModel.getId());
 | 
			
		||||
        } else if (which == 6) {
 | 
			
		||||
            new CommentAction().execute("delete/"+commentModel.getId());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private final View.OnClickListener clickListener = v -> {
 | 
			
		||||
        final Object tag = v.getTag();
 | 
			
		||||
        if (tag instanceof CommentModel) {
 | 
			
		||||
            commentModel = (CommentModel) tag;
 | 
			
		||||
 | 
			
		||||
            final String username = commentModel.getProfileModel().getUsername();
 | 
			
		||||
            final SpannableString title = new SpannableString(username + ":\n" + commentModel.getText());
 | 
			
		||||
            title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
 | 
			
		||||
 | 
			
		||||
            String[] commentDialogList;
 | 
			
		||||
 | 
			
		||||
            if (!Utils.isEmpty(cookie) &&
 | 
			
		||||
                    (Utils.getUserIdFromCookie(cookie).equals(commentModel.getProfileModel().getId()) ||
 | 
			
		||||
                            Utils.getUserIdFromCookie(cookie).equals(userId))) commentDialogList = new String[]{
 | 
			
		||||
                    resources.getString(R.string.open_profile),
 | 
			
		||||
                    resources.getString(R.string.view_pfp),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_copy_user),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_copy_comment),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_reply_comment),
 | 
			
		||||
                    commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) : resources.getString(R.string.comment_viewer_like_comment),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_delete_comment)
 | 
			
		||||
            };
 | 
			
		||||
            else if (!Utils.isEmpty(cookie)) commentDialogList = new String[]{
 | 
			
		||||
                    resources.getString(R.string.open_profile),
 | 
			
		||||
                    resources.getString(R.string.view_pfp),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_copy_user),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_copy_comment),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_reply_comment),
 | 
			
		||||
                    commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) : resources.getString(R.string.comment_viewer_like_comment),
 | 
			
		||||
            };
 | 
			
		||||
            else commentDialogList = new String[]{
 | 
			
		||||
                    resources.getString(R.string.open_profile),
 | 
			
		||||
                    resources.getString(R.string.view_pfp),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_copy_user),
 | 
			
		||||
                    resources.getString(R.string.comment_viewer_copy_comment)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            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, isLocation) ->
 | 
			
		||||
            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 final View.OnClickListener newCommentListener = v -> {
 | 
			
		||||
        if (Utils.isEmpty(commentsBinding.commentText.getText().toString()) && v == commentsBinding.commentSend)
 | 
			
		||||
            Toast.makeText(getApplicationContext(), R.string.comment_send_empty_comment, Toast.LENGTH_SHORT).show();
 | 
			
		||||
        else if (v == commentsBinding.commentSend) new CommentAction().execute("add");
 | 
			
		||||
        else if (v == commentsBinding.commentCancelParent) {
 | 
			
		||||
            focus.setBackgroundColor(commentModel.getLiked() ? 0x40FF69B4 : 0x00000000);
 | 
			
		||||
            commentsBinding.commentCancelParent.setVisibility(View.GONE);
 | 
			
		||||
            commentsBinding.commentText.setText("");
 | 
			
		||||
            commentModel = null;
 | 
			
		||||
            focus = null;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private void searchUsername(final String text) {
 | 
			
		||||
        startActivity(
 | 
			
		||||
                new Intent(getApplicationContext(), ProfileViewer.class)
 | 
			
		||||
                        .putExtra(Constants.EXTRAS_USERNAME, text)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCreateOptionsMenu(final Menu menu) {
 | 
			
		||||
        getMenuInflater().inflate(R.menu.follow, menu);
 | 
			
		||||
 | 
			
		||||
        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() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean onQueryTextSubmit(final String query) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean onQueryTextChange(final String query) {
 | 
			
		||||
                if (commentsAdapter != null) commentsAdapter.getFilter().filter(query);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        menu.findItem(R.id.action_compare).setVisible(false);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class CommentAction extends AsyncTask<String, Void, Void> {
 | 
			
		||||
        boolean ok = false;
 | 
			
		||||
 | 
			
		||||
        protected Void doInBackground(String... rawAction) {
 | 
			
		||||
            final String action = rawAction[0];
 | 
			
		||||
            final String url = "https://www.instagram.com/web/comments/"+postId+"/"+action+"/";
 | 
			
		||||
            try {
 | 
			
		||||
                final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
 | 
			
		||||
                urlConnection.setRequestMethod("POST");
 | 
			
		||||
                urlConnection.setUseCaches(false);
 | 
			
		||||
                urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
 | 
			
		||||
                urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
 | 
			
		||||
                if (action == "add") {
 | 
			
		||||
                    // https://stackoverflow.com/questions/14321873/java-url-encoding-urlencoder-vs-uri
 | 
			
		||||
                    final String commentText = URLEncoder.encode(commentsBinding.commentText.getText().toString(), "UTF-8")
 | 
			
		||||
                            .replaceAll("\\+", "%20").replaceAll("\\%21", "!").replaceAll("\\%27", "'")
 | 
			
		||||
                            .replaceAll("\\%28", "(").replaceAll("\\%29", ")").replaceAll("\\%7E", "~");
 | 
			
		||||
                    final String urlParameters = "comment_text="+commentText+"&replied_to_comment_id="+
 | 
			
		||||
                            (commentModel == null ? "" : commentModel.getId());
 | 
			
		||||
                    urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
 | 
			
		||||
                    urlConnection.setRequestProperty("Content-Length", "" +
 | 
			
		||||
                            urlParameters.getBytes().length);
 | 
			
		||||
                    urlConnection.setDoOutput(true);
 | 
			
		||||
                    DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
 | 
			
		||||
                    wr.writeBytes(urlParameters);
 | 
			
		||||
                    wr.flush();
 | 
			
		||||
                    wr.close();
 | 
			
		||||
                }
 | 
			
		||||
                urlConnection.connect();
 | 
			
		||||
                if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
 | 
			
		||||
                    ok = true;
 | 
			
		||||
                    if (action == "add") {
 | 
			
		||||
                        commentsBinding.commentText.setText("");
 | 
			
		||||
                        commentsBinding.commentText.clearFocus();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                urlConnection.disconnect();
 | 
			
		||||
            } catch (Throwable ex) {
 | 
			
		||||
                Log.e("austin_debug", action+": " + ex);
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void onPostExecute(Void result) {
 | 
			
		||||
            if (ok == true) {
 | 
			
		||||
                if (focus != null) {
 | 
			
		||||
                    focus.setBackgroundColor(commentModel.getLiked() ? 0x40FF69B4 : 0x00000000);
 | 
			
		||||
                    commentsBinding.commentCancelParent.setVisibility(View.GONE);
 | 
			
		||||
                    commentModel = null;
 | 
			
		||||
                    focus = null;
 | 
			
		||||
                }
 | 
			
		||||
                onRefresh();
 | 
			
		||||
            }
 | 
			
		||||
            else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,370 @@
 | 
			
		||||
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.Editable;
 | 
			
		||||
import android.text.SpannableString;
 | 
			
		||||
import android.text.Spanned;
 | 
			
		||||
import android.text.TextWatcher;
 | 
			
		||||
import android.text.style.RelativeSizeSpan;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.Menu;
 | 
			
		||||
import android.view.MenuInflater;
 | 
			
		||||
import android.view.MenuItem;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.view.inputmethod.InputMethodManager;
 | 
			
		||||
import android.widget.LinearLayout;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.appcompat.app.ActionBar;
 | 
			
		||||
import androidx.appcompat.app.AlertDialog;
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity;
 | 
			
		||||
import androidx.appcompat.widget.SearchView;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.navigation.NavDirections;
 | 
			
		||||
import androidx.navigation.fragment.NavHostFragment;
 | 
			
		||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.R;
 | 
			
		||||
import awais.instagrabber.adapters.CommentsAdapter;
 | 
			
		||||
import awais.instagrabber.asyncs.CommentsFetcher;
 | 
			
		||||
import awais.instagrabber.databinding.FragmentCommentsBinding;
 | 
			
		||||
import awais.instagrabber.interfaces.MentionClickListener;
 | 
			
		||||
import awais.instagrabber.models.CommentModel;
 | 
			
		||||
import awais.instagrabber.models.ProfileModel;
 | 
			
		||||
import awais.instagrabber.services.MediaService;
 | 
			
		||||
import awais.instagrabber.services.ServiceCallback;
 | 
			
		||||
import awais.instagrabber.utils.Constants;
 | 
			
		||||
import awais.instagrabber.utils.Utils;
 | 
			
		||||
 | 
			
		||||
import static android.content.Context.INPUT_METHOD_SERVICE;
 | 
			
		||||
 | 
			
		||||
public final class CommentsViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
 | 
			
		||||
    private static final String TAG = "CommentsViewerFragment";
 | 
			
		||||
 | 
			
		||||
    private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
 | 
			
		||||
 | 
			
		||||
    private CommentsAdapter commentsAdapter;
 | 
			
		||||
    private CommentModel commentModel;
 | 
			
		||||
    private FragmentCommentsBinding binding;
 | 
			
		||||
    private String shortCode;
 | 
			
		||||
    private String userId;
 | 
			
		||||
    private Resources resources;
 | 
			
		||||
    private InputMethodManager imm;
 | 
			
		||||
    private AppCompatActivity fragmentActivity;
 | 
			
		||||
    private LinearLayout root;
 | 
			
		||||
    private boolean shouldRefresh = true;
 | 
			
		||||
    private MediaService mediaService;
 | 
			
		||||
    private String postId;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate(@Nullable final Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        fragmentActivity = (AppCompatActivity) getActivity();
 | 
			
		||||
        mediaService = MediaService.getInstance();
 | 
			
		||||
        setHasOptionsMenu(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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 = FragmentCommentsBinding.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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
 | 
			
		||||
        inflater.inflate(R.menu.follow, menu);
 | 
			
		||||
        final MenuItem favItem = menu.findItem(R.id.favourites);
 | 
			
		||||
        if (favItem != null) favItem.setVisible(false);
 | 
			
		||||
        menu.findItem(R.id.action_compare).setVisible(false);
 | 
			
		||||
        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() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean onQueryTextSubmit(final String query) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean onQueryTextChange(final String query) {
 | 
			
		||||
                if (commentsAdapter != null) commentsAdapter.getFilter().filter(query);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onRefresh() {
 | 
			
		||||
        binding.swipeRefreshLayout.setRefreshing(true);
 | 
			
		||||
        new CommentsFetcher(shortCode, commentModels -> {
 | 
			
		||||
            binding.swipeRefreshLayout.setRefreshing(false);
 | 
			
		||||
            commentsAdapter = new CommentsAdapter(commentModels, true, clickListener, mentionClickListener);
 | 
			
		||||
            binding.rvComments.setAdapter(commentsAdapter);
 | 
			
		||||
        }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void init() {
 | 
			
		||||
        if (getArguments() == null) return;
 | 
			
		||||
        final CommentsViewerFragmentArgs fragmentArgs = CommentsViewerFragmentArgs.fromBundle(getArguments());
 | 
			
		||||
        shortCode = fragmentArgs.getShortCode();
 | 
			
		||||
        postId = fragmentArgs.getPostId();
 | 
			
		||||
        userId = fragmentArgs.getPostUserId();
 | 
			
		||||
        setTitle();
 | 
			
		||||
        binding.swipeRefreshLayout.setOnRefreshListener(this);
 | 
			
		||||
        binding.swipeRefreshLayout.setRefreshing(true);
 | 
			
		||||
        resources = getResources();
 | 
			
		||||
        if (!Utils.isEmpty(cookie)) {
 | 
			
		||||
            binding.commentField.setStartIconVisible(false);
 | 
			
		||||
            binding.commentField.setEndIconVisible(false);
 | 
			
		||||
            binding.commentField.setVisibility(View.VISIBLE);
 | 
			
		||||
            binding.commentText.addTextChangedListener(new TextWatcher() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {}
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
 | 
			
		||||
                    binding.commentField.setStartIconVisible(s.length() > 0);
 | 
			
		||||
                    binding.commentField.setEndIconVisible(s.length() > 0);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                public void afterTextChanged(final Editable s) {}
 | 
			
		||||
            });
 | 
			
		||||
            binding.commentField.setStartIconOnClickListener(v -> {
 | 
			
		||||
                commentModel = null;
 | 
			
		||||
                binding.commentText.setText("");
 | 
			
		||||
            });
 | 
			
		||||
            binding.commentField.setEndIconOnClickListener(newCommentListener);
 | 
			
		||||
        }
 | 
			
		||||
        new CommentsFetcher(this.shortCode, commentModels -> {
 | 
			
		||||
            commentsAdapter = new CommentsAdapter(commentModels, true, clickListener, mentionClickListener);
 | 
			
		||||
            binding.rvComments.setAdapter(commentsAdapter);
 | 
			
		||||
            binding.swipeRefreshLayout.setRefreshing(false);
 | 
			
		||||
        }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setTitle() {
 | 
			
		||||
        final ActionBar actionBar = fragmentActivity.getSupportActionBar();
 | 
			
		||||
        if (actionBar == null) return;
 | 
			
		||||
        actionBar.setTitle(R.string.title_comments);
 | 
			
		||||
        // actionBar.setSubtitle(shortCode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
 | 
			
		||||
        if (commentModel == null) {
 | 
			
		||||
            Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        final ProfileModel profileModel = commentModel.getProfileModel();
 | 
			
		||||
        switch (which) {
 | 
			
		||||
            case 0: // open profile
 | 
			
		||||
                openProfile(profileModel.getUsername());
 | 
			
		||||
                break;
 | 
			
		||||
            case 1: // view profile pic
 | 
			
		||||
                startActivity(new Intent(requireContext(), ProfilePicViewer.class).putExtra(Constants.EXTRAS_PROFILE, profileModel));
 | 
			
		||||
                break;
 | 
			
		||||
            case 2: // copy username
 | 
			
		||||
                Utils.copyText(requireContext(), profileModel.getUsername());
 | 
			
		||||
                break;
 | 
			
		||||
            case 3: // copy comment
 | 
			
		||||
                Utils.copyText(requireContext(), commentModel.getText().toString());
 | 
			
		||||
                break;
 | 
			
		||||
            case 4: // reply to comment
 | 
			
		||||
                final View focus = binding.rvComments.findViewWithTag(commentModel);
 | 
			
		||||
                focus.setBackgroundColor(0x80888888);
 | 
			
		||||
                String mention = "@" + profileModel.getUsername() + " ";
 | 
			
		||||
                binding.commentText.setText(mention);
 | 
			
		||||
                binding.commentText.requestFocus();
 | 
			
		||||
                binding.commentText.setSelection(mention.length());
 | 
			
		||||
                binding.commentText.postDelayed(new Runnable() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void run() {
 | 
			
		||||
                        imm = (InputMethodManager) requireContext().getSystemService(INPUT_METHOD_SERVICE);
 | 
			
		||||
                        if (imm == null) return;
 | 
			
		||||
                        imm.showSoftInput(binding.commentText, 0);
 | 
			
		||||
                    }
 | 
			
		||||
                }, 200);
 | 
			
		||||
                break;
 | 
			
		||||
            case 5: // like/unlike comment
 | 
			
		||||
                if (!commentModel.getLiked()) {
 | 
			
		||||
                    mediaService.commentLike(commentModel.getId(), Utils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() {
 | 
			
		||||
                        @Override
 | 
			
		||||
                        public void onSuccess(final Boolean result) {
 | 
			
		||||
                            commentModel = null;
 | 
			
		||||
                            if (!result) {
 | 
			
		||||
                                Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
                            onRefresh();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        @Override
 | 
			
		||||
                        public void onFailure(final Throwable t) {
 | 
			
		||||
                            Log.e(TAG, "Error liking comment", t);
 | 
			
		||||
                            Toast.makeText(requireContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                mediaService.commentUnlike(commentModel.getId(), Utils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void onSuccess(final Boolean result) {
 | 
			
		||||
                        commentModel = null;
 | 
			
		||||
                        if (!result) {
 | 
			
		||||
                            Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        onRefresh();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void onFailure(final Throwable t) {
 | 
			
		||||
                        Log.e(TAG, "Error unliking comment", t);
 | 
			
		||||
                        Toast.makeText(requireContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                break;
 | 
			
		||||
            case 6: // delete comment
 | 
			
		||||
                final String userId = Utils.getUserIdFromCookie(cookie);
 | 
			
		||||
                if (userId == null) return;
 | 
			
		||||
                mediaService.deleteComment(
 | 
			
		||||
                        postId, userId, commentModel.getId(), Utils.getCsrfTokenFromCookie(cookie),
 | 
			
		||||
                        new ServiceCallback<Boolean>() {
 | 
			
		||||
                            @Override
 | 
			
		||||
                            public void onSuccess(final Boolean result) {
 | 
			
		||||
                                commentModel = null;
 | 
			
		||||
                                if (!result) {
 | 
			
		||||
                                    Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
                                    return;
 | 
			
		||||
                                }
 | 
			
		||||
                                onRefresh();
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            @Override
 | 
			
		||||
                            public void onFailure(final Throwable t) {
 | 
			
		||||
                                Log.e(TAG, "Error deleting comment", t);
 | 
			
		||||
                                Toast.makeText(requireContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private final View.OnClickListener clickListener = v -> {
 | 
			
		||||
        final Object tag = v.getTag();
 | 
			
		||||
        if (tag instanceof CommentModel) {
 | 
			
		||||
            commentModel = (CommentModel) tag;
 | 
			
		||||
 | 
			
		||||
            final String username = commentModel.getProfileModel().getUsername();
 | 
			
		||||
            final SpannableString title = new SpannableString(username + ":\n" + commentModel.getText());
 | 
			
		||||
            title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
 | 
			
		||||
 | 
			
		||||
            String[] commentDialogList;
 | 
			
		||||
 | 
			
		||||
            final String userIdFromCookie = Utils.getUserIdFromCookie(cookie);
 | 
			
		||||
            if (!Utils.isEmpty(cookie)
 | 
			
		||||
                    && userIdFromCookie != null
 | 
			
		||||
                    && (userIdFromCookie.equals(commentModel.getProfileModel().getId()) || userIdFromCookie.equals(userId))) {
 | 
			
		||||
                commentDialogList = new String[]{
 | 
			
		||||
                        resources.getString(R.string.open_profile),
 | 
			
		||||
                        resources.getString(R.string.view_pfp),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_copy_user),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_copy_comment),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_reply_comment),
 | 
			
		||||
                        commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment)
 | 
			
		||||
                                                : resources.getString(R.string.comment_viewer_like_comment),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_delete_comment)
 | 
			
		||||
                };
 | 
			
		||||
            } else if (!Utils.isEmpty(cookie)) {
 | 
			
		||||
                commentDialogList = new String[]{
 | 
			
		||||
                        resources.getString(R.string.open_profile),
 | 
			
		||||
                        resources.getString(R.string.view_pfp),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_copy_user),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_copy_comment),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_reply_comment),
 | 
			
		||||
                        commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment)
 | 
			
		||||
                                                : resources.getString(R.string.comment_viewer_like_comment),
 | 
			
		||||
                };
 | 
			
		||||
            } else {
 | 
			
		||||
                commentDialogList = new String[]{
 | 
			
		||||
                        resources.getString(R.string.open_profile),
 | 
			
		||||
                        resources.getString(R.string.view_pfp),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_copy_user),
 | 
			
		||||
                        resources.getString(R.string.comment_viewer_copy_comment)
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            new AlertDialog.Builder(requireContext())
 | 
			
		||||
                    .setTitle(title)
 | 
			
		||||
                    .setItems(commentDialogList, profileDialogListener)
 | 
			
		||||
                    .setNegativeButton(R.string.cancel, null)
 | 
			
		||||
                    .show();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private final MentionClickListener mentionClickListener = (view, text, isHashtag, isLocation) -> {
 | 
			
		||||
        if (isHashtag) {
 | 
			
		||||
            final NavDirections action = CommentsViewerFragmentDirections.actionGlobalHashTagFragment(text);
 | 
			
		||||
            NavHostFragment.findNavController(this).navigate(action);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        openProfile(text);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private final View.OnClickListener newCommentListener = v -> {
 | 
			
		||||
        final Editable text = binding.commentText.getText();
 | 
			
		||||
        if (text == null || Utils.isEmpty(text.toString())) {
 | 
			
		||||
            Toast.makeText(requireContext(), R.string.comment_send_empty_comment, Toast.LENGTH_SHORT).show();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        final String userId = Utils.getUserIdFromCookie(cookie);
 | 
			
		||||
        if (userId == null) return;
 | 
			
		||||
        String replyToId = null;
 | 
			
		||||
        if (commentModel != null) {
 | 
			
		||||
            replyToId = commentModel.getId();
 | 
			
		||||
        }
 | 
			
		||||
        mediaService.comment(postId, text.toString(), userId, replyToId, Utils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onSuccess(final Boolean result) {
 | 
			
		||||
                commentModel = null;
 | 
			
		||||
                binding.commentText.setText("");
 | 
			
		||||
                if (!result) {
 | 
			
		||||
                    Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                onRefresh();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(final Throwable t) {
 | 
			
		||||
                Log.e(TAG, "Error during comment", t);
 | 
			
		||||
                Toast.makeText(requireContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private void openProfile(final String username) {
 | 
			
		||||
        final NavDirections action = CommentsViewerFragmentDirections.actionGlobalProfileFragment("@" + username);
 | 
			
		||||
        NavHostFragment.findNavController(this).navigate(action);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -21,6 +21,7 @@ import awais.instagrabber.fragments.directmessages.DirectMessageThreadFragmentAr
 | 
			
		||||
import awais.instagrabber.utils.Constants;
 | 
			
		||||
import static awais.instagrabber.utils.Utils.settingsHelper;
 | 
			
		||||
 | 
			
		||||
@Deprecated
 | 
			
		||||
public class DirectMessagesActivity extends BaseLanguageActivity implements NavController.OnDestinationChangedListener {
 | 
			
		||||
 | 
			
		||||
    private TextView toolbarTitle;
 | 
			
		||||
 | 
			
		||||
@ -14,9 +14,11 @@ import androidx.navigation.NavController;
 | 
			
		||||
import androidx.navigation.ui.NavigationUI;
 | 
			
		||||
 | 
			
		||||
import com.google.android.material.appbar.AppBarLayout;
 | 
			
		||||
import com.google.android.material.appbar.CollapsingToolbarLayout;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.R;
 | 
			
		||||
@ -46,7 +48,9 @@ public class MainActivity extends BaseLanguageActivity {
 | 
			
		||||
            R.id.settingsPreferencesFragment,
 | 
			
		||||
            R.id.hashTagFragment,
 | 
			
		||||
            R.id.locationFragment,
 | 
			
		||||
            R.id.savedViewerFragment);
 | 
			
		||||
            R.id.savedViewerFragment,
 | 
			
		||||
            R.id.commentsViewerFragment);
 | 
			
		||||
    private static final List<Integer> REMOVE_COLLAPSING_TOOLBAR_SCROLL_DESTINATIONS = Collections.singletonList(R.id.commentsViewerFragment);
 | 
			
		||||
    private ActivityMainBinding binding;
 | 
			
		||||
    private LiveData<NavController> currentNavControllerLiveData;
 | 
			
		||||
 | 
			
		||||
@ -110,6 +114,11 @@ public class MainActivity extends BaseLanguageActivity {
 | 
			
		||||
            } else {
 | 
			
		||||
                removeScrollingBehaviour();
 | 
			
		||||
            }
 | 
			
		||||
            if (REMOVE_COLLAPSING_TOOLBAR_SCROLL_DESTINATIONS.contains(destinationId)) {
 | 
			
		||||
                removeCollapsingToolbarScrollFlags();
 | 
			
		||||
            } else {
 | 
			
		||||
                setCollapsingToolbarScrollFlags();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -125,6 +134,22 @@ public class MainActivity extends BaseLanguageActivity {
 | 
			
		||||
        binding.mainNavHost.requestLayout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setCollapsingToolbarScrollFlags() {
 | 
			
		||||
        final CollapsingToolbarLayout collapsingToolbarLayout = binding.collapsingToolbarLayout;
 | 
			
		||||
        final AppBarLayout.LayoutParams toolbarLayoutLayoutParams = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
 | 
			
		||||
        toolbarLayoutLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
 | 
			
		||||
                                                         | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP
 | 
			
		||||
                                                         | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
 | 
			
		||||
        binding.collapsingToolbarLayout.requestLayout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void removeCollapsingToolbarScrollFlags() {
 | 
			
		||||
        final CollapsingToolbarLayout collapsingToolbarLayout = binding.collapsingToolbarLayout;
 | 
			
		||||
        final AppBarLayout.LayoutParams toolbarLayoutLayoutParams = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
 | 
			
		||||
        toolbarLayoutLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL);
 | 
			
		||||
        binding.collapsingToolbarLayout.requestLayout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
 | 
			
		||||
        super.onRestoreInstanceState(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
@ -221,7 +221,7 @@ public final class PostViewer extends BaseLanguageActivity {
 | 
			
		||||
        viewerBinding.bottomPanel.btnComments.setVisibility(View.VISIBLE);
 | 
			
		||||
 | 
			
		||||
        viewerBinding.bottomPanel.btnComments.setOnClickListener(v -> startActivityForResult(
 | 
			
		||||
                new Intent(this, CommentsViewer.class)
 | 
			
		||||
                new Intent(this, CommentsViewerFragment.class)
 | 
			
		||||
                        .putExtra(Constants.EXTRAS_SHORTCODE, postModel.getShortCode())
 | 
			
		||||
                        .putExtra(Constants.EXTRAS_POST, viewerPostModel.getPostId())
 | 
			
		||||
                        .putExtra(Constants.EXTRAS_USER, postUserId),
 | 
			
		||||
 | 
			
		||||
@ -72,6 +72,7 @@ import awaisomereport.LogCollector;
 | 
			
		||||
import static awais.instagrabber.utils.Constants.AUTOLOAD_POSTS;
 | 
			
		||||
import static awais.instagrabber.utils.Utils.logCollector;
 | 
			
		||||
 | 
			
		||||
@Deprecated
 | 
			
		||||
public final class ProfileViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
 | 
			
		||||
    private final ArrayList<PostModel> allItems = new ArrayList<>(), selectedItems = new ArrayList<>();
 | 
			
		||||
    private static AsyncTask<?, ?, ?> currentlyExecuting;
 | 
			
		||||
 | 
			
		||||
@ -1,167 +0,0 @@
 | 
			
		||||
// package awais.instagrabber.activities;
 | 
			
		||||
//
 | 
			
		||||
// import android.content.Intent;
 | 
			
		||||
// import android.os.AsyncTask;
 | 
			
		||||
// import android.os.Bundle;
 | 
			
		||||
// import android.view.MenuItem;
 | 
			
		||||
// import android.view.View;
 | 
			
		||||
// import android.widget.Toast;
 | 
			
		||||
//
 | 
			
		||||
// import androidx.annotation.Nullable;
 | 
			
		||||
// import androidx.core.view.GestureDetectorCompat;
 | 
			
		||||
// import androidx.recyclerview.widget.LinearLayoutManager;
 | 
			
		||||
//
 | 
			
		||||
// import awais.instagrabber.R;
 | 
			
		||||
// import awais.instagrabber.adapters.StoriesAdapter;
 | 
			
		||||
// import awais.instagrabber.asyncs.SeenAction;
 | 
			
		||||
// import awais.instagrabber.asyncs.i.iStoryStatusFetcher;
 | 
			
		||||
// import awais.instagrabber.customviews.helpers.SwipeGestureListener;
 | 
			
		||||
// import awais.instagrabber.databinding.ActivityStoryViewerBinding;
 | 
			
		||||
// import awais.instagrabber.interfaces.SwipeEvent;
 | 
			
		||||
// import awais.instagrabber.models.FeedStoryModel;
 | 
			
		||||
// import awais.instagrabber.models.StoryModel;
 | 
			
		||||
// import awais.instagrabber.models.stickers.PollModel;
 | 
			
		||||
// import awais.instagrabber.models.stickers.QuestionModel;
 | 
			
		||||
// import awais.instagrabber.models.stickers.QuizModel;
 | 
			
		||||
// import awais.instagrabber.utils.Constants;
 | 
			
		||||
// import awais.instagrabber.utils.Utils;
 | 
			
		||||
//
 | 
			
		||||
// import static awais.instagrabber.utils.Constants.MARK_AS_SEEN;
 | 
			
		||||
// import static awais.instagrabber.utils.Utils.settingsHelper;
 | 
			
		||||
//
 | 
			
		||||
// public final class StoryViewer extends BaseLanguageActivity {
 | 
			
		||||
//     private final StoriesAdapter storiesAdapter = new StoriesAdapter(null, new View.OnClickListener() {
 | 
			
		||||
//         @Override
 | 
			
		||||
//         public void onClick(final View v) {
 | 
			
		||||
//             final Object tag = v.getTag();
 | 
			
		||||
//             if (tag instanceof StoryModel) {
 | 
			
		||||
//                 currentStory = (StoryModel) tag;
 | 
			
		||||
//                 slidePos = currentStory.getPosition();
 | 
			
		||||
//                 refreshStory();
 | 
			
		||||
//             }
 | 
			
		||||
//         }
 | 
			
		||||
//     });
 | 
			
		||||
//     private ActivityStoryViewerBinding storyViewerBinding;
 | 
			
		||||
//     private StoryModel[] storyModels;
 | 
			
		||||
//     private GestureDetectorCompat gestureDetector;
 | 
			
		||||
//
 | 
			
		||||
//     private SwipeEvent swipeEvent;
 | 
			
		||||
//     private MenuItem menuDownload, menuDm;
 | 
			
		||||
//     private PollModel poll;
 | 
			
		||||
//     private QuestionModel question;
 | 
			
		||||
//     private String[] mentions;
 | 
			
		||||
//     private QuizModel quiz;
 | 
			
		||||
//     private StoryModel currentStory;
 | 
			
		||||
//     private String url, username;
 | 
			
		||||
//     private int slidePos = 0, lastSlidePos = 0;
 | 
			
		||||
//     private final String cookie = settingsHelper.getString(Constants.COOKIE);
 | 
			
		||||
//     private boolean fetching = false;
 | 
			
		||||
//
 | 
			
		||||
//     @Override
 | 
			
		||||
//     protected void onCreate(@Nullable final Bundle savedInstanceState) {
 | 
			
		||||
//         super.onCreate(savedInstanceState);
 | 
			
		||||
//         storyViewerBinding = ActivityStoryViewerBinding.inflate(getLayoutInflater());
 | 
			
		||||
//         setContentView(storyViewerBinding.getRoot());
 | 
			
		||||
//
 | 
			
		||||
//         setSupportActionBar(storyViewerBinding.toolbar.toolbar);
 | 
			
		||||
//
 | 
			
		||||
//         final Intent intent = getIntent();
 | 
			
		||||
//         if (intent == null || !intent.hasExtra(Constants.EXTRAS_STORIES)
 | 
			
		||||
//                 || (storyModels = (StoryModel[]) intent.getSerializableExtra(Constants.EXTRAS_STORIES)) == null) {
 | 
			
		||||
//             Utils.errorFinish(this);
 | 
			
		||||
//             return;
 | 
			
		||||
//         }
 | 
			
		||||
//
 | 
			
		||||
//         username = intent.getStringExtra(Constants.EXTRAS_USERNAME);
 | 
			
		||||
//         final String highlight = intent.getStringExtra(Constants.EXTRAS_HIGHLIGHT);
 | 
			
		||||
//         final boolean hasUsername = !Utils.isEmpty(username);
 | 
			
		||||
//         final boolean hasHighlight = !Utils.isEmpty(highlight);
 | 
			
		||||
//
 | 
			
		||||
//         if (hasUsername) {
 | 
			
		||||
//             username = username.replace("@", "");
 | 
			
		||||
//             storyViewerBinding.toolbar.toolbar.setTitle(username);
 | 
			
		||||
//             storyViewerBinding.toolbar.toolbar.setOnClickListener(v -> {
 | 
			
		||||
//                 searchUsername(username);
 | 
			
		||||
//             });
 | 
			
		||||
//             if (hasHighlight) storyViewerBinding.toolbar.toolbar.setSubtitle(getString(R.string.title_highlight, highlight));
 | 
			
		||||
//             else storyViewerBinding.toolbar.toolbar.setSubtitle(R.string.title_user_story);
 | 
			
		||||
//         }
 | 
			
		||||
//
 | 
			
		||||
//         storyViewerBinding.storiesList.setVisibility(View.GONE);
 | 
			
		||||
//         storyViewerBinding.storiesList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
 | 
			
		||||
//         storyViewerBinding.storiesList.setAdapter(storiesAdapter);
 | 
			
		||||
//
 | 
			
		||||
//         swipeEvent = new SwipeEvent() {
 | 
			
		||||
//             private final int storiesLen = storyModels != null ? storyModels.length : 0;
 | 
			
		||||
//
 | 
			
		||||
//             @Override
 | 
			
		||||
//             public void onSwipe(final boolean isRightSwipe) {
 | 
			
		||||
//                 if (storyModels != null && storiesLen > 0) {
 | 
			
		||||
//                     if (((slidePos + 1 >= storiesLen && isRightSwipe == false) || (slidePos == 0 && isRightSwipe == true))
 | 
			
		||||
//                             && intent.hasExtra(Constants.FEED)) {
 | 
			
		||||
//                         final FeedStoryModel[] storyFeed = (FeedStoryModel[]) intent.getSerializableExtra(Constants.FEED);
 | 
			
		||||
//                         final int index = intent.getIntExtra(Constants.FEED_ORDER, 1738);
 | 
			
		||||
//                         if (settingsHelper.getBoolean(MARK_AS_SEEN)) new SeenAction(cookie, storyModel).execute();
 | 
			
		||||
//                         if ((isRightSwipe == true && index == 0) || (isRightSwipe == false && index == storyFeed.length - 1))
 | 
			
		||||
//                             Toast.makeText(getApplicationContext(), R.string.no_more_stories, Toast.LENGTH_SHORT).show();
 | 
			
		||||
//                         else {
 | 
			
		||||
//                             final FeedStoryModel feedStoryModel = isRightSwipe ?
 | 
			
		||||
//                                     (index == 0 ? null : storyFeed[index - 1]) :
 | 
			
		||||
//                                     (storyFeed.length == index + 1 ? null : storyFeed[index + 1]);
 | 
			
		||||
//                             if (feedStoryModel != null) {
 | 
			
		||||
//                                 if (fetching) {
 | 
			
		||||
//                                     Toast.makeText(getApplicationContext(), R.string.be_patient, Toast.LENGTH_SHORT).show();
 | 
			
		||||
//                                 } else {
 | 
			
		||||
//                                     fetching = true;
 | 
			
		||||
//                                     new iStoryStatusFetcher(feedStoryModel.getStoryMediaId(), null, false, false, false, false, result -> {
 | 
			
		||||
//                                         if (result != null && result.length > 0) {
 | 
			
		||||
//                                             final Intent newIntent = new Intent(getApplicationContext(), StoryViewer.class)
 | 
			
		||||
//                                                     .putExtra(Constants.EXTRAS_STORIES, result)
 | 
			
		||||
//                                                     .putExtra(Constants.EXTRAS_USERNAME, feedStoryModel.getProfileModel().getUsername())
 | 
			
		||||
//                                                     .putExtra(Constants.FEED, storyFeed)
 | 
			
		||||
//                                                     .putExtra(Constants.FEED_ORDER, isRightSwipe ? (index - 1) : (index + 1));
 | 
			
		||||
//                                             newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 | 
			
		||||
//                                             startActivity(newIntent);
 | 
			
		||||
//                                         } else
 | 
			
		||||
//                                             Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
 | 
			
		||||
//                                     }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
 | 
			
		||||
//                                 }
 | 
			
		||||
//                             }
 | 
			
		||||
//                         }
 | 
			
		||||
//                     }
 | 
			
		||||
//                     else {
 | 
			
		||||
//                         if (isRightSwipe) {
 | 
			
		||||
//                             if (--slidePos <= 0) slidePos = 0;
 | 
			
		||||
//                         } else if (++slidePos >= storiesLen) slidePos = storiesLen - 1;
 | 
			
		||||
//                         currentStory = storyModels[slidePos];
 | 
			
		||||
//                         refreshStory();
 | 
			
		||||
//                     }
 | 
			
		||||
//                 }
 | 
			
		||||
//             }
 | 
			
		||||
//         };
 | 
			
		||||
//         gestureDetector = new GestureDetectorCompat(this, new SwipeGestureListener(swipeEvent));
 | 
			
		||||
//
 | 
			
		||||
//         viewPost();
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     private void searchUsername(final String text) {
 | 
			
		||||
//         startActivity(
 | 
			
		||||
//                 new Intent(getApplicationContext(), ProfileViewer.class)
 | 
			
		||||
//                         .putExtra(Constants.EXTRAS_USERNAME, text)
 | 
			
		||||
//         );
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//     public static int indexOfIntArray(Object[] array, Object key) {
 | 
			
		||||
//         int returnvalue = -1;
 | 
			
		||||
//         for (int i = 0; i < array.length; ++i) {
 | 
			
		||||
//             if (key == array[i]) {
 | 
			
		||||
//                 returnvalue = i;
 | 
			
		||||
//                 break;
 | 
			
		||||
//             }
 | 
			
		||||
//         }
 | 
			
		||||
//         return returnvalue;
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
// }
 | 
			
		||||
@ -10,9 +10,6 @@ import android.widget.Filterable;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
 | 
			
		||||
import com.bumptech.glide.Glide;
 | 
			
		||||
import com.bumptech.glide.request.RequestOptions;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.R;
 | 
			
		||||
@ -24,7 +21,15 @@ import awais.instagrabber.utils.LocaleUtils;
 | 
			
		||||
import awais.instagrabber.utils.Utils;
 | 
			
		||||
 | 
			
		||||
public final class CommentsAdapter extends RecyclerView.Adapter<CommentViewHolder> implements Filterable {
 | 
			
		||||
 | 
			
		||||
    private CommentModel[] filteredCommentModels;
 | 
			
		||||
    private LayoutInflater layoutInflater;
 | 
			
		||||
 | 
			
		||||
    private final boolean isParent;
 | 
			
		||||
    private final View.OnClickListener onClickListener;
 | 
			
		||||
    private final MentionClickListener mentionClickListener;
 | 
			
		||||
    private final CommentModel[] commentModels;
 | 
			
		||||
    private final String[] quantityStrings = new String[2];
 | 
			
		||||
    private final Filter filter = new Filter() {
 | 
			
		||||
        @NonNull
 | 
			
		||||
        @Override
 | 
			
		||||
@ -66,14 +71,10 @@ public final class CommentsAdapter extends RecyclerView.Adapter<CommentViewHolde
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    private final View.OnClickListener onClickListener;
 | 
			
		||||
    private final MentionClickListener mentionClickListener;
 | 
			
		||||
    private final CommentModel[] commentModels;
 | 
			
		||||
    private final String[] quantityStrings = new String[2];
 | 
			
		||||
    private LayoutInflater layoutInflater;
 | 
			
		||||
    private CommentModel[] filteredCommentModels;
 | 
			
		||||
 | 
			
		||||
    public CommentsAdapter(final CommentModel[] commentModels, final boolean isParent, final View.OnClickListener onClickListener,
 | 
			
		||||
    public CommentsAdapter(final CommentModel[] commentModels,
 | 
			
		||||
                           final boolean isParent,
 | 
			
		||||
                           final View.OnClickListener onClickListener,
 | 
			
		||||
                           final MentionClickListener mentionClickListener) {
 | 
			
		||||
        this.commentModels = this.filteredCommentModels = commentModels;
 | 
			
		||||
        this.isParent = isParent;
 | 
			
		||||
@ -93,10 +94,13 @@ public final class CommentsAdapter extends RecyclerView.Adapter<CommentViewHolde
 | 
			
		||||
        if (quantityStrings[0] == null) quantityStrings[0] = context.getString(R.string.single_like);
 | 
			
		||||
        if (quantityStrings[1] == null) quantityStrings[1] = context.getString(R.string.multiple_likes);
 | 
			
		||||
        if (layoutInflater == null) layoutInflater = LayoutInflater.from(context);
 | 
			
		||||
        return new CommentViewHolder(layoutInflater.inflate(
 | 
			
		||||
                isParent ? R.layout.item_comment       // parent
 | 
			
		||||
                        : R.layout.item_comment_small, // child
 | 
			
		||||
                parent, false), onClickListener, mentionClickListener);
 | 
			
		||||
        final View view = layoutInflater.inflate(isParent ? R.layout.item_comment
 | 
			
		||||
                                                          : R.layout.item_comment_small,
 | 
			
		||||
                                                 parent,
 | 
			
		||||
                                                 false);
 | 
			
		||||
        return new CommentViewHolder(view,
 | 
			
		||||
                                     onClickListener,
 | 
			
		||||
                                     mentionClickListener);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@ -105,7 +109,7 @@ public final class CommentsAdapter extends RecyclerView.Adapter<CommentViewHolde
 | 
			
		||||
        if (commentModel != null) {
 | 
			
		||||
            holder.setCommentModel(commentModel);
 | 
			
		||||
 | 
			
		||||
            holder.setCommment(commentModel.getText());
 | 
			
		||||
            holder.setComment(commentModel.getText());
 | 
			
		||||
            holder.setDate(commentModel.getDateTime());
 | 
			
		||||
            holder.setLiked(commentModel.getLiked());
 | 
			
		||||
 | 
			
		||||
@ -115,12 +119,8 @@ public final class CommentsAdapter extends RecyclerView.Adapter<CommentViewHolde
 | 
			
		||||
            final ProfileModel profileModel = commentModel.getProfileModel();
 | 
			
		||||
            if (profileModel != null) {
 | 
			
		||||
                holder.setUsername(profileModel.getUsername());
 | 
			
		||||
 | 
			
		||||
                Glide.with(layoutInflater.getContext())
 | 
			
		||||
                        .applyDefaultRequestOptions(new RequestOptions().skipMemoryCache(true))
 | 
			
		||||
                        .load(profileModel.getSdProfilePic()).into(holder.getProfilePicView());
 | 
			
		||||
                holder.getProfilePicView().setImageURI(profileModel.getSdProfilePic());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (holder.isParent()) {
 | 
			
		||||
                final CommentModel[] childCommentModels = commentModel.getChildCommentModels();
 | 
			
		||||
                if (childCommentModels != null && childCommentModels.length > 0)
 | 
			
		||||
 | 
			
		||||
@ -2,12 +2,13 @@ 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 com.facebook.drawee.view.SimpleDraweeView;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.R;
 | 
			
		||||
import awais.instagrabber.adapters.CommentsAdapter;
 | 
			
		||||
import awais.instagrabber.customviews.RamboTextView;
 | 
			
		||||
@ -17,11 +18,16 @@ import awais.instagrabber.models.CommentModel;
 | 
			
		||||
public final class CommentViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
    private final MentionClickListener mentionClickListener;
 | 
			
		||||
    private final RecyclerView rvChildComments;
 | 
			
		||||
    private final ImageView ivProfilePic;
 | 
			
		||||
    private final TextView tvUsername, tvDate, tvComment, tvLikes;
 | 
			
		||||
    private final SimpleDraweeView ivProfilePic;
 | 
			
		||||
    private final TextView tvUsername;
 | 
			
		||||
    private final TextView tvDate;
 | 
			
		||||
    private final TextView tvComment;
 | 
			
		||||
    private final TextView tvLikes;
 | 
			
		||||
    private final View container;
 | 
			
		||||
 | 
			
		||||
    public CommentViewHolder(@NonNull final View itemView, final View.OnClickListener onClickListener, final MentionClickListener mentionClickListener) {
 | 
			
		||||
    public CommentViewHolder(@NonNull final View itemView,
 | 
			
		||||
                             final View.OnClickListener onClickListener,
 | 
			
		||||
                             final MentionClickListener mentionClickListener) {
 | 
			
		||||
        super(itemView);
 | 
			
		||||
 | 
			
		||||
        container = itemView.findViewById(R.id.container);
 | 
			
		||||
@ -41,7 +47,7 @@ public final class CommentViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        rvChildComments = itemView.findViewById(R.id.rvChildComments);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final ImageView getProfilePicView() {
 | 
			
		||||
    public final SimpleDraweeView getProfilePicView() {
 | 
			
		||||
        return ivProfilePic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -69,9 +75,9 @@ public final class CommentViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        if (liked) container.setBackgroundColor(0x40FF69B4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void setCommment(final CharSequence commment) {
 | 
			
		||||
    public final void setComment(final CharSequence comment) {
 | 
			
		||||
        if (tvComment != null) {
 | 
			
		||||
            tvComment.setText(commment, commment instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL);
 | 
			
		||||
            tvComment.setText(comment, comment instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL);
 | 
			
		||||
            ((RamboTextView) tvComment).setMentionClickListener(mentionClickListener);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,6 @@ import java.net.URL;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.models.ImageUploadOptions;
 | 
			
		||||
@ -52,7 +51,7 @@ public class ImageUploader extends AsyncTask<ImageUploadOptions, Void, ImageUplo
 | 
			
		||||
            final String contentLength = String.valueOf(bytes.length);
 | 
			
		||||
            final Map<String, String> headers = new HashMap<>();
 | 
			
		||||
            final String uploadId = String.valueOf(new Date().getTime());
 | 
			
		||||
            final long random = LOWER + new Random().nextLong() * (UPPER - LOWER + 1);
 | 
			
		||||
            final long random = Utils.random(LOWER, UPPER + 1);
 | 
			
		||||
            final String name = String.format("%s_0_%s", uploadId, random);
 | 
			
		||||
            final String waterfallId = options.getWaterfallId() != null ? options.getWaterfallId() : UUID.randomUUID().toString();
 | 
			
		||||
            headers.put("X-Entity-Type", "image/jpeg");
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ public final class iPostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
 | 
			
		||||
                            user.optBoolean("is_private"),
 | 
			
		||||
                            user.optBoolean("is_private"),
 | 
			
		||||
                            user.optBoolean("is_verified"),
 | 
			
		||||
                            null,
 | 
			
		||||
                            user.optString("pk"),
 | 
			
		||||
                            user.getString(Constants.EXTRAS_USERNAME),
 | 
			
		||||
                            user.optString("fullname"),
 | 
			
		||||
                            null,
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
package awais.instagrabber.fragments;
 | 
			
		||||
 | 
			
		||||
import android.content.DialogInterface;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.pm.PackageManager;
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
@ -26,7 +25,6 @@ import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.R;
 | 
			
		||||
import awais.instagrabber.activities.CommentsViewer;
 | 
			
		||||
import awais.instagrabber.adapters.PostViewAdapter;
 | 
			
		||||
import awais.instagrabber.adapters.PostViewAdapter.OnPostViewChildViewClickListener;
 | 
			
		||||
import awais.instagrabber.asyncs.PostFetcher;
 | 
			
		||||
@ -114,12 +112,18 @@ public class PostViewFragment extends Fragment {
 | 
			
		||||
            case R.id.viewerCaption:
 | 
			
		||||
                break;
 | 
			
		||||
            case R.id.btnComments:
 | 
			
		||||
                startActivity(new Intent(requireContext(), CommentsViewer.class)
 | 
			
		||||
                                      .putExtra(Constants.EXTRAS_SHORTCODE,
 | 
			
		||||
                                                postModel.getShortCode())
 | 
			
		||||
                                      .putExtra(Constants.EXTRAS_POST, postModel.getPostId())
 | 
			
		||||
                                      .putExtra(Constants.EXTRAS_USER,
 | 
			
		||||
                                                Utils.getUserIdFromCookie(COOKIE)));
 | 
			
		||||
                // startActivity(new Intent(requireContext(), CommentsViewerFragment.class)
 | 
			
		||||
                //                       .putExtra(Constants.EXTRAS_SHORTCODE, postModel.getShortCode())
 | 
			
		||||
                //                       .putExtra(Constants.EXTRAS_POST, postModel.getPostId())
 | 
			
		||||
                //                       .putExtra(Constants.EXTRAS_USER, Utils.getUserIdFromCookie(COOKIE)));
 | 
			
		||||
                String postId = postModel.getPostId();
 | 
			
		||||
                if (postId.contains("_")) postId = postId.substring(0, postId.indexOf("_"));
 | 
			
		||||
                final NavDirections commentsAction = PostViewFragmentDirections.actionGlobalCommentsViewerFragment(
 | 
			
		||||
                        postModel.getShortCode(),
 | 
			
		||||
                        postId,
 | 
			
		||||
                        postModel.getProfileModel().getId()
 | 
			
		||||
                );
 | 
			
		||||
                NavHostFragment.findNavController(this).navigate(commentsAction);
 | 
			
		||||
                break;
 | 
			
		||||
            case R.id.btnDownload:
 | 
			
		||||
                if (checkSelfPermission(requireContext(),
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
package awais.instagrabber.fragments.main;
 | 
			
		||||
 | 
			
		||||
import android.content.DialogInterface;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
@ -35,7 +34,6 @@ import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import awais.instagrabber.R;
 | 
			
		||||
import awais.instagrabber.activities.CommentsViewer;
 | 
			
		||||
import awais.instagrabber.activities.MainActivity;
 | 
			
		||||
import awais.instagrabber.adapters.FeedAdapter;
 | 
			
		||||
import awais.instagrabber.adapters.FeedStoriesAdapter;
 | 
			
		||||
@ -187,17 +185,14 @@ public class FeedFragment extends Fragment {
 | 
			
		||||
        final int id = v.getId();
 | 
			
		||||
        switch (id) {
 | 
			
		||||
            case R.id.btnComments:
 | 
			
		||||
                startActivity(new Intent(requireContext(), CommentsViewer.class)
 | 
			
		||||
                                      .putExtra(Constants.EXTRAS_SHORTCODE, feedModel.getShortCode())
 | 
			
		||||
                                      .putExtra(Constants.EXTRAS_POST, feedModel.getPostId())
 | 
			
		||||
                                      .putExtra(Constants.EXTRAS_USER, feedModel.getProfileModel().getId()));
 | 
			
		||||
                final NavDirections commentsAction = FeedFragmentDirections.actionGlobalCommentsViewerFragment(
 | 
			
		||||
                        feedModel.getShortCode(),
 | 
			
		||||
                        feedModel.getPostId(),
 | 
			
		||||
                        feedModel.getProfileModel().getId()
 | 
			
		||||
                );
 | 
			
		||||
                NavHostFragment.findNavController(this).navigate(commentsAction);
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case R.id.viewStoryPost:
 | 
			
		||||
                // startActivity(new Intent(requireContext(), PostViewer.class)
 | 
			
		||||
                //         .putExtra(Constants.EXTRAS_INDEX, feedModel.getPosition())
 | 
			
		||||
                //         .putExtra(Constants.EXTRAS_POST, new PostModel(feedModel.getShortCode(), false))
 | 
			
		||||
                //         .putExtra(Constants.EXTRAS_TYPE, ItemGetType.FEED_ITEMS));
 | 
			
		||||
                final List<FeedModel> feedModels = feedViewModel.getList().getValue();
 | 
			
		||||
                if (feedModels == null || feedModels.size() == 0) return;
 | 
			
		||||
                if (feedModels.get(0) == null) return;
 | 
			
		||||
@ -296,11 +291,9 @@ public class FeedFragment extends Fragment {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
 | 
			
		||||
        if (!shouldRefresh) return;
 | 
			
		||||
        // setupActionBar();
 | 
			
		||||
        setupFeedStories();
 | 
			
		||||
        setupFeed();
 | 
			
		||||
        shouldRefresh = false;
 | 
			
		||||
        // feedService.getFeed(11, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -456,16 +456,14 @@ public class ProfileFragment extends Fragment {
 | 
			
		||||
            binding.mainFollowers.setClickable(true);
 | 
			
		||||
 | 
			
		||||
            if (isLoggedIn) {
 | 
			
		||||
                final View.OnClickListener followClickListener = v -> startActivity(new Intent(
 | 
			
		||||
                        requireContext(),
 | 
			
		||||
                        FollowViewer.class).putExtra(Constants.EXTRAS_FOLLOWERS, v == binding.mainFollowers)
 | 
			
		||||
                final View.OnClickListener followClickListener = v -> startActivity(
 | 
			
		||||
                        new Intent(requireContext(), FollowViewer.class)
 | 
			
		||||
                                .putExtra(Constants.EXTRAS_FOLLOWERS, v == binding.mainFollowers)
 | 
			
		||||
                                .putExtra(Constants.EXTRAS_NAME, profileModel.getUsername())
 | 
			
		||||
                                .putExtra(Constants.EXTRAS_ID, profileId));
 | 
			
		||||
 | 
			
		||||
                binding.mainFollowers
 | 
			
		||||
                        .setOnClickListener(followersCount > 0 ? followClickListener : null);
 | 
			
		||||
                binding.mainFollowing
 | 
			
		||||
                        .setOnClickListener(followingCount > 0 ? followClickListener : null);
 | 
			
		||||
                binding.mainFollowers.setOnClickListener(followersCount > 0 ? followClickListener : null);
 | 
			
		||||
                binding.mainFollowing.setOnClickListener(followingCount > 0 ? followClickListener : null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (profileModel.getPostCount() == 0) {
 | 
			
		||||
 | 
			
		||||
@ -13,8 +13,32 @@ public interface MediaRepository {
 | 
			
		||||
 | 
			
		||||
    @FormUrlEncoded
 | 
			
		||||
    @POST("/api/v1/media/{mediaId}/{action}/")
 | 
			
		||||
    Call<String> likeAction(@Header("User-Agent") final String userAgent,
 | 
			
		||||
    Call<String> action(@Header("User-Agent") final String userAgent,
 | 
			
		||||
                        @Path("action") final String action,
 | 
			
		||||
                        @Path("mediaId") final String mediaId,
 | 
			
		||||
                        @FieldMap final Map<String, String> signedForm);
 | 
			
		||||
 | 
			
		||||
    @FormUrlEncoded
 | 
			
		||||
    @POST("/api/v1/media/{mediaId}/comment/")
 | 
			
		||||
    Call<String> comment(@Header("User-Agent") final String userAgent,
 | 
			
		||||
                         @Path("mediaId") final String mediaId,
 | 
			
		||||
                         @FieldMap final Map<String, String> signedForm);
 | 
			
		||||
 | 
			
		||||
    @FormUrlEncoded
 | 
			
		||||
    @POST("/api/v1/media/{mediaId}/comment/bulk_delete/")
 | 
			
		||||
    Call<String> commentsBulkDelete(@Header("User-Agent") final String userAgent,
 | 
			
		||||
                                    @Path("mediaId") final String mediaId,
 | 
			
		||||
                                    @FieldMap final Map<String, String> signedForm);
 | 
			
		||||
 | 
			
		||||
    @FormUrlEncoded
 | 
			
		||||
    @POST("/api/v1/media/{commentId}/comment_like/")
 | 
			
		||||
    Call<String> commentLike(@Header("User-Agent") final String userAgent,
 | 
			
		||||
                             @Path("commentId") final String commentId,
 | 
			
		||||
                             @FieldMap final Map<String, String> signedForm);
 | 
			
		||||
 | 
			
		||||
    @FormUrlEncoded
 | 
			
		||||
    @POST("/api/v1/media/{commentId}/comment_unlike/")
 | 
			
		||||
    Call<String> commentUnlike(@Header("User-Agent") final String userAgent,
 | 
			
		||||
                               @Path("commentId") final String commentId,
 | 
			
		||||
                               @FieldMap final Map<String, String> signedForm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
 | 
			
		||||
import retrofit2.converter.scalars.ScalarsConverterFactory;
 | 
			
		||||
 | 
			
		||||
public abstract class BaseService {
 | 
			
		||||
    private static final String TAG = "BaseService";
 | 
			
		||||
 | 
			
		||||
    private Retrofit.Builder builder;
 | 
			
		||||
 | 
			
		||||
@ -33,4 +34,29 @@ public abstract class BaseService {
 | 
			
		||||
        }
 | 
			
		||||
        return builder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // protected String userBreadcrumb(final int size) {
 | 
			
		||||
    //     final long term = (random(2, 4) * 1000) + size + (random(15, 21) * 1000);
 | 
			
		||||
    //     final float div = (float) size / random(2, 4);
 | 
			
		||||
    //     final int round = Math.round(div);
 | 
			
		||||
    //     final long textChangeEventCount = round > 0 ? round : 1;
 | 
			
		||||
    //     final String data = String.format(Locale.getDefault(), "%d %d %d %d", size, term, textChangeEventCount, new Date().getTime());
 | 
			
		||||
    //     try {
 | 
			
		||||
    //         final Mac hasher = Mac.getInstance("HmacSHA256");
 | 
			
		||||
    //         hasher.init(new SecretKeySpec(Constants.BREADCRUMB_KEY.getBytes(), "HmacSHA256"));
 | 
			
		||||
    //         byte[] hash = hasher.doFinal(data.getBytes());
 | 
			
		||||
    //         final StringBuilder hexString = new StringBuilder();
 | 
			
		||||
    //         for (byte b : hash) {
 | 
			
		||||
    //             final String hex = Integer.toHexString(0xff & b);
 | 
			
		||||
    //             if (hex.length() == 1) hexString.append('0');
 | 
			
		||||
    //             hexString.append(hex);
 | 
			
		||||
    //         }
 | 
			
		||||
    //         final String encodedData = Base64.encodeToString(data.getBytes(), Base64.NO_WRAP);
 | 
			
		||||
    //         final String encodedHex = Base64.encodeToString(hexString.toString().getBytes(), Base64.NO_WRAP);
 | 
			
		||||
    //         return String.format("%s\n%s\n", encodedHex, encodedData);
 | 
			
		||||
    //     } catch (Exception e) {
 | 
			
		||||
    //         Log.e(TAG, "Error creating breadcrumb", e);
 | 
			
		||||
    //         return null;
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,8 @@ class LoggingInterceptor implements Interceptor {
 | 
			
		||||
        Log.d("OkHttp", content);
 | 
			
		||||
 | 
			
		||||
        ResponseBody wrappedBody = ResponseBody.create(contentType, content);
 | 
			
		||||
        return response.newBuilder().body(wrappedBody).build();
 | 
			
		||||
        return response.newBuilder()
 | 
			
		||||
                       .body(wrappedBody)
 | 
			
		||||
                       .build();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,16 @@
 | 
			
		||||
package awais.instagrabber.services;
 | 
			
		||||
 | 
			
		||||
import android.text.TextUtils;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
 | 
			
		||||
import org.json.JSONException;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@ -42,31 +47,31 @@ public class MediaService extends BaseService {
 | 
			
		||||
                     final String userId,
 | 
			
		||||
                     final String csrfToken,
 | 
			
		||||
                     final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        likeAction(mediaId, userId, "like", csrfToken, callback);
 | 
			
		||||
        action(mediaId, userId, "like", csrfToken, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void unlike(final String mediaId,
 | 
			
		||||
                       final String userId,
 | 
			
		||||
                       final String csrfToken,
 | 
			
		||||
                       final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        likeAction(mediaId, userId, "unlike", csrfToken, callback);
 | 
			
		||||
        action(mediaId, userId, "unlike", csrfToken, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void save(final String mediaId,
 | 
			
		||||
                     final String userId,
 | 
			
		||||
                     final String csrfToken,
 | 
			
		||||
                     final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        likeAction(mediaId, userId, "save", csrfToken, callback);
 | 
			
		||||
        action(mediaId, userId, "save", csrfToken, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void unsave(final String mediaId,
 | 
			
		||||
                       final String userId,
 | 
			
		||||
                       final String csrfToken,
 | 
			
		||||
                       final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        likeAction(mediaId, userId, "unsave", csrfToken, callback);
 | 
			
		||||
        action(mediaId, userId, "unsave", csrfToken, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void likeAction(final String mediaId,
 | 
			
		||||
    private void action(final String mediaId,
 | 
			
		||||
                        final String userId,
 | 
			
		||||
                        final String action,
 | 
			
		||||
                        final String csrfToken,
 | 
			
		||||
@ -78,7 +83,7 @@ public class MediaService extends BaseService {
 | 
			
		||||
        form.put("_uuid", UUID.randomUUID().toString());
 | 
			
		||||
        // form.put("radio_type", "wifi-none");
 | 
			
		||||
        final Map<String, String> signedForm = Utils.sign(form);
 | 
			
		||||
        final Call<String> request = repository.likeAction(Constants.I_USER_AGENT, action, mediaId, signedForm);
 | 
			
		||||
        final Call<String> request = repository.action(Constants.I_USER_AGENT, action, mediaId, signedForm);
 | 
			
		||||
        request.enqueue(new Callback<String>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(@NonNull final Call<String> call,
 | 
			
		||||
@ -106,23 +111,170 @@ public class MediaService extends BaseService {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        // const signedFormData = this.client.request.sign({
 | 
			
		||||
        //             media_id: options.mediaId,
 | 
			
		||||
        //             _csrftoken: this.client.state.cookieCsrfToken,
 | 
			
		||||
        //             _uid: this.client.state.cookieUserId,
 | 
			
		||||
        //             _uuid: this.client.state.uuid,
 | 
			
		||||
        // });
 | 
			
		||||
        //
 | 
			
		||||
        // const { body } = await this.client.request.send({
 | 
			
		||||
        //                                                         url: `/api/v1/media/${options.mediaId}/${options.action}/`,
 | 
			
		||||
        //     method: 'POST',
 | 
			
		||||
        //             form: {
 | 
			
		||||
        //     ...signedFormData,
 | 
			
		||||
        //                 d: options.d,
 | 
			
		||||
        //     },
 | 
			
		||||
        // });
 | 
			
		||||
        //     return body;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public void comment(@NonNull final String mediaId,
 | 
			
		||||
                        @NonNull final String comment,
 | 
			
		||||
                        @NonNull final String userId,
 | 
			
		||||
                        final String replyToCommentId,
 | 
			
		||||
                        final String csrfToken,
 | 
			
		||||
                        @NonNull final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        final String module = "self_comments_v2";
 | 
			
		||||
        final Map<String, Object> form = new HashMap<>();
 | 
			
		||||
        // form.put("user_breadcrumb", userBreadcrumb(comment.length()));
 | 
			
		||||
        form.put("idempotence_token", UUID.randomUUID().toString());
 | 
			
		||||
        form.put("_csrftoken", csrfToken);
 | 
			
		||||
        form.put("_uid", userId);
 | 
			
		||||
        form.put("_uuid", UUID.randomUUID().toString());
 | 
			
		||||
        form.put("comment_text", comment);
 | 
			
		||||
        form.put("containermodule", module);
 | 
			
		||||
        if (!Utils.isEmpty(replyToCommentId)) {
 | 
			
		||||
            form.put("replied_to_comment_id", replyToCommentId);
 | 
			
		||||
        }
 | 
			
		||||
        final Map<String, String> signedForm = Utils.sign(form);
 | 
			
		||||
        final Call<String> commentRequest = repository.comment(Constants.I_USER_AGENT, mediaId, signedForm);
 | 
			
		||||
        commentRequest.enqueue(new Callback<String>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
 | 
			
		||||
                final String body = response.body();
 | 
			
		||||
                if (body == null) {
 | 
			
		||||
                    Log.e(TAG, "Error occurred while creating comment");
 | 
			
		||||
                    callback.onSuccess(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                try {
 | 
			
		||||
                    final JSONObject jsonObject = new JSONObject(body);
 | 
			
		||||
                    final String status = jsonObject.optString("status");
 | 
			
		||||
                    callback.onSuccess(status.equals("ok"));
 | 
			
		||||
                } catch (JSONException e) {
 | 
			
		||||
                    // Log.e(TAG, "Error parsing body", e);
 | 
			
		||||
                    callback.onFailure(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
 | 
			
		||||
                callback.onFailure(t);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void deleteComment(final String mediaId,
 | 
			
		||||
                              final String userId,
 | 
			
		||||
                              final String commentId,
 | 
			
		||||
                              final String csrfToken,
 | 
			
		||||
                              @NonNull final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        deleteComments(mediaId, userId, Collections.singletonList(commentId), csrfToken, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void deleteComments(final String mediaId,
 | 
			
		||||
                               final String userId,
 | 
			
		||||
                               final List<String> commentIds,
 | 
			
		||||
                               final String csrfToken,
 | 
			
		||||
                               @NonNull final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        final Map<String, Object> form = new HashMap<>();
 | 
			
		||||
        form.put("comment_ids_to_delete", TextUtils.join(",", commentIds));
 | 
			
		||||
        form.put("_csrftoken", csrfToken);
 | 
			
		||||
        form.put("_uid", userId);
 | 
			
		||||
        form.put("_uuid", UUID.randomUUID().toString());
 | 
			
		||||
        final Map<String, String> signedForm = Utils.sign(form);
 | 
			
		||||
        final Call<String> bulkDeleteRequest = repository.commentsBulkDelete(Constants.USER_AGENT, mediaId, signedForm);
 | 
			
		||||
        bulkDeleteRequest.enqueue(new Callback<String>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
 | 
			
		||||
                final String body = response.body();
 | 
			
		||||
                if (body == null) {
 | 
			
		||||
                    Log.e(TAG, "Error occurred while deleting comments");
 | 
			
		||||
                    callback.onSuccess(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                try {
 | 
			
		||||
                    final JSONObject jsonObject = new JSONObject(body);
 | 
			
		||||
                    final String status = jsonObject.optString("status");
 | 
			
		||||
                    callback.onSuccess(status.equals("ok"));
 | 
			
		||||
                } catch (JSONException e) {
 | 
			
		||||
                    // Log.e(TAG, "Error parsing body", e);
 | 
			
		||||
                    callback.onFailure(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
 | 
			
		||||
                // Log.e(TAG, "Error deleting comments", t);
 | 
			
		||||
                callback.onFailure(t);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void commentLike(@NonNull final String commentId,
 | 
			
		||||
                            @NonNull final String csrfToken,
 | 
			
		||||
                            @NonNull final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        final Map<String, Object> form = new HashMap<>();
 | 
			
		||||
        form.put("_csrftoken", csrfToken);
 | 
			
		||||
        // form.put("_uid", userId);
 | 
			
		||||
        // form.put("_uuid", UUID.randomUUID().toString());
 | 
			
		||||
        final Map<String, String> signedForm = Utils.sign(form);
 | 
			
		||||
        final Call<String> commentLikeRequest = repository.commentLike(Constants.USER_AGENT, commentId, signedForm);
 | 
			
		||||
        commentLikeRequest.enqueue(new Callback<String>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
 | 
			
		||||
                final String body = response.body();
 | 
			
		||||
                if (body == null) {
 | 
			
		||||
                    Log.e(TAG, "Error occurred while liking comment");
 | 
			
		||||
                    callback.onSuccess(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                try {
 | 
			
		||||
                    final JSONObject jsonObject = new JSONObject(body);
 | 
			
		||||
                    final String status = jsonObject.optString("status");
 | 
			
		||||
                    callback.onSuccess(status.equals("ok"));
 | 
			
		||||
                } catch (JSONException e) {
 | 
			
		||||
                    // Log.e(TAG, "Error parsing body", e);
 | 
			
		||||
                    callback.onFailure(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
 | 
			
		||||
                Log.e(TAG, "Error liking comment", t);
 | 
			
		||||
                callback.onFailure(t);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void commentUnlike(final String commentId,
 | 
			
		||||
                              @NonNull final String csrfToken,
 | 
			
		||||
                              @NonNull final ServiceCallback<Boolean> callback) {
 | 
			
		||||
        final Map<String, Object> form = new HashMap<>();
 | 
			
		||||
        form.put("_csrftoken", csrfToken);
 | 
			
		||||
        // form.put("_uid", userId);
 | 
			
		||||
        // form.put("_uuid", UUID.randomUUID().toString());
 | 
			
		||||
        final Map<String, String> signedForm = Utils.sign(form);
 | 
			
		||||
        final Call<String> commentUnlikeRequest = repository.commentUnlike(Constants.USER_AGENT, commentId, signedForm);
 | 
			
		||||
        commentUnlikeRequest.enqueue(new Callback<String>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
 | 
			
		||||
                final String body = response.body();
 | 
			
		||||
                if (body == null) {
 | 
			
		||||
                    Log.e(TAG, "Error occurred while unliking comment");
 | 
			
		||||
                    callback.onSuccess(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                try {
 | 
			
		||||
                    final JSONObject jsonObject = new JSONObject(body);
 | 
			
		||||
                    final String status = jsonObject.optString("status");
 | 
			
		||||
                    callback.onSuccess(status.equals("ok"));
 | 
			
		||||
                } catch (JSONException e) {
 | 
			
		||||
                    // Log.e(TAG, "Error parsing body", e);
 | 
			
		||||
                    callback.onFailure(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
 | 
			
		||||
                Log.e(TAG, "Error unliking comment", t);
 | 
			
		||||
                callback.onFailure(t);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -66,5 +66,6 @@ public final class Constants {
 | 
			
		||||
            "\"gyroscope\", \"value\": \"gyroscope_enabled\" } ]";
 | 
			
		||||
    public static final String SIGNATURE_VERSION = "4";
 | 
			
		||||
    public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc";
 | 
			
		||||
    public static final String BREADCRUMB_KEY = "iN4$aGr0m";
 | 
			
		||||
    public static final int LOGIN_RESULT_CODE = 5000;
 | 
			
		||||
}
 | 
			
		||||
@ -63,6 +63,7 @@ import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.regex.Pattern;
 | 
			
		||||
 | 
			
		||||
@ -1220,9 +1221,13 @@ public final class Utils {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String sign(final String message) {
 | 
			
		||||
        return sign(Constants.SIGNATURE_KEY, message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String sign(final String key, final String message) {
 | 
			
		||||
        try {
 | 
			
		||||
            final Mac hasher = Mac.getInstance("HmacSHA256");
 | 
			
		||||
            hasher.init(new SecretKeySpec(Constants.SIGNATURE_KEY.getBytes(), "HmacSHA256"));
 | 
			
		||||
            hasher.init(new SecretKeySpec(key.getBytes(), "HmacSHA256"));
 | 
			
		||||
            byte[] hash = hasher.doFinal(message.getBytes());
 | 
			
		||||
            final StringBuilder hexString = new StringBuilder();
 | 
			
		||||
            for (byte b : hash) {
 | 
			
		||||
@ -1458,4 +1463,29 @@ public final class Utils {
 | 
			
		||||
        }
 | 
			
		||||
        return cookie.split("csrftoken=")[1].split(";")[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // public static long random(final long lower, final long upper) {
 | 
			
		||||
    //     final long result = lower + new Random().nextLong() * (upper - lower + 1);
 | 
			
		||||
    //     return result;
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    public static long random(long origin, long bound) {
 | 
			
		||||
        final Random random = new Random();
 | 
			
		||||
        long r = random.nextLong();
 | 
			
		||||
        long n = bound - origin, m = n - 1;
 | 
			
		||||
        if ((n & m) == 0L)  // power of two
 | 
			
		||||
            r = (r & m) + origin;
 | 
			
		||||
        else if (n > 0L) {  // reject over-represented candidates
 | 
			
		||||
            for (long u = r >>> 1;            // ensure nonnegative
 | 
			
		||||
                 u + m - (r = u % n) < 0L;    // rejection check
 | 
			
		||||
                 u = random.nextLong() >>> 1) // retry
 | 
			
		||||
                ;
 | 
			
		||||
            r += origin;
 | 
			
		||||
        }
 | 
			
		||||
        else {              // range not representable as long
 | 
			
		||||
            while (r < origin || r >= bound)
 | 
			
		||||
                r = random.nextLong();
 | 
			
		||||
        }
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_search_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/drawable/ic_search_24.xml
									
									
									
									
									
										Normal file
									
								
							@ -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="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@ -1,70 +0,0 @@
 | 
			
		||||
<?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.CommentsViewer">
 | 
			
		||||
 | 
			
		||||
    <include
 | 
			
		||||
        android:id="@+id/toolbar"
 | 
			
		||||
        android:layout_weight="1"
 | 
			
		||||
        layout="@layout/layout_include_toolbar" />
 | 
			
		||||
 | 
			
		||||
    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 | 
			
		||||
        android:id="@+id/swipeRefreshLayout"
 | 
			
		||||
        android:layout_weight="8"
 | 
			
		||||
        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_comment" />
 | 
			
		||||
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
 | 
			
		||||
 | 
			
		||||
    <LinearLayout android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
        <androidx.appcompat.widget.AppCompatImageView
 | 
			
		||||
            android:id="@+id/commentCancelParent"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:background="?selectableItemBackgroundBorderless"
 | 
			
		||||
            android:clickable="true"
 | 
			
		||||
            android:paddingRight="8dp"
 | 
			
		||||
            android:visibility="gone"
 | 
			
		||||
            app:srcCompat="@android:drawable/ic_menu_revert" />
 | 
			
		||||
        <EditText
 | 
			
		||||
            android:id="@+id/commentText"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_weight="2"
 | 
			
		||||
            android:paddingLeft="8dp"
 | 
			
		||||
            android:gravity="bottom"
 | 
			
		||||
            android:hint="@string/comment_hint"
 | 
			
		||||
            android:inputType="textMultiLine"
 | 
			
		||||
            android:maxLength="2200"
 | 
			
		||||
            android:maxLines="10"
 | 
			
		||||
            android:visibility="gone"
 | 
			
		||||
            android:scrollHorizontally="false" />
 | 
			
		||||
 | 
			
		||||
        <androidx.appcompat.widget.AppCompatImageView
 | 
			
		||||
            android:id="@+id/commentSend"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:background="?selectableItemBackgroundBorderless"
 | 
			
		||||
            android:clickable="true"
 | 
			
		||||
            android:paddingRight="8dp"
 | 
			
		||||
            android:visibility="gone"
 | 
			
		||||
            app:srcCompat="@android:drawable/ic_menu_send" />
 | 
			
		||||
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -17,6 +17,7 @@
 | 
			
		||||
        app:layout_constraintTop_toTopOf="parent">
 | 
			
		||||
 | 
			
		||||
        <com.google.android.material.appbar.CollapsingToolbarLayout
 | 
			
		||||
            android:id="@+id/collapsingToolbarLayout"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            app:layout_scrollFlags="scroll|snap|enterAlways"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										48
									
								
								app/src/main/res/layout/fragment_comments.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								app/src/main/res/layout/fragment_comments.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
<?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">
 | 
			
		||||
 | 
			
		||||
    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 | 
			
		||||
        android:id="@+id/swipeRefreshLayout"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
        android:layout_weight="1">
 | 
			
		||||
 | 
			
		||||
        <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/rvComments"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:clipToPadding="false"
 | 
			
		||||
            app:layoutManager="LinearLayoutManager"
 | 
			
		||||
            tools:listitem="@layout/item_comment" />
 | 
			
		||||
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
 | 
			
		||||
 | 
			
		||||
    <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
        android:id="@+id/commentField"
 | 
			
		||||
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_margin="4dp"
 | 
			
		||||
        android:hint="@string/comment_hint"
 | 
			
		||||
        app:counterEnabled="true"
 | 
			
		||||
        app:counterMaxLength="2200"
 | 
			
		||||
        app:endIconDrawable="@drawable/ic_send_24"
 | 
			
		||||
        app:endIconMode="custom"
 | 
			
		||||
        app:startIconDrawable="@drawable/ic_close_24">
 | 
			
		||||
 | 
			
		||||
        <com.google.android.material.textfield.TextInputEditText
 | 
			
		||||
            android:id="@+id/commentText"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:autofillHints="no"
 | 
			
		||||
            android:inputType="textMultiLine"
 | 
			
		||||
            android:maxLength="2200"
 | 
			
		||||
            android:maxLines="10"
 | 
			
		||||
            android:scrollHorizontally="false" />
 | 
			
		||||
 | 
			
		||||
    </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -15,8 +15,8 @@
 | 
			
		||||
        android:id="@+id/rvChildComments"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_marginStart="80dp"
 | 
			
		||||
        android:layout_marginLeft="80dp"
 | 
			
		||||
        android:layout_marginStart="40dp"
 | 
			
		||||
        android:layout_marginLeft="40dp"
 | 
			
		||||
        app:layoutManager="LinearLayoutManager"
 | 
			
		||||
        tools:itemCount="5"
 | 
			
		||||
        tools:listitem="@layout/item_comment_small" />
 | 
			
		||||
@ -25,6 +25,8 @@
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="1dp"
 | 
			
		||||
        android:layout_gravity="bottom"
 | 
			
		||||
        android:layout_marginStart="4dp"
 | 
			
		||||
        android:layout_marginEnd="4dp"
 | 
			
		||||
        android:layout_marginBottom="4dp"
 | 
			
		||||
        android:background="#80888888" />
 | 
			
		||||
        android:background="#32888888" />
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -23,12 +23,13 @@
 | 
			
		||||
        android:paddingLeft="4dp"
 | 
			
		||||
        android:paddingRight="4dp">
 | 
			
		||||
 | 
			
		||||
        <androidx.appcompat.widget.AppCompatImageView
 | 
			
		||||
        <com.facebook.drawee.view.SimpleDraweeView
 | 
			
		||||
            android:id="@+id/ivProfilePic"
 | 
			
		||||
            android:layout_width="50dp"
 | 
			
		||||
            android:layout_height="50dp"
 | 
			
		||||
            android:gravity="center"
 | 
			
		||||
            app:srcCompat="@mipmap/ic_launcher" />
 | 
			
		||||
            app:actualImageScaleType="centerCrop"
 | 
			
		||||
            app:roundAsCircle="true" />
 | 
			
		||||
 | 
			
		||||
        <LinearLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
@ -38,7 +39,7 @@
 | 
			
		||||
            <androidx.appcompat.widget.AppCompatTextView
 | 
			
		||||
                android:id="@+id/tvUsername"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_height="0dp"
 | 
			
		||||
                android:layout_gravity="start"
 | 
			
		||||
                android:layout_weight="1.0"
 | 
			
		||||
                android:ellipsize="marquee"
 | 
			
		||||
@ -68,10 +69,12 @@
 | 
			
		||||
                android:paddingRight="8dp"
 | 
			
		||||
                android:paddingBottom="8dp"
 | 
			
		||||
                android:textAppearance="@style/TextAppearance.AppCompat" />
 | 
			
		||||
 | 
			
		||||
            <LinearLayout
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:weightSum="3.5">
 | 
			
		||||
 | 
			
		||||
                <androidx.appcompat.widget.AppCompatTextView
 | 
			
		||||
                    android:id="@+id/tvLikes"
 | 
			
		||||
                    android:layout_width="0dp"
 | 
			
		||||
@ -91,17 +94,17 @@
 | 
			
		||||
                    android:id="@+id/tvDate"
 | 
			
		||||
                    android:layout_width="0dp"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:layout_weight="2.5"
 | 
			
		||||
                    android:layout_gravity="start"
 | 
			
		||||
                    android:layout_weight="2.5"
 | 
			
		||||
                    android:ellipsize="marquee"
 | 
			
		||||
                    android:gravity="end"
 | 
			
		||||
                    android:paddingStart="4dp"
 | 
			
		||||
                    android:paddingLeft="4dp"
 | 
			
		||||
                    android:paddingTop="4dp"
 | 
			
		||||
                    android:paddingEnd="8dp"
 | 
			
		||||
                    android:paddingRight="8dp"
 | 
			
		||||
                    android:singleLine="true"
 | 
			
		||||
                    android:textStyle="italic"
 | 
			
		||||
                    android:gravity="right"/>
 | 
			
		||||
                    android:textStyle="italic" />
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
        </LinearLayout>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
        android:id="@+id/postImage"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        app:actualImageScaleType="fitCenter"
 | 
			
		||||
        app:actualImageScaleType="centerCrop"
 | 
			
		||||
        app:viewAspectRatio="1"/>
 | 
			
		||||
 | 
			
		||||
    <androidx.appcompat.widget.AppCompatImageView
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@
 | 
			
		||||
            android:id="@+id/ivProfilePic"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            app:actualImageScaleType="centerCrop"
 | 
			
		||||
            app:roundAsCircle="true" />
 | 
			
		||||
 | 
			
		||||
        <LinearLayout
 | 
			
		||||
@ -52,8 +53,8 @@
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_gravity="center"
 | 
			
		||||
        android:padding="8dp"
 | 
			
		||||
        android:orientation="vertical">
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        android:padding="8dp">
 | 
			
		||||
 | 
			
		||||
        <androidx.appcompat.widget.AppCompatTextView
 | 
			
		||||
            android:id="@+id/tvUsername"
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/action_search"
 | 
			
		||||
        android:actionLayout="@layout/layout_searchview"
 | 
			
		||||
        android:icon="@android:drawable/ic_menu_search"
 | 
			
		||||
        android:icon="@drawable/ic_search_24"
 | 
			
		||||
        android:title="@string/action_search"
 | 
			
		||||
        android:titleCondensed="@string/action_search"
 | 
			
		||||
        app:actionViewClass="androidx.appcompat.widget.SearchView"
 | 
			
		||||
@ -13,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/action_compare"
 | 
			
		||||
        android:icon="@android:drawable/ic_menu_view"
 | 
			
		||||
        android:icon="@drawable/ic_outline_views_24"
 | 
			
		||||
        android:title="@string/action_compare"
 | 
			
		||||
        android:titleCondensed="@string/action_compare"
 | 
			
		||||
        app:showAsAction="ifRoom" />
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/action_search"
 | 
			
		||||
        android:actionLayout="@layout/layout_searchview"
 | 
			
		||||
        android:icon="@android:drawable/ic_menu_search"
 | 
			
		||||
        android:icon="@drawable/ic_search_24"
 | 
			
		||||
        android:title="@string/action_search"
 | 
			
		||||
        android:titleCondensed="@string/action_search"
 | 
			
		||||
        app:actionViewClass="androidx.appcompat.widget.SearchView"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										65
									
								
								app/src/main/res/navigation/comments_nav_graph.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								app/src/main/res/navigation/comments_nav_graph.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
<?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/comments_nav_graph"
 | 
			
		||||
    app:startDestination="@id/commentsViewerFragment">
 | 
			
		||||
 | 
			
		||||
    <include app:graph="@navigation/hashtag_nav_graph" />
 | 
			
		||||
 | 
			
		||||
    <action
 | 
			
		||||
        android:id="@+id/action_global_hashTagFragment"
 | 
			
		||||
        app:destination="@id/hashtag_nav_graph">
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="hashtag"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
    </action>
 | 
			
		||||
 | 
			
		||||
    <!--<include app:graph="@navigation/profile_nav_graph" />-->
 | 
			
		||||
 | 
			
		||||
    <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/commentsViewerFragment"
 | 
			
		||||
        android:name="awais.instagrabber.activities.CommentsViewerFragment"
 | 
			
		||||
        android:label="Comments"
 | 
			
		||||
        tools:layout="@layout/fragment_comments">
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="shortCode"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postUserId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
    </fragment>
 | 
			
		||||
 | 
			
		||||
    <action
 | 
			
		||||
        android:id="@+id/action_global_commentsViewerFragment"
 | 
			
		||||
        app:destination="@id/commentsViewerFragment">
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="shortCode"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postUserId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
    </action>
 | 
			
		||||
</navigation>
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
 | 
			
		||||
    <include app:graph="@navigation/post_view_nav_graph" />
 | 
			
		||||
    <include app:graph="@navigation/profile_nav_graph" />
 | 
			
		||||
    <include app:graph="@navigation/comments_nav_graph" />
 | 
			
		||||
 | 
			
		||||
    <action
 | 
			
		||||
        android:id="@+id/action_global_postViewFragment"
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,25 @@
 | 
			
		||||
            app:argType="boolean" />
 | 
			
		||||
    </action>
 | 
			
		||||
 | 
			
		||||
    <include app:graph="@navigation/comments_nav_graph" />
 | 
			
		||||
 | 
			
		||||
    <action
 | 
			
		||||
        android:id="@+id/action_global_commentsViewerFragment"
 | 
			
		||||
        app:destination="@id/comments_nav_graph">
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="shortCode"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postUserId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
    </action>
 | 
			
		||||
 | 
			
		||||
    <fragment
 | 
			
		||||
        android:id="@+id/feedFragment"
 | 
			
		||||
        android:name="awais.instagrabber.fragments.main.FeedFragment"
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,24 @@
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
    </action>
 | 
			
		||||
 | 
			
		||||
    <action
 | 
			
		||||
        android:id="@+id/action_global_commentsViewerFragment"
 | 
			
		||||
        app:destination="@id/comments_nav_graph">
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="shortCode"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
        <argument
 | 
			
		||||
            android:name="postUserId"
 | 
			
		||||
            app:argType="string"
 | 
			
		||||
            app:nullable="false" />
 | 
			
		||||
    </action>
 | 
			
		||||
 | 
			
		||||
    <fragment
 | 
			
		||||
        android:id="@+id/postViewFragment"
 | 
			
		||||
        android:name="awais.instagrabber.fragments.PostViewFragment"
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,8 @@
 | 
			
		||||
            app:argType="boolean" />
 | 
			
		||||
    </action>
 | 
			
		||||
 | 
			
		||||
    <include app:graph="@navigation/comments_nav_graph" />
 | 
			
		||||
 | 
			
		||||
    <action
 | 
			
		||||
        android:id="@+id/action_global_profileFragment"
 | 
			
		||||
        app:destination="@id/profileFragment">
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user