Merge pull request #77 from ammargitham/task/update-feed-view
Task/update feed view
This commit is contained in:
commit
d1027b30cd
@ -45,7 +45,7 @@
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
|
||||
</Profilers>
|
||||
<option name="DEEP_LINK" value="" />
|
||||
<option name="ACTIVITY_CLASS" value="awais.instagrabber.activities.Main" />
|
||||
<option name="ACTIVITY_CLASS" value="awais.instagrabber.activities.MainActivity" />
|
||||
<method v="2">
|
||||
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
|
@ -5,13 +5,13 @@ android {
|
||||
compileSdkVersion 29
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'me.austinhuang.instagrabber'
|
||||
applicationId 'me.austinhuang.instagrabbr'
|
||||
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
|
||||
versionCode 49
|
||||
versionName '18.3'
|
||||
versionCode 50
|
||||
versionName '19.0-a1'
|
||||
|
||||
multiDexEnabled true
|
||||
|
||||
@ -37,19 +37,30 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation('androidx.appcompat:appcompat:1.3.0-alpha01@aar') { transitive true }
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||
implementation('com.google.android.material:material:1.3.0-alpha01@aar') { transitive true }
|
||||
implementation('androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-rc01') { transitive true }
|
||||
|
||||
def appcompat_version = "1.2.0"
|
||||
def nav_version = "2.3.0"
|
||||
def preference_version = "1.1.1"
|
||||
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.11.1'
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$appcompat_version"
|
||||
implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha05"
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||
implementation "androidx.navigation:navigation-fragment:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui:$nav_version"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.1"
|
||||
implementation "androidx.preference:preference:$preference_version"
|
||||
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||
|
||||
implementation('org.jsoup:jsoup:1.13.1') { transitive true }
|
||||
implementation('com.github.bumptech.glide:glide:4.11.0') { transitive true }
|
||||
implementation('com.github.chrisbanes:PhotoView:v2.0.0@aar') { transitive true }
|
||||
implementation('com.google.android.exoplayer:exoplayer:2.11.1@aar') { transitive true }
|
||||
implementation 'org.jsoup:jsoup:1.13.1'
|
||||
implementation 'com.facebook.fresco:fresco:2.3.0'
|
||||
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
|
||||
}
|
||||
|
@ -8,18 +8,17 @@
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:name=".InstaApp"
|
||||
android:name=".InstaGrabberApplication"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="@xml/backup_descriptor"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:theme="@style/AppTheme.Light.White"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<activity
|
||||
android:name=".activities.Main"
|
||||
android:name=".activities.MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=".Main"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
@ -29,18 +28,15 @@
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
<action android:name="android.intent.action.WEB_SEARCH" />
|
||||
|
||||
<!--<action android:name="android.intent.action.SEARCH" />-->
|
||||
<!--<action android:name="android.intent.action.WEB_SEARCH" />-->
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
@ -49,18 +45,15 @@
|
||||
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
|
||||
<data android:host="ig.me" />
|
||||
<data android:host="www.ig.me" />
|
||||
<data android:host="instagram.com" />
|
||||
<data android:host="www.instagram.com" />
|
||||
|
||||
<data android:pathPrefix="/" />
|
||||
<data android:pathPrefix="/p" />
|
||||
<data android:pathPrefix="/explore/tags" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="awaisomereport.ErrorReporterActivity"
|
||||
android:allowEmbedded="false"
|
||||
@ -77,7 +70,6 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:taskAffinity="awais.instagrabber.errorreport"
|
||||
android:theme="@android:style/Theme.DeviceDefault.Dialog" />
|
||||
|
||||
<activity
|
||||
android:name=".directdownload.MultiDirectDialog"
|
||||
android:allowEmbedded="false"
|
||||
@ -93,7 +85,6 @@
|
||||
android:noHistory="false"
|
||||
android:taskAffinity="awais.instagrabber.multidialog"
|
||||
android:theme="@style/FlyingGayDialog" />
|
||||
|
||||
<activity
|
||||
android:name=".directdownload.DirectDownload"
|
||||
android:allowEmbedded="false"
|
||||
@ -110,7 +101,6 @@
|
||||
android:lockTaskMode="never"
|
||||
android:noHistory="false"
|
||||
android:theme="@style/CompletelyTransparent">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
@ -121,7 +111,6 @@
|
||||
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
@ -131,96 +120,13 @@
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.PostViewer"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.CommentsViewer"
|
||||
android:parentActivityName=".activities.PostViewer">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.PostViewer" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.StoryViewer"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.FollowViewer"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.ProfilePicViewer"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.ProfileViewer"
|
||||
android:parentActivityName=".activities.PostViewer">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.PostViewer" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.SavedViewer"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.NotificationsViewer"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.Login"
|
||||
android:label="@string/login"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
android:parentActivityName=".activities.MainActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.DirectMessagesActivity"
|
||||
android:parentActivityName=".activities.Main">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.Main" />
|
||||
android:value=".activities.MainActivity" />
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
@ -232,5 +138,6 @@
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
<service android:name=".services.ActivityCheckerService" />
|
||||
</application>
|
||||
</manifest>
|
Binary file not shown.
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 128 KiB |
34
app/src/main/java/awais/instagrabber/InstaApp.java → app/src/main/java/awais/instagrabber/InstaGrabberApplication.java
Executable file → Normal file
34
app/src/main/java/awais/instagrabber/InstaApp.java → app/src/main/java/awais/instagrabber/InstaGrabberApplication.java
Executable file → Normal file
@ -4,9 +4,11 @@ import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.imagepipeline.core.ImagePipelineConfig;
|
||||
|
||||
import java.net.CookieHandler;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.UUID;
|
||||
@ -18,28 +20,33 @@ import awais.instagrabber.utils.SettingsHelper;
|
||||
import awaisomereport.CrashReporter;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.NET_COOKIE_MANAGER;
|
||||
import static awais.instagrabber.utils.CookieUtils.NET_COOKIE_MANAGER;
|
||||
import static awais.instagrabber.utils.Utils.clipboardManager;
|
||||
import static awais.instagrabber.utils.Utils.dataBox;
|
||||
import static awais.instagrabber.utils.Utils.datetimeParser;
|
||||
import static awais.instagrabber.utils.Utils.getInstalledTelegramPackage;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
import static awais.instagrabber.utils.Utils.notificationManager;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
import static awais.instagrabber.utils.Utils.telegramPackage;
|
||||
|
||||
public final class InstaApp extends MultiDexApplication {
|
||||
public final class InstaGrabberApplication extends MultiDexApplication {
|
||||
private static final String TAG = "InstaGrabberApplication";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
|
||||
.newBuilder(this)
|
||||
// .setMainDiskCacheConfig(diskCacheConfig)
|
||||
.setDownsampleEnabled(true)
|
||||
.build();
|
||||
Fresco.initialize(this, imagePipelineConfig);
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
try {
|
||||
Class.forName("dalvik.system.CloseGuard")
|
||||
.getMethod("setEnabled", boolean.class)
|
||||
.invoke(null, true);
|
||||
.getMethod("setEnabled", boolean.class)
|
||||
.invoke(null, true);
|
||||
} catch (Exception e) {
|
||||
Log.e("InstaApp", "Error", e);
|
||||
Log.e(TAG, "Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,8 +57,6 @@ public final class InstaApp extends MultiDexApplication {
|
||||
|
||||
final Context appContext = getApplicationContext();
|
||||
|
||||
telegramPackage = getInstalledTelegramPackage(appContext);
|
||||
|
||||
if (dataBox == null)
|
||||
dataBox = DataBox.getInstance(appContext);
|
||||
|
||||
@ -60,17 +65,14 @@ public final class InstaApp extends MultiDexApplication {
|
||||
|
||||
LocaleUtils.setLocale(getBaseContext());
|
||||
|
||||
if (notificationManager == null)
|
||||
notificationManager = NotificationManagerCompat.from(appContext);
|
||||
|
||||
if (clipboardManager == null)
|
||||
clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
|
||||
if (datetimeParser == null)
|
||||
datetimeParser = new SimpleDateFormat(
|
||||
settingsHelper.getBoolean(Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED) ?
|
||||
settingsHelper.getString(Constants.CUSTOM_DATE_TIME_FORMAT) :
|
||||
settingsHelper.getString(Constants.DATE_TIME_FORMAT), LocaleUtils.getCurrentLocale());
|
||||
settingsHelper.getString(Constants.CUSTOM_DATE_TIME_FORMAT) :
|
||||
settingsHelper.getString(Constants.DATE_TIME_FORMAT), LocaleUtils.getCurrentLocale());
|
||||
|
||||
settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString());
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.ThemeUtils;
|
||||
|
||||
public abstract class BaseLanguageActivity extends AppCompatActivity {
|
||||
protected BaseLanguageActivity() {
|
||||
@ -15,7 +15,7 @@ public abstract class BaseLanguageActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
Utils.changeTheme(this);
|
||||
ThemeUtils.changeTheme(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
@ -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) ->
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDestination;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.navigation.ui.AppBarConfiguration;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ActivityDirectMessagesBinding;
|
||||
import awais.instagrabber.fragments.directmessages.DirectMessageThreadFragmentArgs;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class DirectMessagesActivity extends BaseLanguageActivity implements NavController.OnDestinationChangedListener {
|
||||
|
||||
private TextView toolbarTitle;
|
||||
private AppCompatImageView dmInfo, dmSeen;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final ActivityDirectMessagesBinding binding = ActivityDirectMessagesBinding.inflate(getLayoutInflater());
|
||||
final CoordinatorLayout root = binding.getRoot();
|
||||
setContentView(root);
|
||||
|
||||
toolbarTitle = binding.toolbarTitle;
|
||||
|
||||
final Toolbar toolbar = binding.toolbar;
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
dmInfo = binding.dmInfo;
|
||||
dmSeen = binding.dmSeen;
|
||||
|
||||
final NavController navController = Navigation.findNavController(this, R.id.direct_messages_nav_host_fragment);
|
||||
navController.addOnDestinationChangedListener(this);
|
||||
final AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
|
||||
NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestinationChanged(@NonNull final NavController controller,
|
||||
@NonNull final NavDestination destination,
|
||||
@Nullable final Bundle arguments) {
|
||||
switch (destination.getId()) {
|
||||
case R.id.directMessagesInboxFragment:
|
||||
setToolbarTitle(R.string.action_dms);
|
||||
dmInfo.setVisibility(View.GONE);
|
||||
dmSeen.setVisibility(View.GONE);
|
||||
return;
|
||||
case R.id.directMessagesThreadFragment:
|
||||
if (arguments == null) {
|
||||
return;
|
||||
}
|
||||
final String title = DirectMessageThreadFragmentArgs.fromBundle(arguments).getTitle();
|
||||
setToolbarTitle(title);
|
||||
dmInfo.setVisibility(View.VISIBLE);
|
||||
dmSeen.setVisibility(settingsHelper.getBoolean(Constants.DM_MARK_AS_SEEN) ? View.GONE : View.VISIBLE);
|
||||
return;
|
||||
case R.id.directMessagesSettingsFragment:
|
||||
if (arguments == null) {
|
||||
return;
|
||||
}
|
||||
setToolbarTitle(R.string.action_settings);
|
||||
dmInfo.setVisibility(View.GONE);
|
||||
dmSeen.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void setToolbarTitle(final String text) {
|
||||
if (toolbarTitle == null) {
|
||||
return;
|
||||
}
|
||||
toolbarTitle.setText(text);
|
||||
}
|
||||
|
||||
private void setToolbarTitle(final int resourceId) {
|
||||
if (toolbarTitle == null) {
|
||||
return;
|
||||
}
|
||||
toolbarTitle.setText(resourceId);
|
||||
}
|
||||
}
|
@ -1,333 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.FollowAdapter;
|
||||
import awais.instagrabber.asyncs.FollowFetcher;
|
||||
import awais.instagrabber.databinding.ActivityFollowBinding;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
import thoughtbot.expandableadapter.ExpandableGroup;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class FollowViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
|
||||
private final ArrayList<FollowModel> followModels = new ArrayList<>();
|
||||
private final ArrayList<FollowModel> followingModels = new ArrayList<>();
|
||||
private final ArrayList<FollowModel> followersModels = new ArrayList<>();
|
||||
private final ArrayList<FollowModel> allFollowing = new ArrayList<>();
|
||||
private boolean followers, isCompare = false;
|
||||
private String id, name, namePost, type;
|
||||
private Resources resources;
|
||||
private FollowModel model;
|
||||
private FollowAdapter adapter;
|
||||
private View.OnClickListener clickListener;
|
||||
private ActivityFollowBinding followBinding;
|
||||
private AsyncTask<Void, Void, FollowModel[]> currentlyExecuting;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
followBinding = ActivityFollowBinding.inflate(getLayoutInflater());
|
||||
setContentView(followBinding.getRoot());
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null || Utils.isEmpty(id = intent.getStringExtra(Constants.EXTRAS_ID))) {
|
||||
Utils.errorFinish(this);
|
||||
return;
|
||||
}
|
||||
|
||||
setSupportActionBar(followBinding.toolbar.toolbar);
|
||||
|
||||
followers = intent.getBooleanExtra(Constants.EXTRAS_FOLLOWERS, false);
|
||||
name = intent.getStringExtra(Constants.EXTRAS_NAME);
|
||||
namePost = name;
|
||||
if (Utils.isEmpty(name)) {
|
||||
// this usually should not occur
|
||||
name = "You";
|
||||
namePost = "You're";
|
||||
}
|
||||
|
||||
followBinding.toolbar.toolbar.setTitle(name);
|
||||
|
||||
resources = getResources();
|
||||
|
||||
clickListener = v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof FollowModel) {
|
||||
model = (FollowModel) tag;
|
||||
startActivity(
|
||||
new Intent(getApplicationContext(), ProfileViewer.class)
|
||||
.putExtra(Constants.EXTRAS_USERNAME, model.getUsername())
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
followBinding.swipeRefreshLayout.setOnRefreshListener(this);
|
||||
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
if (isCompare) listCompare();
|
||||
else listFollows();
|
||||
}
|
||||
|
||||
private void listFollows() {
|
||||
stopCurrentExecutor();
|
||||
|
||||
type = resources.getString(followers ? R.string.followers_type_followers : R.string.followers_type_following);
|
||||
followBinding.toolbar.toolbar.setSubtitle(type);
|
||||
|
||||
followModels.clear();
|
||||
|
||||
final FetchListener<FollowModel[]> fetchListener = new FetchListener<FollowModel[]>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
followBinding.swipeRefreshLayout.setRefreshing(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final FollowModel[] result) {
|
||||
if (result == null) followBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
else {
|
||||
followModels.addAll(Arrays.asList(result));
|
||||
|
||||
final FollowModel model = result[result.length - 1];
|
||||
if (model != null && model.hasNextPage()) {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(id, followers, model.getEndCursor(), this)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
model.setPageCursor(false, null);
|
||||
} else {
|
||||
followBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
|
||||
refreshAdapter(followModels, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
currentlyExecuting = new FollowFetcher(id, followers, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void listCompare() {
|
||||
stopCurrentExecutor();
|
||||
|
||||
followBinding.toolbar.toolbar.setSubtitle(R.string.followers_compare);
|
||||
|
||||
allFollowing.clear();
|
||||
followersModels.clear();
|
||||
followingModels.clear();
|
||||
|
||||
final FetchListener<FollowModel[]> followingFetchListener = new FetchListener<FollowModel[]>() {
|
||||
@Override
|
||||
public void onResult(final FollowModel[] result) {
|
||||
if (result != null) {
|
||||
followingModels.addAll(Arrays.asList(result));
|
||||
|
||||
final FollowModel model = result[result.length - 1];
|
||||
if (model != null && model.hasNextPage()) {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(id, false, model.getEndCursor(), this)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
model.setPageCursor(false, null);
|
||||
} else {
|
||||
allFollowing.addAll(followersModels);
|
||||
allFollowing.retainAll(followingModels);
|
||||
|
||||
for (final FollowModel followModel : allFollowing) {
|
||||
followersModels.remove(followModel);
|
||||
followingModels.remove(followModel);
|
||||
}
|
||||
|
||||
allFollowing.trimToSize();
|
||||
followersModels.trimToSize();
|
||||
followingModels.trimToSize();
|
||||
|
||||
followBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
|
||||
refreshAdapter(null, followingModels, followersModels, allFollowing);
|
||||
}
|
||||
} else followBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
};
|
||||
final FetchListener<FollowModel[]> followersFetchListener = new FetchListener<FollowModel[]>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
followBinding.swipeRefreshLayout.setRefreshing(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final FollowModel[] result) {
|
||||
if (result != null) {
|
||||
followersModels.addAll(Arrays.asList(result));
|
||||
final FollowModel model = result[result.length - 1];
|
||||
if (model == null || !model.hasNextPage()) {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(id, false, followingFetchListener)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(id, true, model.getEndCursor(), this)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
model.setPageCursor(false, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
currentlyExecuting = new FollowFetcher(id, true, followersFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@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() {
|
||||
// private final Filter filter = new Filter() {
|
||||
// private final ArrayList<FollowModel> searchFollowModels = new ArrayList<>(followModels.size() / 2);
|
||||
// private final ArrayList<FollowModel> searchFollowingModels = new ArrayList<>(followingModels.size() / 2);
|
||||
// private final ArrayList<FollowModel> searchFollowersModels = new ArrayList<>(followersModels.size() / 2);
|
||||
// private final ArrayList<FollowModel> searchAllFollowing = new ArrayList<>(allFollowing.size() / 2);
|
||||
//
|
||||
// @Nullable
|
||||
// @Override
|
||||
// protected FilterResults performFiltering(@NonNull final CharSequence constraint) {
|
||||
// searchFollowModels.clear();
|
||||
// searchFollowingModels.clear();
|
||||
// searchFollowersModels.clear();
|
||||
// searchAllFollowing.clear();
|
||||
//
|
||||
// final int followModelsSize = followModels.size();
|
||||
// final int followingModelsSize = followingModels.size();
|
||||
// final int followersModelsSize = followersModels.size();
|
||||
// final int allFollowingSize = allFollowing.size();
|
||||
//
|
||||
// int maxSize = followModelsSize;
|
||||
// if (maxSize < followingModelsSize) maxSize = followingModelsSize;
|
||||
// if (maxSize < followersModelsSize) maxSize = followersModelsSize;
|
||||
// if (maxSize < allFollowingSize) maxSize = allFollowingSize;
|
||||
//
|
||||
// final String query = constraint.toString().toLowerCase();
|
||||
// FollowModel followModel;
|
||||
// while (maxSize != -1) {
|
||||
// if (maxSize < followModelsSize) {
|
||||
// followModel = followModels.get(maxSize);
|
||||
// if (Utils.hasKey(query, followModel.getUsername(), followModel.getFullName()))
|
||||
// searchFollowModels.add(followModel);
|
||||
// }
|
||||
//
|
||||
// if (maxSize < followingModelsSize) {
|
||||
// followModel = followingModels.get(maxSize);
|
||||
// if (Utils.hasKey(query, followModel.getUsername(), followModel.getFullName()))
|
||||
// searchFollowingModels.add(followModel);
|
||||
// }
|
||||
//
|
||||
// if (maxSize < followersModelsSize) {
|
||||
// followModel = followersModels.get(maxSize);
|
||||
// if (Utils.hasKey(query, followModel.getUsername(), followModel.getFullName()))
|
||||
// searchFollowersModels.add(followModel);
|
||||
// }
|
||||
//
|
||||
// if (maxSize < allFollowingSize) {
|
||||
// followModel = allFollowing.get(maxSize);
|
||||
// if (Utils.hasKey(query, followModel.getUsername(), followModel.getFullName()))
|
||||
// searchAllFollowing.add(followModel);
|
||||
// }
|
||||
//
|
||||
// --maxSize;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void publishResults(final CharSequence query, final FilterResults results) {
|
||||
// refreshAdapter(searchFollowModels, searchFollowingModels, searchFollowersModels, searchAllFollowing);
|
||||
// }
|
||||
// };
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(final String query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(final String query) {
|
||||
// if (Utils.isEmpty(query)) refreshAdapter(followModels, followingModels, followersModels, allFollowing);
|
||||
// else filter.filter(query.toLowerCase());
|
||||
if (adapter != null) adapter.getFilter().filter(query);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
final MenuItem menuCompare = menu.findItem(R.id.action_compare);
|
||||
menuCompare.setOnMenuItemClickListener(item -> {
|
||||
followBinding.rvFollow.setAdapter(null);
|
||||
if (isCompare) listFollows();
|
||||
else listCompare();
|
||||
isCompare = !isCompare;
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void refreshAdapter(final ArrayList<FollowModel> followModels, final ArrayList<FollowModel> followingModels,
|
||||
final ArrayList<FollowModel> followersModels, final ArrayList<FollowModel> allFollowing) {
|
||||
final ArrayList<ExpandableGroup> groups = new ArrayList<>(1);
|
||||
|
||||
if (isCompare) {
|
||||
if (followingModels != null && followingModels.size() > 0)
|
||||
groups.add(new ExpandableGroup(resources.getString(R.string.followers_not_following, name), followingModels));
|
||||
if (followersModels != null && followersModels.size() > 0)
|
||||
groups.add(new ExpandableGroup(resources.getString(R.string.followers_not_follower, namePost), followersModels));
|
||||
if (allFollowing != null && allFollowing.size() > 0)
|
||||
groups.add(new ExpandableGroup(resources.getString(R.string.followers_both_following), allFollowing));
|
||||
} else {
|
||||
final ExpandableGroup group = new ExpandableGroup(type, followModels);
|
||||
groups.add(group);
|
||||
}
|
||||
|
||||
adapter = new FollowAdapter(this, clickListener, groups);
|
||||
adapter.toggleGroup(0);
|
||||
followBinding.rvFollow.setAdapter(adapter);
|
||||
}
|
||||
|
||||
public void stopCurrentExecutor() {
|
||||
if (currentlyExecuting != null) {
|
||||
try {
|
||||
currentlyExecuting.cancel(true);
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@ -19,9 +20,8 @@ import androidx.annotation.Nullable;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ActivityLoginBinding;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public final class Login extends BaseLanguageActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||
private final WebViewClient webViewClient = new WebViewClient() {
|
||||
@ -33,16 +33,24 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
||||
@Override
|
||||
public void onPageFinished(final WebView view, final String url) {
|
||||
webViewUrl = url;
|
||||
final String mainCookie = Utils.getCookie(url);
|
||||
if (Utils.isEmpty(mainCookie) || !mainCookie.contains("; ds_user_id=")) ready = true;
|
||||
else if (mainCookie.contains("; ds_user_id=") && ready) {
|
||||
Utils.setupCookies(mainCookie);
|
||||
settingsHelper.putString(Constants.COOKIE, mainCookie);
|
||||
Toast.makeText(getApplicationContext(), R.string.login_success_loading_cookies, Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
final String mainCookie = CookieUtils.getCookie(url);
|
||||
if (TextUtils.isEmpty(mainCookie) || !mainCookie.contains("; ds_user_id=")) {
|
||||
ready = true;
|
||||
return;
|
||||
}
|
||||
if (mainCookie.contains("; ds_user_id=") && ready) {
|
||||
returnCookieResult(mainCookie);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void returnCookieResult(final String mainCookie) {
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra("cookie", mainCookie);
|
||||
setResult(Constants.LOGIN_RESULT_CODE, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private final WebChromeClient webChromeClient = new WebChromeClient();
|
||||
private String webViewUrl, defaultUserAgent;
|
||||
private boolean ready = false;
|
||||
@ -65,16 +73,15 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
||||
public void onClick(final View v) {
|
||||
if (v == loginBinding.refresh) {
|
||||
loginBinding.webView.loadUrl("https://instagram.com/");
|
||||
} else if (v == loginBinding.cookies) {
|
||||
final String mainCookie = Utils.getCookie(webViewUrl);
|
||||
if (Utils.isEmpty(mainCookie) || !mainCookie.contains("; ds_user_id="))
|
||||
return;
|
||||
}
|
||||
if (v == loginBinding.cookies) {
|
||||
final String mainCookie = CookieUtils.getCookie(webViewUrl);
|
||||
if (TextUtils.isEmpty(mainCookie) || !mainCookie.contains("; ds_user_id=")) {
|
||||
Toast.makeText(this, R.string.login_error_loading_cookies, Toast.LENGTH_SHORT).show();
|
||||
else {
|
||||
Utils.setupCookies(mainCookie);
|
||||
settingsHelper.putString(Constants.COOKIE, mainCookie);
|
||||
Toast.makeText(this, R.string.login_success_loading_cookies, Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
returnCookieResult(mainCookie);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,8 +89,9 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||
final WebSettings webSettings = loginBinding.webView.getSettings();
|
||||
|
||||
final String newUserAgent = isChecked ? "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
|
||||
: defaultUserAgent;
|
||||
final String newUserAgent = isChecked
|
||||
? "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
|
||||
: defaultUserAgent;
|
||||
|
||||
webSettings.setUserAgentString(newUserAgent);
|
||||
webSettings.setUseWideViewPort(isChecked);
|
||||
@ -95,7 +103,6 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@SuppressWarnings("deprecation")
|
||||
private void initWebView() {
|
||||
if (loginBinding != null) {
|
||||
loginBinding.webView.setWebChromeClient(webChromeClient);
|
||||
|
@ -1,602 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.MatrixCursor;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.PersistableBundle;
|
||||
import android.provider.BaseColumns;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.MainHelper;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.HighlightsAdapter;
|
||||
import awais.instagrabber.adapters.SuggestionsAdapter;
|
||||
import awais.instagrabber.asyncs.GetActivityAsyncTask;
|
||||
import awais.instagrabber.asyncs.SuggestionsFetcher;
|
||||
import awais.instagrabber.asyncs.UsernameFetcher;
|
||||
import awais.instagrabber.asyncs.i.iStoryStatusFetcher;
|
||||
import awais.instagrabber.customviews.MouseDrawer;
|
||||
import awais.instagrabber.databinding.ActivityMainBinding;
|
||||
import awais.instagrabber.dialogs.AboutDialog;
|
||||
import awais.instagrabber.dialogs.QuickAccessDialog;
|
||||
import awais.instagrabber.dialogs.SettingsDialog;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.interfaces.ItemGetter;
|
||||
import awais.instagrabber.models.DiscoverItemModel;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.HashtagModel;
|
||||
import awais.instagrabber.models.HighlightModel;
|
||||
import awais.instagrabber.models.LocationModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.SuggestionModel;
|
||||
import awais.instagrabber.models.enums.DownloadMethod;
|
||||
import awais.instagrabber.models.enums.ItemGetType;
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DataBox;
|
||||
import awais.instagrabber.utils.FlavorTown;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.CHANNEL_ID;
|
||||
import static awais.instagrabber.utils.Utils.notificationManager;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class Main extends BaseLanguageActivity {
|
||||
private static final int INITIAL_DELAY_MILLIS = 200;
|
||||
private static final int DELAY_MILLIS = 60000;
|
||||
public static FetchListener<String> scanHack;
|
||||
public static ItemGetter itemGetter;
|
||||
// -------- items --------
|
||||
public final ArrayList<PostModel> allItems = new ArrayList<>();
|
||||
public final ArrayList<FeedModel> feedItems = new ArrayList<>();
|
||||
public final ArrayList<DiscoverItemModel> discoverItems = new ArrayList<>();
|
||||
// -------- items --------
|
||||
public final ArrayList<PostModel> selectedItems = new ArrayList<>();
|
||||
public final ArrayList<DiscoverItemModel> selectedDiscoverItems = new ArrayList<>();
|
||||
// -------- items --------
|
||||
public final HighlightsAdapter highlightsAdapter = new HighlightsAdapter(null, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof HighlightModel) {
|
||||
final HighlightModel highlightModel = (HighlightModel) tag;
|
||||
new iStoryStatusFetcher(highlightModel.getId(), null, false, false,
|
||||
(!mainHelper.isLoggedIn && Utils.settingsHelper.getBoolean(Constants.STORIESIG)), true, result -> {
|
||||
if (result != null && result.length > 0)
|
||||
startActivity(new Intent(Main.this, StoryViewer.class)
|
||||
.putExtra(Constants.EXTRAS_USERNAME, userQuery.replace("@", ""))
|
||||
.putExtra(Constants.EXTRAS_HIGHLIGHT, highlightModel.getTitle())
|
||||
.putExtra(Constants.EXTRAS_STORIES, result)
|
||||
);
|
||||
else
|
||||
Toast.makeText(Main.this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
});
|
||||
private SuggestionsAdapter suggestionAdapter;
|
||||
private MenuItem searchAction;
|
||||
public ActivityMainBinding mainBinding;
|
||||
public SearchView searchView;
|
||||
public MenuItem downloadAction, settingsAction, dmsAction, notifAction;
|
||||
public StoryModel[] storyModels;
|
||||
public String userQuery = null, cookie, uid = null;
|
||||
public MainHelper mainHelper;
|
||||
public ProfileModel profileModel;
|
||||
public HashtagModel hashtagModel;
|
||||
public LocationModel locationModel;
|
||||
private AutoCompleteTextView searchAutoComplete;
|
||||
private ArrayAdapter<String> profileDialogAdapter;
|
||||
private DialogInterface.OnClickListener profileDialogListener;
|
||||
private Stack<String> queriesStack;
|
||||
private DataBox.CookieModel cookieModel;
|
||||
private Runnable runnable;
|
||||
private Handler handler;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
mainBinding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(mainBinding.getRoot());
|
||||
|
||||
if (settingsHelper.getBoolean(Constants.CHECK_UPDATES)) FlavorTown.updateCheck(this);
|
||||
FlavorTown.changelogCheck(this);
|
||||
|
||||
cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
uid = Utils.getUserIdFromCookie(cookie);
|
||||
Utils.setupCookies(cookie);
|
||||
|
||||
MainHelper.stopCurrentExecutor();
|
||||
mainHelper = new MainHelper(this);
|
||||
if (bundle == null) {
|
||||
queriesStack = new Stack<>();
|
||||
userQuery = null;
|
||||
} else {
|
||||
setStack(bundle);
|
||||
userQuery = bundle.getString("query");
|
||||
}
|
||||
mainHelper.isLoggedIn = !Utils.isEmpty(Utils.settingsHelper.getString(Constants.COOKIE));
|
||||
|
||||
itemGetter = itemGetType -> {
|
||||
if (itemGetType == ItemGetType.MAIN_ITEMS) return allItems;
|
||||
if (itemGetType == ItemGetType.DISCOVER_ITEMS) return discoverItems;
|
||||
if (itemGetType == ItemGetType.FEED_ITEMS) return feedItems;
|
||||
return null;
|
||||
};
|
||||
|
||||
scanHack = result -> {
|
||||
if (mainHelper != null && !Utils.isEmpty(result)) {
|
||||
closeAnyOpenDrawer();
|
||||
addToStack();
|
||||
userQuery = (result.contains("/") || result.startsWith("#") || result.startsWith("@")) ? result : ("@" + result);
|
||||
mainHelper.onRefresh();
|
||||
}
|
||||
};
|
||||
|
||||
// searches for your userid and returns username
|
||||
if (uid != null) {
|
||||
final FetchListener<String> fetchListener = username -> {
|
||||
if (!Utils.isEmpty(username)) {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
userQuery = username;
|
||||
if (mainHelper != null && !mainBinding.profileView.swipeRefreshLayout.isRefreshing())
|
||||
mainHelper.onRefresh();
|
||||
}
|
||||
// adds cookies to database for quick access
|
||||
cookieModel = Utils.dataBox.getCookie(uid);
|
||||
if (Utils.dataBox.getCookieCount() == 0 || cookieModel == null || Utils.isEmpty(cookieModel.getUsername()))
|
||||
Utils.dataBox.addUserCookie(new DataBox.CookieModel(uid, username, cookie));
|
||||
}
|
||||
};
|
||||
boolean found = false;
|
||||
cookieModel = Utils.dataBox.getCookie(uid);
|
||||
if (cookieModel != null) {
|
||||
final String username = cookieModel.getUsername();
|
||||
if (username != null) {
|
||||
found = true;
|
||||
fetchListener.onResult("@" + username);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) // if not in database, fetch info from instagram
|
||||
new UsernameFetcher(uid, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
suggestionAdapter = new SuggestionsAdapter(this, v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof CharSequence) {
|
||||
addToStack();
|
||||
userQuery = tag.toString();
|
||||
mainHelper.onRefresh();
|
||||
}
|
||||
if (searchView != null && !searchView.isIconified()) {
|
||||
if (searchAction != null) searchAction.collapseActionView();
|
||||
searchView.setIconified(true);
|
||||
searchView.setIconified(true);
|
||||
}
|
||||
});
|
||||
|
||||
final Resources resources = getResources();
|
||||
profileDialogAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
|
||||
new String[]{resources.getString(R.string.view_pfp), resources.getString(R.string.show_stories)});
|
||||
profileDialogListener = (dialog, which) -> {
|
||||
final Intent intent;
|
||||
if (which == 0 || storyModels == null || storyModels.length < 1) {
|
||||
intent = new Intent(this, ProfilePicViewer.class).putExtra(
|
||||
((hashtagModel != null) ? Constants.EXTRAS_HASHTAG : (locationModel != null ? Constants.EXTRAS_LOCATION : Constants.EXTRAS_PROFILE)),
|
||||
((hashtagModel != null) ? hashtagModel : (locationModel != null ? locationModel : profileModel)));
|
||||
} else
|
||||
intent = new Intent(this, StoryViewer.class).putExtra(Constants.EXTRAS_USERNAME, userQuery.replace("@", ""))
|
||||
.putExtra(Constants.EXTRAS_STORIES, storyModels)
|
||||
.putExtra(Constants.EXTRAS_HASHTAG, (hashtagModel != null));
|
||||
startActivity(intent);
|
||||
};
|
||||
|
||||
final View.OnClickListener onClickListener = v -> {
|
||||
if (v == mainBinding.profileView.mainBiography) {
|
||||
Utils.copyText(this, mainBinding.profileView.mainBiography.getText().toString());
|
||||
} else if (v == mainBinding.profileView.locationBiography) {
|
||||
Utils.copyText(this, mainBinding.profileView.locationBiography.getText().toString());
|
||||
} else if (v == mainBinding.profileView.mainProfileImage || v == mainBinding.profileView.mainHashtagImage || v == mainBinding.profileView.mainLocationImage) {
|
||||
if (storyModels == null || storyModels.length <= 0) {
|
||||
profileDialogListener.onClick(null, 0);
|
||||
} else {
|
||||
// because sometimes configuration changes made this crash on some phones
|
||||
new AlertDialog.Builder(this).setAdapter(profileDialogAdapter, profileDialogListener)
|
||||
.setNeutralButton(R.string.cancel, null).show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mainBinding.profileView.mainBiography.setOnClickListener(onClickListener);
|
||||
mainBinding.profileView.locationBiography.setOnClickListener(onClickListener);
|
||||
mainBinding.profileView.mainProfileImage.setOnClickListener(onClickListener);
|
||||
mainBinding.profileView.mainHashtagImage.setOnClickListener(onClickListener);
|
||||
mainBinding.profileView.mainLocationImage.setOnClickListener(onClickListener);
|
||||
|
||||
mainBinding.profileView.mainBiography.setEnabled(false);
|
||||
mainBinding.profileView.mainProfileImage.setEnabled(false);
|
||||
mainBinding.profileView.mainHashtagImage.setEnabled(false);
|
||||
mainBinding.profileView.mainLocationImage.setEnabled(false);
|
||||
|
||||
final boolean isQueryNull = userQuery == null;
|
||||
if (isQueryNull) {
|
||||
allItems.clear();
|
||||
mainBinding.profileView.privatePage1.setImageResource(R.drawable.ic_info);
|
||||
mainBinding.profileView.privatePage2.setTextSize(20);
|
||||
mainBinding.profileView.privatePage2.setText(mainHelper.isLoggedIn ? R.string.no_acc_logged_in : R.string.no_acc);
|
||||
mainBinding.profileView.privatePage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (!mainBinding.profileView.swipeRefreshLayout.isRefreshing() && userQuery != null)
|
||||
mainHelper.onRefresh();
|
||||
|
||||
mainHelper.onIntent(getIntent());
|
||||
|
||||
handler = new Handler();
|
||||
runnable = () -> {
|
||||
final GetActivityAsyncTask activityAsyncTask = new GetActivityAsyncTask(uid, cookie, result -> {
|
||||
if (result == null || notificationManager == null) {
|
||||
return;
|
||||
}
|
||||
final List<String> list = new ArrayList<>();
|
||||
if (result.getRelationshipsCount() != 0) {
|
||||
list.add(getString(R.string.activity_count_relationship, result.getRelationshipsCount()));
|
||||
}
|
||||
if (result.getUserTagsCount() != 0) {
|
||||
list.add(getString(R.string.activity_count_usertags, result.getUserTagsCount()));
|
||||
}
|
||||
if (result.getCommentsCount() != 0) {
|
||||
list.add(getString(R.string.activity_count_comments, result.getCommentsCount()));
|
||||
}
|
||||
if (result.getCommentLikesCount() != 0) {
|
||||
list.add(getString(R.string.activity_count_commentlikes, result.getCommentLikesCount()));
|
||||
}
|
||||
if (result.getLikesCount() != 0) {
|
||||
list.add(getString(R.string.activity_count_likes, result.getLikesCount()));
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final String join = TextUtils.join(", ", list);
|
||||
final String notificationString = getString(R.string.activity_count_prefix) + " " + join + ".";
|
||||
final Intent intent = new Intent(getApplicationContext(), NotificationsViewer.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
final Notification notification = new NotificationCompat.Builder(Main.this, CHANNEL_ID)
|
||||
.setCategory(NotificationCompat.CATEGORY_STATUS)
|
||||
.setSmallIcon(R.drawable.ic_notif)
|
||||
.setAutoCancel(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.setContentText(notificationString)
|
||||
.setContentIntent(PendingIntent.getActivity(getApplicationContext(), 1738, intent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.build();
|
||||
notificationManager.cancel(1800000000);
|
||||
notificationManager.notify(1800000000, notification);
|
||||
});
|
||||
if (!Utils.isEmpty(cookie) && Utils.settingsHelper.getBoolean(Constants.CHECK_ACTIVITY)) activityAsyncTask.execute();
|
||||
handler.postDelayed(runnable, DELAY_MILLIS);
|
||||
};
|
||||
handler.postDelayed(runnable, INITIAL_DELAY_MILLIS);
|
||||
}
|
||||
|
||||
private void downloadSelectedItems() {
|
||||
if (selectedItems.size() > 0) {
|
||||
Utils.batchDownload(this, userQuery, DownloadMethod.DOWNLOAD_MAIN, selectedItems);
|
||||
} else if (selectedDiscoverItems.size() > 0) {
|
||||
Utils.batchDownload(this, null, DownloadMethod.DOWNLOAD_DISCOVER, selectedDiscoverItems);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(final Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
mainHelper.onIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull final Bundle outState, @NonNull final PersistableBundle outPersistentState) {
|
||||
outState.putString("query", userQuery);
|
||||
outState.putSerializable("stack", queriesStack);
|
||||
super.onSaveInstanceState(outState, outPersistentState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(@Nullable final Bundle savedInstanceState, @Nullable final PersistableBundle persistentState) {
|
||||
super.onRestoreInstanceState(savedInstanceState, persistentState);
|
||||
if (savedInstanceState != null) {
|
||||
userQuery = savedInstanceState.getString("query");
|
||||
setStack(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||
outState.putString("query", userQuery);
|
||||
outState.putSerializable("stack", queriesStack);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
userQuery = savedInstanceState.getString("query");
|
||||
setStack(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu, menu);
|
||||
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
final MenuItem quickAccessAction = menu.findItem(R.id.action_quickaccess).setVisible(true);
|
||||
|
||||
final MenuItem.OnMenuItemClickListener clickListener = item -> {
|
||||
if (item == downloadAction)
|
||||
downloadSelectedItems();
|
||||
else if (item == dmsAction)
|
||||
startActivity(new Intent(this, DirectMessagesActivity.class));
|
||||
else if (item == notifAction)
|
||||
startActivity(new Intent(this, NotificationsViewer.class));
|
||||
else if (item == settingsAction)
|
||||
new SettingsDialog().show(fragmentManager, "settings");
|
||||
else if (item == quickAccessAction)
|
||||
new QuickAccessDialog()
|
||||
.setQuery(userQuery, locationModel != null ? locationModel.getName() : userQuery)
|
||||
.show(fragmentManager, "quickAccess");
|
||||
else
|
||||
new AboutDialog().show(fragmentManager, "about");
|
||||
return true;
|
||||
};
|
||||
|
||||
quickAccessAction.setOnMenuItemClickListener(clickListener);
|
||||
menu.findItem(R.id.action_about).setVisible(true).setOnMenuItemClickListener(clickListener);
|
||||
dmsAction = menu.findItem(R.id.action_dms).setOnMenuItemClickListener(clickListener);
|
||||
notifAction = menu.findItem(R.id.action_notif).setOnMenuItemClickListener(clickListener);
|
||||
settingsAction = menu.findItem(R.id.action_settings).setVisible(true).setOnMenuItemClickListener(clickListener);
|
||||
downloadAction = menu.findItem(R.id.action_download).setOnMenuItemClickListener(clickListener);
|
||||
|
||||
if (!Utils.isEmpty(Utils.settingsHelper.getString(Constants.COOKIE))) {
|
||||
notifAction.setVisible(true);
|
||||
dmsAction.setVisible(true).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
}
|
||||
|
||||
searchAction = menu.findItem(R.id.action_search);
|
||||
searchView = (SearchView) searchAction.getActionView();
|
||||
final View searchText = searchView.findViewById(R.id.search_src_text);
|
||||
if (searchText instanceof AutoCompleteTextView)
|
||||
searchAutoComplete = (AutoCompleteTextView) searchText;
|
||||
|
||||
searchView.setQueryHint(getResources().getString(R.string.action_search));
|
||||
searchView.setSuggestionsAdapter(suggestionAdapter);
|
||||
searchView.setOnSearchClickListener(v -> {
|
||||
searchView.setQuery((cookieModel != null && userQuery != null && userQuery.equals("@" + cookieModel.getUsername())) ? "" : userQuery, false);
|
||||
menu.findItem(R.id.action_about).setVisible(false);
|
||||
menu.findItem(R.id.action_settings).setVisible(false);
|
||||
menu.findItem(R.id.action_dms).setVisible(false);
|
||||
menu.findItem(R.id.action_quickaccess).setVisible(false);
|
||||
menu.findItem(R.id.action_notif).setVisible(false);
|
||||
});
|
||||
searchAction.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||
menu.findItem(R.id.action_about).setVisible(true);
|
||||
menu.findItem(R.id.action_settings).setVisible(true);
|
||||
menu.findItem(R.id.action_dms).setVisible(!Utils.isEmpty(Utils.settingsHelper.getString(Constants.COOKIE)));
|
||||
menu.findItem(R.id.action_quickaccess).setVisible(true);
|
||||
menu.findItem(R.id.action_notif).setVisible(true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
private boolean searchUser, searchHash;
|
||||
private AsyncTask<?, ?, ?> prevSuggestionAsync;
|
||||
private final String[] COLUMNS = {BaseColumns._ID, Constants.EXTRAS_USERNAME, Constants.EXTRAS_NAME,
|
||||
Constants.EXTRAS_TYPE, "pfp", "verified"};
|
||||
private final FetchListener<SuggestionModel[]> fetchListener = new FetchListener<SuggestionModel[]>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
suggestionAdapter.changeCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final SuggestionModel[] result) {
|
||||
final MatrixCursor cursor;
|
||||
if (result == null) cursor = null;
|
||||
else {
|
||||
cursor = new MatrixCursor(COLUMNS, 0);
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
final SuggestionModel suggestionModel = result[i];
|
||||
if (suggestionModel != null) {
|
||||
final SuggestionType suggestionType = suggestionModel.getSuggestionType();
|
||||
final Object[] objects = {i,
|
||||
(suggestionType == SuggestionType.TYPE_LOCATION) ? suggestionModel.getName() : suggestionModel.getUsername(),
|
||||
(suggestionType == SuggestionType.TYPE_LOCATION) ? suggestionModel.getUsername() : suggestionModel.getName(),
|
||||
suggestionType, suggestionModel.getProfilePic(), suggestionModel.isVerified()};
|
||||
|
||||
if (!searchHash && !searchUser) cursor.addRow(objects);
|
||||
else {
|
||||
final boolean isCurrHash = suggestionType == SuggestionType.TYPE_HASHTAG;
|
||||
if (searchHash && isCurrHash || !searchHash && !isCurrHash)
|
||||
cursor.addRow(objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
suggestionAdapter.changeCursor(cursor);
|
||||
}
|
||||
};
|
||||
|
||||
private void cancelSuggestionsAsync() {
|
||||
if (prevSuggestionAsync != null)
|
||||
try {
|
||||
prevSuggestionAsync.cancel(true);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(final String query) {
|
||||
cancelSuggestionsAsync();
|
||||
menu.findItem(R.id.action_about).setVisible(true);
|
||||
menu.findItem(R.id.action_settings).setVisible(true);
|
||||
|
||||
closeAnyOpenDrawer();
|
||||
addToStack();
|
||||
userQuery = (query.contains("@") || query.contains("#")) ? query : ("@" + query);
|
||||
searchAction.collapseActionView();
|
||||
searchView.setIconified(true);
|
||||
searchView.setIconified(true);
|
||||
mainHelper.onRefresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(final String newText) {
|
||||
cancelSuggestionsAsync();
|
||||
|
||||
if (!Utils.isEmpty(newText)) {
|
||||
searchUser = newText.charAt(0) == '@';
|
||||
searchHash = newText.charAt(0) == '#';
|
||||
|
||||
if (newText.length() == 1 && (searchHash || searchUser)) {
|
||||
if (searchAutoComplete != null) searchAutoComplete.setThreshold(2);
|
||||
} else {
|
||||
if (searchAutoComplete != null) searchAutoComplete.setThreshold(1);
|
||||
prevSuggestionAsync = new SuggestionsFetcher(fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
searchUser || searchHash ? newText.substring(1) : newText);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (closeAnyOpenDrawer()) return;
|
||||
|
||||
if (searchView != null && !searchView.isIconified()) {
|
||||
if (searchAction != null) searchAction.collapseActionView();
|
||||
searchView.setIconified(true);
|
||||
searchView.setIconified(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mainHelper.isSelectionCleared()) return;
|
||||
|
||||
final GridLayoutManager layoutManager = (GridLayoutManager) mainBinding.profileView.mainPosts.getLayoutManager();
|
||||
if (layoutManager != null && layoutManager.findFirstCompletelyVisibleItemPosition() >= layoutManager.getSpanCount()) {
|
||||
mainBinding.profileView.mainPosts.smoothScrollToPosition(0);
|
||||
mainBinding.profileView.appBarLayout.setExpanded(true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (queriesStack != null && queriesStack.size() > 0) {
|
||||
userQuery = queriesStack.pop();
|
||||
if (userQuery != null) {
|
||||
mainHelper.onRefresh();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
downloadSelectedItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == 9629 && (resultCode == 1692 || resultCode == RESULT_CANCELED))
|
||||
finish();
|
||||
else if (requestCode == 6007)
|
||||
Utils.showImportExportDialog(this);
|
||||
else if (requestCode == 6969 && mainHelper.currentFeedPlayer != null)
|
||||
mainHelper.currentFeedPlayer.setPlayWhenReady(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (mainHelper != null) mainHelper.onPause();
|
||||
if (handler != null && runnable != null) {
|
||||
handler.removeCallbacks(runnable);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
if (mainHelper != null) mainHelper.onResume();
|
||||
if (handler != null && runnable != null) {
|
||||
handler.postDelayed(runnable, INITIAL_DELAY_MILLIS);
|
||||
}
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
private void setStack(final Bundle bundle) {
|
||||
final Object stack = bundle != null ? bundle.get("stack") : null;
|
||||
if (stack instanceof Stack) //noinspection unchecked
|
||||
queriesStack = (Stack<String>) stack;
|
||||
}
|
||||
|
||||
public void addToStack() {
|
||||
if (userQuery != null) {
|
||||
if (queriesStack == null) queriesStack = new Stack<>();
|
||||
queriesStack.add(userQuery);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean closeAnyOpenDrawer() {
|
||||
final int childCount = mainBinding.drawerLayout.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = mainBinding.drawerLayout.getChildAt(i);
|
||||
final MouseDrawer.LayoutParams childLp = (MouseDrawer.LayoutParams) child.getLayoutParams();
|
||||
|
||||
if ((childLp.openState & MouseDrawer.LayoutParams.FLAG_IS_OPENED) == 1 ||
|
||||
(childLp.openState & MouseDrawer.LayoutParams.FLAG_IS_OPENING) == 2 ||
|
||||
childLp.onScreen >= 0.6 || childLp.isPeeking) {
|
||||
mainBinding.drawerLayout.closeDrawer(child);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,585 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.provider.BaseColumns;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDestination;
|
||||
import androidx.navigation.NavDirections;
|
||||
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.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.SuggestionsAdapter;
|
||||
import awais.instagrabber.asyncs.SuggestionsFetcher;
|
||||
import awais.instagrabber.customviews.helpers.CustomHideBottomViewOnScrollBehavior;
|
||||
import awais.instagrabber.databinding.ActivityMainBinding;
|
||||
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.IntentModel;
|
||||
import awais.instagrabber.models.SuggestionModel;
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
import awais.instagrabber.services.ActivityCheckerService;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.FlavorTown;
|
||||
import awais.instagrabber.utils.IntentUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class MainActivity extends BaseLanguageActivity {
|
||||
private static final String TAG = "MainActivity";
|
||||
|
||||
private static final List<Integer> SHOW_BOTTOM_VIEW_DESTINATIONS = Arrays.asList(
|
||||
R.id.directMessagesInboxFragment,
|
||||
R.id.feedFragment,
|
||||
R.id.profileFragment,
|
||||
R.id.discoverFragment,
|
||||
R.id.morePreferencesFragment);
|
||||
private static final List<Integer> KEEP_SCROLL_BEHAVIOUR_DESTINATIONS = Arrays.asList(
|
||||
R.id.directMessagesInboxFragment,
|
||||
R.id.feedFragment,
|
||||
R.id.profileFragment,
|
||||
R.id.discoverFragment,
|
||||
R.id.morePreferencesFragment,
|
||||
R.id.settingsPreferencesFragment,
|
||||
R.id.aboutFragment,
|
||||
R.id.hashTagFragment,
|
||||
R.id.locationFragment,
|
||||
R.id.savedViewerFragment,
|
||||
R.id.commentsViewerFragment,
|
||||
R.id.followViewerFragment,
|
||||
R.id.directMessagesSettingsFragment,
|
||||
R.id.notificationsViewer,
|
||||
R.id.themePreferencesFragment);
|
||||
private static final Map<Integer, Integer> NAV_TO_MENU_ID_MAP = new HashMap<>();
|
||||
private static final List<Integer> REMOVE_COLLAPSING_TOOLBAR_SCROLL_DESTINATIONS = Collections.singletonList(R.id.commentsViewerFragment);
|
||||
private static final String FIRST_FRAGMENT_GRAPH_INDEX_KEY = "firstFragmentGraphIndex";
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
private LiveData<NavController> currentNavControllerLiveData;
|
||||
private MenuItem searchMenuItem;
|
||||
private SuggestionsAdapter suggestionAdapter;
|
||||
private AutoCompleteTextView searchAutoComplete;
|
||||
private SearchView searchView;
|
||||
private boolean showSearch = true;
|
||||
private Handler suggestionsFetchHandler;
|
||||
private int firstFragmentGraphIndex;
|
||||
private boolean isActivityCheckerServiceBound = false;
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
||||
// final ActivityCheckerService.LocalBinder binder = (ActivityCheckerService.LocalBinder) service;
|
||||
// final ActivityCheckerService activityCheckerService = binder.getService();
|
||||
isActivityCheckerServiceBound = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(final ComponentName name) {
|
||||
isActivityCheckerServiceBound = false;
|
||||
}
|
||||
};
|
||||
|
||||
static {
|
||||
NAV_TO_MENU_ID_MAP.put(R.navigation.direct_messages_nav_graph, R.id.direct_messages_nav_graph);
|
||||
NAV_TO_MENU_ID_MAP.put(R.navigation.feed_nav_graph, R.id.feed_nav_graph);
|
||||
NAV_TO_MENU_ID_MAP.put(R.navigation.profile_nav_graph, R.id.profile_nav_graph);
|
||||
NAV_TO_MENU_ID_MAP.put(R.navigation.discover_nav_graph, R.id.discover_nav_graph);
|
||||
NAV_TO_MENU_ID_MAP.put(R.navigation.more_nav_graph, R.id.more_nav_graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
CookieUtils.setupCookies(cookie);
|
||||
setContentView(binding.getRoot());
|
||||
final Toolbar toolbar = binding.toolbar;
|
||||
setSupportActionBar(toolbar);
|
||||
createNotificationChannels();
|
||||
if (savedInstanceState == null) {
|
||||
setupBottomNavigationBar(true);
|
||||
}
|
||||
setupScrollingListener();
|
||||
setupSuggestions();
|
||||
final boolean checkUpdates = settingsHelper.getBoolean(Constants.CHECK_UPDATES);
|
||||
if (checkUpdates) FlavorTown.updateCheck(this);
|
||||
FlavorTown.changelogCheck(this);
|
||||
final Intent intent = getIntent();
|
||||
handleIntent(intent);
|
||||
if (!TextUtils.isEmpty(cookie) && settingsHelper.getBoolean(Constants.CHECK_ACTIVITY)) {
|
||||
bindActivityCheckerService();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main_menu, menu);
|
||||
searchMenuItem = menu.findItem(R.id.search);
|
||||
if (showSearch && currentNavControllerLiveData != null && currentNavControllerLiveData.getValue() != null) {
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
final NavDestination currentDestination = navController.getCurrentDestination();
|
||||
if (currentDestination != null) {
|
||||
final int destinationId = currentDestination.getId();
|
||||
showSearch = destinationId == R.id.profileFragment;
|
||||
}
|
||||
}
|
||||
if (!showSearch) {
|
||||
searchMenuItem.setVisible(false);
|
||||
return true;
|
||||
}
|
||||
return setupSearchView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||
outState.putString(FIRST_FRAGMENT_GRAPH_INDEX_KEY, String.valueOf(firstFragmentGraphIndex));
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
final String key = (String) savedInstanceState.get(FIRST_FRAGMENT_GRAPH_INDEX_KEY);
|
||||
if (key != null) {
|
||||
try {
|
||||
firstFragmentGraphIndex = Integer.parseInt(key);
|
||||
} catch (NumberFormatException ignored) { }
|
||||
}
|
||||
setupBottomNavigationBar(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
if (currentNavControllerLiveData != null && currentNavControllerLiveData.getValue() != null) {
|
||||
return currentNavControllerLiveData.getValue().navigateUp();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(final Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
handleIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unbindActivityCheckerService();
|
||||
}
|
||||
|
||||
private void createNotificationChannels() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(Constants.DOWNLOAD_CHANNEL_ID,
|
||||
Constants.DOWNLOAD_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT));
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(Constants.ACTIVITY_CHANNEL_ID,
|
||||
Constants.ACTIVITY_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT));
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSuggestions() {
|
||||
suggestionsFetchHandler = new Handler();
|
||||
suggestionAdapter = new SuggestionsAdapter(this, (type, query) -> {
|
||||
if (searchMenuItem != null) searchMenuItem.collapseActionView();
|
||||
if (searchView != null && !searchView.isIconified()) searchView.setIconified(true);
|
||||
if (currentNavControllerLiveData != null && currentNavControllerLiveData.getValue() != null) {
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
final Bundle bundle = new Bundle();
|
||||
switch (type) {
|
||||
case TYPE_LOCATION:
|
||||
bundle.putString("locationId", query);
|
||||
navController.navigate(R.id.action_global_locationFragment, bundle);
|
||||
break;
|
||||
case TYPE_HASHTAG:
|
||||
bundle.putString("hashtag", query);
|
||||
navController.navigate(R.id.action_global_hashTagFragment, bundle);
|
||||
break;
|
||||
case TYPE_USER:
|
||||
bundle.putString("username", query);
|
||||
navController.navigate(R.id.action_global_profileFragment, bundle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupScrollingListener() {
|
||||
final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) binding.bottomNavView.getLayoutParams();
|
||||
layoutParams.setBehavior(new CustomHideBottomViewOnScrollBehavior());
|
||||
binding.bottomNavView.requestLayout();
|
||||
}
|
||||
|
||||
private boolean setupSearchView() {
|
||||
final View actionView = searchMenuItem.getActionView();
|
||||
if (!(actionView instanceof SearchView)) return false;
|
||||
searchView = (SearchView) actionView;
|
||||
searchView.setSuggestionsAdapter(suggestionAdapter);
|
||||
searchView.setMaxWidth(Integer.MAX_VALUE);
|
||||
final View searchText = searchView.findViewById(R.id.search_src_text);
|
||||
if (searchText instanceof AutoCompleteTextView) {
|
||||
searchAutoComplete = (AutoCompleteTextView) searchText;
|
||||
}
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
private boolean searchUser;
|
||||
private boolean searchHash;
|
||||
private AsyncTask<?, ?, ?> prevSuggestionAsync;
|
||||
private final String[] COLUMNS = {
|
||||
BaseColumns._ID,
|
||||
Constants.EXTRAS_USERNAME,
|
||||
Constants.EXTRAS_NAME,
|
||||
Constants.EXTRAS_TYPE,
|
||||
"pfp",
|
||||
"verified"
|
||||
};
|
||||
private String currentSearchQuery;
|
||||
|
||||
private final FetchListener<SuggestionModel[]> fetchListener = new FetchListener<SuggestionModel[]>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
suggestionAdapter.changeCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final SuggestionModel[] result) {
|
||||
final MatrixCursor cursor;
|
||||
if (result == null) cursor = null;
|
||||
else {
|
||||
cursor = new MatrixCursor(COLUMNS, 0);
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
final SuggestionModel suggestionModel = result[i];
|
||||
if (suggestionModel != null) {
|
||||
final SuggestionType suggestionType = suggestionModel.getSuggestionType();
|
||||
final Object[] objects = {
|
||||
i,
|
||||
suggestionType == SuggestionType.TYPE_LOCATION ? suggestionModel.getName() : suggestionModel.getUsername(),
|
||||
suggestionType == SuggestionType.TYPE_LOCATION ? suggestionModel.getUsername() : suggestionModel.getName(),
|
||||
suggestionType,
|
||||
suggestionModel.getProfilePic(),
|
||||
suggestionModel.isVerified()};
|
||||
if (!searchHash && !searchUser) cursor.addRow(objects);
|
||||
else {
|
||||
final boolean isCurrHash = suggestionType == SuggestionType.TYPE_HASHTAG;
|
||||
if (searchHash && isCurrHash || !searchHash && !isCurrHash)
|
||||
cursor.addRow(objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
suggestionAdapter.changeCursor(cursor);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable runnable = () -> {
|
||||
cancelSuggestionsAsync();
|
||||
if (TextUtils.isEmpty(currentSearchQuery)) {
|
||||
suggestionAdapter.changeCursor(null);
|
||||
return;
|
||||
}
|
||||
searchUser = currentSearchQuery.charAt(0) == '@';
|
||||
searchHash = currentSearchQuery.charAt(0) == '#';
|
||||
if (currentSearchQuery.length() == 1 && (searchHash || searchUser)) {
|
||||
if (searchAutoComplete != null) {
|
||||
searchAutoComplete.setThreshold(2);
|
||||
}
|
||||
} else {
|
||||
if (searchAutoComplete != null) {
|
||||
searchAutoComplete.setThreshold(1);
|
||||
}
|
||||
prevSuggestionAsync = new SuggestionsFetcher(fetchListener).executeOnExecutor(
|
||||
AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
searchUser || searchHash ? currentSearchQuery.substring(1)
|
||||
: currentSearchQuery);
|
||||
}
|
||||
};
|
||||
|
||||
private void cancelSuggestionsAsync() {
|
||||
if (prevSuggestionAsync != null)
|
||||
try {
|
||||
prevSuggestionAsync.cancel(true);
|
||||
} catch (final Exception ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(final String query) {
|
||||
return onQueryTextChange(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(final String query) {
|
||||
suggestionsFetchHandler.removeCallbacks(runnable);
|
||||
currentSearchQuery = query;
|
||||
suggestionsFetchHandler.postDelayed(runnable, 800);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setupBottomNavigationBar(final boolean setDefaultFromSettings) {
|
||||
int main_nav_ids = R.array.main_nav_ids;
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) != null;
|
||||
if (!isLoggedIn) {
|
||||
main_nav_ids = R.array.logged_out_main_nav_ids;
|
||||
binding.bottomNavView.getMenu().clear();
|
||||
binding.bottomNavView.inflateMenu(R.menu.logged_out_bottom_navigation_menu);
|
||||
}
|
||||
final TypedArray navIds = getResources().obtainTypedArray(main_nav_ids);
|
||||
final List<Integer> mainNavList = new ArrayList<>(navIds.length());
|
||||
final int length = navIds.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
final int resourceId = navIds.getResourceId(i, -1);
|
||||
if (resourceId < 0) continue;
|
||||
mainNavList.add(resourceId);
|
||||
}
|
||||
navIds.recycle();
|
||||
if (setDefaultFromSettings || !isLoggedIn) {
|
||||
final String defaultTabIdString = settingsHelper.getString(Constants.DEFAULT_TAB);
|
||||
try {
|
||||
final int defaultNavId = TextUtils.isEmpty(defaultTabIdString) || !isLoggedIn
|
||||
? R.navigation.profile_nav_graph
|
||||
: Integer.parseInt(defaultTabIdString);
|
||||
final int index = mainNavList.indexOf(defaultNavId);
|
||||
if (index >= 0) {
|
||||
firstFragmentGraphIndex = index;
|
||||
final Integer menuId = NAV_TO_MENU_ID_MAP.get(defaultNavId);
|
||||
if (menuId != null) {
|
||||
binding.bottomNavView.setSelectedItemId(menuId);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Error parsing id", e);
|
||||
}
|
||||
}
|
||||
final LiveData<NavController> navControllerLiveData = setupWithNavController(
|
||||
binding.bottomNavView,
|
||||
mainNavList,
|
||||
getSupportFragmentManager(),
|
||||
R.id.main_nav_host,
|
||||
getIntent(),
|
||||
firstFragmentGraphIndex);
|
||||
navControllerLiveData.observe(this, this::setupNavigation);
|
||||
currentNavControllerLiveData = navControllerLiveData;
|
||||
}
|
||||
|
||||
private void setupNavigation(final NavController navController) {
|
||||
NavigationUI.setupWithNavController(binding.toolbar, navController);
|
||||
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
|
||||
// below is a hack to check if we are at the end of the current stack, to setup the search view
|
||||
binding.appBarLayout.setExpanded(true, true);
|
||||
final int destinationId = destination.getId();
|
||||
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
|
||||
setupMenu(backStack.size(), destinationId);
|
||||
binding.bottomNavView.setVisibility(SHOW_BOTTOM_VIEW_DESTINATIONS.contains(destinationId) ? View.VISIBLE : View.GONE);
|
||||
if (KEEP_SCROLL_BEHAVIOUR_DESTINATIONS.contains(destinationId)) {
|
||||
setScrollingBehaviour();
|
||||
} else {
|
||||
removeScrollingBehaviour();
|
||||
}
|
||||
if (REMOVE_COLLAPSING_TOOLBAR_SCROLL_DESTINATIONS.contains(destinationId)) {
|
||||
removeCollapsingToolbarScrollFlags();
|
||||
} else {
|
||||
setCollapsingToolbarScrollFlags();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupMenu(final int backStackSize, final int destinationId) {
|
||||
if (searchMenuItem == null) return;
|
||||
if (backStackSize >= 2 && destinationId == R.id.profileFragment) {
|
||||
showSearch = true;
|
||||
searchMenuItem.setVisible(true);
|
||||
return;
|
||||
}
|
||||
showSearch = false;
|
||||
searchMenuItem.setVisible(false);
|
||||
}
|
||||
|
||||
private void setScrollingBehaviour() {
|
||||
final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) binding.mainNavHost.getLayoutParams();
|
||||
layoutParams.setBehavior(new AppBarLayout.ScrollingViewBehavior());
|
||||
binding.mainNavHost.requestLayout();
|
||||
}
|
||||
|
||||
private void removeScrollingBehaviour() {
|
||||
final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) binding.mainNavHost.getLayoutParams();
|
||||
layoutParams.setBehavior(null);
|
||||
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();
|
||||
}
|
||||
|
||||
private void handleIntent(final Intent intent) {
|
||||
if (intent == null) return;
|
||||
final String action = intent.getAction();
|
||||
final String type = intent.getType();
|
||||
// Log.d(TAG, action + " " + type);
|
||||
if (Intent.ACTION_MAIN.equals(action)) return;
|
||||
if (Constants.ACTION_SHOW_ACTIVITY.equals(action)) {
|
||||
showActivityView();
|
||||
return;
|
||||
}
|
||||
if (Intent.ACTION_SEND.equals(action) && type != null) {
|
||||
if (type.equals("text/plain")) {
|
||||
handleUrl(intent.getStringExtra(Intent.EXTRA_TEXT));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Intent.ACTION_VIEW.equals(action)) {
|
||||
final Uri data = intent.getData();
|
||||
if (data == null) return;
|
||||
handleUrl(data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUrl(final String url) {
|
||||
if (url == null) return;
|
||||
// Log.d(TAG, url);
|
||||
final IntentModel intentModel = IntentUtils.parseUrl(url);
|
||||
if (intentModel == null) return;
|
||||
showView(intentModel);
|
||||
}
|
||||
|
||||
private void showView(final IntentModel intentModel) {
|
||||
switch (intentModel.getType()) {
|
||||
case USERNAME:
|
||||
showProfileView(intentModel);
|
||||
break;
|
||||
case POST:
|
||||
showPostView(intentModel);
|
||||
break;
|
||||
case LOCATION:
|
||||
showLocationView(intentModel);
|
||||
break;
|
||||
case HASHTAG:
|
||||
showHashtagView(intentModel);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
default:
|
||||
Log.w(TAG, "Unknown model type received!");
|
||||
}
|
||||
}
|
||||
|
||||
private void showProfileView(@NonNull final IntentModel intentModel) {
|
||||
final String username = intentModel.getText();
|
||||
// Log.d(TAG, "username: " + username);
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (currentNavControllerLiveData == null || navController == null) return;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString("username", "@" + username);
|
||||
navController.navigate(R.id.action_global_profileFragment, bundle);
|
||||
}
|
||||
|
||||
private void showPostView(@NonNull final IntentModel intentModel) {
|
||||
final String shortCode = intentModel.getText();
|
||||
// Log.d(TAG, "shortCode: " + shortCode);
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (currentNavControllerLiveData == null || navController == null) return;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putStringArray("idOrCodeArray", new String[]{shortCode});
|
||||
bundle.putInt("index", 0);
|
||||
bundle.putBoolean("isId", false);
|
||||
navController.navigate(R.id.action_global_postViewFragment, bundle);
|
||||
}
|
||||
|
||||
private void showLocationView(@NonNull final IntentModel intentModel) {
|
||||
final String locationId = intentModel.getText();
|
||||
// Log.d(TAG, "locationId: " + locationId);
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (currentNavControllerLiveData == null || navController == null) return;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString("locationId", locationId);
|
||||
navController.navigate(R.id.action_global_locationFragment, bundle);
|
||||
}
|
||||
|
||||
private void showHashtagView(@NonNull final IntentModel intentModel) {
|
||||
final String hashtag = intentModel.getText();
|
||||
// Log.d(TAG, "hashtag: " + hashtag);
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (currentNavControllerLiveData == null || navController == null) return;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString("hashtag", "#" + hashtag);
|
||||
navController.navigate(R.id.action_global_hashTagFragment, bundle);
|
||||
}
|
||||
|
||||
private void showActivityView() {
|
||||
binding.bottomNavView.setSelectedItemId(R.id.more_nav_graph);
|
||||
binding.bottomNavView.post(() -> {
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (currentNavControllerLiveData == null || navController == null) return;
|
||||
final NavDirections navDirections = MorePreferencesFragmentDirections.actionMorePreferencesFragmentToNotificationsViewer();
|
||||
navController.navigate(navDirections);
|
||||
});
|
||||
}
|
||||
|
||||
private void bindActivityCheckerService() {
|
||||
bindService(new Intent(this, ActivityCheckerService.class), serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
isActivityCheckerServiceBound = true;
|
||||
}
|
||||
|
||||
private void unbindActivityCheckerService() {
|
||||
if (!isActivityCheckerServiceBound) return;
|
||||
unbindService(serviceConnection);
|
||||
isActivityCheckerServiceBound = false;
|
||||
}
|
||||
}
|
@ -1,189 +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.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.NotificationsAdapter;
|
||||
import awais.instagrabber.asyncs.NotificationsFetcher;
|
||||
import awais.instagrabber.databinding.ActivityNotificationBinding;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.NotificationModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.notificationManager;
|
||||
|
||||
public final class NotificationsViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
|
||||
private NotificationModel notificationModel;
|
||||
private ActivityNotificationBinding notificationsBinding;
|
||||
private ArrayAdapter<String> commmentDialogAdapter;
|
||||
private String shortCode, postId, userId;
|
||||
private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
||||
private Resources resources;
|
||||
String[] commentDialogList;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
notificationManager.cancel(1800000000);
|
||||
if (Utils.isEmpty(cookie)) {
|
||||
Toast.makeText(this, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
notificationsBinding = ActivityNotificationBinding.inflate(getLayoutInflater());
|
||||
setContentView(notificationsBinding.getRoot());
|
||||
notificationsBinding.swipeRefreshLayout.setOnRefreshListener(this);
|
||||
resources = getResources();
|
||||
setSupportActionBar(notificationsBinding.toolbar.toolbar);
|
||||
notificationsBinding.toolbar.toolbar.setTitle(R.string.action_notif);
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
notificationsBinding.swipeRefreshLayout.setRefreshing(true);
|
||||
new NotificationsFetcher(new FetchListener<NotificationModel[]>() {
|
||||
@Override
|
||||
public void onResult(final NotificationModel[] notificationModels) {
|
||||
notificationsBinding.rvComments.setAdapter(new NotificationsAdapter(notificationModels, clickListener, mentionClickListener));
|
||||
notificationsBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
new SeenAction().execute();
|
||||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
|
||||
if (which == 0)
|
||||
searchUsername(notificationModel.getUsername());
|
||||
else if (which == 1 && commentDialogList.length == 2)
|
||||
startActivity(new Intent(getApplicationContext(), PostViewer.class)
|
||||
.putExtra(Constants.EXTRAS_POST, new PostModel(notificationModel.getShortcode(), false)));
|
||||
else if (which == 1) new ProfileAction().execute("/approve/");
|
||||
else if (which == 2) new ProfileAction().execute("/ignore/");
|
||||
};
|
||||
|
||||
private final View.OnClickListener clickListener = v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof NotificationModel) {
|
||||
notificationModel = (NotificationModel) tag;
|
||||
|
||||
final String username = notificationModel.getUsername();
|
||||
final SpannableString title = new SpannableString(username + ":\n" + notificationModel.getText());
|
||||
title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
if (notificationModel.getShortcode() != null) commentDialogList = new String[]{
|
||||
resources.getString(R.string.open_profile),
|
||||
resources.getString(R.string.view_post)
|
||||
};
|
||||
else if (notificationModel.getType() == NotificationType.REQUEST)
|
||||
commentDialogList = new String[]{
|
||||
resources.getString(R.string.open_profile),
|
||||
resources.getString(R.string.request_approve),
|
||||
resources.getString(R.string.request_reject)
|
||||
};
|
||||
else commentDialogList = new String[]{
|
||||
resources.getString(R.string.open_profile)
|
||||
};
|
||||
|
||||
commmentDialogAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, commentDialogList);
|
||||
|
||||
new AlertDialog.Builder(this).setTitle(title)
|
||||
.setAdapter(commmentDialogAdapter, profileDialogListener)
|
||||
.setNeutralButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
};
|
||||
|
||||
private final MentionClickListener mentionClickListener = (view, text, isHashtag) ->
|
||||
new AlertDialog.Builder(this).setTitle(text)
|
||||
.setMessage(isHashtag ? R.string.comment_view_mention_hash_search : R.string.comment_view_mention_user_search)
|
||||
.setNegativeButton(R.string.cancel, null).setPositiveButton(R.string.ok,
|
||||
(dialog, which) -> searchUsername(text)).show();
|
||||
|
||||
|
||||
private void searchUsername(final String text) {
|
||||
startActivity(new Intent(getApplicationContext(), ProfileViewer.class).putExtra(Constants.EXTRAS_USERNAME, text));
|
||||
}
|
||||
|
||||
class ProfileAction extends AsyncTask<String, Void, Void> {
|
||||
boolean ok = false;
|
||||
String action;
|
||||
|
||||
protected Void doInBackground(String... rawAction) {
|
||||
action = rawAction[0];
|
||||
final String url = "https://www.instagram.com/web/friendships/"+notificationModel.getId()+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",
|
||||
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
|
||||
urlConnection.connect();
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
ok = true;
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", action+": " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (ok == true) {
|
||||
onRefresh();
|
||||
}
|
||||
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
class SeenAction extends AsyncTask<Void, Void, Void> {
|
||||
protected Void doInBackground(Void... lmao) {
|
||||
try {
|
||||
final HttpURLConnection urlConnection =
|
||||
(HttpURLConnection) new URL("https://www.instagram.com/web/activity/mark_checked/").openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
|
||||
urlConnection.setRequestProperty("x-csrftoken",
|
||||
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
|
||||
final String urlParameters = "timestamp="+(System.currentTimeMillis()/1000);
|
||||
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();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "seen: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,767 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.SpannableString;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.GestureDetectorCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.PostsMediaAdapter;
|
||||
import awais.instagrabber.asyncs.PostFetcher;
|
||||
import awais.instagrabber.asyncs.ProfileFetcher;
|
||||
import awais.instagrabber.asyncs.i.iPostFetcher;
|
||||
import awais.instagrabber.customviews.CommentMentionClickSpan;
|
||||
import awais.instagrabber.customviews.helpers.SwipeGestureListener;
|
||||
import awais.instagrabber.databinding.ActivityViewerBinding;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.interfaces.SwipeEvent;
|
||||
import awais.instagrabber.models.BasePostModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.DownloadMethod;
|
||||
import awais.instagrabber.models.enums.ItemGetType;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class PostViewer extends BaseLanguageActivity {
|
||||
private ActivityViewerBinding viewerBinding;
|
||||
private String url, prevUsername, commentsEndCursor;
|
||||
private ProfileModel profileModel;
|
||||
private BasePostModel postModel;
|
||||
private ViewerPostModel viewerPostModel;
|
||||
private SimpleExoPlayer player;
|
||||
private ArrayAdapter<String> profileDialogAdapter;
|
||||
private View viewsContainer, viewerCaptionParent;
|
||||
private GestureDetectorCompat gestureDetector;
|
||||
private SwipeEvent swipeEvent;
|
||||
private CharSequence postCaption = null, postUserId;
|
||||
private Resources resources;
|
||||
private boolean session = false, isFromShare, liked, saved, ok = false;
|
||||
private int slidePos = 0, lastSlidePos = 0;
|
||||
private ItemGetType itemGetType;
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
final View.OnTouchListener gestureTouchListener = new View.OnTouchListener() {
|
||||
private float startX;
|
||||
private float startY;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(final View v, final MotionEvent event) {
|
||||
if (v == viewerCaptionParent) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
startX = event.getX();
|
||||
startY = event.getY();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (!(Utils.isEmpty(postCaption) ||
|
||||
Math.abs(startX - event.getX()) > 50 || Math.abs(startY - event.getY()) > 50)) {
|
||||
Utils.copyText(PostViewer.this, postCaption);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
};
|
||||
private final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
|
||||
final String username = viewerPostModel.getUsername();
|
||||
|
||||
if (which == 0) {
|
||||
searchUsername(username);
|
||||
} else if (profileModel != null && which == 1) {
|
||||
startActivity(new Intent(this, ProfilePicViewer.class)
|
||||
.putExtra(Constants.EXTRAS_PROFILE, profileModel));
|
||||
}
|
||||
};
|
||||
private final View.OnClickListener onClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (v == viewerBinding.topPanel.ivProfilePic) {
|
||||
new AlertDialog.Builder(PostViewer.this).setAdapter(profileDialogAdapter, profileDialogListener)
|
||||
.setNeutralButton(R.string.cancel, null).setTitle(viewerPostModel.getUsername()).show();
|
||||
|
||||
} else if (v == viewerBinding.ivToggleFullScreen) {
|
||||
toggleFullscreen();
|
||||
|
||||
final LinearLayout topPanelRoot = viewerBinding.topPanel.getRoot();
|
||||
final int iconRes;
|
||||
|
||||
if (containerLayoutParams.weight != 3.3f) {
|
||||
containerLayoutParams.weight = 3.3f;
|
||||
iconRes = R.drawable.ic_fullscreen_exit;
|
||||
topPanelRoot.setVisibility(View.GONE);
|
||||
viewerBinding.btnDownload.setVisibility(View.VISIBLE);
|
||||
viewerBinding.bottomPanel.tvPostDate.setVisibility(View.GONE);
|
||||
} else {
|
||||
containerLayoutParams.weight = (viewerBinding.mediaList.getVisibility() == View.VISIBLE) ? 1.35f : 1.9f;
|
||||
containerLayoutParams.weight += (Utils.isEmpty(settingsHelper.getString(Constants.COOKIE))) ? 0.3f : 0;
|
||||
iconRes = R.drawable.ic_fullscreen;
|
||||
topPanelRoot.setVisibility(View.VISIBLE);
|
||||
viewerBinding.btnDownload.setVisibility(View.GONE);
|
||||
viewerBinding.bottomPanel.tvPostDate.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
viewerBinding.ivToggleFullScreen.setImageResource(iconRes);
|
||||
viewerBinding.container.setLayoutParams(containerLayoutParams);
|
||||
|
||||
} else if (v == viewerBinding.bottomPanel.btnMute) {
|
||||
if (player != null) {
|
||||
final float intVol = player.getVolume() == 0f ? 1f : 0f;
|
||||
player.setVolume(intVol);
|
||||
viewerBinding.bottomPanel.btnMute.setImageResource(intVol == 0f ? R.drawable.mute : R.drawable.vol);
|
||||
Utils.sessionVolumeFull = intVol == 1f;
|
||||
}
|
||||
} else if (v == viewerBinding.btnLike) {
|
||||
new PostAction().execute("likes");
|
||||
} else if (v == viewerBinding.btnBookmark) {
|
||||
new PostAction().execute("save");
|
||||
} else {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof ViewerPostModel) {
|
||||
viewerPostModel = (ViewerPostModel) tag;
|
||||
slidePos = Math.max(0, viewerPostModel.getPosition());
|
||||
refreshPost();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
private final View.OnClickListener downloadClickListener = v -> {
|
||||
if (ContextCompat.checkSelfPermission(this, Utils.PERMS[0]) == PackageManager.PERMISSION_GRANTED)
|
||||
showDownloadDialog();
|
||||
else
|
||||
ActivityCompat.requestPermissions(this, Utils.PERMS, 8020);
|
||||
};
|
||||
private final PostsMediaAdapter mediaAdapter = new PostsMediaAdapter(null, onClickListener);
|
||||
private RequestManager glideRequestManager;
|
||||
private LinearLayout.LayoutParams containerLayoutParams;
|
||||
private final FetchListener<ViewerPostModel[]> pfl = result -> {
|
||||
if (result == null || result.length < 1) {
|
||||
Toast.makeText(this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
viewerPostModel = result[0];
|
||||
|
||||
mediaAdapter.setData(result);
|
||||
if (result.length > 1) {
|
||||
viewerBinding.mediaList.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT, 0, 0.55f
|
||||
));
|
||||
containerLayoutParams.weight = 1.35f;
|
||||
containerLayoutParams.weight += (Utils.isEmpty(settingsHelper.getString(Constants.COOKIE))) ? 0.3f : 0;
|
||||
viewerBinding.container.setLayoutParams(containerLayoutParams);
|
||||
viewerBinding.mediaList.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
viewerCaptionParent.setOnTouchListener(gestureTouchListener);
|
||||
viewerBinding.playerView.setOnTouchListener(gestureTouchListener);
|
||||
viewerBinding.imageViewer.setOnSingleFlingListener((e1, e2, velocityX, velocityY) -> {
|
||||
final float diffX = e2.getX() - e1.getX();
|
||||
if (Math.abs(diffX) > Math.abs(e2.getY() - e1.getY()) && Math.abs(diffX) > SwipeGestureListener.SWIPE_THRESHOLD
|
||||
&& Math.abs(velocityX) > SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD) {
|
||||
swipeEvent.onSwipe(diffX > 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
final long commentsCount = viewerPostModel.getCommentsCount();
|
||||
viewerBinding.bottomPanel.commentsCount.setText(String.valueOf(commentsCount));
|
||||
viewerBinding.bottomPanel.btnComments.setVisibility(View.VISIBLE);
|
||||
|
||||
viewerBinding.bottomPanel.btnComments.setOnClickListener(v ->
|
||||
startActivityForResult(new Intent(this, CommentsViewer.class)
|
||||
.putExtra(Constants.EXTRAS_SHORTCODE, postModel.getShortCode())
|
||||
.putExtra(Constants.EXTRAS_POST, viewerPostModel.getPostId())
|
||||
.putExtra(Constants.EXTRAS_USER, postUserId), 6969));
|
||||
viewerBinding.bottomPanel.btnComments.setClickable(true);
|
||||
viewerBinding.bottomPanel.btnComments.setEnabled(true);
|
||||
|
||||
if (postModel instanceof PostModel) {
|
||||
final PostModel postModel = (PostModel) this.postModel;
|
||||
postModel.setPostId(viewerPostModel.getPostId());
|
||||
postModel.setTimestamp(viewerPostModel.getTimestamp());
|
||||
postModel.setPostCaption(viewerPostModel.getPostCaption());
|
||||
if (!ok) {
|
||||
liked = viewerPostModel.getLike();
|
||||
saved = viewerPostModel.getBookmark();
|
||||
}
|
||||
}
|
||||
|
||||
setupPostInfoBar("@"+viewerPostModel.getUsername(), viewerPostModel.getItemType(),
|
||||
viewerPostModel.getLocationName(), viewerPostModel.getLocation());
|
||||
|
||||
postCaption = postModel.getPostCaption();
|
||||
viewerCaptionParent.setVisibility(View.VISIBLE);
|
||||
|
||||
viewerBinding.bottomPanel.btnDownload.setOnClickListener(downloadClickListener);
|
||||
|
||||
refreshPost();
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
viewerBinding = ActivityViewerBinding.inflate(getLayoutInflater());
|
||||
setContentView(viewerBinding.getRoot());
|
||||
|
||||
glideRequestManager = Glide.with(this);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null || !intent.hasExtra(Constants.EXTRAS_POST)
|
||||
|| (postModel = (PostModel) intent.getSerializableExtra(Constants.EXTRAS_POST)) == null) {
|
||||
Utils.errorFinish(this);
|
||||
return;
|
||||
}
|
||||
|
||||
containerLayoutParams = (LinearLayout.LayoutParams) viewerBinding.container.getLayoutParams();
|
||||
|
||||
if (intent.hasExtra(Constants.EXTRAS_TYPE))
|
||||
itemGetType = (ItemGetType) intent.getSerializableExtra(Constants.EXTRAS_TYPE);
|
||||
|
||||
resources = getResources();
|
||||
|
||||
viewerBinding.topPanel.title.setMovementMethod(new LinkMovementMethod());
|
||||
viewerBinding.topPanel.title.setMentionClickListener((view, text, isHashtag) -> searchUsername(text));
|
||||
viewerBinding.topPanel.ivProfilePic.setOnClickListener(onClickListener);
|
||||
|
||||
viewerBinding.ivToggleFullScreen.setOnClickListener(onClickListener);
|
||||
if (Utils.isEmpty(settingsHelper.getString(Constants.COOKIE))) {
|
||||
viewerBinding.btnLike.setVisibility(View.GONE);
|
||||
viewerBinding.btnBookmark.setVisibility(View.GONE);
|
||||
viewerBinding.postActions.setVisibility(View.GONE);
|
||||
viewerBinding.postActions.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT, 0, 0
|
||||
));
|
||||
containerLayoutParams.weight = (containerLayoutParams.weight == 3.3f) ? 3.3f : 2.2f;
|
||||
viewerBinding.container.setLayoutParams(containerLayoutParams);
|
||||
}
|
||||
else {
|
||||
viewerBinding.btnLike.setOnClickListener(onClickListener);
|
||||
viewerBinding.btnBookmark.setOnClickListener(onClickListener);
|
||||
}
|
||||
viewerBinding.btnDownload.setOnClickListener(downloadClickListener);
|
||||
|
||||
profileDialogAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
|
||||
new String[]{resources.getString(R.string.open_profile), resources.getString(R.string.view_pfp)});
|
||||
|
||||
postModel.setPosition(intent.getIntExtra(Constants.EXTRAS_INDEX, -1));
|
||||
|
||||
final boolean postIdNull = postModel.getPostId() == null;
|
||||
if (!postIdNull)
|
||||
setupPostInfoBar(intent.getStringExtra(Constants.EXTRAS_USER), postModel.getItemType(), null, null);
|
||||
|
||||
isFromShare = postModel.getPosition() == -1 || postIdNull;
|
||||
|
||||
viewerCaptionParent = (View) viewerBinding.bottomPanel.viewerCaption.getParent();
|
||||
viewsContainer = (View) viewerBinding.bottomPanel.tvVideoViews.getParent();
|
||||
|
||||
viewerBinding.mediaList.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
|
||||
viewerBinding.mediaList.setAdapter(mediaAdapter);
|
||||
viewerBinding.mediaList.setVisibility(View.GONE);
|
||||
|
||||
swipeEvent = isRight -> {
|
||||
final List<? extends BasePostModel> itemGetterItems;
|
||||
final boolean isMainSwipe;
|
||||
|
||||
if (itemGetType == ItemGetType.SAVED_ITEMS && SavedViewer.itemGetter != null) {
|
||||
itemGetterItems = SavedViewer.itemGetter.get(itemGetType);
|
||||
isMainSwipe = !(itemGetterItems.size() < 1 || itemGetType == ItemGetType.SAVED_ITEMS && isFromShare);
|
||||
}
|
||||
else if (itemGetType != null && Main.itemGetter != null) {
|
||||
itemGetterItems = Main.itemGetter.get(itemGetType);
|
||||
isMainSwipe = !(itemGetterItems.size() < 1 || itemGetType == ItemGetType.MAIN_ITEMS && isFromShare);
|
||||
} else {
|
||||
itemGetterItems = null;
|
||||
isMainSwipe = false;
|
||||
}
|
||||
|
||||
final BasePostModel[] basePostModels = mediaAdapter.getPostModels();
|
||||
final int slides = basePostModels.length;
|
||||
|
||||
int position = postModel.getPosition();
|
||||
|
||||
if (isRight) {
|
||||
--slidePos;
|
||||
if (!isMainSwipe && slidePos < 0) slidePos = 0;
|
||||
if (slides > 0 && slidePos >= 0) {
|
||||
if (basePostModels[slidePos] instanceof ViewerPostModel) {
|
||||
viewerPostModel = (ViewerPostModel) basePostModels[slidePos];
|
||||
}
|
||||
refreshPost();
|
||||
return;
|
||||
}
|
||||
if (isMainSwipe && --position < 0) position = itemGetterItems.size() - 1;
|
||||
} else {
|
||||
++slidePos;
|
||||
if (!isMainSwipe && slidePos >= slides) slidePos = slides - 1;
|
||||
if (slides > 0 && slidePos < slides) {
|
||||
if (basePostModels[slidePos] instanceof ViewerPostModel) {
|
||||
viewerPostModel = (ViewerPostModel) basePostModels[slidePos];
|
||||
}
|
||||
refreshPost();
|
||||
return;
|
||||
}
|
||||
if (isMainSwipe && ++position >= itemGetterItems.size()) position = 0;
|
||||
}
|
||||
|
||||
if (isMainSwipe) {
|
||||
slidePos = 0;
|
||||
ok = false;
|
||||
Log.d("AWAISKING_APP", "swipe left <<< post[" + position + "]: " + postModel + " -- " + slides);
|
||||
postModel = itemGetterItems.get(position);
|
||||
postModel.setPosition(position);
|
||||
viewPost();
|
||||
}
|
||||
};
|
||||
gestureDetector = new GestureDetectorCompat(this, new SwipeGestureListener(swipeEvent));
|
||||
|
||||
viewPost();
|
||||
}
|
||||
|
||||
private void viewPost() {
|
||||
lastSlidePos = 0;
|
||||
mediaAdapter.setData(null);
|
||||
viewsContainer.setVisibility(View.GONE);
|
||||
viewerCaptionParent.setVisibility(View.GONE);
|
||||
viewerBinding.mediaList.setVisibility(View.GONE);
|
||||
viewerBinding.btnDownload.setVisibility(View.GONE);
|
||||
viewerBinding.bottomPanel.btnMute.setVisibility(View.GONE);
|
||||
viewerBinding.bottomPanel.tvPostDate.setVisibility(View.GONE);
|
||||
viewerBinding.bottomPanel.btnComments.setVisibility(View.GONE);
|
||||
viewerBinding.bottomPanel.btnDownload.setVisibility(View.INVISIBLE);
|
||||
viewerBinding.bottomPanel.viewerCaption.setText(null);
|
||||
viewerBinding.bottomPanel.viewerCaption.setMentionClickListener(null);
|
||||
|
||||
viewerBinding.playerView.setVisibility(View.GONE);
|
||||
viewerBinding.playerView.setPlayer(null);
|
||||
viewerBinding.imageViewer.setImageResource(0);
|
||||
viewerBinding.imageViewer.setImageDrawable(null);
|
||||
|
||||
if (postModel.getShortCode() != null)
|
||||
new PostFetcher(postModel.getShortCode(), pfl).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if (postModel.getPostId() != null)
|
||||
new iPostFetcher(postModel.getPostId(), pfl).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void searchUsername(final String text) {
|
||||
startActivity(
|
||||
new Intent(getApplicationContext(), ProfileViewer.class)
|
||||
.putExtra(Constants.EXTRAS_USERNAME, text)
|
||||
);
|
||||
}
|
||||
|
||||
private void setupVideo() {
|
||||
viewerBinding.playerView.setVisibility(View.VISIBLE);
|
||||
viewerBinding.bottomPanel.btnDownload.setVisibility(View.VISIBLE);
|
||||
viewerBinding.bottomPanel.btnMute.setVisibility(View.VISIBLE);
|
||||
viewerBinding.progressView.setVisibility(View.GONE);
|
||||
viewerBinding.imageViewer.setVisibility(View.GONE);
|
||||
viewerBinding.imageViewer.setImageDrawable(null);
|
||||
|
||||
if (viewerPostModel.getVideoViews() > -1) {
|
||||
viewsContainer.setVisibility(View.VISIBLE);
|
||||
viewerBinding.bottomPanel.tvVideoViews.setText(String.valueOf(viewerPostModel.getVideoViews()));
|
||||
}
|
||||
|
||||
player = new SimpleExoPlayer.Builder(this).build();
|
||||
viewerBinding.playerView.setPlayer(player);
|
||||
float vol = Utils.settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
if (vol == 0f && Utils.sessionVolumeFull) vol = 1f;
|
||||
|
||||
player.setVolume(vol);
|
||||
player.setPlayWhenReady(Utils.settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
|
||||
final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(new DefaultDataSourceFactory(this, "instagram"))
|
||||
.createMediaSource(Uri.parse(url));
|
||||
mediaSource.addEventListener(new Handler(), new MediaSourceEventListener() {
|
||||
@Override
|
||||
public void onLoadCompleted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
viewerBinding.progressView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadStarted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
viewerBinding.progressView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCanceled(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
viewerBinding.progressView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadError(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData, final IOException error, final boolean wasCanceled) {
|
||||
viewerBinding.progressView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
player.prepare(mediaSource);
|
||||
|
||||
player.setVolume(vol);
|
||||
viewerBinding.bottomPanel.btnMute.setImageResource(vol == 0f ? R.drawable.vol : R.drawable.mute);
|
||||
|
||||
viewerBinding.bottomPanel.btnMute.setOnClickListener(onClickListener);
|
||||
}
|
||||
|
||||
private void setupImage() {
|
||||
viewsContainer.setVisibility(View.GONE);
|
||||
viewerBinding.playerView.setVisibility(View.GONE);
|
||||
viewerBinding.progressView.setVisibility(View.VISIBLE);
|
||||
viewerBinding.bottomPanel.btnMute.setVisibility(View.GONE);
|
||||
viewerBinding.bottomPanel.btnDownload.setVisibility(View.VISIBLE);
|
||||
|
||||
viewerBinding.imageViewer.setImageDrawable(null);
|
||||
viewerBinding.imageViewer.setVisibility(View.VISIBLE);
|
||||
viewerBinding.imageViewer.setZoomable(true);
|
||||
viewerBinding.imageViewer.setZoomTransitionDuration(420);
|
||||
viewerBinding.imageViewer.setMaximumScale(7.2f);
|
||||
|
||||
glideRequestManager.load(url).listener(new RequestListener<Drawable>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable final GlideException e, final Object model, final Target<Drawable> target, final boolean isFirstResource) {
|
||||
viewerBinding.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(final Drawable resource, final Object model, final Target<Drawable> target, final DataSource dataSource, final boolean isFirstResource) {
|
||||
viewerBinding.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
}).into(viewerBinding.imageViewer);
|
||||
}
|
||||
|
||||
private void showDownloadDialog() {
|
||||
final ArrayList<BasePostModel> postModels = new ArrayList<>();
|
||||
|
||||
if (!session && viewerBinding.mediaList.getVisibility() == View.VISIBLE) {
|
||||
final DialogInterface.OnClickListener clickListener = (dialog, which) -> {
|
||||
postModels.clear();
|
||||
|
||||
if (which == DialogInterface.BUTTON_NEGATIVE) {
|
||||
final BasePostModel[] adapterPostModels = mediaAdapter.getPostModels();
|
||||
for (int i = 0, size = mediaAdapter.getItemCount(); i < size; ++i) {
|
||||
if (adapterPostModels[i] instanceof ViewerPostModel)
|
||||
postModels.add(adapterPostModels[i]);
|
||||
}
|
||||
} else if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
postModels.add(viewerPostModel);
|
||||
} else {
|
||||
session = true;
|
||||
postModels.add(viewerPostModel);
|
||||
}
|
||||
|
||||
if (postModels.size() > 0)
|
||||
Utils.batchDownload(this, viewerPostModel.getUsername(), DownloadMethod.DOWNLOAD_POST_VIEWER, postModels);
|
||||
};
|
||||
|
||||
new AlertDialog.Builder(this).setTitle(R.string.post_viewer_download_dialog_title)
|
||||
.setMessage(R.string.post_viewer_download_message)
|
||||
.setNeutralButton(R.string.post_viewer_download_session, clickListener).setPositiveButton(R.string.post_viewer_download_current, clickListener)
|
||||
.setNegativeButton(R.string.post_viewer_download_album, clickListener).show();
|
||||
} else {
|
||||
Utils.batchDownload(this, viewerPostModel.getUsername(), DownloadMethod.DOWNLOAD_POST_VIEWER, Collections.singletonList(viewerPostModel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
showDownloadDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode == 6969) {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (Build.VERSION.SDK_INT < 24) releasePlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (Build.VERSION.SDK_INT >= 24) releasePlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (player == null && viewerPostModel != null && viewerPostModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO)
|
||||
setupVideo();
|
||||
else if (player != null) {
|
||||
player.setPlayWhenReady(true);
|
||||
player.getPlaybackState();
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshPost() {
|
||||
if (containerLayoutParams.weight != 3.3f) {
|
||||
containerLayoutParams.weight = (viewerBinding.mediaList.getVisibility() == View.VISIBLE) ? 1.35f : 1.9f;
|
||||
viewerBinding.container.setLayoutParams(containerLayoutParams);
|
||||
}
|
||||
if (viewerBinding.mediaList.getVisibility() == View.VISIBLE) {
|
||||
ViewerPostModel item = mediaAdapter.getItemAt(lastSlidePos);
|
||||
if (item != null) {
|
||||
item.setCurrentSlide(false);
|
||||
mediaAdapter.notifyItemChanged(lastSlidePos, item);
|
||||
}
|
||||
|
||||
item = mediaAdapter.getItemAt(slidePos);
|
||||
if (item != null) {
|
||||
item.setCurrentSlide(true);
|
||||
mediaAdapter.notifyItemChanged(slidePos, item);
|
||||
}
|
||||
}
|
||||
lastSlidePos = slidePos;
|
||||
|
||||
postCaption = viewerPostModel.getPostCaption();
|
||||
|
||||
if (Utils.hasMentions(postCaption)) {
|
||||
viewerBinding.bottomPanel.viewerCaption.setText(Utils.getMentionText(postCaption), TextView.BufferType.SPANNABLE);
|
||||
viewerBinding.bottomPanel.viewerCaption.setMentionClickListener((view, text, isHashtag) -> searchUsername(text));
|
||||
} else {
|
||||
viewerBinding.bottomPanel.viewerCaption.setMentionClickListener(null);
|
||||
viewerBinding.bottomPanel.viewerCaption.setText(postCaption);
|
||||
}
|
||||
|
||||
setupPostInfoBar("@"+viewerPostModel.getUsername(), viewerPostModel.getItemType(),
|
||||
viewerPostModel.getLocationName(), viewerPostModel.getLocation());
|
||||
|
||||
if (postModel instanceof PostModel) {
|
||||
final PostModel postModel = (PostModel) this.postModel;
|
||||
postModel.setPostId(viewerPostModel.getPostId());
|
||||
postModel.setTimestamp(viewerPostModel.getTimestamp());
|
||||
postModel.setPostCaption(viewerPostModel.getPostCaption());
|
||||
if (liked == true) {
|
||||
viewerBinding.btnLike.setText(resources.getString(R.string.unlike, viewerPostModel.getLikes()
|
||||
+ ((ok && viewerPostModel.getLike() != liked) ? (liked ? 1L : -1L) : 0L)));
|
||||
viewerBinding.btnLike.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
getApplicationContext(), R.color.btn_pink_background)));
|
||||
}
|
||||
else {
|
||||
viewerBinding.btnLike.setText(resources.getString(R.string.like, viewerPostModel.getLikes()
|
||||
+ ((ok && viewerPostModel.getLike() != liked) ? (liked ? 1L : -1L) : 0L)));
|
||||
viewerBinding.btnLike.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
getApplicationContext(), R.color.btn_lightpink_background)));
|
||||
}
|
||||
if (saved == true) {
|
||||
viewerBinding.btnBookmark.setText(R.string.unbookmark);
|
||||
viewerBinding.btnBookmark.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
getApplicationContext(), R.color.btn_orange_background)));
|
||||
}
|
||||
else {
|
||||
viewerBinding.btnBookmark.setText(R.string.bookmark);
|
||||
viewerBinding.btnBookmark.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
getApplicationContext(), R.color.btn_lightorange_background)));
|
||||
}
|
||||
}
|
||||
|
||||
viewerBinding.bottomPanel.tvPostDate.setText(viewerPostModel.getPostDate());
|
||||
viewerBinding.bottomPanel.tvPostDate.setVisibility(containerLayoutParams.weight != 3.3f ? View.VISIBLE : View.GONE);
|
||||
viewerBinding.bottomPanel.tvPostDate.setSelected(true);
|
||||
|
||||
url = viewerPostModel.getDisplayUrl();
|
||||
releasePlayer();
|
||||
|
||||
viewerBinding.btnDownload.setVisibility(containerLayoutParams.weight == 3.3f ? View.VISIBLE : View.GONE);
|
||||
if (viewerPostModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
|
||||
else setupImage();
|
||||
}
|
||||
|
||||
private void releasePlayer() {
|
||||
if (player != null) {
|
||||
player.release();
|
||||
player = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPostInfoBar(final String from, final MediaItemType mediaItemType, final String locationName, final String location) {
|
||||
if (prevUsername == null || !prevUsername.equals(from)) {
|
||||
viewerBinding.topPanel.ivProfilePic.setImageBitmap(null);
|
||||
viewerBinding.topPanel.ivProfilePic.setImageDrawable(null);
|
||||
viewerBinding.topPanel.ivProfilePic.setImageResource(0);
|
||||
|
||||
if (!Utils.isEmpty(from) && from.charAt(0) == '@')
|
||||
new ProfileFetcher(from.substring(1), result -> {
|
||||
profileModel = result;
|
||||
|
||||
if (result != null) {
|
||||
final String hdProfilePic = result.getHdProfilePic();
|
||||
final String sdProfilePic = result.getSdProfilePic();
|
||||
postUserId = result.getId();
|
||||
|
||||
final boolean hdPicEmpty = Utils.isEmpty(hdProfilePic);
|
||||
RequestListener<Drawable> profilePicListener = new RequestListener<Drawable>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable final GlideException e, final Object model, final Target<Drawable> target, final boolean isFirstResource) {
|
||||
viewerBinding.topPanel.ivProfilePic.setEnabled(false);
|
||||
viewerBinding.topPanel.ivProfilePic.setOnClickListener(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(final Drawable resource, final Object model, final Target<Drawable> target, final DataSource dataSource, final boolean isFirstResource) {
|
||||
viewerBinding.topPanel.ivProfilePic.setEnabled(true);
|
||||
viewerBinding.topPanel.ivProfilePic.setOnClickListener(onClickListener);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
glideRequestManager.load(hdPicEmpty ? sdProfilePic : hdProfilePic).listener(profilePicListener)
|
||||
.error(glideRequestManager.load(sdProfilePic).listener(profilePicListener)).into(viewerBinding.topPanel.ivProfilePic);
|
||||
|
||||
final View viewStoryPost = findViewById(R.id.viewStoryPost);
|
||||
if (viewStoryPost != null) {
|
||||
viewStoryPost.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (result.isPrivate())
|
||||
Toast.makeText(getApplicationContext(), R.string.share_private_post, Toast.LENGTH_LONG).show();
|
||||
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/plain");
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, "https://instagram.com/p/"+postModel.getShortCode());
|
||||
startActivity(Intent.createChooser(sharingIntent,
|
||||
(result.isPrivate()) ? getString(R.string.share_private_post) : getString(R.string.share_public_post)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
prevUsername = from;
|
||||
}
|
||||
|
||||
final String titlePrefix = resources.getString(mediaItemType == MediaItemType.MEDIA_TYPE_VIDEO ?
|
||||
R.string.post_viewer_video_post : R.string.post_viewer_image_post);
|
||||
if (Utils.isEmpty(from)) viewerBinding.topPanel.title.setText(titlePrefix);
|
||||
else {
|
||||
final int titleLen = from.length();
|
||||
final SpannableString spannableString = new SpannableString(from);
|
||||
spannableString.setSpan(new CommentMentionClickSpan(), 0, titleLen, 0);
|
||||
viewerBinding.topPanel.title.setText(spannableString);
|
||||
}
|
||||
|
||||
if (location == null) {
|
||||
viewerBinding.topPanel.location.setVisibility(View.GONE);
|
||||
viewerBinding.topPanel.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
}
|
||||
else {
|
||||
viewerBinding.topPanel.location.setVisibility(View.VISIBLE);
|
||||
viewerBinding.topPanel.location.setText(locationName);
|
||||
viewerBinding.topPanel.location.setOnClickListener(v -> searchUsername(location));
|
||||
viewerBinding.topPanel.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleFullscreen() {
|
||||
final View decorView = getWindow().getDecorView();
|
||||
int newUiOptions = decorView.getSystemUiVisibility();
|
||||
newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
|
||||
newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||
newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
decorView.setSystemUiVisibility(newUiOptions);
|
||||
}
|
||||
|
||||
class PostAction extends AsyncTask<String, Void, Void> {
|
||||
String action;
|
||||
|
||||
protected Void doInBackground(String... rawAction) {
|
||||
action = rawAction[0];
|
||||
final String url = "https://www.instagram.com/web/"+action+"/"+postModel.getPostId()+"/"+ (action == "save" ?
|
||||
(saved ? "unsave/" : "save/") :
|
||||
(liked ? "unlike/" : "like/"));
|
||||
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",
|
||||
settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
|
||||
urlConnection.connect();
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
ok = true;
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", action+": " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (ok == true && action == "likes") {
|
||||
liked = !liked;
|
||||
refreshPost();
|
||||
}
|
||||
else if (ok == true && action == "save") {
|
||||
saved = !saved;
|
||||
refreshPost();
|
||||
}
|
||||
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,211 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.asyncs.DownloadAsync;
|
||||
import awais.instagrabber.asyncs.ProfilePictureFetcher;
|
||||
import awais.instagrabber.databinding.ActivityProfilepicBinding;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.HashtagModel;
|
||||
import awais.instagrabber.models.LocationModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public final class ProfilePicViewer extends BaseLanguageActivity {
|
||||
private ActivityProfilepicBinding profileBinding;
|
||||
private ProfileModel profileModel;
|
||||
private HashtagModel hashtagModel;
|
||||
private LocationModel locationModel;
|
||||
private MenuItem menuItemDownload;
|
||||
private String profilePicUrl;
|
||||
private FragmentManager fragmentManager;
|
||||
private FetchListener<String> fetchListener;
|
||||
private boolean errorHandled = false;
|
||||
private boolean fallbackToProfile = false;
|
||||
private boolean destroyed = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
profileBinding = ActivityProfilepicBinding.inflate(getLayoutInflater());
|
||||
setContentView(profileBinding.getRoot());
|
||||
|
||||
setSupportActionBar(profileBinding.toolbar.toolbar);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null || (!intent.hasExtra(Constants.EXTRAS_PROFILE) && !intent.hasExtra(Constants.EXTRAS_HASHTAG) && !intent.hasExtra(Constants.EXTRAS_LOCATION))
|
||||
|| ((profileModel = (ProfileModel) intent.getSerializableExtra(Constants.EXTRAS_PROFILE)) == null
|
||||
&& (hashtagModel = (HashtagModel) intent.getSerializableExtra(Constants.EXTRAS_HASHTAG)) == null
|
||||
&& (locationModel = (LocationModel) intent.getSerializableExtra(Constants.EXTRAS_LOCATION)) == null)) {
|
||||
Utils.errorFinish(this);
|
||||
return;
|
||||
}
|
||||
|
||||
fragmentManager = getSupportFragmentManager();
|
||||
|
||||
final String id = hashtagModel != null ? hashtagModel.getId() : (locationModel != null ? locationModel.getId() : profileModel.getId());
|
||||
final String username = hashtagModel != null ? hashtagModel.getName() : (locationModel != null ? locationModel.getName() : profileModel.getUsername());
|
||||
|
||||
profileBinding.toolbar.toolbar.setTitle(username);
|
||||
|
||||
profileBinding.progressView.setVisibility(View.VISIBLE);
|
||||
profileBinding.imageViewer.setVisibility(View.VISIBLE);
|
||||
|
||||
profileBinding.imageViewer.setZoomable(true);
|
||||
profileBinding.imageViewer.setZoomTransitionDuration(420);
|
||||
profileBinding.imageViewer.setMaximumScale(7.2f);
|
||||
|
||||
fetchListener = profileUrl -> {
|
||||
profilePicUrl = profileUrl;
|
||||
|
||||
if (!fallbackToProfile && Utils.isEmpty(profilePicUrl)) {
|
||||
fallbackToProfile = true;
|
||||
new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorHandled && fallbackToProfile || Utils.isEmpty(profilePicUrl))
|
||||
profilePicUrl = hashtagModel != null ? hashtagModel.getSdProfilePic() : (locationModel != null ? locationModel.getSdProfilePic() : profileModel.getHdProfilePic());
|
||||
|
||||
if (destroyed == true) return;
|
||||
|
||||
final RequestManager glideRequestManager = Glide.with(this);
|
||||
|
||||
glideRequestManager.load(profilePicUrl).addListener(new RequestListener<Drawable>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable final GlideException e, final Object model, final Target<Drawable> target, final boolean isFirstResource) {
|
||||
fallbackToProfile = true;
|
||||
if (!errorHandled) {
|
||||
errorHandled = true;
|
||||
new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null))
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
profileBinding.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(final Drawable resource, final Object model, final Target<Drawable> target, final DataSource dataSource, final boolean isFirstResource) {
|
||||
if (menuItemDownload != null) menuItemDownload.setEnabled(true);
|
||||
showImageInfo();
|
||||
profileBinding.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void showImageInfo() {
|
||||
final Drawable drawable = profileBinding.imageViewer.getDrawable();
|
||||
if (drawable != null) {
|
||||
final StringBuilder info = new StringBuilder(getString(R.string.profile_viewer_imageinfo, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()));
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
|
||||
if (bitmap != null) {
|
||||
final String colorDepthPrefix = getString(R.string.profile_viewer_colordepth_prefix);
|
||||
switch (bitmap.getConfig()) {
|
||||
case ALPHA_8:
|
||||
info.append(colorDepthPrefix).append(" 8-bits(A)");
|
||||
break;
|
||||
case RGB_565:
|
||||
info.append(colorDepthPrefix).append(" 16-bits-A");
|
||||
break;
|
||||
case ARGB_4444:
|
||||
info.append(colorDepthPrefix).append(" 16-bits+A");
|
||||
break;
|
||||
case ARGB_8888:
|
||||
info.append(colorDepthPrefix).append(" 32-bits+A");
|
||||
break;
|
||||
case RGBA_F16:
|
||||
info.append(colorDepthPrefix).append(" 64-bits+A");
|
||||
break;
|
||||
case HARDWARE:
|
||||
info.append(colorDepthPrefix).append(" auto");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
profileBinding.imageInfo.setText(info);
|
||||
profileBinding.imageInfo.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}).error(glideRequestManager.load(profilePicUrl)).into(profileBinding.imageViewer);
|
||||
};
|
||||
|
||||
new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null))
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void downloadProfilePicture() {
|
||||
int error = 0;
|
||||
|
||||
if (profileModel != null) {
|
||||
final File dir = new File(Environment.getExternalStorageDirectory(), "Download");
|
||||
if (dir.exists() || dir.mkdirs()) {
|
||||
|
||||
final File saveFile = new File(dir, profileModel.getUsername() + '_' + System.currentTimeMillis()
|
||||
+ Utils.getExtensionFromModel(profilePicUrl, profileModel));
|
||||
|
||||
new DownloadAsync(this,
|
||||
profilePicUrl,
|
||||
saveFile,
|
||||
result -> {
|
||||
final int toastRes = result != null && result.exists() ?
|
||||
R.string.downloader_downloaded_in_folder : R.string.downloader_error_download_file;
|
||||
Toast.makeText(this, toastRes, Toast.LENGTH_SHORT).show();
|
||||
}).setItems(null, profileModel.getUsername()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else error = 1;
|
||||
} else error = 2;
|
||||
|
||||
if (error == 1) Toast.makeText(this, R.string.downloader_error_creating_folder, Toast.LENGTH_SHORT).show();
|
||||
else if (error == 2) Toast.makeText(this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
getDelegate().onDestroy();
|
||||
destroyed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu, menu);
|
||||
|
||||
final MenuItem.OnMenuItemClickListener menuItemClickListener = item -> {
|
||||
if (item == menuItemDownload) {
|
||||
downloadProfilePicture();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
menu.findItem(R.id.action_search).setVisible(false);
|
||||
menuItemDownload = menu.findItem(R.id.action_download);
|
||||
menuItemDownload.setVisible(true);
|
||||
menuItemDownload.setEnabled(false);
|
||||
menuItemDownload.setOnMenuItemClickListener(menuItemClickListener);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,930 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.RelativeSizeSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.HighlightsAdapter;
|
||||
import awais.instagrabber.adapters.PostsAdapter;
|
||||
import awais.instagrabber.asyncs.HashtagFetcher;
|
||||
import awais.instagrabber.asyncs.HighlightsFetcher;
|
||||
import awais.instagrabber.asyncs.LocationFetcher;
|
||||
import awais.instagrabber.asyncs.PostsFetcher;
|
||||
import awais.instagrabber.asyncs.ProfileFetcher;
|
||||
import awais.instagrabber.asyncs.i.iStoryStatusFetcher;
|
||||
import awais.instagrabber.customviews.RamboTextView;
|
||||
import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager;
|
||||
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration;
|
||||
import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
|
||||
import awais.instagrabber.databinding.ActivityProfileBinding;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.BasePostModel;
|
||||
import awais.instagrabber.models.HashtagModel;
|
||||
import awais.instagrabber.models.HighlightModel;
|
||||
import awais.instagrabber.models.LocationModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.enums.DownloadMethod;
|
||||
import awais.instagrabber.models.enums.ItemGetType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DataBox;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Constants.AUTOLOAD_POSTS;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class ProfileViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
|
||||
private final ArrayList<PostModel> allItems = new ArrayList<>(), selectedItems = new ArrayList<>();
|
||||
private static AsyncTask<?, ?, ?> currentlyExecuting;
|
||||
private final boolean autoloadPosts = Utils.settingsHelper.getBoolean(AUTOLOAD_POSTS);
|
||||
private boolean hasNextPage = false;
|
||||
private View collapsingToolbar;
|
||||
private String endCursor = null;
|
||||
private ProfileModel profileModel;
|
||||
private HashtagModel hashtagModel;
|
||||
private LocationModel locationModel;
|
||||
private StoryModel[] storyModels;
|
||||
private MenuItem downloadAction, favouriteAction;
|
||||
private final FetchListener<PostModel[]> postsFetchListener = new FetchListener<PostModel[]>() {
|
||||
@Override
|
||||
public void onResult(final PostModel[] result) {
|
||||
if (result != null) {
|
||||
final int oldSize = allItems.size();
|
||||
allItems.addAll(Arrays.asList(result));
|
||||
|
||||
postsAdapter.notifyItemRangeInserted(oldSize, result.length);
|
||||
|
||||
profileBinding.profileView.mainPosts.post(() -> {
|
||||
profileBinding.profileView.mainPosts.setNestedScrollingEnabled(true);
|
||||
profileBinding.profileView.mainPosts.setVisibility(View.VISIBLE);
|
||||
});
|
||||
|
||||
if (isHashtag)
|
||||
profileBinding.toolbar.toolbar.setTitle(userQuery);
|
||||
else if (isLocation)
|
||||
profileBinding.toolbar.toolbar.setTitle(locationModel.getName());
|
||||
else profileBinding.toolbar.toolbar.setTitle("@"+profileModel.getUsername());
|
||||
|
||||
final PostModel model = result[result.length - 1];
|
||||
if (model != null) {
|
||||
endCursor = model.getEndCursor();
|
||||
hasNextPage = model.hasNextPage();
|
||||
if (autoloadPosts && hasNextPage)
|
||||
currentlyExecuting = new PostsFetcher(
|
||||
profileModel != null ? profileModel.getId()
|
||||
: (hashtagModel != null ? ("#"+hashtagModel.getName()) : locationModel.getId()), endCursor, this)
|
||||
.setUsername((isLocation || isHashtag) ? null : profileModel.getUsername())
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
model.setPageCursor(false, null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
profileBinding.profileView.privatePage1.setImageResource(R.drawable.ic_cancel);
|
||||
profileBinding.profileView.privatePage2.setText(R.string.empty_acc);
|
||||
profileBinding.profileView.privatePage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final MentionClickListener mentionClickListener = new MentionClickListener() {
|
||||
@Override
|
||||
public void onClick(final RamboTextView view, final String text, final boolean isHashtag) {
|
||||
startActivity(new Intent(getApplicationContext(), ProfileViewer.class).putExtra(Constants.EXTRAS_USERNAME, text));
|
||||
}
|
||||
};
|
||||
public final HighlightsAdapter highlightsAdapter = new HighlightsAdapter(null, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof HighlightModel) {
|
||||
final HighlightModel highlightModel = (HighlightModel) tag;
|
||||
new iStoryStatusFetcher(highlightModel.getId(), null, false, false,
|
||||
(!isLoggedIn && Utils.settingsHelper.getBoolean(Constants.STORIESIG)), true, result -> {
|
||||
if (result != null && result.length > 0)
|
||||
startActivity(new Intent(ProfileViewer.this, StoryViewer.class)
|
||||
.putExtra(Constants.EXTRAS_USERNAME, userQuery.replace("@", ""))
|
||||
.putExtra(Constants.EXTRAS_HIGHLIGHT, highlightModel.getTitle())
|
||||
.putExtra(Constants.EXTRAS_STORIES, result)
|
||||
);
|
||||
else Toast.makeText(ProfileViewer.this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
});
|
||||
private Resources resources;
|
||||
private RecyclerLazyLoader lazyLoader;
|
||||
private boolean isHashtag, isUser, isLocation;
|
||||
private PostsAdapter postsAdapter;
|
||||
private String cookie = Utils.settingsHelper.getString(Constants.COOKIE), userQuery;
|
||||
public boolean isLoggedIn = !Utils.isEmpty(cookie);
|
||||
private ActivityProfileBinding profileBinding;
|
||||
private ArrayAdapter<String> profileDialogAdapter;
|
||||
private DialogInterface.OnClickListener profileDialogListener;
|
||||
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
stopCurrentExecutor();
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null || !intent.hasExtra(Constants.EXTRAS_USERNAME)
|
||||
|| Utils.isEmpty((userQuery = intent.getStringExtra(Constants.EXTRAS_USERNAME)))) {
|
||||
Utils.errorFinish(this);
|
||||
return;
|
||||
}
|
||||
|
||||
userQuery = (userQuery.contains("/") || userQuery.startsWith("#") || userQuery.startsWith("@")) ? userQuery : ("@"+userQuery);
|
||||
|
||||
profileBinding = ActivityProfileBinding.inflate(getLayoutInflater());
|
||||
setContentView(profileBinding.getRoot());
|
||||
|
||||
resources = getResources();
|
||||
|
||||
profileDialogAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
|
||||
new String[]{resources.getString(R.string.view_pfp), resources.getString(R.string.show_stories)});
|
||||
profileDialogListener = (dialog, which) -> {
|
||||
final Intent newintent;
|
||||
if (which == 0 || storyModels == null || storyModels.length < 1) {
|
||||
newintent = new Intent(this, ProfilePicViewer.class).putExtra(
|
||||
((hashtagModel != null) ? Constants.EXTRAS_HASHTAG : (locationModel != null ? Constants.EXTRAS_LOCATION : Constants.EXTRAS_PROFILE)),
|
||||
((hashtagModel != null) ? hashtagModel : (locationModel != null ? locationModel : profileModel)));
|
||||
}
|
||||
else newintent = new Intent(this, StoryViewer.class).putExtra(Constants.EXTRAS_USERNAME, userQuery.replace("@", ""))
|
||||
.putExtra(Constants.EXTRAS_STORIES, storyModels)
|
||||
.putExtra(Constants.EXTRAS_HASHTAG, (hashtagModel != null));
|
||||
startActivity(newintent);
|
||||
};
|
||||
|
||||
profileBinding.profileView.swipeRefreshLayout.setOnRefreshListener(this);
|
||||
profileBinding.profileView.mainUrl.setMovementMethod(new LinkMovementMethod());
|
||||
|
||||
isLoggedIn = !Utils.isEmpty(cookie);
|
||||
|
||||
collapsingToolbar = profileBinding.profileView.appBarLayout.getChildAt(0);
|
||||
|
||||
profileBinding.profileView.mainPosts.setNestedScrollingEnabled(false);
|
||||
profileBinding.profileView.highlightsList.setLayoutManager(
|
||||
new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
profileBinding.profileView.highlightsList.setAdapter(highlightsAdapter);
|
||||
|
||||
setSupportActionBar(profileBinding.toolbar.toolbar);
|
||||
|
||||
// change the next number to adjust grid
|
||||
final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(ProfileViewer.this, Utils.convertDpToPx(110));
|
||||
profileBinding.profileView.mainPosts.setLayoutManager(layoutManager);
|
||||
profileBinding.profileView.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4)));
|
||||
profileBinding.profileView.mainPosts.setAdapter(postsAdapter = new PostsAdapter(allItems, v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof PostModel) {
|
||||
final PostModel postModel = (PostModel) tag;
|
||||
|
||||
if (postsAdapter.isSelecting) toggleSelection(postModel);
|
||||
else startActivity(new Intent(ProfileViewer.this, PostViewer.class)
|
||||
.putExtra(Constants.EXTRAS_INDEX, postModel.getPosition())
|
||||
.putExtra(Constants.EXTRAS_POST, postModel)
|
||||
.putExtra(Constants.EXTRAS_USER, userQuery)
|
||||
.putExtra(Constants.EXTRAS_TYPE, ItemGetType.MAIN_ITEMS));
|
||||
}
|
||||
}, v -> { // long click listener
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof PostModel) {
|
||||
postsAdapter.isSelecting = true;
|
||||
toggleSelection((PostModel) tag);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
this.lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> {
|
||||
if ((!autoloadPosts || isHashtag) && hasNextPage) {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(true);
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new PostsFetcher(profileModel != null ? profileModel.getId()
|
||||
: (hashtagModel != null ? ("#"+hashtagModel.getName()) : locationModel.getId()), endCursor, postsFetchListener)
|
||||
.setUsername((isHashtag || isLocation) ? null : profileModel.getUsername())
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
endCursor = null;
|
||||
}
|
||||
});
|
||||
profileBinding.profileView.mainPosts.addOnScrollListener(lazyLoader);
|
||||
|
||||
final View.OnClickListener onClickListener = v -> {
|
||||
if (v == profileBinding.profileView.mainBiography) {
|
||||
Utils.copyText(this, profileBinding.profileView.mainBiography.getText().toString());
|
||||
} else if (v == profileBinding.profileView.locationBiography) {
|
||||
Utils.copyText(this, profileBinding.profileView.locationBiography.getText().toString());
|
||||
} else if (v == profileBinding.profileView.mainProfileImage || v == profileBinding.profileView.mainHashtagImage || v == profileBinding.profileView.mainLocationImage) {
|
||||
if (storyModels == null || storyModels.length <= 0) {
|
||||
profileDialogListener.onClick(null, 0);
|
||||
} else {
|
||||
// because sometimes configuration changes made this crash on some phones
|
||||
new AlertDialog.Builder(this).setAdapter(profileDialogAdapter, profileDialogListener)
|
||||
.setNeutralButton(R.string.cancel, null).show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
profileBinding.profileView.mainBiography.setOnClickListener(onClickListener);
|
||||
profileBinding.profileView.locationBiography.setOnClickListener(onClickListener);
|
||||
profileBinding.profileView.mainProfileImage.setOnClickListener(onClickListener);
|
||||
profileBinding.profileView.mainHashtagImage.setOnClickListener(onClickListener);
|
||||
profileBinding.profileView.mainLocationImage.setOnClickListener(onClickListener);
|
||||
|
||||
this.onRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
if (lazyLoader != null) lazyLoader.resetState();
|
||||
stopCurrentExecutor();
|
||||
allItems.clear();
|
||||
selectedItems.clear();
|
||||
if (postsAdapter != null) {
|
||||
postsAdapter.isSelecting = false;
|
||||
postsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
profileBinding.profileView.appBarLayout.setExpanded(true, true);
|
||||
profileBinding.profileView.privatePage.setVisibility(View.GONE);
|
||||
profileBinding.profileView.privatePage2.setTextSize(28);
|
||||
profileBinding.profileView.mainProfileImage.setImageBitmap(null);
|
||||
profileBinding.profileView.mainHashtagImage.setImageBitmap(null);
|
||||
profileBinding.profileView.mainLocationImage.setImageBitmap(null);
|
||||
profileBinding.profileView.mainUrl.setText(null);
|
||||
profileBinding.profileView.locationUrl.setText(null);
|
||||
profileBinding.profileView.mainFullName.setText(null);
|
||||
profileBinding.profileView.locationFullName.setText(null);
|
||||
profileBinding.profileView.mainPostCount.setText(null);
|
||||
profileBinding.profileView.mainLocPostCount.setText(null);
|
||||
profileBinding.profileView.mainTagPostCount.setText(null);
|
||||
profileBinding.profileView.mainFollowers.setText(null);
|
||||
profileBinding.profileView.mainFollowing.setText(null);
|
||||
profileBinding.profileView.mainBiography.setText(null);
|
||||
profileBinding.profileView.locationBiography.setText(null);
|
||||
profileBinding.profileView.mainBiography.setEnabled(false);
|
||||
profileBinding.profileView.locationBiography.setEnabled(false);
|
||||
profileBinding.profileView.mainProfileImage.setEnabled(false);
|
||||
profileBinding.profileView.mainLocationImage.setEnabled(false);
|
||||
profileBinding.profileView.mainHashtagImage.setEnabled(false);
|
||||
profileBinding.profileView.mainBiography.setMentionClickListener(null);
|
||||
profileBinding.profileView.locationBiography.setMentionClickListener(null);
|
||||
profileBinding.profileView.mainUrl.setVisibility(View.GONE);
|
||||
profileBinding.profileView.locationUrl.setVisibility(View.GONE);
|
||||
profileBinding.profileView.isVerified.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnFollow.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnRestrict.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnBlock.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnSaved.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnLiked.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnTagged.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnMap.setVisibility(View.GONE);
|
||||
|
||||
profileBinding.profileView.btnFollow.setOnClickListener(profileActionListener);
|
||||
profileBinding.profileView.btnRestrict.setOnClickListener(profileActionListener);
|
||||
profileBinding.profileView.btnBlock.setOnClickListener(profileActionListener);
|
||||
profileBinding.profileView.btnSaved.setOnClickListener(profileActionListener);
|
||||
profileBinding.profileView.btnLiked.setOnClickListener(profileActionListener);
|
||||
profileBinding.profileView.btnTagged.setOnClickListener(profileActionListener);
|
||||
profileBinding.profileView.btnFollowTag.setOnClickListener(profileActionListener);
|
||||
|
||||
profileBinding.profileView.infoContainer.setVisibility(View.GONE);
|
||||
profileBinding.profileView.tagInfoContainer.setVisibility(View.GONE);
|
||||
profileBinding.profileView.locInfoContainer.setVisibility(View.GONE);
|
||||
|
||||
profileBinding.profileView.mainPosts.setNestedScrollingEnabled(false);
|
||||
profileBinding.profileView.highlightsList.setVisibility(View.GONE);
|
||||
collapsingToolbar.setVisibility(View.GONE);
|
||||
highlightsAdapter.setData(null);
|
||||
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(userQuery != null);
|
||||
if (userQuery == null) {
|
||||
profileBinding.toolbar.toolbar.setTitle(R.string.app_name);
|
||||
return;
|
||||
}
|
||||
|
||||
isHashtag = userQuery.charAt(0) == '#';
|
||||
isUser = userQuery.charAt(0) == '@';
|
||||
isLocation = userQuery.contains("/");
|
||||
collapsingToolbar.setVisibility(isUser ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (isHashtag) {
|
||||
profileModel = null;
|
||||
locationModel = null;
|
||||
profileBinding.toolbar.toolbar.setTitle(userQuery);
|
||||
profileBinding.profileView.tagInfoContainer.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnFollowTag.setVisibility(View.GONE);
|
||||
|
||||
currentlyExecuting = new HashtagFetcher(userQuery.substring(1), result -> {
|
||||
hashtagModel = result;
|
||||
|
||||
if (hashtagModel == null) {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
Toast.makeText(ProfileViewer.this, R.string.error_loading_profile, Toast.LENGTH_SHORT).show();
|
||||
profileBinding.toolbar.toolbar.setTitle(R.string.app_name);
|
||||
return;
|
||||
}
|
||||
|
||||
currentlyExecuting = new PostsFetcher(userQuery, postsFetchListener)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
||||
profileBinding.profileView.btnFollowTag.setVisibility(View.VISIBLE);
|
||||
|
||||
if (isLoggedIn) {
|
||||
new iStoryStatusFetcher(hashtagModel.getName(), null, false, true, false, false, stories -> {
|
||||
storyModels = stories;
|
||||
if (stories != null && stories.length > 0) profileBinding.profileView.mainHashtagImage.setStoriesBorder();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
||||
if (hashtagModel.getFollowing() == true) {
|
||||
profileBinding.profileView.btnFollowTag.setText(R.string.unfollow);
|
||||
profileBinding.profileView.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_purple_background)));
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.btnFollowTag.setText(R.string.follow);
|
||||
profileBinding.profileView.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_pink_background)));
|
||||
}
|
||||
} else {
|
||||
if (Utils.dataBox.getFavorite(userQuery) != null) {
|
||||
profileBinding.profileView.btnFollowTag.setText(R.string.unfavorite_short);
|
||||
profileBinding.profileView.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_purple_background)));
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.btnFollowTag.setText(R.string.favorite_short);
|
||||
profileBinding.profileView.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_pink_background)));
|
||||
}
|
||||
}
|
||||
|
||||
profileBinding.profileView.mainHashtagImage.setEnabled(false);
|
||||
new MyTask().execute();
|
||||
profileBinding.profileView.mainHashtagImage.setEnabled(true);
|
||||
|
||||
final String postCount = String.valueOf(hashtagModel.getPostCount());
|
||||
|
||||
SpannableStringBuilder span = new SpannableStringBuilder(resources.getString(R.string.main_posts_count, postCount));
|
||||
span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0);
|
||||
span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0);
|
||||
profileBinding.profileView.mainTagPostCount.setText(span);
|
||||
profileBinding.profileView.mainTagPostCount.setVisibility(View.VISIBLE);
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else if (isUser) {
|
||||
hashtagModel = null;
|
||||
locationModel = null;
|
||||
profileBinding.toolbar.toolbar.setTitle(userQuery);
|
||||
profileBinding.profileView.infoContainer.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnFollowTag.setVisibility(View.GONE);
|
||||
|
||||
currentlyExecuting = new ProfileFetcher(userQuery.substring(1), result -> {
|
||||
profileModel = result;
|
||||
|
||||
if (profileModel == null) {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
Toast.makeText(ProfileViewer.this, R.string.error_loading_profile, Toast.LENGTH_SHORT).show();
|
||||
profileBinding.toolbar.toolbar.setTitle(R.string.app_name);
|
||||
return;
|
||||
}
|
||||
|
||||
profileBinding.profileView.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE);
|
||||
final String profileId = profileModel.getId();
|
||||
|
||||
if (isLoggedIn || Utils.settingsHelper.getBoolean(Constants.STORIESIG)) {
|
||||
new iStoryStatusFetcher(profileId, profileModel.getUsername(), false, false,
|
||||
(!isLoggedIn && Utils.settingsHelper.getBoolean(Constants.STORIESIG)), false,
|
||||
stories -> {
|
||||
storyModels = stories;
|
||||
if (stories != null && stories.length > 0) profileBinding.profileView.mainProfileImage.setStoriesBorder();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
||||
new HighlightsFetcher(profileId, (!isLoggedIn && Utils.settingsHelper.getBoolean(Constants.STORIESIG)), hls -> {
|
||||
if (hls != null && hls.length > 0) {
|
||||
profileBinding.profileView.highlightsList.setVisibility(View.VISIBLE);
|
||||
highlightsAdapter.setData(hls);
|
||||
}
|
||||
else profileBinding.profileView.highlightsList.setVisibility(View.GONE);
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
if (isLoggedIn) {
|
||||
final String myId = Utils.getUserIdFromCookie(cookie);
|
||||
if (!profileId.equals(myId)) {
|
||||
profileBinding.profileView.btnTagged.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnSaved.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnLiked.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnFollow.setVisibility(View.VISIBLE);
|
||||
if (profileModel.getFollowing() == true) {
|
||||
profileBinding.profileView.btnFollow.setText(R.string.unfollow);
|
||||
profileBinding.profileView.btnFollow.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_purple_background)));
|
||||
}
|
||||
else if (profileModel.getRequested() == true) {
|
||||
profileBinding.profileView.btnFollow.setText(R.string.cancel);
|
||||
profileBinding.profileView.btnFollow.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_purple_background)));
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.btnFollow.setText(R.string.follow);
|
||||
profileBinding.profileView.btnFollow.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_pink_background)));
|
||||
}
|
||||
profileBinding.profileView.btnRestrict.setVisibility(View.VISIBLE);
|
||||
if (profileModel.getRestricted() == true) {
|
||||
profileBinding.profileView.btnRestrict.setText(R.string.unrestrict);
|
||||
profileBinding.profileView.btnRestrict.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_green_background)));
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.btnRestrict.setText(R.string.restrict);
|
||||
profileBinding.profileView.btnRestrict.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_orange_background)));
|
||||
}
|
||||
if (profileModel.isReallyPrivate()) {
|
||||
profileBinding.profileView.btnBlock.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnTagged.setVisibility(View.GONE);
|
||||
if (profileModel.getBlocked() == true) {
|
||||
profileBinding.profileView.btnBlock.setText(R.string.unblock);
|
||||
profileBinding.profileView.btnBlock.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_green_background)));
|
||||
} else {
|
||||
profileBinding.profileView.btnBlock.setText(R.string.block);
|
||||
profileBinding.profileView.btnBlock.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_red_background)));
|
||||
}
|
||||
} else {
|
||||
profileBinding.profileView.btnBlock.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnSaved.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnTagged.setVisibility(View.VISIBLE);
|
||||
if (profileModel.getBlocked() == true) {
|
||||
profileBinding.profileView.btnSaved.setText(R.string.unblock);
|
||||
profileBinding.profileView.btnSaved.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_green_background)));
|
||||
} else {
|
||||
profileBinding.profileView.btnSaved.setText(R.string.block);
|
||||
profileBinding.profileView.btnSaved.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_red_background)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.btnTagged.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnSaved.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnLiked.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnSaved.setText(R.string.saved);
|
||||
profileBinding.profileView.btnSaved.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_orange_background)));
|
||||
}
|
||||
} else {
|
||||
if (Utils.dataBox.getFavorite(userQuery) != null) {
|
||||
profileBinding.profileView.btnFollow.setText(R.string.unfavorite_short);
|
||||
profileBinding.profileView.btnFollow.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_purple_background)));
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.btnFollow.setText(R.string.favorite_short);
|
||||
profileBinding.profileView.btnFollow.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_pink_background)));
|
||||
}
|
||||
profileBinding.profileView.btnFollow.setVisibility(View.VISIBLE);
|
||||
if (!profileModel.isReallyPrivate()) {
|
||||
profileBinding.profileView.btnRestrict.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnRestrict.setText(R.string.tagged);
|
||||
profileBinding.profileView.btnRestrict.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(
|
||||
ProfileViewer.this, R.color.btn_blue_background)));
|
||||
}
|
||||
}
|
||||
|
||||
profileBinding.profileView.mainProfileImage.setEnabled(false);
|
||||
new MyTask().execute();
|
||||
profileBinding.profileView.mainProfileImage.setEnabled(true);
|
||||
|
||||
final long followersCount = profileModel.getFollowersCount();
|
||||
final long followingCount = profileModel.getFollowingCount();
|
||||
|
||||
final String postCount = String.valueOf(profileModel.getPostCount());
|
||||
|
||||
SpannableStringBuilder span = new SpannableStringBuilder(resources.getString(R.string.main_posts_count, postCount));
|
||||
span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0);
|
||||
span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0);
|
||||
profileBinding.profileView.mainPostCount.setText(span);
|
||||
|
||||
final String followersCountStr = String.valueOf(followersCount);
|
||||
final int followersCountStrLen = followersCountStr.length();
|
||||
span = new SpannableStringBuilder(resources.getString(R.string.main_posts_followers, followersCountStr));
|
||||
span.setSpan(new RelativeSizeSpan(1.2f), 0, followersCountStrLen, 0);
|
||||
span.setSpan(new StyleSpan(Typeface.BOLD), 0, followersCountStrLen, 0);
|
||||
profileBinding.profileView.mainFollowers.setText(span);
|
||||
|
||||
final String followingCountStr = String.valueOf(followingCount);
|
||||
final int followingCountStrLen = followingCountStr.length();
|
||||
span = new SpannableStringBuilder(resources.getString(R.string.main_posts_following, followingCountStr));
|
||||
span.setSpan(new RelativeSizeSpan(1.2f), 0, followingCountStrLen, 0);
|
||||
span.setSpan(new StyleSpan(Typeface.BOLD), 0, followingCountStrLen, 0);
|
||||
profileBinding.profileView.mainFollowing.setText(span);
|
||||
|
||||
profileBinding.profileView.mainFullName.setText(Utils.isEmpty(profileModel.getName()) ? profileModel.getUsername() : profileModel.getName());
|
||||
|
||||
CharSequence biography = profileModel.getBiography();
|
||||
profileBinding.profileView.mainBiography.setCaptionIsExpandable(true);
|
||||
profileBinding.profileView.mainBiography.setCaptionIsExpanded(true);
|
||||
if (Utils.hasMentions(biography)) {
|
||||
biography = Utils.getMentionText(biography);
|
||||
profileBinding.profileView.mainBiography.setText(biography, TextView.BufferType.SPANNABLE);
|
||||
profileBinding.profileView.mainBiography.setMentionClickListener(mentionClickListener);
|
||||
} else {
|
||||
profileBinding.profileView.mainBiography.setText(biography);
|
||||
profileBinding.profileView.mainBiography.setMentionClickListener(null);
|
||||
}
|
||||
|
||||
final String url = profileModel.getUrl();
|
||||
if (Utils.isEmpty(url)) {
|
||||
profileBinding.profileView.mainUrl.setVisibility(View.GONE);
|
||||
} else {
|
||||
profileBinding.profileView.mainUrl.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.mainUrl.setText(Utils.getSpannableUrl(url));
|
||||
}
|
||||
|
||||
profileBinding.profileView.mainFullName.setSelected(true);
|
||||
profileBinding.profileView.mainBiography.setEnabled(true);
|
||||
|
||||
if (!profileModel.isReallyPrivate()) {
|
||||
profileBinding.profileView.mainFollowing.setClickable(true);
|
||||
profileBinding.profileView.mainFollowers.setClickable(true);
|
||||
|
||||
if (isLoggedIn) {
|
||||
final View.OnClickListener followClickListener = v -> startActivity(new Intent(ProfileViewer.this, FollowViewer.class)
|
||||
.putExtra(Constants.EXTRAS_FOLLOWERS, v == profileBinding.profileView.mainFollowers)
|
||||
.putExtra(Constants.EXTRAS_NAME, profileModel.getUsername())
|
||||
.putExtra(Constants.EXTRAS_ID, profileId));
|
||||
|
||||
profileBinding.profileView.mainFollowers.setOnClickListener(followersCount > 0 ? followClickListener : null);
|
||||
profileBinding.profileView.mainFollowing.setOnClickListener(followingCount > 0 ? followClickListener : null);
|
||||
}
|
||||
|
||||
if (profileModel.getPostCount() == 0) {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
profileBinding.profileView.privatePage1.setImageResource(R.drawable.ic_cancel);
|
||||
profileBinding.profileView.privatePage2.setText(R.string.empty_acc);
|
||||
profileBinding.profileView.privatePage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(true);
|
||||
profileBinding.profileView.mainPosts.setVisibility(View.VISIBLE);
|
||||
currentlyExecuting = new PostsFetcher(profileId, postsFetchListener).setUsername(profileModel.getUsername())
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
} else {
|
||||
profileBinding.profileView.mainFollowers.setClickable(false);
|
||||
profileBinding.profileView.mainFollowing.setClickable(false);
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
// error
|
||||
profileBinding.profileView.privatePage1.setImageResource(R.drawable.lock);
|
||||
profileBinding.profileView.privatePage2.setText(R.string.priv_acc);
|
||||
profileBinding.profileView.privatePage.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.mainPosts.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
else if (isLocation) {
|
||||
profileModel = null;
|
||||
hashtagModel = null;
|
||||
profileBinding.toolbar.toolbar.setTitle(userQuery);
|
||||
profileBinding.profileView.locInfoContainer.setVisibility(View.VISIBLE);
|
||||
|
||||
currentlyExecuting = new LocationFetcher(userQuery.split("/")[0], result -> {
|
||||
locationModel = result;
|
||||
|
||||
if (locationModel == null) {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
Toast.makeText(ProfileViewer.this, R.string.error_loading_profile, Toast.LENGTH_SHORT).show();
|
||||
profileBinding.toolbar.toolbar.setTitle(R.string.app_name);
|
||||
return;
|
||||
}
|
||||
profileBinding.toolbar.toolbar.setTitle(locationModel.getName());
|
||||
|
||||
final String profileId = locationModel.getId();
|
||||
|
||||
if (isLoggedIn) {
|
||||
new iStoryStatusFetcher(profileId.split("/")[0], null, true, false, false, false, stories -> {
|
||||
storyModels = stories;
|
||||
if (stories != null && stories.length > 0) profileBinding.profileView.mainLocationImage.setStoriesBorder();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
profileBinding.profileView.mainLocationImage.setEnabled(false);
|
||||
new MyTask().execute();
|
||||
profileBinding.profileView.mainLocationImage.setEnabled(true);
|
||||
|
||||
final String postCount = String.valueOf(locationModel.getPostCount());
|
||||
|
||||
SpannableStringBuilder span = new SpannableStringBuilder(resources.getString(R.string.main_posts_count, postCount));
|
||||
span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0);
|
||||
span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0);
|
||||
profileBinding.profileView.mainLocPostCount.setText(span);
|
||||
|
||||
profileBinding.profileView.locationFullName.setText(locationModel.getName());
|
||||
|
||||
CharSequence biography = locationModel.getBio();
|
||||
profileBinding.profileView.locationBiography.setCaptionIsExpandable(true);
|
||||
profileBinding.profileView.locationBiography.setCaptionIsExpanded(true);
|
||||
|
||||
if (Utils.isEmpty(biography)) {
|
||||
profileBinding.profileView.locationBiography.setVisibility(View.GONE);
|
||||
}
|
||||
else if (Utils.hasMentions(biography)) {
|
||||
profileBinding.profileView.locationBiography.setVisibility(View.VISIBLE);
|
||||
biography = Utils.getMentionText(biography);
|
||||
profileBinding.profileView.locationBiography.setText(biography, TextView.BufferType.SPANNABLE);
|
||||
profileBinding.profileView.locationBiography.setMentionClickListener(mentionClickListener);
|
||||
} else {
|
||||
profileBinding.profileView.locationBiography.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.locationBiography.setText(biography);
|
||||
profileBinding.profileView.locationBiography.setMentionClickListener(null);
|
||||
}
|
||||
|
||||
if (!locationModel.getGeo().startsWith("geo:0.0,0.0?z=17")) {
|
||||
profileBinding.profileView.btnMap.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.btnMap.setOnClickListener(v -> {
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(locationModel.getGeo()));
|
||||
startActivity(intent);
|
||||
});
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.btnMap.setVisibility(View.GONE);
|
||||
profileBinding.profileView.btnMap.setOnClickListener(null);
|
||||
}
|
||||
|
||||
final String url = locationModel.getUrl();
|
||||
if (Utils.isEmpty(url)) {
|
||||
profileBinding.profileView.locationUrl.setVisibility(View.GONE);
|
||||
} else if (!url.startsWith("http")) {
|
||||
profileBinding.profileView.locationUrl.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.locationUrl.setText(Utils.getSpannableUrl("http://"+url));
|
||||
} else {
|
||||
profileBinding.profileView.locationUrl.setVisibility(View.VISIBLE);
|
||||
profileBinding.profileView.locationUrl.setText(Utils.getSpannableUrl(url));
|
||||
}
|
||||
|
||||
profileBinding.profileView.locationFullName.setSelected(true);
|
||||
profileBinding.profileView.locationBiography.setEnabled(true);
|
||||
|
||||
if (locationModel.getPostCount() == 0) {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(false);
|
||||
profileBinding.profileView.privatePage1.setImageResource(R.drawable.ic_cancel);
|
||||
profileBinding.profileView.privatePage2.setText(R.string.empty_acc);
|
||||
profileBinding.profileView.privatePage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
profileBinding.profileView.swipeRefreshLayout.setRefreshing(true);
|
||||
profileBinding.profileView.mainPosts.setVisibility(View.VISIBLE);
|
||||
currentlyExecuting = new PostsFetcher(profileId, postsFetchListener)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopCurrentExecutor() {
|
||||
if (currentlyExecuting != null) {
|
||||
try {
|
||||
currentlyExecuting.cancel(true);
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.saved, menu);
|
||||
|
||||
downloadAction = menu.findItem(R.id.downloadAction);
|
||||
downloadAction.setVisible(false);
|
||||
|
||||
favouriteAction = menu.findItem(R.id.favouriteAction);
|
||||
favouriteAction.setVisible(!Utils.isEmpty(cookie));
|
||||
favouriteAction.setIcon(Utils.dataBox.getFavorite(userQuery) == null ? R.drawable.ic_not_liked : R.drawable.ic_like);
|
||||
|
||||
downloadAction.setOnMenuItemClickListener(item -> {
|
||||
if (selectedItems.size() > 0) {
|
||||
Utils.batchDownload(this, userQuery, DownloadMethod.DOWNLOAD_MAIN, selectedItems);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
favouriteAction.setOnMenuItemClickListener(item -> {
|
||||
if (Utils.dataBox.getFavorite(userQuery) == null) {
|
||||
Utils.dataBox.addFavorite(new DataBox.FavoriteModel(userQuery, System.currentTimeMillis(),
|
||||
locationModel != null ? locationModel.getName() : userQuery.replaceAll("^@", "")));
|
||||
favouriteAction.setIcon(R.drawable.ic_like);
|
||||
}
|
||||
else {
|
||||
Utils.dataBox.delFavorite(new DataBox.FavoriteModel(userQuery,
|
||||
Long.parseLong(Utils.dataBox.getFavorite(userQuery).split("/")[1]),
|
||||
locationModel != null ? locationModel.getName() : userQuery.replaceAll("^@", "")));
|
||||
favouriteAction.setIcon(R.drawable.ic_not_liked);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void toggleSelection(final PostModel postModel) {
|
||||
if (postModel != null && postsAdapter != null) {
|
||||
if (postModel.isSelected()) selectedItems.remove(postModel);
|
||||
else if (selectedItems.size() >= 100) {
|
||||
Toast.makeText(ProfileViewer.this, R.string.downloader_too_many, Toast.LENGTH_SHORT);
|
||||
return;
|
||||
}
|
||||
else selectedItems.add(postModel);
|
||||
postModel.setSelected(!postModel.isSelected());
|
||||
notifyAdapter(postModel);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyAdapter(final PostModel postModel) {
|
||||
if (selectedItems.size() < 1) postsAdapter.isSelecting = false;
|
||||
if (postModel.getPosition() < 0) postsAdapter.notifyDataSetChanged();
|
||||
else postsAdapter.notifyItemChanged(postModel.getPosition(), postModel);
|
||||
|
||||
if (downloadAction != null) downloadAction.setVisible(postsAdapter.isSelecting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED && selectedItems.size() > 0)
|
||||
Utils.batchDownload(this, userQuery, DownloadMethod.DOWNLOAD_MAIN, selectedItems);
|
||||
}
|
||||
|
||||
public void deselectSelection(final BasePostModel postModel) {
|
||||
if (postModel instanceof PostModel) {
|
||||
selectedItems.remove(postModel);
|
||||
postModel.setSelected(false);
|
||||
if (postsAdapter != null) notifyAdapter((PostModel) postModel);
|
||||
}
|
||||
}
|
||||
|
||||
class MyTask extends AsyncTask<Void, Bitmap, Void> {
|
||||
private Bitmap mIcon_val;
|
||||
|
||||
protected Void doInBackground(Void... voids) {
|
||||
try {
|
||||
mIcon_val = BitmapFactory.decodeStream((InputStream) new URL(
|
||||
(hashtagModel != null) ? hashtagModel.getSdProfilePic() : (
|
||||
(locationModel != null) ? locationModel.getSdProfilePic() :
|
||||
profileModel.getSdProfilePic())
|
||||
).getContent());
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "bitmap: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (hashtagModel != null) profileBinding.profileView.mainHashtagImage.setImageBitmap(mIcon_val);
|
||||
else if (locationModel != null) profileBinding.profileView.mainLocationImage.setImageBitmap(mIcon_val);
|
||||
else profileBinding.profileView.mainProfileImage.setImageBitmap(mIcon_val);
|
||||
}
|
||||
}
|
||||
|
||||
private final View.OnClickListener profileActionListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
final boolean iamme = (isLoggedIn && profileModel != null) && Utils.getUserIdFromCookie(cookie).equals(profileModel.getId());
|
||||
if (!isLoggedIn && Utils.dataBox.getFavorite(userQuery) != null && v == profileBinding.profileView.btnFollow) {
|
||||
Utils.dataBox.delFavorite(new DataBox.FavoriteModel(userQuery,
|
||||
Long.parseLong(Utils.dataBox.getFavorite(userQuery).split("/")[1]),
|
||||
locationModel != null ? locationModel.getName() : userQuery.replaceAll("^@", "")));
|
||||
onRefresh();
|
||||
} else if (!isLoggedIn && (v == profileBinding.profileView.btnFollow || v == profileBinding.profileView.btnFollowTag)) {
|
||||
Utils.dataBox.addFavorite(new DataBox.FavoriteModel(userQuery, System.currentTimeMillis(),
|
||||
locationModel != null ? locationModel.getName() : userQuery.replaceAll("^@", "")));
|
||||
onRefresh();
|
||||
} else if (v == profileBinding.profileView.btnFollow) {
|
||||
new ProfileAction().execute("follow");
|
||||
} else if (v == profileBinding.profileView.btnRestrict && isLoggedIn) {
|
||||
new ProfileAction().execute("restrict");
|
||||
} else if (v == profileBinding.profileView.btnSaved && !iamme) {
|
||||
new ProfileAction().execute("block");
|
||||
} else if (v == profileBinding.profileView.btnFollowTag) {
|
||||
new ProfileAction().execute("followtag");
|
||||
} else if (v == profileBinding.profileView.btnTagged || (v == profileBinding.profileView.btnRestrict && !isLoggedIn)) {
|
||||
startActivity(new Intent(ProfileViewer.this, SavedViewer.class)
|
||||
.putExtra(Constants.EXTRAS_INDEX, "%"+profileModel.getId())
|
||||
.putExtra(Constants.EXTRAS_USER, "@"+profileModel.getUsername())
|
||||
);
|
||||
} else if (v == profileBinding.profileView.btnSaved) {
|
||||
startActivity(new Intent(ProfileViewer.this, SavedViewer.class)
|
||||
.putExtra(Constants.EXTRAS_INDEX, "$"+profileModel.getId())
|
||||
.putExtra(Constants.EXTRAS_USER, "@"+profileModel.getUsername())
|
||||
);
|
||||
} else if (v == profileBinding.profileView.btnLiked) {
|
||||
startActivity(new Intent(ProfileViewer.this, SavedViewer.class)
|
||||
.putExtra(Constants.EXTRAS_INDEX, "^"+profileModel.getId())
|
||||
.putExtra(Constants.EXTRAS_USER, "@"+profileModel.getUsername())
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ProfileAction extends AsyncTask<String, Void, Void> {
|
||||
boolean ok = false;
|
||||
String action;
|
||||
|
||||
protected Void doInBackground(String... rawAction) {
|
||||
action = rawAction[0];
|
||||
final String url = "https://www.instagram.com/web/"+
|
||||
((action == "followtag" && hashtagModel != null) ? ("tags/"+
|
||||
(hashtagModel.getFollowing() == true ? "unfollow/" : "follow/")+hashtagModel.getName()+"/") : (
|
||||
((action == "restrict" && profileModel != null) ? "restrict_action" : ("friendships/"+profileModel.getId()))+"/"+
|
||||
((action == "follow" && profileModel != null) ?
|
||||
((profileModel.getFollowing() == true ||
|
||||
(profileModel.getFollowing() == false && profileModel.getRequested() == true))
|
||||
? "unfollow/" : "follow/") :
|
||||
((action == "restrict" && profileModel != null) ?
|
||||
(profileModel.getRestricted() == true ? "unrestrict/" : "restrict/") :
|
||||
(profileModel.getBlocked() == true ? "unblock/" : "block/")))));
|
||||
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 == "restrict") {
|
||||
final String urlParameters = "target_user_id="+profileModel.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();
|
||||
}
|
||||
else urlConnection.connect();
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
ok = true;
|
||||
}
|
||||
else Toast.makeText(ProfileViewer.this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", action+": " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (ok == true) {
|
||||
onRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,250 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.PostsAdapter;
|
||||
import awais.instagrabber.asyncs.PostsFetcher;
|
||||
import awais.instagrabber.asyncs.i.iLikedFetcher;
|
||||
import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager;
|
||||
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration;
|
||||
import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
|
||||
import awais.instagrabber.databinding.ActivitySavedBinding;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.interfaces.ItemGetter;
|
||||
import awais.instagrabber.models.BasePostModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.enums.DownloadMethod;
|
||||
import awais.instagrabber.models.enums.ItemGetType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Constants.AUTOLOAD_POSTS;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class SavedViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
|
||||
private static AsyncTask<?, ?, ?> currentlyExecuting;
|
||||
public static ItemGetter itemGetter;
|
||||
private PostsAdapter postsAdapter;
|
||||
private boolean hasNextPage, autoloadPosts;
|
||||
//private CommentModel commentModel;
|
||||
private ActivitySavedBinding savedBinding;
|
||||
private String action, username, endCursor;
|
||||
private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
||||
private RecyclerLazyLoader lazyLoader;
|
||||
private Resources resources;
|
||||
private ArrayList<PostModel> selectedItems = new ArrayList<>();
|
||||
private final ArrayList<PostModel> allItems = new ArrayList<>();
|
||||
private MenuItem downloadAction;
|
||||
|
||||
private final FetchListener<PostModel[]> postsFetchListener = new FetchListener<PostModel[]>() {
|
||||
@Override
|
||||
public void onResult(final PostModel[] result) {
|
||||
final int oldSize = allItems.size();
|
||||
if (result != null && result.length > 0) {
|
||||
allItems.addAll(Arrays.asList(result));
|
||||
|
||||
postsAdapter.notifyItemRangeInserted(oldSize, result.length);
|
||||
|
||||
savedBinding.mainPosts.post(() -> {
|
||||
savedBinding.mainPosts.setNestedScrollingEnabled(true);
|
||||
savedBinding.mainPosts.setVisibility(View.VISIBLE);
|
||||
});
|
||||
|
||||
final PostModel model = result[result.length - 1];
|
||||
if (model != null) {
|
||||
endCursor = model.getEndCursor();
|
||||
|
||||
hasNextPage = model.hasNextPage();
|
||||
if (autoloadPosts && hasNextPage && action.charAt(0) == '^')
|
||||
currentlyExecuting = new iLikedFetcher(endCursor, postsFetchListener)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if (autoloadPosts && hasNextPage)
|
||||
currentlyExecuting = new PostsFetcher(action, endCursor, this)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else {
|
||||
savedBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
model.setPageCursor(false, null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
savedBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
if (oldSize == 0) {
|
||||
Toast.makeText(getApplicationContext(), R.string.empty_list, Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
savedBinding = ActivitySavedBinding.inflate(getLayoutInflater());
|
||||
setContentView(savedBinding.getRoot());
|
||||
savedBinding.swipeRefreshLayout.setOnRefreshListener(this);
|
||||
autoloadPosts = Utils.settingsHelper.getBoolean(AUTOLOAD_POSTS);
|
||||
savedBinding.mainPosts.setNestedScrollingEnabled(false);
|
||||
final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(this, Utils.convertDpToPx(110));
|
||||
savedBinding.mainPosts.setLayoutManager(layoutManager);
|
||||
savedBinding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4)));
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null || !intent.hasExtra(Constants.EXTRAS_INDEX)
|
||||
|| Utils.isEmpty((action = intent.getStringExtra(Constants.EXTRAS_INDEX)))
|
||||
|| !intent.hasExtra(Constants.EXTRAS_USER)
|
||||
|| Utils.isEmpty((username = intent.getStringExtra(Constants.EXTRAS_USER)))) {
|
||||
Utils.errorFinish(this);
|
||||
return;
|
||||
}
|
||||
|
||||
savedBinding.mainPosts.setAdapter(postsAdapter = new PostsAdapter(allItems, v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof PostModel) {
|
||||
final PostModel postModel = (PostModel) tag;
|
||||
|
||||
if (postsAdapter.isSelecting) toggleSelection(postModel);
|
||||
else startActivity(new Intent(this, PostViewer.class)
|
||||
.putExtra(Constants.EXTRAS_INDEX, postModel.getPosition())
|
||||
.putExtra(Constants.EXTRAS_POST, postModel)
|
||||
.putExtra(Constants.EXTRAS_USER, username)
|
||||
.putExtra(Constants.EXTRAS_TYPE, ItemGetType.SAVED_ITEMS));
|
||||
}
|
||||
}, v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof PostModel) {
|
||||
postsAdapter.isSelecting = true;
|
||||
toggleSelection((PostModel) tag);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
savedBinding.swipeRefreshLayout.setRefreshing(true);
|
||||
setSupportActionBar(savedBinding.toolbar.toolbar);
|
||||
savedBinding.toolbar.toolbar.setTitle((action.charAt(0) == '$' ? R.string.saved :
|
||||
(action.charAt(0) == '%' ? R.string.tagged : R.string.liked)));
|
||||
savedBinding.toolbar.toolbar.setSubtitle(username);
|
||||
|
||||
lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> {
|
||||
if (!autoloadPosts && hasNextPage) {
|
||||
savedBinding.swipeRefreshLayout.setRefreshing(true);
|
||||
stopCurrentExecutor();
|
||||
|
||||
currentlyExecuting = action.charAt(0) == '^'
|
||||
? new iLikedFetcher(endCursor, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||
: new PostsFetcher(action, endCursor, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
endCursor = null;
|
||||
}
|
||||
});
|
||||
savedBinding.mainPosts.addOnScrollListener(lazyLoader);
|
||||
|
||||
itemGetter = itemGetType -> {
|
||||
if (itemGetType == ItemGetType.SAVED_ITEMS) return allItems;
|
||||
return null;
|
||||
};
|
||||
|
||||
if (action.charAt(0) == '^') new iLikedFetcher(postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else new PostsFetcher(action, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.saved, menu);
|
||||
|
||||
downloadAction = menu.findItem(R.id.downloadAction);
|
||||
downloadAction.setVisible(false);
|
||||
|
||||
menu.findItem(R.id.favouriteAction).setVisible(false);
|
||||
|
||||
downloadAction.setOnMenuItemClickListener(item -> {
|
||||
if (selectedItems.size() > 0) {
|
||||
Utils.batchDownload(this, null, DownloadMethod.DOWNLOAD_SAVED, selectedItems);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public void deselectSelection(final BasePostModel postModel) {
|
||||
if (postModel instanceof PostModel) {
|
||||
selectedItems.remove(postModel);
|
||||
postModel.setSelected(false);
|
||||
if (postsAdapter != null) notifyAdapter((PostModel) postModel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
if (lazyLoader != null) lazyLoader.resetState();
|
||||
stopCurrentExecutor();
|
||||
allItems.clear();
|
||||
selectedItems.clear();
|
||||
if (postsAdapter != null) {
|
||||
postsAdapter.isSelecting = false;
|
||||
postsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
savedBinding.swipeRefreshLayout.setRefreshing(true);
|
||||
if (action.charAt(0) == '^') new iLikedFetcher(postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else new PostsFetcher(action, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED && selectedItems.size() > 0)
|
||||
Utils.batchDownload(this, null, DownloadMethod.DOWNLOAD_SAVED, selectedItems);
|
||||
}
|
||||
|
||||
public static void stopCurrentExecutor() {
|
||||
if (currentlyExecuting != null) {
|
||||
try {
|
||||
currentlyExecuting.cancel(true);
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleSelection(final PostModel postModel) {
|
||||
if (postModel != null && postsAdapter != null) {
|
||||
if (postModel.isSelected()) selectedItems.remove(postModel);
|
||||
else if (selectedItems.size() >= 100) {
|
||||
Toast.makeText(SavedViewer.this, R.string.downloader_too_many, Toast.LENGTH_SHORT);
|
||||
return;
|
||||
}
|
||||
else selectedItems.add(postModel);
|
||||
postModel.setSelected(!postModel.isSelected());
|
||||
notifyAdapter(postModel);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyAdapter(final PostModel postModel) {
|
||||
if (selectedItems.size() < 1) postsAdapter.isSelecting = false;
|
||||
if (postModel.getPosition() < 0) postsAdapter.notifyDataSetChanged();
|
||||
else postsAdapter.notifyItemChanged(postModel.getPosition(), postModel);
|
||||
|
||||
if (downloadAction != null) {
|
||||
downloadAction.setVisible(postsAdapter.isSelecting);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,781 +0,0 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.GestureDetectorCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.StoriesAdapter;
|
||||
import awais.instagrabber.asyncs.DownloadAsync;
|
||||
import awais.instagrabber.asyncs.direct_messages.DirectThreadBroadcaster;
|
||||
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.PostModel;
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.models.stickers.PollModel;
|
||||
import awais.instagrabber.models.stickers.QuestionModel;
|
||||
import awais.instagrabber.models.stickers.QuizModel;
|
||||
import awais.instagrabber.models.stickers.SwipeUpModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_THRESHOLD;
|
||||
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD;
|
||||
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
|
||||
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
||||
import static awais.instagrabber.utils.Constants.MARK_AS_SEEN;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
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 SimpleExoPlayer player;
|
||||
private SwipeEvent swipeEvent;
|
||||
private MenuItem menuDownload, menuDm;
|
||||
private PollModel poll;
|
||||
private QuestionModel question;
|
||||
private String[] mentions;
|
||||
private QuizModel quiz;
|
||||
private SwipeUpModel swipeUp;
|
||||
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().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();
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private void viewPost() {
|
||||
lastSlidePos = 0;
|
||||
storyViewerBinding.storiesList.setVisibility(View.GONE);
|
||||
storiesAdapter.setData(null);
|
||||
|
||||
if (menuDownload != null) menuDownload.setVisible(false);
|
||||
if (menuDm != null) menuDm.setVisible(false);
|
||||
|
||||
storyViewerBinding.playerView.setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event));
|
||||
storyViewerBinding.imageViewer.setOnSingleFlingListener((e1, e2, velocityX, velocityY) -> {
|
||||
final float diffX = e2.getX() - e1.getX();
|
||||
try {
|
||||
if (Math.abs(diffX) > Math.abs(e2.getY() - e1.getY()) && Math.abs(diffX) > SWIPE_THRESHOLD
|
||||
&& Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
|
||||
swipeEvent.onSwipe(diffX > 0);
|
||||
return true;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ACTIVITY_STORY_VIEWER, "viewPost",
|
||||
new Pair<>("swipeEvent", swipeEvent),
|
||||
new Pair<>("diffX", diffX));
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
final View.OnClickListener linkActionListener = v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof CharSequence) {
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(tag.toString()));
|
||||
startActivity(intent);
|
||||
}
|
||||
};
|
||||
|
||||
storyViewerBinding.spotify.setOnClickListener(linkActionListener);
|
||||
storyViewerBinding.swipeUp.setOnClickListener(linkActionListener);
|
||||
|
||||
storyViewerBinding.viewStoryPost.setOnClickListener(v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof CharSequence) startActivity(new Intent(this, PostViewer.class)
|
||||
.putExtra(Constants.EXTRAS_POST, new PostModel(tag.toString(), tag.toString().matches("^[\\d]+$"))));
|
||||
});
|
||||
|
||||
final View.OnClickListener storyActionListener = v -> {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof PollModel) {
|
||||
poll = (PollModel) tag;
|
||||
if (poll.getMyChoice() > -1)
|
||||
new AlertDialog.Builder(this).setTitle(R.string.voted_story_poll)
|
||||
.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new String[]{
|
||||
(poll.getMyChoice() == 0 ? "√ " : "") + poll.getLeftChoice() + " (" + poll.getLeftCount() + ")",
|
||||
(poll.getMyChoice() == 1 ? "√ " : "") + poll.getRightChoice() + " (" + poll.getRightCount() + ")"
|
||||
}), null)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show();
|
||||
else new AlertDialog.Builder(this).setTitle(poll.getQuestion())
|
||||
.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new String[]{
|
||||
poll.getLeftChoice() + " (" + poll.getLeftCount() + ")",
|
||||
poll.getRightChoice() + " (" + poll.getRightCount() + ")"
|
||||
}), (d, w) -> {
|
||||
if (!Utils.isEmpty(cookie)) new VoteAction().execute(w);
|
||||
})
|
||||
.setPositiveButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
else if (tag instanceof QuestionModel) {
|
||||
question = (QuestionModel) tag;
|
||||
final EditText input = new EditText(this);
|
||||
input.setHint(R.string.answer_hint);
|
||||
new AlertDialog.Builder(this).setTitle(question.getQuestion())
|
||||
.setView(input)
|
||||
.setPositiveButton(R.string.ok, (d,w) -> {
|
||||
new RespondAction().execute(input.getText().toString());
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
else if (tag instanceof String[]) {
|
||||
mentions = (String[]) tag;
|
||||
new AlertDialog.Builder(this).setTitle(R.string.story_mentions)
|
||||
.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mentions), (d,w) -> {
|
||||
searchUsername(mentions[w]);
|
||||
})
|
||||
.setPositiveButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
else if (tag instanceof QuizModel) {
|
||||
quiz = quiz;
|
||||
String[] choices = new String[quiz.getChoices().length];
|
||||
for (int q = 0; q < choices.length; ++q) {
|
||||
choices[q] = (quiz.getMyChoice() == q ? "√ " :"") + quiz.getChoices()[q]+ " (" + quiz.getCounts()[q] + ")";
|
||||
}
|
||||
new AlertDialog.Builder(this).setTitle(quiz.getMyChoice() > -1 ? getString(R.string.story_quizzed) : quiz.getQuestion())
|
||||
.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, choices), (d,w) -> {
|
||||
if (quiz.getMyChoice() == -1 && !Utils.isEmpty(cookie)) new QuizAction().execute(w);
|
||||
})
|
||||
.setPositiveButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
};
|
||||
|
||||
storyViewerBinding.poll.setOnClickListener(storyActionListener);
|
||||
storyViewerBinding.answer.setOnClickListener(storyActionListener);
|
||||
storyViewerBinding.mention.setOnClickListener(storyActionListener);
|
||||
storyViewerBinding.quiz.setOnClickListener(storyActionListener);
|
||||
|
||||
storiesAdapter.setData(storyModels);
|
||||
if (storyModels.length > 1) storyViewerBinding.storiesList.setVisibility(View.VISIBLE);
|
||||
|
||||
currentStory = storyModels[0];
|
||||
refreshStory();
|
||||
}
|
||||
|
||||
private void setupVideo() {
|
||||
storyViewerBinding.playerView.setVisibility(View.VISIBLE);
|
||||
storyViewerBinding.progressView.setVisibility(View.GONE);
|
||||
storyViewerBinding.imageViewer.setVisibility(View.GONE);
|
||||
storyViewerBinding.imageViewer.setImageDrawable(null);
|
||||
|
||||
player = new SimpleExoPlayer.Builder(this).build();
|
||||
storyViewerBinding.playerView.setPlayer(player);
|
||||
player.setPlayWhenReady(settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
|
||||
|
||||
final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(new DefaultDataSourceFactory(this, "instagram"))
|
||||
.createMediaSource(Uri.parse(url));
|
||||
mediaSource.addEventListener(new Handler(), new MediaSourceEventListener() {
|
||||
@Override
|
||||
public void onLoadCompleted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
if (menuDownload != null) menuDownload.setVisible(true);
|
||||
if (currentStory.canReply() && menuDm != null && !Utils.isEmpty(cookie)) menuDm.setVisible(true);
|
||||
storyViewerBinding.progressView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadStarted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
if (menuDownload != null) menuDownload.setVisible(true);
|
||||
if (currentStory.canReply() && menuDm != null && !Utils.isEmpty(cookie)) menuDm.setVisible(true);
|
||||
storyViewerBinding.progressView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCanceled(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
storyViewerBinding.progressView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadError(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData, final IOException error, final boolean wasCanceled) {
|
||||
if (menuDownload != null) menuDownload.setVisible(false);
|
||||
if (menuDm != null) menuDm.setVisible(false);
|
||||
storyViewerBinding.progressView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
player.prepare(mediaSource);
|
||||
|
||||
storyViewerBinding.playerView.setOnClickListener(v -> {
|
||||
if (player != null) {
|
||||
if (player.getPlaybackState() == Player.STATE_ENDED) player.seekTo(0);
|
||||
player.setPlayWhenReady(player.getPlaybackState() == Player.STATE_ENDED || !player.isPlaying());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupImage() {
|
||||
storyViewerBinding.progressView.setVisibility(View.VISIBLE);
|
||||
storyViewerBinding.playerView.setVisibility(View.GONE);
|
||||
|
||||
storyViewerBinding.imageViewer.setImageDrawable(null);
|
||||
storyViewerBinding.imageViewer.setVisibility(View.VISIBLE);
|
||||
storyViewerBinding.imageViewer.setZoomable(true);
|
||||
storyViewerBinding.imageViewer.setZoomTransitionDuration(420);
|
||||
storyViewerBinding.imageViewer.setMaximumScale(7.2f);
|
||||
|
||||
Glide.with(this).load(url).listener(new RequestListener<Drawable>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable final GlideException e, final Object model, final Target<Drawable> target, final boolean isFirstResource) {
|
||||
storyViewerBinding.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(final Drawable resource, final Object model, final Target<Drawable> target, final DataSource dataSource, final boolean isFirstResource) {
|
||||
if (menuDownload != null) menuDownload.setVisible(true);
|
||||
if (currentStory.canReply() && menuDm != null && !Utils.isEmpty(cookie)) menuDm.setVisible(true);
|
||||
storyViewerBinding.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
}).into(storyViewerBinding.imageViewer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu, menu);
|
||||
|
||||
menu.findItem(R.id.action_settings).setVisible(false);
|
||||
menu.findItem(R.id.action_search).setVisible(false);
|
||||
|
||||
menuDownload = menu.findItem(R.id.action_download);
|
||||
menuDm = menu.findItem(R.id.action_dms);
|
||||
menuDownload.setVisible(true);
|
||||
menuDm.setVisible(false);
|
||||
menuDownload.setOnMenuItemClickListener(item -> {
|
||||
if (ContextCompat.checkSelfPermission(this, Utils.PERMS[0]) == PackageManager.PERMISSION_GRANTED)
|
||||
downloadStory();
|
||||
else
|
||||
ActivityCompat.requestPermissions(this, Utils.PERMS, 8020);
|
||||
return true;
|
||||
});
|
||||
menuDm.setOnMenuItemClickListener(item -> {
|
||||
final EditText input = new EditText(this);
|
||||
input.setHint(R.string.reply_hint);
|
||||
new AlertDialog.Builder(this).setTitle(R.string.reply_story)
|
||||
.setView(input)
|
||||
.setPositiveButton(R.string.ok, (d,w) -> {
|
||||
new CommentAction().execute(input.getText().toString());
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED) downloadStory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (Build.VERSION.SDK_INT < 24) releasePlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (Build.VERSION.SDK_INT >= 24) releasePlayer();
|
||||
}
|
||||
|
||||
private void downloadStory() {
|
||||
int error = 0;
|
||||
if (currentStory != null) {
|
||||
File dir = new File(Environment.getExternalStorageDirectory(), "Download");
|
||||
|
||||
if (settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
|
||||
final String customPath = settingsHelper.getString(FOLDER_PATH);
|
||||
if (!Utils.isEmpty(customPath)) dir = new File(customPath);
|
||||
}
|
||||
|
||||
if (settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER) && !Utils.isEmpty(username))
|
||||
dir = new File(dir, username);
|
||||
|
||||
if (dir.exists() || dir.mkdirs()) {
|
||||
final String storyUrl = currentStory.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO ? currentStory.getVideoUrl() : currentStory.getStoryUrl();
|
||||
final File saveFile = new File(dir, currentStory.getStoryMediaId() + "_" + currentStory.getTimestamp()
|
||||
+ Utils.getExtensionFromModel(storyUrl, currentStory));
|
||||
|
||||
new DownloadAsync(this, storyUrl, saveFile, result -> {
|
||||
final int toastRes = result != null && result.exists() ? R.string.downloader_complete
|
||||
: R.string.downloader_error_download_file;
|
||||
Toast.makeText(this, toastRes, Toast.LENGTH_SHORT).show();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
||||
} else error = 1;
|
||||
} else error = 2;
|
||||
|
||||
if (error == 1) Toast.makeText(this, R.string.downloader_error_creating_folder, Toast.LENGTH_SHORT).show();
|
||||
else if (error == 2) Toast.makeText(this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void refreshStory() {
|
||||
if (storyViewerBinding.storiesList.getVisibility() == View.VISIBLE) {
|
||||
StoryModel item = storiesAdapter.getItemAt(lastSlidePos);
|
||||
if (item != null) {
|
||||
item.setCurrentSlide(false);
|
||||
storiesAdapter.notifyItemChanged(lastSlidePos, item);
|
||||
}
|
||||
|
||||
item = storiesAdapter.getItemAt(slidePos);
|
||||
if (item != null) {
|
||||
item.setCurrentSlide(true);
|
||||
storiesAdapter.notifyItemChanged(slidePos, item);
|
||||
}
|
||||
}
|
||||
lastSlidePos = slidePos;
|
||||
|
||||
final MediaItemType itemType = currentStory.getItemType();
|
||||
|
||||
if (menuDownload != null) menuDownload.setVisible(false);
|
||||
url = itemType == MediaItemType.MEDIA_TYPE_VIDEO ? currentStory.getVideoUrl() : currentStory.getStoryUrl();
|
||||
|
||||
final String shortCode = currentStory.getTappableShortCode();
|
||||
storyViewerBinding.viewStoryPost.setVisibility(shortCode != null ? View.VISIBLE : View.GONE);
|
||||
storyViewerBinding.viewStoryPost.setTag(shortCode);
|
||||
|
||||
final String spotify = currentStory.getSpotify();
|
||||
storyViewerBinding.spotify.setVisibility(spotify != null ? View.VISIBLE : View.GONE);
|
||||
storyViewerBinding.spotify.setTag(spotify);
|
||||
|
||||
poll = currentStory.getPoll();
|
||||
storyViewerBinding.poll.setVisibility(poll != null ? View.VISIBLE : View.GONE);
|
||||
storyViewerBinding.poll.setTag(poll);
|
||||
|
||||
question = currentStory.getQuestion();
|
||||
storyViewerBinding.answer.setVisibility((question != null && !Utils.isEmpty(cookie)) ? View.VISIBLE : View.GONE);
|
||||
storyViewerBinding.answer.setTag(question);
|
||||
|
||||
mentions = currentStory.getMentions();
|
||||
storyViewerBinding.mention.setVisibility((mentions != null && mentions.length > 0) ? View.VISIBLE : View.GONE);
|
||||
storyViewerBinding.mention.setTag(mentions);
|
||||
|
||||
quiz = currentStory.getQuiz();
|
||||
storyViewerBinding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE);
|
||||
storyViewerBinding.quiz.setTag(quiz);
|
||||
|
||||
swipeUp = currentStory.getSwipeUp();
|
||||
storyViewerBinding.swipeUp.setVisibility(swipeUp != null ? View.VISIBLE : View.GONE);
|
||||
if (swipeUp != null) {
|
||||
storyViewerBinding.swipeUp.setText(swipeUp.getText());
|
||||
storyViewerBinding.swipeUp.setTag(swipeUp.getUrl());
|
||||
}
|
||||
|
||||
releasePlayer();
|
||||
final Intent intent = getIntent();
|
||||
if (intent.getBooleanExtra(Constants.EXTRAS_HASHTAG, false)) {
|
||||
storyViewerBinding.toolbar.toolbar.setTitle(currentStory.getUsername() + " (" + intent.getStringExtra(Constants.EXTRAS_USERNAME) + ")");
|
||||
storyViewerBinding.toolbar.toolbar.setOnClickListener(v -> {
|
||||
searchUsername(currentStory.getUsername());
|
||||
});
|
||||
}
|
||||
if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
|
||||
else setupImage();
|
||||
|
||||
if (!intent.hasExtra(Constants.EXTRAS_HIGHLIGHT))
|
||||
storyViewerBinding.toolbar.toolbar.setSubtitle(Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L)));
|
||||
|
||||
if (settingsHelper.getBoolean(MARK_AS_SEEN)) new SeenAction().execute();
|
||||
}
|
||||
|
||||
private void searchUsername(final String text) {
|
||||
startActivity(
|
||||
new Intent(getApplicationContext(), ProfileViewer.class)
|
||||
.putExtra(Constants.EXTRAS_USERNAME, text)
|
||||
);
|
||||
}
|
||||
|
||||
private void releasePlayer() {
|
||||
if (player != null) {
|
||||
try { player.stop(true); } catch (Exception ignored) { }
|
||||
try { player.release(); } catch (Exception ignored) { }
|
||||
player = null;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
class VoteAction extends AsyncTask<Integer, Void, Void> {
|
||||
int ok = -1;
|
||||
String action;
|
||||
|
||||
protected Void doInBackground(Integer... rawchoice) {
|
||||
int choice = rawchoice[0];
|
||||
final String url = "https://www.instagram.com/media/"+currentStory.getStoryMediaId().split("_")[0]+"/"+poll.getId()+"/story_poll_vote/";
|
||||
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]);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", "6");
|
||||
urlConnection.setDoOutput(true);
|
||||
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
|
||||
wr.writeBytes("vote="+choice);
|
||||
wr.flush();
|
||||
wr.close();
|
||||
urlConnection.connect();
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
ok = choice;
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "vote: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (ok > -1) {
|
||||
poll.setMyChoice(ok);
|
||||
Toast.makeText(getApplicationContext(), R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
class QuizAction extends AsyncTask<Integer, Void, Void> {
|
||||
int ok = -1;
|
||||
String action;
|
||||
|
||||
protected Void doInBackground(Integer... rawchoice) {
|
||||
int choice = rawchoice[0];
|
||||
final String url = "https://i.instagram.com/api/v1/media/"+currentStory.getStoryMediaId().split("_")[0]+"/"+quiz.getId()+"/story_quiz_answer/";
|
||||
try {
|
||||
JSONObject ogbody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString()
|
||||
+"\",\"mutation_token\":\"" + UUID.randomUUID().toString()
|
||||
+"\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
|
||||
+"\",\"_uid\":\"" + Utils.getUserIdFromCookie(cookie)
|
||||
+"\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
+"\"}");
|
||||
ogbody.put("answer", String.valueOf(choice));
|
||||
String urlParameters = Utils.sign(ogbody.toString());
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
|
||||
urlConnection.setDoOutput(true);
|
||||
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
|
||||
wr.writeBytes(urlParameters);
|
||||
wr.flush();
|
||||
wr.close();
|
||||
Log.d("austin_debug", "quiz: "+url+" "+cookie+" "+urlParameters);
|
||||
urlConnection.connect();
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
ok = choice;
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "quiz: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (ok > -1) {
|
||||
quiz.setMyChoice(ok);
|
||||
Toast.makeText(getApplicationContext(), R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
class RespondAction extends AsyncTask<String, Void, Void> {
|
||||
boolean ok = false;
|
||||
String action;
|
||||
|
||||
protected Void doInBackground(String... rawchoice) {
|
||||
final String url = "https://i.instagram.com/api/v1/media/"
|
||||
+currentStory.getStoryMediaId().split("_")[0]+"/"+question.getId()+"/story_question_response/";
|
||||
try {
|
||||
JSONObject ogbody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString()
|
||||
+"\",\"mutation_token\":\"" + UUID.randomUUID().toString()
|
||||
+"\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
|
||||
+"\",\"_uid\":\"" + Utils.getUserIdFromCookie(cookie)
|
||||
+"\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
+"\"}");
|
||||
String choice = rawchoice[0].replaceAll("\"", ("\\\""));
|
||||
ogbody.put("response", choice);
|
||||
String urlParameters = Utils.sign(ogbody.toString());
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", Integer.toString(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;
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "respond: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (ok) {
|
||||
Toast.makeText(getApplicationContext(), R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
class SeenAction extends AsyncTask<Void, Void, Void> {
|
||||
protected Void doInBackground(Void... lmao) {
|
||||
final String url = "https://www.instagram.com/stories/reel/seen";
|
||||
try {
|
||||
String urlParameters = "reelMediaId="+currentStory.getStoryMediaId().split("_")[0]
|
||||
+"&reelMediaOwnerId="+currentStory.getUserId()
|
||||
+"&reelId="+currentStory.getUserId()
|
||||
+"&reelMediaTakenAt="+ currentStory.getTimestamp()
|
||||
+"&viewSeenAt="+ currentStory.getTimestamp();
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
|
||||
urlConnection.setDoOutput(true);
|
||||
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
|
||||
wr.writeBytes(urlParameters);
|
||||
wr.flush();
|
||||
wr.close();
|
||||
urlConnection.connect();
|
||||
Log.d("austin_debug", urlConnection.getResponseCode() + " " + Utils.readFromConnection(urlConnection));
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "seen: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class CommentAction extends AsyncTask<String, Void, Void> {
|
||||
protected Void doInBackground(String... rawAction) {
|
||||
final String action = rawAction[0];
|
||||
final String url = "https://i.instagram.com/api/v1/direct_v2/create_group_thread/";
|
||||
try {
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
urlConnection.setUseCaches(false);
|
||||
final String urlParameters = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
|
||||
+"\",\"_uid\":\"" + Utils.getUserIdFromCookie(cookie)
|
||||
+"\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
+"\",\"recipient_users\":\"["+currentStory.getUserId() // <- string of array of number (not joking)
|
||||
+"]\"}");
|
||||
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) {
|
||||
final String threadid = new JSONObject(Utils.readFromConnection(urlConnection)).getString("thread_id");
|
||||
final DirectThreadBroadcaster.StoryReplyBroadcastOptions options =
|
||||
new DirectThreadBroadcaster.StoryReplyBroadcastOptions(
|
||||
action,
|
||||
currentStory.getStoryMediaId(),
|
||||
currentStory.getUserId()
|
||||
);
|
||||
final DirectThreadBroadcaster broadcast = new DirectThreadBroadcaster(threadid);
|
||||
broadcast.setOnTaskCompleteListener(result -> {
|
||||
Toast.makeText(getApplicationContext(),
|
||||
result != null ? R.string.answered_story : R.string.downloader_unknown_error,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
broadcast.execute(options);
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "reply (CT): " + ex);
|
||||
Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.PrefAccountSwitcherBinding;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DataBox;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class AccountSwitcherAdapter extends ListAdapter<DataBox.CookieModel, AccountSwitcherAdapter.ViewHolder> {
|
||||
private static final String TAG = "AccountSwitcherAdapter";
|
||||
private static final DiffUtil.ItemCallback<DataBox.CookieModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<DataBox.CookieModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final DataBox.CookieModel oldItem, @NonNull final DataBox.CookieModel newItem) {
|
||||
return oldItem.getUid().equals(newItem.getUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final DataBox.CookieModel oldItem, @NonNull final DataBox.CookieModel newItem) {
|
||||
return oldItem.getUid().equals(newItem.getUid());
|
||||
}
|
||||
};
|
||||
|
||||
private final OnAccountClickListener clickListener;
|
||||
private final OnAccountLongClickListener longClickListener;
|
||||
|
||||
public AccountSwitcherAdapter(final OnAccountClickListener clickListener,
|
||||
final OnAccountLongClickListener longClickListener) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.clickListener = clickListener;
|
||||
this.longClickListener = longClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final PrefAccountSwitcherBinding binding = PrefAccountSwitcherBinding.inflate(layoutInflater, parent, false);
|
||||
return new ViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
|
||||
final DataBox.CookieModel model = getItem(position);
|
||||
if (model == null) return;
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
final boolean isCurrent = model.getCookie().equals(cookie);
|
||||
holder.bind(model, isCurrent, clickListener, longClickListener);
|
||||
}
|
||||
|
||||
public interface OnAccountClickListener {
|
||||
void onAccountClick(final DataBox.CookieModel model, final boolean isCurrent);
|
||||
}
|
||||
|
||||
public interface OnAccountLongClickListener {
|
||||
boolean onAccountLongClick(final DataBox.CookieModel model, final boolean isCurrent);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private final PrefAccountSwitcherBinding binding;
|
||||
|
||||
public ViewHolder(final PrefAccountSwitcherBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
binding.arrowDown.setImageResource(R.drawable.ic_check_24);
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
public void bind(final DataBox.CookieModel model,
|
||||
final boolean isCurrent,
|
||||
final OnAccountClickListener clickListener,
|
||||
final OnAccountLongClickListener longClickListener) {
|
||||
// Log.d(TAG, model.getFullName());
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (clickListener == null) return;
|
||||
clickListener.onAccountClick(model, isCurrent);
|
||||
});
|
||||
itemView.setOnLongClickListener(v -> {
|
||||
if (longClickListener == null) return false;
|
||||
return longClickListener.onAccountLongClick(model, isCurrent);
|
||||
});
|
||||
binding.profilePic.setImageURI(model.getProfilePic());
|
||||
binding.username.setText("@" + model.getUsername());
|
||||
binding.fullName.setTypeface(null);
|
||||
final String fullName = model.getFullName();
|
||||
if (TextUtils.isEmpty(fullName)) {
|
||||
binding.fullName.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.fullName.setVisibility(View.VISIBLE);
|
||||
binding.fullName.setText(fullName);
|
||||
}
|
||||
if (!isCurrent) {
|
||||
binding.arrowDown.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
binding.fullName.setTypeface(binding.fullName.getTypeface(), Typeface.BOLD);
|
||||
binding.arrowDown.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
@ -21,10 +18,18 @@ import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.CommentModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
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
|
||||
@ -33,7 +38,7 @@ public final class CommentsAdapter extends RecyclerView.Adapter<CommentViewHolde
|
||||
results.values = commentModels;
|
||||
|
||||
final int commentsLen = commentModels == null ? 0 : commentModels.length;
|
||||
if (commentModels != null && commentsLen > 0 && !Utils.isEmpty(filter)) {
|
||||
if (commentModels != null && commentsLen > 0 && !TextUtils.isEmpty(filter)) {
|
||||
final String query = filter.toString().toLowerCase();
|
||||
final ArrayList<CommentModel> filterList = new ArrayList<>(commentsLen);
|
||||
|
||||
@ -66,15 +71,12 @@ 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) {
|
||||
super();
|
||||
this.commentModels = this.filteredCommentModels = commentModels;
|
||||
this.isParent = isParent;
|
||||
this.onClickListener = onClickListener;
|
||||
@ -93,10 +95,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 +110,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 +120,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)
|
||||
|
@ -8,7 +8,7 @@ import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.DirectMessageInboxItemViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutIncludeSimpleItemBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||
import awais.instagrabber.models.direct_messages.InboxThreadModel;
|
||||
|
||||
public final class DirectMessageInboxAdapter extends ListAdapter<InboxThreadModel, DirectMessageInboxItemViewHolder> {
|
||||
@ -35,7 +35,7 @@ public final class DirectMessageInboxAdapter extends ListAdapter<InboxThreadMode
|
||||
@Override
|
||||
public DirectMessageInboxItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final LayoutIncludeSimpleItemBinding binding = LayoutIncludeSimpleItemBinding.inflate(layoutInflater, parent, false);
|
||||
final LayoutDmInboxItemBinding binding = LayoutDmInboxItemBinding.inflate(layoutInflater, parent, false);
|
||||
return new DirectMessageInboxItemViewHolder(binding);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -8,52 +7,37 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.FollowsViewHolder;
|
||||
import awais.instagrabber.databinding.ItemFollowBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
|
||||
public final class DirectMessageMembersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
public final class DirectMessageMembersAdapter extends RecyclerView.Adapter<FollowsViewHolder> {
|
||||
private final ProfileModel[] profileModels;
|
||||
private final List<Long> admins;
|
||||
private final View.OnClickListener onClickListener;
|
||||
private final LayoutInflater layoutInflater;
|
||||
|
||||
public DirectMessageMembersAdapter(final ProfileModel[] profileModels, final List<Long> admins,
|
||||
final Context context, final View.OnClickListener onClickListener) {
|
||||
public DirectMessageMembersAdapter(final ProfileModel[] profileModels,
|
||||
final List<Long> admins,
|
||||
final View.OnClickListener onClickListener) {
|
||||
this.profileModels = profileModels;
|
||||
this.admins = admins;
|
||||
this.layoutInflater = LayoutInflater.from(context);
|
||||
this.onClickListener = onClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final View view = layoutInflater.inflate(R.layout.item_follow, parent, false);
|
||||
return new FollowsViewHolder(view);
|
||||
public FollowsViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemFollowBinding binding = ItemFollowBinding.inflate(layoutInflater, parent, false);
|
||||
return new FollowsViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
|
||||
public void onBindViewHolder(@NonNull final FollowsViewHolder holder, final int position) {
|
||||
final ProfileModel model = profileModels[position];
|
||||
|
||||
final FollowsViewHolder followHolder = (FollowsViewHolder) holder;
|
||||
if (model != null) {
|
||||
followHolder.itemView.setTag(model);
|
||||
followHolder.itemView.setOnClickListener(onClickListener);
|
||||
|
||||
followHolder.tvUsername.setText(model.getUsername());
|
||||
followHolder.tvFullName.setText(model.getName());
|
||||
|
||||
if (admins != null && admins.contains(Long.parseLong(model.getId())))
|
||||
followHolder.isAdmin.setVisibility(View.VISIBLE);
|
||||
|
||||
Glide.with(layoutInflater.getContext()).load(model.getSdProfilePic()).into(followHolder.profileImage);
|
||||
}
|
||||
holder.bind(model, admins, onClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,87 +1,57 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.DiscoverViewHolder;
|
||||
import awais.instagrabber.models.DiscoverItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
|
||||
public final class DiscoverAdapter extends RecyclerView.Adapter<DiscoverViewHolder> {
|
||||
private final ArrayList<DiscoverItemModel> discoverItemModels;
|
||||
private final View.OnClickListener clickListener;
|
||||
private final View.OnLongClickListener longClickListener;
|
||||
private LayoutInflater layoutInflater;
|
||||
public boolean isSelecting = false;
|
||||
public final class DiscoverAdapter extends MultiSelectListAdapter<DiscoverItemModel, DiscoverViewHolder> {
|
||||
|
||||
public DiscoverAdapter(final ArrayList<DiscoverItemModel> discoverItemModels, final View.OnClickListener clickListener,
|
||||
final View.OnLongClickListener longClickListener) {
|
||||
this.discoverItemModels = discoverItemModels;
|
||||
this.longClickListener = longClickListener;
|
||||
this.clickListener = clickListener;
|
||||
private static final DiffUtil.ItemCallback<DiscoverItemModel> diffCallback = new DiffUtil.ItemCallback<DiscoverItemModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final DiscoverItemModel oldItem, @NonNull final DiscoverItemModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final DiscoverItemModel oldItem, @NonNull final DiscoverItemModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
};
|
||||
|
||||
public DiscoverAdapter(final OnItemClickListener<DiscoverItemModel> clickListener,
|
||||
final OnItemLongClickListener<DiscoverItemModel> longClickListener) {
|
||||
super(diffCallback, clickListener, longClickListener);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DiscoverViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
if (layoutInflater == null) layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
return new DiscoverViewHolder(layoutInflater.inflate(R.layout.item_post, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final DiscoverViewHolder holder, final int position) {
|
||||
final DiscoverItemModel itemModel = discoverItemModels.get(position);
|
||||
final DiscoverItemModel itemModel = getItem(position);
|
||||
if (itemModel != null) {
|
||||
itemModel.setPosition(position);
|
||||
holder.itemView.setTag(itemModel);
|
||||
|
||||
holder.itemView.setOnClickListener(clickListener);
|
||||
holder.itemView.setOnLongClickListener(longClickListener);
|
||||
|
||||
holder.itemView.setOnClickListener(v -> getInternalOnItemClickListener().onItemClick(itemModel, position));
|
||||
holder.itemView.setOnLongClickListener(v -> getInternalOnLongItemClickListener().onItemLongClick(itemModel, position));
|
||||
final MediaItemType mediaType = itemModel.getItemType();
|
||||
|
||||
holder.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO || mediaType == MediaItemType.MEDIA_TYPE_SLIDER
|
||||
? View.VISIBLE : View.GONE);
|
||||
|
||||
holder.typeIcon.setImageResource(mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? R.drawable.slider : R.drawable.video);
|
||||
|
||||
holder.typeIcon.setVisibility(
|
||||
mediaType == MediaItemType.MEDIA_TYPE_VIDEO || mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
holder.typeIcon.setImageResource(mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? R.drawable.ic_slider_24 : R.drawable.ic_video_24);
|
||||
holder.selectedView.setVisibility(itemModel.isSelected() ? View.VISIBLE : View.GONE);
|
||||
holder.progressView.setVisibility(View.VISIBLE);
|
||||
|
||||
Glide.with(layoutInflater.getContext()).load(itemModel.getDisplayUrl()).listener(new RequestListener<Drawable>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable final GlideException e, final Object model, final Target<Drawable> target, final boolean isFirstResource) {
|
||||
holder.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(final Drawable resource, final Object model, final Target<Drawable> target, final DataSource dataSource, final boolean isFirstResource) {
|
||||
holder.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
}).into(holder.postImage);
|
||||
|
||||
holder.postImage.setImageURI(itemModel.getDisplayUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return discoverItemModels == null ? 0 : discoverItemModels.size();
|
||||
}
|
||||
}
|
@ -1,496 +1,111 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.github.chrisbanes.photoview.PhotoView;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.activities.CommentsViewer;
|
||||
import awais.instagrabber.activities.PostViewer;
|
||||
import awais.instagrabber.adapters.viewholder.FeedItemViewHolder;
|
||||
import awais.instagrabber.customviews.CommentMentionClickSpan;
|
||||
import awais.instagrabber.adapters.viewholder.feed.FeedItemViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.feed.FeedPhotoViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.feed.FeedSliderViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.feed.FeedVideoViewHolder;
|
||||
import awais.instagrabber.customviews.RamboTextView;
|
||||
import awais.instagrabber.databinding.ItemFeedPhotoBinding;
|
||||
import awais.instagrabber.databinding.ItemFeedSliderBinding;
|
||||
import awais.instagrabber.databinding.ItemFeedVideoBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.BasePostModel;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.DownloadMethod;
|
||||
import awais.instagrabber.models.enums.ItemGetType;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class FeedAdapter extends RecyclerView.Adapter<FeedItemViewHolder> {
|
||||
private final static String ellipsize = "… more";
|
||||
private final Activity activity;
|
||||
private final LayoutInflater layoutInflater;
|
||||
private final ArrayList<FeedModel> feedModels;
|
||||
public final class FeedAdapter extends ListAdapter<FeedModel, FeedItemViewHolder> {
|
||||
private static final String TAG = "FeedAdapter";
|
||||
private final View.OnClickListener clickListener;
|
||||
private final MentionClickListener mentionClickListener;
|
||||
private final View.OnClickListener clickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(@NonNull final View v) {
|
||||
final Object tag = v.getTag();
|
||||
|
||||
if (tag instanceof FeedModel) {
|
||||
final FeedModel feedModel = (FeedModel) tag;
|
||||
|
||||
if (v instanceof RamboTextView) {
|
||||
if (feedModel.isMentionClicked())
|
||||
feedModel.toggleCaption();
|
||||
feedModel.setMentionClicked(false);
|
||||
if (!expandCollapseTextView((RamboTextView) v, feedModel))
|
||||
feedModel.toggleCaption();
|
||||
|
||||
} else {
|
||||
final int id = v.getId();
|
||||
switch (id) {
|
||||
case R.id.btnComments:
|
||||
activity.startActivityForResult(new Intent(activity, CommentsViewer.class)
|
||||
.putExtra(Constants.EXTRAS_SHORTCODE, feedModel.getShortCode())
|
||||
.putExtra(Constants.EXTRAS_POST, feedModel.getPostId())
|
||||
.putExtra(Constants.EXTRAS_USER, feedModel.getProfileModel().getId()), 6969);
|
||||
break;
|
||||
|
||||
case R.id.viewStoryPost:
|
||||
activity.startActivity(new Intent(activity, PostViewer.class)
|
||||
.putExtra(Constants.EXTRAS_INDEX, feedModel.getPosition())
|
||||
.putExtra(Constants.EXTRAS_POST, new PostModel(feedModel.getShortCode(), false))
|
||||
.putExtra(Constants.EXTRAS_TYPE, ItemGetType.FEED_ITEMS));
|
||||
break;
|
||||
|
||||
case R.id.btnDownload:
|
||||
final Context context = v.getContext();
|
||||
ProfileModel profileModel = feedModel.getProfileModel();
|
||||
final String username = profileModel != null ? profileModel.getUsername() : null;
|
||||
|
||||
final ViewerPostModel[] sliderItems = feedModel.getSliderItems();
|
||||
|
||||
if (feedModel.getItemType() != MediaItemType.MEDIA_TYPE_SLIDER || sliderItems == null || sliderItems.length == 1)
|
||||
Utils.batchDownload(context, username, DownloadMethod.DOWNLOAD_FEED, Collections.singletonList(feedModel));
|
||||
else {
|
||||
final ArrayList<BasePostModel> postModels = new ArrayList<>();
|
||||
final DialogInterface.OnClickListener clickListener = (dialog, which) -> {
|
||||
postModels.clear();
|
||||
|
||||
final boolean breakWhenFoundSelected = which == DialogInterface.BUTTON_POSITIVE;
|
||||
|
||||
for (final ViewerPostModel sliderItem : sliderItems) {
|
||||
if (sliderItem != null) {
|
||||
if (!breakWhenFoundSelected) postModels.add(sliderItem);
|
||||
else if (sliderItem.isSelected()) {
|
||||
postModels.add(sliderItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// shows 0 items on first item of viewpager cause onPageSelected hasn't been called yet
|
||||
if (breakWhenFoundSelected && postModels.size() == 0)
|
||||
postModels.add(sliderItems[0]);
|
||||
|
||||
if (postModels.size() > 0)
|
||||
Utils.batchDownload(context, username, DownloadMethod.DOWNLOAD_FEED, postModels);
|
||||
};
|
||||
|
||||
new AlertDialog.Builder(context).setTitle(R.string.post_viewer_download_dialog_title)
|
||||
.setPositiveButton(R.string.post_viewer_download_current, clickListener)
|
||||
.setNegativeButton(R.string.post_viewer_download_album, clickListener).show();
|
||||
}
|
||||
break;
|
||||
|
||||
case R.id.ivProfilePic:
|
||||
if (mentionClickListener != null) {
|
||||
profileModel = feedModel.getProfileModel();
|
||||
if (profileModel != null)
|
||||
mentionClickListener.onClick(null, profileModel.getUsername(), false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
private final View.OnLongClickListener longClickListener = v -> {
|
||||
final Object tag;
|
||||
if (v instanceof RamboTextView && (tag = v.getTag()) instanceof FeedModel)
|
||||
Utils.copyText(v.getContext(), ((FeedModel) tag).getPostCaption());
|
||||
return true;
|
||||
};
|
||||
public SimpleExoPlayer pagerPlayer;
|
||||
private final PlayerChangeListener playerChangeListener = (childPos, player) -> {
|
||||
// todo
|
||||
pagerPlayer = player;
|
||||
|
||||
private static final DiffUtil.ItemCallback<FeedModel> diffCallback = new DiffUtil.ItemCallback<FeedModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
};
|
||||
|
||||
public FeedAdapter(final Activity activity, final ArrayList<FeedModel> FeedModels, final MentionClickListener mentionClickListener) {
|
||||
this.activity = activity;
|
||||
this.feedModels = FeedModels;
|
||||
public FeedAdapter(final View.OnClickListener clickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
super(diffCallback);
|
||||
// private final static String ellipsize = "… more";
|
||||
this.clickListener = clickListener;
|
||||
this.mentionClickListener = mentionClickListener;
|
||||
this.layoutInflater = LayoutInflater.from(activity);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FeedItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final View view;
|
||||
if (viewType == MediaItemType.MEDIA_TYPE_VIDEO.ordinal())
|
||||
view = layoutInflater.inflate(R.layout.item_feed_video, parent, false);
|
||||
else if (viewType == MediaItemType.MEDIA_TYPE_SLIDER.ordinal())
|
||||
view = layoutInflater.inflate(R.layout.item_feed_slider, parent, false);
|
||||
else
|
||||
view = layoutInflater.inflate(R.layout.item_feed, parent, false);
|
||||
return new FeedItemViewHolder(view);
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final FeedItemViewHolder viewHolder, final int position) {
|
||||
final FeedModel feedModel = feedModels.get(position);
|
||||
if (feedModel != null) {
|
||||
final RequestManager glideRequestManager = Glide.with(viewHolder.itemView);
|
||||
|
||||
feedModel.setPosition(position);
|
||||
|
||||
viewHolder.viewPost.setTag(feedModel);
|
||||
viewHolder.profilePic.setTag(feedModel);
|
||||
viewHolder.btnDownload.setTag(feedModel);
|
||||
viewHolder.viewerCaption.setTag(feedModel);
|
||||
|
||||
final ProfileModel profileModel = feedModel.getProfileModel();
|
||||
if (profileModel != null) {
|
||||
glideRequestManager.load(profileModel.getSdProfilePic()).into(viewHolder.profilePic);
|
||||
final int titleLen = profileModel.getUsername().length() + 1;
|
||||
final SpannableString spannableString = new SpannableString("@"+profileModel.getUsername());
|
||||
spannableString.setSpan(new CommentMentionClickSpan(), 0, titleLen, 0);
|
||||
viewHolder.username.setText(spannableString);
|
||||
viewHolder.username.setMovementMethod(new LinkMovementMethod());
|
||||
viewHolder.username.setMentionClickListener((view, text, isHashtag) ->
|
||||
mentionClickListener.onClick(null, profileModel.getUsername(), false));
|
||||
final Context context = parent.getContext();
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(context);
|
||||
final MediaItemType type = MediaItemType.valueOf(viewType);
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_VIDEO: {
|
||||
final ItemFeedVideoBinding binding = ItemFeedVideoBinding.inflate(layoutInflater, parent, false);
|
||||
return new FeedVideoViewHolder(binding, mentionClickListener, clickListener, longClickListener);
|
||||
}
|
||||
|
||||
viewHolder.viewPost.setOnClickListener(clickListener);
|
||||
viewHolder.profilePic.setOnClickListener(clickListener);
|
||||
viewHolder.btnDownload.setOnClickListener(clickListener);
|
||||
|
||||
viewHolder.tvPostDate.setText(feedModel.getPostDate());
|
||||
|
||||
final long commentsCount = feedModel.getCommentsCount();
|
||||
viewHolder.commentsCount.setText(String.valueOf(commentsCount));
|
||||
|
||||
viewHolder.btnComments.setTag(feedModel);
|
||||
viewHolder.btnComments.setOnClickListener(clickListener);
|
||||
viewHolder.btnComments.setEnabled(true);
|
||||
|
||||
final JSONObject location = feedModel.getLocation();
|
||||
|
||||
if (location == null) {
|
||||
viewHolder.location.setVisibility(View.GONE);
|
||||
viewHolder.username.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
case MEDIA_TYPE_SLIDER: {
|
||||
final ItemFeedSliderBinding binding = ItemFeedSliderBinding.inflate(layoutInflater, parent, false);
|
||||
return new FeedSliderViewHolder(binding, mentionClickListener, clickListener, longClickListener);
|
||||
}
|
||||
else {
|
||||
viewHolder.location.setVisibility(View.VISIBLE);
|
||||
viewHolder.location.setText(location.optString("name"));
|
||||
viewHolder.username.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
viewHolder.location.setOnClickListener(v ->
|
||||
new AlertDialog.Builder(v.getContext()).setTitle(location.optString("name"))
|
||||
.setMessage(R.string.comment_view_mention_location_search)
|
||||
.setNegativeButton(R.string.cancel, null).setPositiveButton(R.string.ok,
|
||||
(dialog, which) -> mentionClickListener.onClick(null, location.optString("id")+"/"+location.optString("slug"), false)).show()
|
||||
);
|
||||
}
|
||||
|
||||
final String thumbnailUrl = feedModel.getThumbnailUrl();
|
||||
final String displayUrl = feedModel.getDisplayUrl();
|
||||
CharSequence postCaption = feedModel.getPostCaption();
|
||||
|
||||
final boolean captionEmpty = Utils.isEmpty(postCaption);
|
||||
|
||||
viewHolder.viewerCaption.setOnClickListener(clickListener);
|
||||
viewHolder.viewerCaption.setOnLongClickListener(longClickListener);
|
||||
viewHolder.viewerCaption.setVisibility(captionEmpty ? View.GONE : View.VISIBLE);
|
||||
|
||||
if (!captionEmpty && Utils.hasMentions(postCaption)) {
|
||||
postCaption = Utils.getMentionText(postCaption);
|
||||
feedModel.setPostCaption(postCaption);
|
||||
viewHolder.viewerCaption.setText(postCaption, TextView.BufferType.SPANNABLE);
|
||||
viewHolder.viewerCaption.setMentionClickListener(mentionClickListener);
|
||||
} else {
|
||||
viewHolder.viewerCaption.setText(postCaption);
|
||||
}
|
||||
|
||||
expandCollapseTextView(viewHolder.viewerCaption, feedModel);
|
||||
|
||||
final MediaItemType itemType = feedModel.getItemType();
|
||||
final View viewToChangeHeight;
|
||||
|
||||
if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
viewToChangeHeight = viewHolder.playerView;
|
||||
final Player player = viewHolder.playerView.getPlayer();
|
||||
if (player != null) {
|
||||
final boolean shouldAutoplay = settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS);
|
||||
player.setPlayWhenReady(shouldAutoplay);
|
||||
}
|
||||
viewHolder.videoViewsParent.setVisibility(View.VISIBLE);
|
||||
viewHolder.videoViews.setText(String.valueOf(feedModel.getViewCount()));
|
||||
} else {
|
||||
viewHolder.videoViewsParent.setVisibility(View.GONE);
|
||||
viewHolder.btnMute.setVisibility(View.GONE);
|
||||
|
||||
if (itemType == MediaItemType.MEDIA_TYPE_SLIDER) {
|
||||
viewToChangeHeight = viewHolder.mediaList;
|
||||
|
||||
final ViewerPostModel[] sliderItems = feedModel.getSliderItems();
|
||||
final int sliderItemLen = sliderItems != null ? sliderItems.length : 0;
|
||||
|
||||
if (sliderItemLen > 0) {
|
||||
viewHolder.mediaCounter.setText("1/" + sliderItemLen);
|
||||
viewHolder.mediaList.setOffscreenPageLimit(Math.min(5, sliderItemLen));
|
||||
|
||||
final ViewPager.SimpleOnPageChangeListener simpleOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
|
||||
private int prevPos = 0;
|
||||
|
||||
@Override
|
||||
public void onPageSelected(final int position) {
|
||||
ViewerPostModel sliderItem = sliderItems[prevPos];
|
||||
if (sliderItem != null) sliderItem.setSelected(false);
|
||||
sliderItem = sliderItems[position];
|
||||
if (sliderItem != null) sliderItem.setSelected(true);
|
||||
|
||||
View childAt = viewHolder.mediaList.getChildAt(prevPos);
|
||||
if (childAt instanceof PlayerView) {
|
||||
pagerPlayer = (SimpleExoPlayer) ((PlayerView) childAt).getPlayer();
|
||||
if (pagerPlayer != null) pagerPlayer.setPlayWhenReady(false);
|
||||
}
|
||||
childAt = viewHolder.mediaList.getChildAt(position);
|
||||
if (childAt instanceof PlayerView) {
|
||||
pagerPlayer = (SimpleExoPlayer) ((PlayerView) childAt).getPlayer();
|
||||
if (pagerPlayer != null) pagerPlayer.setPlayWhenReady(true);
|
||||
}
|
||||
prevPos = position;
|
||||
viewHolder.mediaCounter.setText((position + 1) + "/" + sliderItemLen);
|
||||
}
|
||||
};
|
||||
|
||||
//noinspection deprecation
|
||||
viewHolder.mediaList.setOnPageChangeListener(simpleOnPageChangeListener); // cause add listeners might add to recycled holders
|
||||
|
||||
final View.OnClickListener muteClickListener = v -> {
|
||||
Player player = null;
|
||||
if (v instanceof PlayerView) player = ((PlayerView) v).getPlayer();
|
||||
else if (v instanceof ImageView || v == viewHolder.btnMute) {
|
||||
final int currentItem = viewHolder.mediaList.getCurrentItem();
|
||||
if (currentItem < viewHolder.mediaList.getChildCount()) {
|
||||
final View childAt = viewHolder.mediaList.getChildAt(currentItem);
|
||||
if (childAt instanceof PlayerView) player = ((PlayerView) childAt).getPlayer();
|
||||
}
|
||||
|
||||
} else {
|
||||
final Object tag = v.getTag();
|
||||
if (tag instanceof Player) player = (Player) tag;
|
||||
}
|
||||
|
||||
if (player instanceof SimpleExoPlayer) {
|
||||
final SimpleExoPlayer exoPlayer = (SimpleExoPlayer) player;
|
||||
final float intVol = exoPlayer.getVolume() == 0f ? 1f : 0f;
|
||||
exoPlayer.setVolume(intVol);
|
||||
viewHolder.btnMute.setImageResource(intVol == 0f ? R.drawable.mute : R.drawable.vol);
|
||||
Utils.sessionVolumeFull = intVol == 1f;
|
||||
}
|
||||
};
|
||||
|
||||
viewHolder.btnMute.setOnClickListener(muteClickListener);
|
||||
viewHolder.mediaList.setAdapter(new ChildMediaItemsAdapter(sliderItems, viewHolder.btnMute, playerChangeListener));
|
||||
}
|
||||
} else {
|
||||
viewToChangeHeight = viewHolder.imageView;
|
||||
String url = displayUrl;
|
||||
if (Utils.isEmpty(url)) url = thumbnailUrl;
|
||||
glideRequestManager.load(url).into(viewHolder.imageView);
|
||||
}
|
||||
}
|
||||
|
||||
if (viewToChangeHeight != null) {
|
||||
final ViewGroup.LayoutParams layoutParams = viewToChangeHeight.getLayoutParams();
|
||||
layoutParams.height = Utils.displayMetrics.widthPixels + 1;
|
||||
viewToChangeHeight.setLayoutParams(layoutParams);
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
default: {
|
||||
final ItemFeedPhotoBinding binding = ItemFeedPhotoBinding.inflate(layoutInflater, parent, false);
|
||||
return new FeedPhotoViewHolder(binding, mentionClickListener, clickListener, longClickListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return feedModels == null ? 0 : feedModels.size();
|
||||
public void onBindViewHolder(@NonNull final FeedItemViewHolder viewHolder, final int position) {
|
||||
final FeedModel feedModel = getItem(position);
|
||||
if (feedModel == null) {
|
||||
return;
|
||||
}
|
||||
feedModel.setPosition(position);
|
||||
viewHolder.bind(feedModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
if (feedModels != null) return feedModels.get(position).getItemType().ordinal();
|
||||
return MediaItemType.MEDIA_TYPE_IMAGE.ordinal();
|
||||
return getItem(position).getItemType().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* expands or collapses {@link RamboTextView} [stg idek why i wrote this documentation]
|
||||
*
|
||||
* @param textView the {@link RamboTextView} view, to expand and collapse
|
||||
* @param feedModel the {@link FeedModel} model to check wether model is collapsed to expanded
|
||||
*
|
||||
* @return true if expanded/collapsed, false if empty or text size is <= 255 chars
|
||||
*/
|
||||
public static boolean expandCollapseTextView(@NonNull final RamboTextView textView, @NonNull final FeedModel feedModel) {
|
||||
final CharSequence caption = feedModel.getPostCaption();
|
||||
if (Utils.isEmpty(caption)) return false;
|
||||
|
||||
final TextView.BufferType bufferType = caption instanceof Spanned ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL;
|
||||
|
||||
if (!feedModel.isCaptionExpanded()) {
|
||||
int i = Utils.indexOfChar(caption, '\r', 0);
|
||||
if (i == -1) i = Utils.indexOfChar(caption, '\n', 0);
|
||||
if (i == -1) i = 255;
|
||||
|
||||
final int captionLen = caption.length();
|
||||
final int minTrim = Math.min(255, i);
|
||||
if (captionLen <= minTrim) return false;
|
||||
|
||||
if (Utils.hasMentions(caption))
|
||||
textView.setText(Utils.getMentionText(caption), TextView.BufferType.SPANNABLE);
|
||||
textView.setCaptionIsExpandable(true);
|
||||
textView.setCaptionIsExpanded(true);
|
||||
} else {
|
||||
textView.setText(caption, bufferType);
|
||||
textView.setCaptionIsExpanded(false);
|
||||
}
|
||||
return true;
|
||||
@Override
|
||||
public void onViewAttachedToWindow(@NonNull final FeedItemViewHolder holder) {
|
||||
super.onViewAttachedToWindow(holder);
|
||||
// Log.d(TAG, "attached holder: " + holder);
|
||||
if (!(holder instanceof FeedSliderViewHolder)) return;
|
||||
final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder;
|
||||
feedSliderViewHolder.startPlayingVideo();
|
||||
}
|
||||
|
||||
private interface PlayerChangeListener {
|
||||
void playerChanged(final int childPos, final SimpleExoPlayer player);
|
||||
}
|
||||
|
||||
private static final class ChildMediaItemsAdapter extends PagerAdapter {
|
||||
private final PlayerChangeListener playerChangeListener;
|
||||
private final ViewerPostModel[] sliderItems;
|
||||
private final View btnMute;
|
||||
private SimpleExoPlayer player;
|
||||
|
||||
private ChildMediaItemsAdapter(final ViewerPostModel[] sliderItems, final View btnMute,
|
||||
final PlayerChangeListener playerChangeListener) {
|
||||
this.sliderItems = sliderItems;
|
||||
this.btnMute = btnMute;
|
||||
if (BuildConfig.DEBUG) this.playerChangeListener = playerChangeListener;
|
||||
else this.playerChangeListener = null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object instantiateItem(@NonNull final ViewGroup container, final int position) {
|
||||
final Context context = container.getContext();
|
||||
final ViewerPostModel sliderItem = sliderItems[position];
|
||||
|
||||
if (sliderItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
if (btnMute != null) btnMute.setVisibility(View.VISIBLE);
|
||||
final PlayerView playerView = new PlayerView(context);
|
||||
|
||||
player = new SimpleExoPlayer.Builder(context).build();
|
||||
playerView.setPlayer(player);
|
||||
|
||||
float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
if (vol == 0f && Utils.sessionVolumeFull) vol = 1f;
|
||||
player.setVolume(vol);
|
||||
player.setPlayWhenReady(Utils.settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
|
||||
|
||||
final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(new DefaultDataSourceFactory(context, "instagram"))
|
||||
.createMediaSource(Uri.parse(sliderItem.getDisplayUrl()));
|
||||
|
||||
player.setRepeatMode(Player.REPEAT_MODE_ALL);
|
||||
player.prepare(mediaSource);
|
||||
player.setVolume(vol);
|
||||
|
||||
playerView.setTag(player);
|
||||
|
||||
if (playerChangeListener != null) {
|
||||
//todo
|
||||
// playerChangeListener.playerChanged(position, player);
|
||||
Log.d("AWAISKING_APP", "playerChangeListener: " + playerChangeListener);
|
||||
}
|
||||
|
||||
container.addView(playerView);
|
||||
return playerView;
|
||||
} else {
|
||||
if (btnMute != null) btnMute.setVisibility(View.GONE);
|
||||
|
||||
final PhotoView photoView = new PhotoView(context);
|
||||
photoView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
Glide.with(context).load(sliderItem.getDisplayUrl()).into(photoView);
|
||||
container.addView(photoView);
|
||||
return photoView;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(@NonNull final ViewGroup container, final int position, @NonNull final Object object) {
|
||||
final Player player = object instanceof PlayerView ? ((PlayerView) object).getPlayer() : this.player;
|
||||
|
||||
if (player == this.player && this.player != null) {
|
||||
this.player.stop(true);
|
||||
this.player.release();
|
||||
} else if (player != null) {
|
||||
player.stop(true);
|
||||
player.release();
|
||||
}
|
||||
|
||||
container.removeView((View) object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return sliderItems != null ? sliderItems.length : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(@NonNull final View view, @NonNull final Object object) {
|
||||
return view == object;
|
||||
}
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull final FeedItemViewHolder holder) {
|
||||
super.onViewDetachedFromWindow(holder);
|
||||
// Log.d(TAG, "detached holder: " + holder);
|
||||
if (!(holder instanceof FeedSliderViewHolder)) return;
|
||||
final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder;
|
||||
feedSliderViewHolder.stopPlayingVideo();
|
||||
}
|
||||
}
|
@ -1,59 +1,51 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.HighlightViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.FeedStoryViewHolder;
|
||||
import awais.instagrabber.databinding.ItemHighlightBinding;
|
||||
import awais.instagrabber.models.FeedStoryModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
|
||||
public final class FeedStoriesAdapter extends RecyclerView.Adapter<HighlightViewHolder> {
|
||||
private final View.OnClickListener clickListener;
|
||||
private LayoutInflater layoutInflater;
|
||||
private FeedStoryModel[] feedStoryModels;
|
||||
public final class FeedStoriesAdapter extends ListAdapter<FeedStoryModel, FeedStoryViewHolder> {
|
||||
private final OnFeedStoryClickListener listener;
|
||||
|
||||
public FeedStoriesAdapter(final FeedStoryModel[] feedStoryModels, final View.OnClickListener clickListener) {
|
||||
this.feedStoryModels = feedStoryModels;
|
||||
this.clickListener = clickListener;
|
||||
private static final DiffUtil.ItemCallback<FeedStoryModel> diffCallback = new DiffUtil.ItemCallback<FeedStoryModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) {
|
||||
return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final FeedStoryModel oldItem, @NonNull final FeedStoryModel newItem) {
|
||||
return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId());
|
||||
}
|
||||
};
|
||||
|
||||
public FeedStoriesAdapter(final OnFeedStoryClickListener listener) {
|
||||
super(diffCallback);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public HighlightViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
if (layoutInflater == null) layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
return new HighlightViewHolder(layoutInflater.inflate(R.layout.item_highlight, parent, false));
|
||||
public FeedStoryViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemHighlightBinding binding = ItemHighlightBinding.inflate(layoutInflater, parent, false);
|
||||
return new FeedStoryViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final HighlightViewHolder holder, final int position) {
|
||||
final FeedStoryModel feedStoryModel = feedStoryModels[position];
|
||||
if (feedStoryModel != null) {
|
||||
holder.itemView.setTag(feedStoryModel);
|
||||
holder.itemView.setOnClickListener(clickListener);
|
||||
|
||||
final ProfileModel profileModel = feedStoryModel.getProfileModel();
|
||||
|
||||
holder.title.setText(profileModel.getUsername());
|
||||
Glide.with(layoutInflater.getContext()).load(profileModel.getSdProfilePic()).into(holder.icon);
|
||||
holder.icon.setAlpha(feedStoryModel.getFullyRead() ? 0.5F : 1.0F);
|
||||
holder.title.setAlpha(feedStoryModel.getFullyRead() ? 0.5F : 1.0F);
|
||||
}
|
||||
public void onBindViewHolder(@NonNull final FeedStoryViewHolder holder, final int position) {
|
||||
final FeedStoryModel model = getItem(position);
|
||||
holder.bind(model, position, listener);
|
||||
}
|
||||
|
||||
public void setData(final FeedStoryModel[] feedStoryModels) {
|
||||
this.feedStoryModels = feedStoryModels;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return feedStoryModels == null ? 0 : feedStoryModels.length;
|
||||
public interface OnFeedStoryClickListener {
|
||||
void onFeedStoryClick(FeedStoryModel model, int position);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -11,16 +10,15 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.FollowsViewHolder;
|
||||
import awais.instagrabber.databinding.ItemFollowBinding;
|
||||
import awais.instagrabber.interfaces.OnGroupClickListener;
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import thoughtbot.expandableadapter.ExpandableGroup;
|
||||
import thoughtbot.expandableadapter.ExpandableList;
|
||||
import thoughtbot.expandableadapter.ExpandableListPosition;
|
||||
@ -34,7 +32,7 @@ public final class FollowAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
@Override
|
||||
protected FilterResults performFiltering(final CharSequence filter) {
|
||||
if (expandableList.groups != null) {
|
||||
final boolean isFilterEmpty = Utils.isEmpty(filter);
|
||||
final boolean isFilterEmpty = TextUtils.isEmpty(filter);
|
||||
final String query = isFilterEmpty ? null : filter.toString().toLowerCase();
|
||||
|
||||
for (int x = 0; x < expandableList.groups.size(); ++x) {
|
||||
@ -46,25 +44,30 @@ public final class FollowAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
final FollowModel followModel = items.get(i);
|
||||
|
||||
if (isFilterEmpty) followModel.setShown(true);
|
||||
else followModel.setShown(Utils.hasKey(query, followModel.getUsername(), followModel.getFullName()));
|
||||
else followModel.setShown(hasKey(query, followModel.getUsername(), followModel.getFullName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hasKey(final String key, final String username, final String name) {
|
||||
if (TextUtils.isEmpty(key)) return true;
|
||||
final boolean hasUserName = username != null && username.toLowerCase().contains(key);
|
||||
if (!hasUserName && name != null) return name.toLowerCase().contains(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(final CharSequence constraint, final FilterResults results) {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
private final View.OnClickListener onClickListener;
|
||||
private final LayoutInflater layoutInflater;
|
||||
private final ExpandableList expandableList;
|
||||
private final boolean hasManyGroups;
|
||||
|
||||
public FollowAdapter(final Context context, final View.OnClickListener onClickListener, @NonNull final ArrayList<ExpandableGroup> groups) {
|
||||
this.layoutInflater = LayoutInflater.from(context);
|
||||
public FollowAdapter(final View.OnClickListener onClickListener, @NonNull final ArrayList<ExpandableGroup> groups) {
|
||||
this.expandableList = new ExpandableList(groups);
|
||||
this.onClickListener = onClickListener;
|
||||
this.hasManyGroups = groups.size() > 1;
|
||||
@ -79,10 +82,15 @@ public final class FollowAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final boolean isGroup = hasManyGroups && viewType == ExpandableListPosition.GROUP;
|
||||
|
||||
final View view = layoutInflater.inflate(isGroup ? R.layout.header_follow : R.layout.item_follow, parent, false);
|
||||
|
||||
return isGroup ? new GroupViewHolder(view, this) : new FollowsViewHolder(view);
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final View view;
|
||||
if (isGroup) {
|
||||
view = layoutInflater.inflate(R.layout.header_follow, parent, false);
|
||||
return new GroupViewHolder(view, this);
|
||||
} else {
|
||||
final ItemFollowBinding binding = ItemFollowBinding.inflate(layoutInflater, parent, false);
|
||||
return new FollowsViewHolder(binding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -94,21 +102,10 @@ public final class FollowAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
final GroupViewHolder gvh = (GroupViewHolder) holder;
|
||||
gvh.setTitle(group.getTitle());
|
||||
gvh.toggle(isGroupExpanded(group));
|
||||
|
||||
} else {
|
||||
final FollowModel model = group.getItems(true).get(hasManyGroups ? listPos.childPos : position);
|
||||
|
||||
final FollowsViewHolder followHolder = (FollowsViewHolder) holder;
|
||||
if (model != null) {
|
||||
followHolder.itemView.setTag(model);
|
||||
followHolder.itemView.setOnClickListener(onClickListener);
|
||||
|
||||
followHolder.tvUsername.setText(model.getUsername());
|
||||
followHolder.tvFullName.setText(model.getFullName());
|
||||
|
||||
Glide.with(layoutInflater.getContext()).load(model.getProfilePicUrl()).into(followHolder.profileImage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
final FollowModel model = group.getItems(true).get(hasManyGroups ? listPos.childPos : position);
|
||||
((FollowsViewHolder) holder).bind(model, onClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,53 +1,55 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.HighlightViewHolder;
|
||||
import awais.instagrabber.databinding.ItemHighlightBinding;
|
||||
import awais.instagrabber.models.HighlightModel;
|
||||
|
||||
public final class HighlightsAdapter extends RecyclerView.Adapter<HighlightViewHolder> {
|
||||
private final View.OnClickListener clickListener;
|
||||
private LayoutInflater layoutInflater;
|
||||
private HighlightModel[] highlightModels;
|
||||
public final class HighlightsAdapter extends ListAdapter<HighlightModel, HighlightViewHolder> {
|
||||
|
||||
public HighlightsAdapter(final HighlightModel[] highlightModels, final View.OnClickListener clickListener) {
|
||||
this.highlightModels = highlightModels;
|
||||
private final OnHighlightClickListener clickListener;
|
||||
|
||||
private static final DiffUtil.ItemCallback<HighlightModel> diffCallback = new DiffUtil.ItemCallback<HighlightModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) {
|
||||
return oldItem.getId().equals(newItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) {
|
||||
return oldItem.getId().equals(newItem.getId());
|
||||
}
|
||||
};
|
||||
|
||||
public HighlightsAdapter(final OnHighlightClickListener clickListener) {
|
||||
super(diffCallback);
|
||||
this.clickListener = clickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public HighlightViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
if (layoutInflater == null) layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
return new HighlightViewHolder(layoutInflater.inflate(R.layout.item_highlight, parent, false));
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemHighlightBinding binding = ItemHighlightBinding.inflate(layoutInflater, parent, false);
|
||||
return new HighlightViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final HighlightViewHolder holder, final int position) {
|
||||
final HighlightModel highlightModel = highlightModels[position];
|
||||
if (highlightModel != null) {
|
||||
holder.itemView.setTag(highlightModel);
|
||||
holder.itemView.setOnClickListener(clickListener);
|
||||
holder.title.setText(highlightModel.getTitle());
|
||||
Glide.with(holder.itemView).load(highlightModel.getThumbnailUrl()).into(holder.icon);
|
||||
final HighlightModel highlightModel = getItem(position);
|
||||
if (clickListener != null) {
|
||||
holder.itemView.setOnClickListener(v -> clickListener.onHighlightClick(highlightModel, position));
|
||||
}
|
||||
holder.bind(highlightModel);
|
||||
}
|
||||
|
||||
public void setData(final HighlightModel[] highlightModels) {
|
||||
this.highlightModels = highlightModels;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return highlightModels == null ? 0 : highlightModels.length;
|
||||
public interface OnHighlightClickListener {
|
||||
void onHighlightClick(final HighlightModel model, final int position);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,104 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MultiSelectListAdapter<T extends MultiSelectListAdapter.Selectable, VH extends RecyclerView.ViewHolder> extends
|
||||
ListAdapter<T, VH> {
|
||||
|
||||
private boolean isSelecting;
|
||||
private final OnItemClickListener<T> internalOnItemClickListener;
|
||||
private final OnItemLongClickListener<T> internalOnLongItemClickListener;
|
||||
|
||||
private final List<T> selectedItems = new ArrayList<>();
|
||||
|
||||
protected MultiSelectListAdapter(@NonNull final DiffUtil.ItemCallback<T> diffCallback,
|
||||
final OnItemClickListener<T> clickListener,
|
||||
final OnItemLongClickListener<T> longClickListener) {
|
||||
super(diffCallback);
|
||||
internalOnItemClickListener = (item, position) -> {
|
||||
if (isSelecting) {
|
||||
toggleSelection(item, position);
|
||||
}
|
||||
if (clickListener == null) {
|
||||
return;
|
||||
}
|
||||
clickListener.onItemClick(item, position);
|
||||
};
|
||||
internalOnLongItemClickListener = (item, position) -> {
|
||||
if (!isSelecting) {
|
||||
isSelecting = true;
|
||||
}
|
||||
toggleSelection(item, position);
|
||||
if (longClickListener == null) {
|
||||
return true;
|
||||
}
|
||||
return longClickListener.onItemLongClick(item, position);
|
||||
};
|
||||
}
|
||||
|
||||
public OnItemClickListener<T> getInternalOnItemClickListener() {
|
||||
return internalOnItemClickListener;
|
||||
}
|
||||
|
||||
public OnItemLongClickListener<T> getInternalOnLongItemClickListener() {
|
||||
return internalOnLongItemClickListener;
|
||||
}
|
||||
|
||||
private void toggleSelection(final T item, final int position) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
if (selectedItems.size() >= 100) {
|
||||
// Toast.makeText(mainActivity, R.string.downloader_too_many, Toast.LENGTH_SHORT);
|
||||
return;
|
||||
}
|
||||
if (item.isSelected()) {
|
||||
item.setSelected(false);
|
||||
selectedItems.remove(item);
|
||||
} else {
|
||||
item.setSelected(true);
|
||||
selectedItems.add(item);
|
||||
}
|
||||
if (selectedItems.size() == 0) {
|
||||
isSelecting = false;
|
||||
}
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
public boolean isSelecting() {
|
||||
return isSelecting;
|
||||
}
|
||||
|
||||
public List<T> getSelectedModels() {
|
||||
return selectedItems;
|
||||
}
|
||||
|
||||
public void clearSelection() {
|
||||
for (final T item : selectedItems) {
|
||||
item.setSelected(false);
|
||||
}
|
||||
selectedItems.clear();
|
||||
isSelecting = false;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public interface Selectable {
|
||||
boolean isSelected();
|
||||
|
||||
void setSelected(boolean selected);
|
||||
}
|
||||
|
||||
public interface OnItemClickListener<T> {
|
||||
void onItemClick(T item, int position);
|
||||
}
|
||||
|
||||
public interface OnItemLongClickListener<T> {
|
||||
boolean onItemLongClick(T item, int position);
|
||||
}
|
||||
}
|
90
app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java
Executable file → Normal file
90
app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java
Executable file → Normal file
@ -1,91 +1,55 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.NotificationViewHolder;
|
||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.NotificationModel;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
|
||||
public final class NotificationsAdapter extends RecyclerView.Adapter<NotificationViewHolder> {
|
||||
private final View.OnClickListener onClickListener;
|
||||
public final class NotificationsAdapter extends ListAdapter<NotificationModel, NotificationViewHolder> {
|
||||
private final OnNotificationClickListener notificationClickListener;
|
||||
private final MentionClickListener mentionClickListener;
|
||||
private final NotificationModel[] notificationModels;
|
||||
private LayoutInflater layoutInflater;
|
||||
|
||||
public NotificationsAdapter(final NotificationModel[] notificationModels, final View.OnClickListener onClickListener,
|
||||
private static final DiffUtil.ItemCallback<NotificationModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<NotificationModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final NotificationModel oldItem, @NonNull final NotificationModel newItem) {
|
||||
return oldItem.getId().equals(newItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final NotificationModel oldItem, @NonNull final NotificationModel newItem) {
|
||||
return oldItem.getId().equals(newItem.getId());
|
||||
}
|
||||
};
|
||||
|
||||
public NotificationsAdapter(final OnNotificationClickListener notificationClickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
this.notificationModels = notificationModels;
|
||||
this.onClickListener = onClickListener;
|
||||
super(DIFF_CALLBACK);
|
||||
this.notificationClickListener = notificationClickListener;
|
||||
this.mentionClickListener = mentionClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public NotificationViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) {
|
||||
final Context context = parent.getContext();
|
||||
if (layoutInflater == null) layoutInflater = LayoutInflater.from(context);
|
||||
return new NotificationViewHolder(layoutInflater.inflate(R.layout.item_notification,
|
||||
parent, false), onClickListener, mentionClickListener);
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemNotificationBinding binding = ItemNotificationBinding.inflate(layoutInflater, parent, false);
|
||||
return new NotificationViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final NotificationViewHolder holder, final int position) {
|
||||
final NotificationModel notificationModel = notificationModels[position];
|
||||
if (notificationModel != null) {
|
||||
holder.setNotificationModel(notificationModel);
|
||||
|
||||
int text = -1;
|
||||
CharSequence subtext = null;
|
||||
switch (notificationModel.getType()) {
|
||||
case LIKE:
|
||||
text = R.string.liked_notif;
|
||||
break;
|
||||
case COMMENT:
|
||||
text = R.string.comment_notif;
|
||||
subtext = notificationModel.getText();
|
||||
break;
|
||||
case MENTION:
|
||||
text = R.string.mention_notif;
|
||||
subtext = notificationModel.getText();
|
||||
break;
|
||||
case FOLLOW:
|
||||
text = R.string.follow_notif;
|
||||
break;
|
||||
case REQUEST:
|
||||
text = R.string.request_notif;
|
||||
subtext = notificationModel.getText();
|
||||
break;
|
||||
}
|
||||
|
||||
holder.setCommment(text);
|
||||
holder.setSubCommment(subtext);
|
||||
if (notificationModel.getType() != NotificationType.REQUEST)
|
||||
holder.setDate(notificationModel.getDateTime());
|
||||
|
||||
holder.setUsername(notificationModel.getUsername());
|
||||
|
||||
final RequestManager rm = Glide.with(layoutInflater.getContext())
|
||||
.applyDefaultRequestOptions(new RequestOptions().skipMemoryCache(true));
|
||||
|
||||
rm.load(notificationModel.getProfilePic()).into(holder.getProfilePicView());
|
||||
rm.load(notificationModel.getPreviewPic()).into(holder.getPreviewPicView());
|
||||
}
|
||||
final NotificationModel notificationModel = getItem(position);
|
||||
holder.bind(notificationModel, notificationClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return notificationModels == null ? 0 : notificationModels.length;
|
||||
public interface OnNotificationClickListener {
|
||||
void onNotificationClick(final NotificationModel model);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.PostViewerViewHolder;
|
||||
import awais.instagrabber.databinding.ItemFullPostViewBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.ViewerPostModelWrapper;
|
||||
|
||||
public class PostViewAdapter extends ListAdapter<ViewerPostModelWrapper, PostViewerViewHolder> {
|
||||
private final OnPostViewChildViewClickListener clickListener;
|
||||
private final OnPostCaptionLongClickListener longClickListener;
|
||||
private final MentionClickListener mentionClickListener;
|
||||
|
||||
private static final DiffUtil.ItemCallback<ViewerPostModelWrapper> diffCallback = new DiffUtil.ItemCallback<ViewerPostModelWrapper>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final ViewerPostModelWrapper oldItem,
|
||||
@NonNull final ViewerPostModelWrapper newItem) {
|
||||
return oldItem.getPosition() == newItem.getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final ViewerPostModelWrapper oldItem,
|
||||
@NonNull final ViewerPostModelWrapper newItem) {
|
||||
return Arrays.equals(oldItem.getViewerPostModels(), newItem.getViewerPostModels());
|
||||
}
|
||||
};
|
||||
|
||||
public PostViewAdapter(final OnPostViewChildViewClickListener clickListener,
|
||||
final OnPostCaptionLongClickListener longClickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
super(diffCallback);
|
||||
this.clickListener = clickListener;
|
||||
this.longClickListener = longClickListener;
|
||||
this.mentionClickListener = mentionClickListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull final PostViewerViewHolder holder) {
|
||||
holder.stopPlayingVideo();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PostViewerViewHolder onCreateViewHolder(@NonNull final ViewGroup parent,
|
||||
final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemFullPostViewBinding binding = ItemFullPostViewBinding
|
||||
.inflate(layoutInflater, parent, false);
|
||||
return new PostViewerViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final PostViewerViewHolder holder, final int position) {
|
||||
final ViewerPostModelWrapper item = getItem(position);
|
||||
holder.bind(item, position, clickListener, longClickListener, mentionClickListener);
|
||||
}
|
||||
|
||||
public interface OnPostViewChildViewClickListener {
|
||||
void onClick(View v,
|
||||
ViewerPostModelWrapper viewerPostModelWrapper,
|
||||
int postPosition,
|
||||
int childPosition);
|
||||
}
|
||||
|
||||
public interface OnPostCaptionLongClickListener {
|
||||
void onLongClick(String text);
|
||||
}
|
||||
}
|
@ -0,0 +1,203 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
|
||||
import awais.instagrabber.customviews.drawee.ZoomableDraweeView;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class PostViewerChildAdapter extends ListAdapter<ViewerPostModel, PostViewerChildAdapter.ChildViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<ViewerPostModel> diffCallback = new DiffUtil.ItemCallback<ViewerPostModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final ViewerPostModel oldItem, @NonNull final ViewerPostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId()) && oldItem.getShortCode().equals(newItem.getShortCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final ViewerPostModel oldItem, @NonNull final ViewerPostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId()) && oldItem.getShortCode().equals(newItem.getShortCode());
|
||||
}
|
||||
};
|
||||
|
||||
public PostViewerChildAdapter() {
|
||||
super(diffCallback);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ChildViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
// final AppCompatTextView textView = new AppCompatTextView(parent.getContext());
|
||||
// textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
// return new ChildViewHolder(textView);
|
||||
final MediaItemType mediaItemType = MediaItemType.valueOf(viewType);
|
||||
if (mediaItemType == null) return getPlaceholder(parent);
|
||||
switch (mediaItemType) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
return getImageViewHolder(parent);
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
return getVideoViewHolder(parent);
|
||||
default:
|
||||
return getPlaceholder(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private ChildViewHolder getImageViewHolder(final ViewGroup parent) {
|
||||
final ZoomableDraweeView view = new ZoomableDraweeView(parent.getContext());
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
return new ChildViewHolder(view);
|
||||
}
|
||||
|
||||
private ChildViewHolder getVideoViewHolder(final ViewGroup parent) {
|
||||
final PlayerView view = new PlayerView(parent.getContext());
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
return new ChildViewHolder(view);
|
||||
}
|
||||
|
||||
private ChildViewHolder getPlaceholder(final ViewGroup parent) {
|
||||
final AppCompatTextView textView = new AppCompatTextView(parent.getContext());
|
||||
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
textView.setGravity(Gravity.CENTER);
|
||||
textView.setText("Placeholder");
|
||||
return new ChildViewHolder(textView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final ChildViewHolder holder, final int position) {
|
||||
holder.bind(getItem(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
final ViewerPostModel item = getItem(position);
|
||||
return item.getItemType().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull final ChildViewHolder holder) {
|
||||
if (holder.itemView instanceof PlayerView) {
|
||||
final Player player = ((PlayerView) holder.itemView).getPlayer();
|
||||
if (player != null) {
|
||||
player.setPlayWhenReady(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull final ChildViewHolder holder) {
|
||||
if (holder.itemView instanceof PlayerView) {
|
||||
final Player player = ((PlayerView) holder.itemView).getPlayer();
|
||||
if (player != null) {
|
||||
player.release();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (holder.itemView instanceof ZoomableDraweeView) {
|
||||
((ZoomableDraweeView) holder.itemView).setController(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ChildViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public ChildViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public void bind(final ViewerPostModel item) {
|
||||
final MediaItemType mediaItemType = item.getItemType();
|
||||
switch (mediaItemType) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
bindImage(item);
|
||||
break;
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
bindVideo(item);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private void bindImage(final ViewerPostModel item) {
|
||||
final ZoomableDraweeView imageView = (ZoomableDraweeView) itemView;
|
||||
imageView.setController(null);
|
||||
final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(item.getDisplayUrl()))
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
final DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(requestBuilder)
|
||||
.setOldController(imageView.getController())
|
||||
// .setControllerListener(new BaseControllerListener<ImageInfo>() {
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(final String id, final Throwable throwable) {
|
||||
// // viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFinalImageSet(final String id, final ImageInfo imageInfo, final Animatable animatable) {
|
||||
// // viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
// })
|
||||
.build();
|
||||
imageView.setController(controller);
|
||||
}
|
||||
|
||||
private void bindVideo(final ViewerPostModel item) {
|
||||
final SimpleExoPlayer player = new SimpleExoPlayer.Builder(itemView.getContext()).build();
|
||||
final PlayerView playerView = (PlayerView) itemView;
|
||||
playerView.setPlayer(player);
|
||||
float vol = Utils.settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
if (vol == 0f && Utils.sessionVolumeFull) vol = 1f;
|
||||
player.setVolume(vol);
|
||||
player.setPlayWhenReady(Utils.settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
|
||||
final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(new DefaultDataSourceFactory(itemView.getContext(), "instagram"))
|
||||
.createMediaSource(Uri.parse(item.getDisplayUrl()));
|
||||
// mediaSource.addEventListener(new Handler(), new MediaSourceEventListener() {
|
||||
// @Override
|
||||
// public void onLoadCompleted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
// viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onLoadStarted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
// viewerBinding.progressView.setVisibility(View.VISIBLE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onLoadCanceled(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
// viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onLoadError(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData, final IOException error, final boolean wasCanceled) {
|
||||
// viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
// });
|
||||
player.prepare(mediaSource);
|
||||
player.setVolume(vol);
|
||||
// viewerBinding.bottomPanel.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24);
|
||||
// viewerBinding.bottomPanel.btnMute.setOnClickListener(onClickListener);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,92 +1,45 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.PostViewHolder;
|
||||
import awais.instagrabber.databinding.ItemPostBinding;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
|
||||
public final class PostsAdapter extends RecyclerView.Adapter<PostViewHolder> {
|
||||
private final ArrayList<PostModel> postModels;
|
||||
private final View.OnClickListener clickListener;
|
||||
private final View.OnLongClickListener longClickListener;
|
||||
private LayoutInflater layoutInflater;
|
||||
public boolean isSelecting = false;
|
||||
public final class PostsAdapter extends MultiSelectListAdapter<PostModel, PostViewHolder> {
|
||||
|
||||
public PostsAdapter(final ArrayList<PostModel> postModels, final View.OnClickListener clickListener,
|
||||
final View.OnLongClickListener longClickListener) {
|
||||
this.postModels = postModels;
|
||||
this.clickListener = clickListener;
|
||||
this.longClickListener = longClickListener;
|
||||
private static final DiffUtil.ItemCallback<PostModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<PostModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final PostModel oldItem, @NonNull final PostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final PostModel oldItem, @NonNull final PostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
};
|
||||
|
||||
public PostsAdapter(final OnItemClickListener<PostModel> clickListener,
|
||||
final OnItemLongClickListener<PostModel> longClickListener) {
|
||||
super(DIFF_CALLBACK, clickListener, longClickListener);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PostViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
if (layoutInflater == null) layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
return new PostViewHolder(layoutInflater.inflate(R.layout.item_post, parent, false));
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemPostBinding binding = ItemPostBinding.inflate(layoutInflater, parent, false);
|
||||
return new PostViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final PostViewHolder holder, final int position) {
|
||||
final PostModel postModel = postModels.get(position);
|
||||
if (postModel != null) {
|
||||
postModel.setPosition(position);
|
||||
|
||||
holder.itemView.setTag(postModel);
|
||||
|
||||
holder.itemView.setOnClickListener(clickListener);
|
||||
holder.itemView.setOnLongClickListener(longClickListener);
|
||||
|
||||
final MediaItemType itemType = postModel.getItemType();
|
||||
final boolean isSlider = itemType == MediaItemType.MEDIA_TYPE_SLIDER;
|
||||
|
||||
holder.isDownloaded.setVisibility(postModel.isDownloaded() ? View.VISIBLE : View.GONE);
|
||||
|
||||
holder.typeIcon.setVisibility(itemType == MediaItemType.MEDIA_TYPE_VIDEO || isSlider ? View.VISIBLE : View.GONE);
|
||||
holder.typeIcon.setImageResource(isSlider ? R.drawable.slider : R.drawable.video);
|
||||
|
||||
holder.selectedView.setVisibility(postModel.isSelected() ? View.VISIBLE : View.GONE);
|
||||
holder.progressView.setVisibility(View.VISIBLE);
|
||||
|
||||
final RequestManager glideRequestManager = Glide.with(holder.postImage);
|
||||
|
||||
glideRequestManager.load(postModel.getThumbnailUrl()).listener(new RequestListener<Drawable>() {
|
||||
@Override
|
||||
public boolean onResourceReady(final Drawable resource, final Object model, final Target<Drawable> target, final DataSource dataSource, final boolean isFirstResource) {
|
||||
holder.progressView.setVisibility(View.GONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable final GlideException e, final Object model, final Target<Drawable> target, final boolean isFirstResource) {
|
||||
holder.progressView.setVisibility(View.GONE);
|
||||
// glideRequestManager.load(postModel.getDisplayUrl()).into(holder.postImage);
|
||||
return false;
|
||||
}
|
||||
}).into(holder.postImage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return postModels == null ? 0 : postModels.size();
|
||||
final PostModel postModel = getItem(position);
|
||||
holder.bind(postModel, position, getInternalOnItemClickListener(), getInternalOnLongItemClickListener());
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,14 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.PostMediaViewHolder;
|
||||
import awais.instagrabber.databinding.ItemChildPostBinding;
|
||||
import awais.instagrabber.models.BasePostModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
|
||||
public final class PostsMediaAdapter extends RecyclerView.Adapter<PostMediaViewHolder> {
|
||||
private final View.OnClickListener clickListener;
|
||||
private LayoutInflater layoutInflater;
|
||||
private ViewerPostModel[] postModels;
|
||||
|
||||
public PostsMediaAdapter(final ViewerPostModel[] postModels, final View.OnClickListener clickListener) {
|
||||
@ -27,25 +25,16 @@ public final class PostsMediaAdapter extends RecyclerView.Adapter<PostMediaViewH
|
||||
@NonNull
|
||||
@Override
|
||||
public PostMediaViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
if (layoutInflater == null) layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
return new PostMediaViewHolder(layoutInflater.inflate(R.layout.item_child_post, parent, false));
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
layoutInflater.inflate(R.layout.item_child_post, parent, false);
|
||||
final ItemChildPostBinding binding = ItemChildPostBinding.inflate(layoutInflater, parent, false);
|
||||
return new PostMediaViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final PostMediaViewHolder holder, final int position) {
|
||||
final ViewerPostModel postModel = postModels[position];
|
||||
if (postModel != null) {
|
||||
postModel.setPosition(position);
|
||||
|
||||
holder.itemView.setTag(postModel);
|
||||
holder.itemView.setOnClickListener(clickListener);
|
||||
|
||||
holder.selectedView.setVisibility(postModel.isCurrentSlide() ? View.VISIBLE : View.GONE);
|
||||
|
||||
holder.isDownloaded.setVisibility(postModel.isDownloaded() ? View.VISIBLE : View.GONE);
|
||||
|
||||
Glide.with(layoutInflater.getContext()).load(postModel.getSliderDisplayUrl()).into(holder.icon);
|
||||
}
|
||||
holder.bind(postModel, position, clickListener);
|
||||
}
|
||||
|
||||
public void setData(final ViewerPostModel[] postModels) {
|
||||
|
@ -1,84 +1,80 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ItemStoryBinding;
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
|
||||
public final class StoriesAdapter extends RecyclerView.Adapter<StoriesAdapter.StoryViewHolder> {
|
||||
private final View.OnClickListener clickListener;
|
||||
private LayoutInflater layoutInflater;
|
||||
private StoryModel[] storyModels;
|
||||
private Resources resources;
|
||||
private int width, height;
|
||||
public final class StoriesAdapter extends ListAdapter<StoryModel, StoriesAdapter.StoryViewHolder> {
|
||||
private final OnItemClickListener onItemClickListener;
|
||||
|
||||
public StoriesAdapter(final StoryModel[] storyModels, final View.OnClickListener clickListener) {
|
||||
this.storyModels = storyModels;
|
||||
this.clickListener = clickListener;
|
||||
private static final DiffUtil.ItemCallback<StoryModel> diffCallback = new DiffUtil.ItemCallback<StoryModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final StoryModel oldItem, @NonNull final StoryModel newItem) {
|
||||
return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final StoryModel oldItem, @NonNull final StoryModel newItem) {
|
||||
return oldItem.getStoryMediaId().equals(newItem.getStoryMediaId());
|
||||
}
|
||||
};
|
||||
|
||||
public StoriesAdapter(final OnItemClickListener onItemClickListener) {
|
||||
super(diffCallback);
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StoryViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final Context context = parent.getContext();
|
||||
if (layoutInflater == null) layoutInflater = LayoutInflater.from(context);
|
||||
if (resources == null) resources = context.getResources();
|
||||
|
||||
height = Math.round(resources.getDimension(R.dimen.story_item_height));
|
||||
width = Math.round(resources.getDimension(R.dimen.story_item_width));
|
||||
|
||||
return new StoryViewHolder(layoutInflater.inflate(R.layout.item_story, parent, false));
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemStoryBinding binding = ItemStoryBinding.inflate(layoutInflater, parent, false);
|
||||
return new StoryViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final StoryViewHolder holder, final int position) {
|
||||
final StoryModel storyModel = storyModels[position];
|
||||
if (storyModel != null) {
|
||||
storyModel.setPosition(position);
|
||||
|
||||
holder.itemView.setTag(storyModel);
|
||||
holder.itemView.setOnClickListener(clickListener);
|
||||
|
||||
holder.selectedView.setVisibility(storyModel.isCurrentSlide() ? View.VISIBLE : View.GONE);
|
||||
|
||||
Glide.with(holder.itemView).load(storyModel.getStoryUrl())
|
||||
.apply(new RequestOptions().override(width, height))
|
||||
.into(holder.icon);
|
||||
}
|
||||
}
|
||||
|
||||
public void setData(final StoryModel[] storyModels) {
|
||||
this.storyModels = storyModels;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public StoryModel getItemAt(final int position) {
|
||||
return storyModels == null ? null : storyModels[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return storyModels == null ? 0 : storyModels.length;
|
||||
final StoryModel storyModel = getItem(position);
|
||||
holder.bind(storyModel, position, onItemClickListener);
|
||||
}
|
||||
|
||||
public final static class StoryViewHolder extends RecyclerView.ViewHolder {
|
||||
public final ImageView icon, selectedView;
|
||||
private final ItemStoryBinding binding;
|
||||
|
||||
public StoryViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
selectedView = itemView.findViewById(R.id.selectedView);
|
||||
icon = itemView.findViewById(R.id.icon);
|
||||
public StoryViewHolder(final ItemStoryBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final StoryModel model,
|
||||
final int position,
|
||||
final OnItemClickListener clickListener) {
|
||||
if (model == null) return;
|
||||
model.setPosition(position);
|
||||
|
||||
itemView.setTag(model);
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (clickListener == null) return;
|
||||
clickListener.onItemClick(model, position);
|
||||
});
|
||||
|
||||
binding.selectedView.setVisibility(model.isCurrentSlide() ? View.VISIBLE : View.GONE);
|
||||
binding.icon.setImageURI(model.getStoryUrl());
|
||||
// Glide.with(itemView).load(model.getStoryUrl())
|
||||
// .apply(new RequestOptions().override(width, height))
|
||||
// .into(holder.icon);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(StoryModel storyModel, int position);
|
||||
}
|
||||
}
|
@ -2,60 +2,87 @@ package awais.instagrabber.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cursoradapter.widget.CursorAdapter;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ItemSuggestionBinding;
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
|
||||
public final class SuggestionsAdapter extends CursorAdapter {
|
||||
private final LayoutInflater layoutInflater;
|
||||
private final View.OnClickListener onClickListener;
|
||||
private final RequestManager glideRequestManager;
|
||||
private static final String TAG = "SuggestionsAdapter";
|
||||
|
||||
public SuggestionsAdapter(final Context context, final View.OnClickListener onClickListener) {
|
||||
private final OnSuggestionClickListener onSuggestionClickListener;
|
||||
|
||||
public SuggestionsAdapter(final Context context,
|
||||
final OnSuggestionClickListener onSuggestionClickListener) {
|
||||
super(context, null, FLAG_REGISTER_CONTENT_OBSERVER);
|
||||
this.glideRequestManager = Glide.with(context);
|
||||
this.layoutInflater = LayoutInflater.from(context);
|
||||
this.onClickListener = onClickListener;
|
||||
this.onSuggestionClickListener = onSuggestionClickListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
|
||||
return layoutInflater.inflate(R.layout.item_suggestion, parent, false);
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(context);
|
||||
final ItemSuggestionBinding binding = ItemSuggestionBinding.inflate(layoutInflater, parent, false);
|
||||
return binding.getRoot();
|
||||
// return layoutInflater.inflate(R.layout.item_suggestion, parent, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(@NonNull final View view, final Context context, @NonNull final Cursor cursor) {
|
||||
// i, username, fullname, type, picUrl, verified
|
||||
// 0, 1 , 2 , 3 , 4 , 5
|
||||
|
||||
final String fullname = cursor.getString(2);
|
||||
final String fullName = cursor.getString(2);
|
||||
String username = cursor.getString(1);
|
||||
final String picUrl = cursor.getString(4);
|
||||
final boolean verified = cursor.getString(5).charAt(0) == 't';
|
||||
|
||||
if ("TYPE_HASHTAG".equals(cursor.getString(3))) username = '#' + username;
|
||||
else if ("TYPE_USER".equals(cursor.getString(3))) username = '@' + username;
|
||||
final String type = cursor.getString(3);
|
||||
SuggestionType suggestionType = null;
|
||||
try {
|
||||
suggestionType = SuggestionType.valueOf(type);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "Unknown suggestion type: " + type, e);
|
||||
}
|
||||
if (suggestionType == null) return;
|
||||
final String query;
|
||||
switch (suggestionType) {
|
||||
case TYPE_USER:
|
||||
username = '@' + username;
|
||||
query = username;
|
||||
break;
|
||||
case TYPE_HASHTAG:
|
||||
username = '#' + username;
|
||||
query = username;
|
||||
break;
|
||||
case TYPE_LOCATION:
|
||||
query = fullName;
|
||||
break;
|
||||
default:
|
||||
return; // will never come here
|
||||
}
|
||||
|
||||
view.setOnClickListener(onClickListener);
|
||||
view.setTag("TYPE_LOCATION".equals(cursor.getString(3)) ? fullname : username);
|
||||
if (onSuggestionClickListener != null) {
|
||||
final SuggestionType finalSuggestionType = suggestionType;
|
||||
view.setOnClickListener(v -> onSuggestionClickListener.onSuggestionClick(finalSuggestionType, query));
|
||||
}
|
||||
final ItemSuggestionBinding binding = ItemSuggestionBinding.bind(view);
|
||||
binding.isVerified.setVisibility(verified ? View.VISIBLE : View.GONE);
|
||||
binding.tvUsername.setText(username);
|
||||
if (suggestionType.equals(SuggestionType.TYPE_LOCATION)) {
|
||||
binding.tvFullName.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.tvFullName.setVisibility(View.VISIBLE);
|
||||
binding.tvFullName.setText(fullName);
|
||||
}
|
||||
binding.ivProfilePic.setImageURI(picUrl);
|
||||
}
|
||||
|
||||
view.findViewById(R.id.isVerified).setVisibility(verified ? View.VISIBLE : View.GONE);
|
||||
|
||||
((TextView) view.findViewById(R.id.tvUsername)).setText(username);
|
||||
((TextView) view.findViewById(R.id.tvFullName)).setText(fullname);
|
||||
|
||||
glideRequestManager.applyDefaultRequestOptions(new RequestOptions().skipMemoryCache(true))
|
||||
.load(picUrl == null ? R.drawable.ic_location : picUrl).into((ImageView) view.findViewById(R.id.ivProfilePic));
|
||||
public interface OnSuggestionClickListener {
|
||||
void onSuggestionClick(final SuggestionType type, final String query);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,22 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.common.ResizeOptions;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutIncludeSimpleItemBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.direct_messages.InboxThreadModel;
|
||||
@ -21,19 +24,18 @@ import awais.instagrabber.models.enums.DirectItemType;
|
||||
|
||||
public final class DirectMessageInboxItemViewHolder extends RecyclerView.ViewHolder {
|
||||
private final LinearLayout multipleProfilePicsContainer;
|
||||
private final ImageView[] multipleProfilePics;
|
||||
private final LayoutIncludeSimpleItemBinding binding;
|
||||
private final SimpleDraweeView[] multipleProfilePics;
|
||||
private final LayoutDmInboxItemBinding binding;
|
||||
|
||||
public DirectMessageInboxItemViewHolder(@NonNull final LayoutIncludeSimpleItemBinding binding) {
|
||||
public DirectMessageInboxItemViewHolder(@NonNull final LayoutDmInboxItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
binding.tvLikes.setVisibility(View.GONE);
|
||||
multipleProfilePicsContainer = binding.container;
|
||||
multipleProfilePicsContainer = binding.multiPicContainer;
|
||||
final LinearLayout containerChild = (LinearLayout) multipleProfilePicsContainer.getChildAt(1);
|
||||
multipleProfilePics = new ImageView[]{
|
||||
(ImageView) multipleProfilePicsContainer.getChildAt(0),
|
||||
(ImageView) containerChild.getChildAt(0),
|
||||
(ImageView) containerChild.getChildAt(1)
|
||||
multipleProfilePics = new SimpleDraweeView[]{
|
||||
(SimpleDraweeView) multipleProfilePicsContainer.getChildAt(0),
|
||||
(SimpleDraweeView) containerChild.getChildAt(0),
|
||||
(SimpleDraweeView) containerChild.getChildAt(1)
|
||||
};
|
||||
binding.tvDate.setSelected(true);
|
||||
binding.tvUsername.setSelected(true);
|
||||
@ -45,22 +47,35 @@ public final class DirectMessageInboxItemViewHolder extends RecyclerView.ViewHol
|
||||
return;
|
||||
}
|
||||
itemView.setTag(model);
|
||||
final RequestManager glideRequestManager = Glide.with(itemView);
|
||||
final ProfileModel[] users = model.getUsers();
|
||||
if (users.length > 1) {
|
||||
binding.ivProfilePic.setVisibility(View.GONE);
|
||||
multipleProfilePicsContainer.setVisibility(View.VISIBLE);
|
||||
for (int i = 0; i < Math.min(3, users.length); ++i)
|
||||
glideRequestManager.load(users[i].getSdProfilePic()).into(multipleProfilePics[i]);
|
||||
for (int i = 0; i < Math.min(3, users.length); ++i) {
|
||||
multipleProfilePics[i].setImageURI(users[i].getSdProfilePic());
|
||||
}
|
||||
} else {
|
||||
binding.ivProfilePic.setVisibility(View.VISIBLE);
|
||||
multipleProfilePicsContainer.setVisibility(View.GONE);
|
||||
glideRequestManager.load(users.length == 1 ? users[0].getSdProfilePic() : null).into(binding.ivProfilePic);
|
||||
final String uriString = users.length == 1 ? users[0].getSdProfilePic() : null;
|
||||
if (uriString == null) {
|
||||
binding.ivProfilePic.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.ivProfilePic.setVisibility(View.VISIBLE);
|
||||
multipleProfilePicsContainer.setVisibility(View.GONE);
|
||||
final ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(uriString))
|
||||
.setResizeOptions(new ResizeOptions(50, 50))
|
||||
.build();
|
||||
binding.ivProfilePic.setController(
|
||||
Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding.ivProfilePic.getController())
|
||||
.setImageRequest(request)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
binding.tvUsername.setText(model.getThreadTitle());
|
||||
final DirectItemModel lastItemModel = itemModels[itemModels.length - 1];
|
||||
final DirectItemType itemType = lastItemModel.getItemType();
|
||||
binding.notTextType.setVisibility(itemType != DirectItemType.TEXT ? View.VISIBLE : View.GONE);
|
||||
// binding.notTextType.setVisibility(itemType != DirectItemType.TEXT ? View.VISIBLE : View.GONE);
|
||||
final Context context = itemView.getContext();
|
||||
final CharSequence messageText;
|
||||
switch (itemType) {
|
||||
@ -104,6 +119,6 @@ public final class DirectMessageInboxItemViewHolder extends RecyclerView.ViewHol
|
||||
}
|
||||
binding.tvComment.setText(HtmlCompat.fromHtml(messageText.toString(), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
binding.tvDate.setText(lastItemModel.getDateTime());
|
||||
binding.unread.setVisibility(model.getUnreadCount() > 0L ? View.VISIBLE : View.GONE);
|
||||
binding.unread.setVisibility(model.getUnreadCount() > 0L ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
@ -6,17 +6,21 @@ import android.widget.ImageView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
|
||||
public final class DiscoverViewHolder extends RecyclerView.ViewHolder {
|
||||
public final ImageView postImage, typeIcon;
|
||||
public final View selectedView, progressView;
|
||||
public final SimpleDraweeView postImage;
|
||||
public final ImageView typeIcon;
|
||||
public final View selectedView;
|
||||
// public final View progressView;
|
||||
|
||||
public DiscoverViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
typeIcon = itemView.findViewById(R.id.typeIcon);
|
||||
postImage = itemView.findViewById(R.id.postImage);
|
||||
selectedView = itemView.findViewById(R.id.selectedView);
|
||||
progressView = itemView.findViewById(R.id.progressView);
|
||||
// progressView = itemView.findViewById(R.id.progressView);
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.github.chrisbanes.photoview.PhotoView;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.customviews.RamboTextView;
|
||||
|
||||
public final class FeedItemViewHolder extends RecyclerView.ViewHolder {
|
||||
public final ImageView profilePic, btnMute, btnDownload;
|
||||
public final TextView commentsCount, videoViews, mediaCounter, tvPostDate, location;
|
||||
public final RamboTextView username, viewerCaption;
|
||||
public final View btnComments, videoViewsParent, viewPost;
|
||||
public final ViewPager mediaList;
|
||||
public final PhotoView imageView;
|
||||
public final PlayerView playerView;
|
||||
|
||||
public FeedItemViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
|
||||
// common
|
||||
viewerCaption = itemView.findViewById(R.id.viewerCaption);
|
||||
btnDownload = itemView.findViewById(R.id.btnDownload);
|
||||
btnComments = itemView.findViewById(R.id.btnComments);
|
||||
profilePic = itemView.findViewById(R.id.ivProfilePic);
|
||||
tvPostDate = itemView.findViewById(R.id.tvPostDate);
|
||||
viewPost = itemView.findViewById(R.id.viewStoryPost);
|
||||
username = itemView.findViewById(R.id.title);
|
||||
location = itemView.findViewById(R.id.location);
|
||||
|
||||
// video view
|
||||
btnMute = itemView.findViewById(R.id.btnMute);
|
||||
videoViews = itemView.findViewById(R.id.tvVideoViews);
|
||||
commentsCount = btnComments.findViewById(R.id.commentsCount);
|
||||
videoViewsParent = videoViews != null ? (View) videoViews.getParent() : null;
|
||||
|
||||
// slider view
|
||||
mediaCounter = itemView.findViewById(R.id.mediaCounter);
|
||||
|
||||
// different types
|
||||
mediaList = itemView.findViewById(R.id.media_list);
|
||||
imageView = itemView.findViewById(R.id.imageViewer);
|
||||
playerView = itemView.findViewById(R.id.playerView);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.adapters.FeedStoriesAdapter;
|
||||
import awais.instagrabber.databinding.ItemHighlightBinding;
|
||||
import awais.instagrabber.models.FeedStoryModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
|
||||
public final class FeedStoryViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ItemHighlightBinding binding;
|
||||
|
||||
public FeedStoryViewHolder(final ItemHighlightBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final FeedStoryModel model,
|
||||
final int position,
|
||||
final FeedStoriesAdapter.OnFeedStoryClickListener listener) {
|
||||
if (model == null) return;
|
||||
binding.getRoot().setOnClickListener(v -> {
|
||||
if (listener == null) return;
|
||||
listener.onFeedStoryClick(model, position);
|
||||
});
|
||||
final ProfileModel profileModel = model.getProfileModel();
|
||||
binding.title.setText(profileModel.getUsername());
|
||||
binding.title.setAlpha(model.getFullyRead() ? 0.5F : 1.0F);
|
||||
binding.icon.setImageURI(profileModel.getSdProfilePic());
|
||||
binding.icon.setAlpha(model.getFullyRead() ? 0.5F : 1.0F);
|
||||
}
|
||||
}
|
@ -1,23 +1,45 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.databinding.ItemFollowBinding;
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
|
||||
public final class FollowsViewHolder extends RecyclerView.ViewHolder {
|
||||
public final ImageView profileImage, isAdmin;
|
||||
public final TextView tvFullName, tvUsername;
|
||||
|
||||
public FollowsViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
profileImage = itemView.findViewById(R.id.ivProfilePic);
|
||||
tvFullName = itemView.findViewById(R.id.tvFullName);
|
||||
tvUsername = itemView.findViewById(R.id.tvUsername);
|
||||
isAdmin = itemView.findViewById(R.id.isAdmin);
|
||||
private final ItemFollowBinding binding;
|
||||
|
||||
public FollowsViewHolder(final ItemFollowBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final ProfileModel model,
|
||||
final List<Long> admins,
|
||||
final View.OnClickListener onClickListener) {
|
||||
if (model == null) return;
|
||||
itemView.setTag(model);
|
||||
itemView.setOnClickListener(onClickListener);
|
||||
binding.tvUsername.setText(model.getUsername());
|
||||
binding.tvFullName.setText(model.getName());
|
||||
if (admins != null && admins.contains(Long.parseLong(model.getId()))) {
|
||||
binding.isAdmin.setVisibility(View.VISIBLE);
|
||||
}
|
||||
binding.ivProfilePic.setImageURI(model.getSdProfilePic());
|
||||
}
|
||||
|
||||
public void bind(final FollowModel model,
|
||||
final View.OnClickListener onClickListener) {
|
||||
if (model == null) return;
|
||||
itemView.setTag(model);
|
||||
itemView.setOnClickListener(onClickListener);
|
||||
binding.tvUsername.setText(model.getUsername());
|
||||
binding.tvFullName.setText(model.getFullName());
|
||||
binding.ivProfilePic.setImageURI(model.getProfilePicUrl());
|
||||
}
|
||||
}
|
@ -1,21 +1,31 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ItemHighlightBinding;
|
||||
import awais.instagrabber.models.HighlightModel;
|
||||
|
||||
public final class HighlightViewHolder extends RecyclerView.ViewHolder {
|
||||
public final ImageView icon;
|
||||
public final TextView title;
|
||||
|
||||
public HighlightViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
icon = itemView.findViewById(R.id.icon);
|
||||
title = itemView.findViewById(R.id.title);
|
||||
private final ItemHighlightBinding binding;
|
||||
|
||||
public HighlightViewHolder(final ItemHighlightBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final HighlightModel model) {
|
||||
if (model == null) return;
|
||||
binding.title.setText(model.getTitle());
|
||||
binding.icon.setImageURI(model.getThumbnailUrl());
|
||||
// binding.getRoot().setOnClickListener(v -> {
|
||||
// if (listener == null) return;
|
||||
// listener.onFeedStoryClick(model, position);
|
||||
// });
|
||||
// final ProfileModel profileModel = model.getProfileModel();
|
||||
// binding.title.setText(profileModel.getUsername());
|
||||
// binding.title.setAlpha(model.getFullyRead() ? 0.5F : 1.0F);
|
||||
// binding.icon.setImageURI(profileModel.getSdProfilePic());
|
||||
// binding.icon.setAlpha(model.getFullyRead() ? 0.5F : 1.0F);
|
||||
}
|
||||
}
|
105
app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java
Executable file → Normal file
105
app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java
Executable file → Normal file
@ -1,75 +1,68 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.customviews.RamboTextView;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener;
|
||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||
import awais.instagrabber.models.NotificationModel;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
|
||||
public final class NotificationViewHolder extends RecyclerView.ViewHolder {
|
||||
private final MentionClickListener mentionClickListener;
|
||||
private final ImageView ivProfilePic, ivPreviewPic;
|
||||
private final TextView tvUsername, tvDate, tvComment, tvSubComment;
|
||||
private final View container, rightContainer;
|
||||
private final ItemNotificationBinding binding;
|
||||
|
||||
public NotificationViewHolder(@NonNull final View itemView, final View.OnClickListener onClickListener, final MentionClickListener mentionClickListener) {
|
||||
super(itemView);
|
||||
|
||||
container = itemView.findViewById(R.id.container);
|
||||
rightContainer = itemView.findViewById(R.id.rightContainer);
|
||||
if (onClickListener != null) container.setOnClickListener(onClickListener);
|
||||
|
||||
this.mentionClickListener = mentionClickListener;
|
||||
|
||||
ivProfilePic = itemView.findViewById(R.id.ivProfilePic);
|
||||
ivPreviewPic = itemView.findViewById(R.id.ivPreviewPic);
|
||||
tvUsername = itemView.findViewById(R.id.tvUsername);
|
||||
tvDate = itemView.findViewById(R.id.tvDate);
|
||||
tvComment = itemView.findViewById(R.id.tvComment);
|
||||
tvSubComment = itemView.findViewById(R.id.tvSubComment);
|
||||
|
||||
tvUsername.setSelected(true);
|
||||
tvDate.setSelected(true);
|
||||
public NotificationViewHolder(final ItemNotificationBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public final ImageView getProfilePicView() {
|
||||
return ivProfilePic;
|
||||
}
|
||||
|
||||
public final ImageView getPreviewPicView() {
|
||||
return ivPreviewPic;
|
||||
}
|
||||
|
||||
public final void setNotificationModel(final NotificationModel notificationModel) {
|
||||
if (container != null) container.setTag(notificationModel);
|
||||
if (rightContainer != null) rightContainer.setTag(notificationModel);
|
||||
}
|
||||
|
||||
public final void setUsername(final String username) {
|
||||
if (tvUsername != null) tvUsername.setText(username);
|
||||
}
|
||||
|
||||
public final void setDate(final String date) {
|
||||
if (tvDate != null) tvDate.setText(date);
|
||||
}
|
||||
|
||||
public final void setCommment(final int commment) {
|
||||
if (tvComment != null) {
|
||||
tvComment.setText(commment);
|
||||
public void bind(final NotificationModel model,
|
||||
final OnNotificationClickListener notificationClickListener) {
|
||||
if (model == null) return;
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (notificationClickListener == null) return;
|
||||
notificationClickListener.onNotificationClick(model);
|
||||
});
|
||||
int text = -1;
|
||||
CharSequence subtext = null;
|
||||
switch (model.getType()) {
|
||||
case LIKE:
|
||||
text = R.string.liked_notif;
|
||||
break;
|
||||
case COMMENT:
|
||||
text = R.string.comment_notif;
|
||||
subtext = model.getText();
|
||||
break;
|
||||
case MENTION:
|
||||
text = R.string.mention_notif;
|
||||
subtext = model.getText();
|
||||
break;
|
||||
case FOLLOW:
|
||||
text = R.string.follow_notif;
|
||||
break;
|
||||
case REQUEST:
|
||||
text = R.string.request_notif;
|
||||
subtext = model.getText();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public final void setSubCommment(final CharSequence commment) {
|
||||
if (tvSubComment != null) {
|
||||
tvSubComment.setText(commment, commment instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL);
|
||||
((RamboTextView) tvSubComment).setMentionClickListener(mentionClickListener);
|
||||
binding.tvUsername.setText(model.getUsername());
|
||||
binding.tvComment.setText(text);
|
||||
binding.tvSubComment.setText(subtext, subtext instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL);
|
||||
// binding.tvSubComment.setMentionClickListener(mentionClickListener);
|
||||
if (model.getType() != NotificationType.REQUEST) {
|
||||
binding.tvDate.setText(model.getDateTime());
|
||||
}
|
||||
binding.ivProfilePic.setImageURI(model.getProfilePic());
|
||||
if (TextUtils.isEmpty(model.getPreviewPic())) {
|
||||
binding.ivPreviewPic.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.ivPreviewPic.setVisibility(View.VISIBLE);
|
||||
binding.ivPreviewPic.setImageURI(model.getPreviewPic());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,29 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ItemChildPostBinding;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
|
||||
public final class PostMediaViewHolder extends RecyclerView.ViewHolder {
|
||||
public final ImageView icon, isDownloaded, selectedView;
|
||||
|
||||
public PostMediaViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
selectedView = itemView.findViewById(R.id.selectedView);
|
||||
isDownloaded = itemView.findViewById(R.id.isDownloaded);
|
||||
icon = itemView.findViewById(R.id.icon);
|
||||
private final ItemChildPostBinding binding;
|
||||
|
||||
public PostMediaViewHolder(@NonNull final ItemChildPostBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final ViewerPostModel model, final int position, final View.OnClickListener clickListener) {
|
||||
if (model == null) return;
|
||||
model.setPosition(position);
|
||||
itemView.setTag(model);
|
||||
itemView.setOnClickListener(clickListener);
|
||||
binding.selectedView.setVisibility(model.isCurrentSlide() ? View.VISIBLE : View.GONE);
|
||||
binding.isDownloaded.setVisibility(model.isDownloaded() ? View.VISIBLE : View.GONE);
|
||||
binding.icon.setImageURI(model.getSliderDisplayUrl());
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,43 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.MultiSelectListAdapter.OnItemClickListener;
|
||||
import awais.instagrabber.adapters.MultiSelectListAdapter.OnItemLongClickListener;
|
||||
import awais.instagrabber.databinding.ItemPostBinding;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
|
||||
public final class PostViewHolder extends RecyclerView.ViewHolder {
|
||||
public final ImageView postImage, typeIcon;
|
||||
public final View selectedView, progressView, isDownloaded;
|
||||
private final ItemPostBinding binding;
|
||||
|
||||
public PostViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
typeIcon = itemView.findViewById(R.id.typeIcon);
|
||||
postImage = itemView.findViewById(R.id.postImage);
|
||||
isDownloaded = itemView.findViewById(R.id.isDownloaded);
|
||||
selectedView = itemView.findViewById(R.id.selectedView);
|
||||
progressView = itemView.findViewById(R.id.progressView);
|
||||
public PostViewHolder(@NonNull final ItemPostBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final PostModel postModel,
|
||||
final int position,
|
||||
final OnItemClickListener<PostModel> clickListener,
|
||||
final OnItemLongClickListener<PostModel> longClickListener) {
|
||||
if (postModel == null) return;
|
||||
postModel.setPosition(position);
|
||||
itemView.setOnClickListener(v -> clickListener.onItemClick(postModel, position));
|
||||
itemView.setOnLongClickListener(v -> longClickListener.onItemLongClick(postModel, position));
|
||||
|
||||
final MediaItemType itemType = postModel.getItemType();
|
||||
final boolean isSlider = itemType == MediaItemType.MEDIA_TYPE_SLIDER;
|
||||
|
||||
binding.isDownloaded.setVisibility(postModel.isDownloaded() ? View.VISIBLE : View.GONE);
|
||||
|
||||
binding.typeIcon.setVisibility(itemType == MediaItemType.MEDIA_TYPE_VIDEO || isSlider ? View.VISIBLE : View.GONE);
|
||||
binding.typeIcon.setImageResource(isSlider ? R.drawable.ic_slider_24 : R.drawable.ic_video_24);
|
||||
|
||||
binding.selectedView.setVisibility(postModel.isSelected() ? View.VISIBLE : View.GONE);
|
||||
binding.postImage.setImageURI(postModel.getThumbnailUrl());
|
||||
}
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.PostViewAdapter.OnPostCaptionLongClickListener;
|
||||
import awais.instagrabber.adapters.PostViewAdapter.OnPostViewChildViewClickListener;
|
||||
import awais.instagrabber.adapters.PostViewerChildAdapter;
|
||||
import awais.instagrabber.databinding.ItemFullPostViewBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.ViewerPostModelWrapper;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class PostViewerViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = "PostViewerViewHolder";
|
||||
|
||||
private final ItemFullPostViewBinding binding;
|
||||
private int currentChildPosition;
|
||||
|
||||
public PostViewerViewHolder(@NonNull final ItemFullPostViewBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
binding.topPanel.viewStoryPost.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void bind(final ViewerPostModelWrapper wrapper,
|
||||
final int position,
|
||||
final OnPostViewChildViewClickListener clickListener,
|
||||
final OnPostCaptionLongClickListener longClickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
if (wrapper == null) return;
|
||||
final ViewerPostModel[] items = wrapper.getViewerPostModels();
|
||||
if (items == null || items.length <= 0) return;
|
||||
if (items[0] == null) return;
|
||||
final PostViewerChildAdapter adapter = new PostViewerChildAdapter();
|
||||
binding.mediaViewPager.setAdapter(adapter);
|
||||
final ViewerPostModel firstPost = items[0];
|
||||
setPostInfo(firstPost, mentionClickListener);
|
||||
setMediaItems(items, adapter);
|
||||
setupListeners(wrapper,
|
||||
position,
|
||||
clickListener,
|
||||
longClickListener,
|
||||
mentionClickListener,
|
||||
firstPost.getLocation());
|
||||
}
|
||||
|
||||
private void setPostInfo(final ViewerPostModel firstPost,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
final ProfileModel profileModel = firstPost.getProfileModel();
|
||||
if (profileModel == null) return;
|
||||
binding.topPanel.title.setText(profileModel.getUsername());
|
||||
final String locationName = firstPost.getLocationName();
|
||||
if (!TextUtils.isEmpty(locationName)) {
|
||||
binding.topPanel.location.setVisibility(View.VISIBLE);
|
||||
binding.topPanel.location.setText(locationName);
|
||||
} else binding.topPanel.location.setVisibility(View.GONE);
|
||||
binding.topPanel.ivProfilePic.setImageURI(profileModel.getSdProfilePic());
|
||||
binding.bottomPanel.commentsCount.setText(String.valueOf(firstPost.getCommentsCount()));
|
||||
final CharSequence postCaption = firstPost.getPostCaption();
|
||||
if (TextUtils.hasMentions(postCaption)) {
|
||||
binding.bottomPanel.viewerCaption.setMentionClickListener(mentionClickListener);
|
||||
binding.bottomPanel.viewerCaption
|
||||
.setText(TextUtils.getMentionText(postCaption), TextView.BufferType.SPANNABLE);
|
||||
} else {
|
||||
binding.bottomPanel.viewerCaption.setMentionClickListener(null);
|
||||
binding.bottomPanel.viewerCaption.setText(postCaption);
|
||||
}
|
||||
binding.bottomPanel.tvPostDate.setText(firstPost.getPostDate());
|
||||
setupLikes(firstPost);
|
||||
setupSave(firstPost);
|
||||
}
|
||||
|
||||
private void setupLikes(final ViewerPostModel firstPost) {
|
||||
final boolean liked = firstPost.getLike();
|
||||
final long likeCount = firstPost.getLikes();
|
||||
final Resources resources = itemView.getContext().getResources();
|
||||
if (liked) {
|
||||
final String unlikeString = resources.getString(R.string.unlike, String.valueOf(likeCount));
|
||||
binding.btnLike.setText(unlikeString);
|
||||
ViewCompat.setBackgroundTintList(binding.btnLike,
|
||||
ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_pink_background)));
|
||||
} else {
|
||||
final String likeString = resources.getString(R.string.like, String.valueOf(likeCount));
|
||||
binding.btnLike.setText(likeString);
|
||||
ViewCompat.setBackgroundTintList(binding.btnLike,
|
||||
ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_lightpink_background)));
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSave(final ViewerPostModel firstPost) {
|
||||
final boolean saved = firstPost.getBookmark();
|
||||
if (saved) {
|
||||
binding.btnBookmark.setText(R.string.unbookmark);
|
||||
ViewCompat.setBackgroundTintList(binding.btnBookmark,
|
||||
ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_orange_background)));
|
||||
} else {
|
||||
binding.btnBookmark.setText(R.string.bookmark);
|
||||
ViewCompat.setBackgroundTintList(
|
||||
binding.btnBookmark,
|
||||
ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_lightorange_background)));
|
||||
}
|
||||
}
|
||||
|
||||
private void setupListeners(final ViewerPostModelWrapper wrapper,
|
||||
final int position,
|
||||
final OnPostViewChildViewClickListener clickListener,
|
||||
final OnPostCaptionLongClickListener longClickListener,
|
||||
final MentionClickListener mentionClickListener,
|
||||
final String location) {
|
||||
final View.OnClickListener onClickListener = v -> clickListener
|
||||
.onClick(v, wrapper, position, currentChildPosition);
|
||||
binding.bottomPanel.btnComments.setOnClickListener(onClickListener);
|
||||
binding.topPanel.title.setOnClickListener(onClickListener);
|
||||
binding.topPanel.ivProfilePic.setOnClickListener(onClickListener);
|
||||
binding.bottomPanel.btnDownload.setOnClickListener(onClickListener);
|
||||
binding.bottomPanel.viewerCaption.setOnClickListener(onClickListener);
|
||||
binding.btnLike.setOnClickListener(onClickListener);
|
||||
binding.btnBookmark.setOnClickListener(onClickListener);
|
||||
binding.bottomPanel.viewerCaption.setOnLongClickListener(v -> {
|
||||
longClickListener.onLongClick(binding.bottomPanel.viewerCaption.getText().toString());
|
||||
return true;
|
||||
});
|
||||
if (!TextUtils.isEmpty(location)) {
|
||||
binding.topPanel.location.setOnClickListener(v -> mentionClickListener
|
||||
.onClick(binding.topPanel.location, location, false, true));
|
||||
}
|
||||
}
|
||||
|
||||
private void setMediaItems(final ViewerPostModel[] items,
|
||||
final PostViewerChildAdapter adapter) {
|
||||
final List<ViewerPostModel> filteredList = new ArrayList<>();
|
||||
for (final ViewerPostModel model : items) {
|
||||
final MediaItemType itemType = model.getItemType();
|
||||
if (itemType == MediaItemType.MEDIA_TYPE_VIDEO || itemType == MediaItemType.MEDIA_TYPE_IMAGE) {
|
||||
filteredList.add(model);
|
||||
}
|
||||
}
|
||||
binding.mediaCounter.setVisibility(filteredList.size() > 1 ? View.VISIBLE : View.GONE);
|
||||
final String counter = "1/" + filteredList.size();
|
||||
binding.mediaCounter.setText(counter);
|
||||
adapter.submitList(filteredList);
|
||||
binding.mediaViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(final int position) {
|
||||
if (filteredList.size() <= 0 || position >= filteredList.size()) return;
|
||||
currentChildPosition = position;
|
||||
final String counter = (position + 1) + "/" + filteredList.size();
|
||||
binding.mediaCounter.setText(counter);
|
||||
final ViewerPostModel viewerPostModel = filteredList.get(position);
|
||||
if (viewerPostModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
setVideoDetails(viewerPostModel);
|
||||
setVolumeListener(position);
|
||||
return;
|
||||
}
|
||||
setImageDetails();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setVolumeListener(final int position) {
|
||||
binding.bottomPanel.btnMute.setOnClickListener(v -> {
|
||||
try {
|
||||
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) binding.mediaViewPager
|
||||
.getChildAt(0)).findViewHolderForAdapterPosition(position);
|
||||
if (viewHolder != null) {
|
||||
final View itemView = viewHolder.itemView;
|
||||
if (itemView instanceof PlayerView) {
|
||||
final SimpleExoPlayer player = (SimpleExoPlayer) ((PlayerView) itemView)
|
||||
.getPlayer();
|
||||
if (player == null) return;
|
||||
final float vol = player.getVolume() == 0f ? 1f : 0f;
|
||||
player.setVolume(vol);
|
||||
binding.bottomPanel.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24
|
||||
: R.drawable.ic_volume_off_24);
|
||||
Utils.sessionVolumeFull = vol == 1f;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setImageDetails() {
|
||||
binding.bottomPanel.btnMute.setVisibility(View.GONE);
|
||||
binding.bottomPanel.videoViewsContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setVideoDetails(final ViewerPostModel viewerPostModel) {
|
||||
binding.bottomPanel.btnMute.setVisibility(View.VISIBLE);
|
||||
final long videoViews = viewerPostModel.getVideoViews();
|
||||
if (videoViews < 0) {
|
||||
binding.bottomPanel.videoViewsContainer.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
binding.bottomPanel.tvVideoViews.setText(String.valueOf(videoViews));
|
||||
binding.bottomPanel.videoViewsContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void stopPlayingVideo() {
|
||||
try {
|
||||
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) binding.mediaViewPager
|
||||
.getChildAt(0)).findViewHolderForAdapterPosition(currentChildPosition);
|
||||
if (viewHolder != null) {
|
||||
final View itemView = viewHolder.itemView;
|
||||
if (itemView instanceof PlayerView) {
|
||||
final Player player = ((PlayerView) itemView).getPlayer();
|
||||
if (player != null) {
|
||||
player.setPlayWhenReady(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmAnimatedMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
@ -22,8 +24,10 @@ public class DirectMessageAnimatedMediaViewHolder extends DirectMessageItemViewH
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
getGlideRequestManager().asGif().load(directItemModel.getAnimatedMediaModel().getGifUrl())
|
||||
.into(binding.ivAnimatedMessage);
|
||||
binding.ivAnimatedMessage.setController(Fresco.newDraweeControllerBuilder()
|
||||
.setUri(directItemModel.getAnimatedMediaModel().getGifUrl())
|
||||
.setAutoPlayAnimations(true)
|
||||
.build());
|
||||
binding.ivAnimatedMessage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
@ -8,37 +8,32 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final int MESSAGE_INCOMING = 69;
|
||||
private static final int MESSAGE_OUTGOING = 420;
|
||||
|
||||
private final ProfileModel myProfileHolder = ProfileModel.getDefaultProfileModel(Utils.getUserIdFromCookie(Utils.settingsHelper.getString(Constants.COOKIE)));
|
||||
private final ProfileModel myProfileHolder = ProfileModel.getDefaultProfileModel(
|
||||
CookieUtils.getUserIdFromCookie(Utils.settingsHelper.getString(Constants.COOKIE)));
|
||||
private final LayoutDmBaseBinding binding;
|
||||
private final String strDmYou;
|
||||
private final int itemMargin;
|
||||
|
||||
private final RequestManager glideRequestManager;
|
||||
|
||||
public DirectMessageItemViewHolder(@NonNull final LayoutDmBaseBinding binding, @NonNull final View.OnClickListener onClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
binding.ivProfilePic.setOnClickListener(onClickListener);
|
||||
binding.messageCard.setOnClickListener(onClickListener);
|
||||
strDmYou = binding.getRoot().getContext().getString(R.string.direct_messages_you);
|
||||
// final String strDmYou = binding.getRoot().getContext().getString(R.string.direct_messages_you);
|
||||
itemMargin = Utils.displayMetrics.widthPixels / 5;
|
||||
glideRequestManager = Glide.with(itemView);
|
||||
}
|
||||
|
||||
public void bind(final DirectItemModel directItemModel, final List<ProfileModel> users, final List<ProfileModel> leftUsers) {
|
||||
@ -47,7 +42,7 @@ public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolde
|
||||
|
||||
final RecyclerView.LayoutParams itemViewLayoutParams = (RecyclerView.LayoutParams) itemView.getLayoutParams();
|
||||
itemViewLayoutParams.setMargins(type == MESSAGE_OUTGOING ? itemMargin : 0, 0,
|
||||
type == MESSAGE_INCOMING ? itemMargin : 0, 0);
|
||||
type == MESSAGE_INCOMING ? itemMargin : 0, 0);
|
||||
|
||||
final ViewGroup messageCardParent = (ViewGroup) binding.messageCard.getParent();
|
||||
binding.contentContainer.setGravity(type == MESSAGE_INCOMING ? Gravity.START : Gravity.END);
|
||||
@ -56,7 +51,7 @@ public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolde
|
||||
if (user != null && user != myProfileHolder) {
|
||||
text = user.getUsername();
|
||||
} else if (user == myProfileHolder) text = "";
|
||||
text = (Utils.isEmpty(text) ? "" : text + " - ") + directItemModel.getDateTime();
|
||||
text = (TextUtils.isEmpty(text) ? "" : text + " - ") + directItemModel.getDateTime();
|
||||
binding.tvUsername.setText(text);
|
||||
binding.tvUsername.setGravity(type == MESSAGE_INCOMING ? Gravity.START : Gravity.END);
|
||||
binding.ivProfilePic.setVisibility(type == MESSAGE_INCOMING ? View.VISIBLE : View.GONE);
|
||||
@ -66,7 +61,7 @@ public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolde
|
||||
binding.messageCard.setTag(directItemModel);
|
||||
|
||||
if (type == MESSAGE_INCOMING && user != null) {
|
||||
glideRequestManager.load(user.getSdProfilePic()).into(binding.ivProfilePic);
|
||||
binding.ivProfilePic.setImageURI(user.getSdProfilePic());
|
||||
}
|
||||
|
||||
bindItem(directItemModel);
|
||||
@ -76,10 +71,6 @@ public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolde
|
||||
this.binding.messageCard.addView(view);
|
||||
}
|
||||
|
||||
public RequestManager getGlideRequestManager() {
|
||||
return glideRequestManager;
|
||||
}
|
||||
|
||||
public abstract void bindItem(final DirectItemModel directItemModel);
|
||||
|
||||
@Nullable
|
||||
|
@ -7,7 +7,7 @@ import androidx.annotation.NonNull;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmLinkBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectMessageLinkViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
@ -26,21 +26,21 @@ public class DirectMessageLinkViewHolder extends DirectMessageItemViewHolder {
|
||||
final DirectItemModel.DirectItemLinkModel link = directItemModel.getLinkModel();
|
||||
final DirectItemModel.DirectItemLinkContext linkContext = link.getLinkContext();
|
||||
final String linkImageUrl = linkContext.getLinkImageUrl();
|
||||
if (Utils.isEmpty(linkImageUrl)) {
|
||||
if (TextUtils.isEmpty(linkImageUrl)) {
|
||||
binding.ivLinkPreview.setVisibility(View.GONE);
|
||||
} else {
|
||||
getGlideRequestManager().load(linkImageUrl).into(binding.ivLinkPreview);
|
||||
binding.ivLinkPreview.setImageURI(linkImageUrl);
|
||||
}
|
||||
if (Utils.isEmpty(linkContext.getLinkTitle())) {
|
||||
if (TextUtils.isEmpty(linkContext.getLinkTitle())) {
|
||||
binding.tvLinkTitle.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.tvLinkTitle.setText(linkContext.getLinkTitle());
|
||||
}
|
||||
if (Utils.isEmpty(linkContext.getLinkSummary())) {
|
||||
if (TextUtils.isEmpty(linkContext.getLinkSummary())) {
|
||||
binding.tvLinkSummary.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.tvLinkSummary.setText(linkContext.getLinkSummary());
|
||||
}
|
||||
binding.tvMessage.setText(Utils.getSpannableUrl(link.getText()));
|
||||
binding.tvMessage.setText(TextUtils.getSpannableUrl(link.getText()));
|
||||
}
|
||||
}
|
||||
|
@ -34,11 +34,13 @@ public class DirectMessageMediaShareViewHolder extends DirectMessageItemViewHold
|
||||
final DirectItemMediaModel mediaModel = directItemModel.getMediaModel();
|
||||
final ProfileModel modelUser = mediaModel.getUser();
|
||||
if (modelUser != null) {
|
||||
binding.tvMessage.setText(HtmlCompat.fromHtml("<small>" + context.getString(R.string.dms_inbox_media_shared_from, modelUser.getUsername()) + "</small>", FROM_HTML_MODE_COMPACT));
|
||||
binding.tvMessage.setText(HtmlCompat.fromHtml(
|
||||
"<small>" + context.getString(R.string.dms_inbox_media_shared_from, modelUser.getUsername()) + "</small>",
|
||||
FROM_HTML_MODE_COMPACT));
|
||||
}
|
||||
getGlideRequestManager().load(mediaModel.getThumbUrl()).into(binding.ivMediaPreview);
|
||||
binding.ivMediaPreview.setImageURI(mediaModel.getThumbUrl());
|
||||
final MediaItemType modelMediaType = mediaModel.getMediaType();
|
||||
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO
|
||||
|| modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
|| modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ public class DirectMessageMediaViewHolder extends DirectMessageItemViewHolder {
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemMediaModel mediaModel = directItemModel.getMediaModel();
|
||||
getGlideRequestManager().load(mediaModel.getThumbUrl()).into(binding.ivMediaPreview);
|
||||
binding.ivMediaPreview.setImageURI(mediaModel.getThumbUrl());
|
||||
final MediaItemType modelMediaType = mediaModel.getMediaType();
|
||||
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO
|
||||
|| modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
|| modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmProfileBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
@ -27,9 +25,8 @@ public class DirectMessageProfileViewHolder extends DirectMessageItemViewHolder
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final ProfileModel profileModel = directItemModel.getProfileModel();
|
||||
Glide.with(binding.profileInfo)
|
||||
.load(profileModel.getSdProfilePic())
|
||||
.into(binding.profileInfo);
|
||||
if (profileModel == null) return;
|
||||
binding.profileInfo.setImageURI(profileModel.getSdProfilePic());
|
||||
binding.btnOpenProfile.setTag(profileModel);
|
||||
binding.tvFullName.setText(profileModel.getName());
|
||||
binding.profileInfoText.setText(profileModel.getUsername());
|
||||
|
@ -12,7 +12,7 @@ import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.models.enums.RavenExpiringMediaType;
|
||||
import awais.instagrabber.models.enums.RavenMediaViewType;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectMessageRavenMediaViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
@ -33,7 +33,7 @@ public class DirectMessageRavenMediaViewHolder extends DirectMessageItemViewHold
|
||||
final DirectItemModel.DirectItemRavenMediaModel ravenMediaModel = directItemModel.getRavenMediaModel();
|
||||
DirectItemModel.DirectItemMediaModel mediaModel = directItemModel.getMediaModel();
|
||||
final boolean isExpired = ravenMediaModel == null || (mediaModel = ravenMediaModel.getMedia()) == null ||
|
||||
Utils.isEmpty(mediaModel.getThumbUrl()) && mediaModel.getPk() < 1;
|
||||
TextUtils.isEmpty(mediaModel.getThumbUrl()) && mediaModel.getPk() < 1;
|
||||
|
||||
DirectItemModel.RavenExpiringMediaActionSummaryModel mediaActionSummary = null;
|
||||
if (ravenMediaModel != null) {
|
||||
@ -73,8 +73,8 @@ public class DirectMessageRavenMediaViewHolder extends DirectMessageItemViewHold
|
||||
final MediaItemType mediaType = mediaModel.getMediaType();
|
||||
textRes = -1;
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO ||
|
||||
mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
getGlideRequestManager().load(mediaModel.getThumbUrl()).into(binding.ivMediaPreview);
|
||||
mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
binding.ivMediaPreview.setImageURI(mediaModel.getThumbUrl());
|
||||
}
|
||||
}
|
||||
if (textRes != -1) {
|
||||
|
@ -9,7 +9,7 @@ import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectMessageReelShareViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
@ -29,10 +29,10 @@ public class DirectMessageReelShareViewHolder extends DirectMessageItemViewHolde
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemReelShareModel reelShare = directItemModel.getReelShare();
|
||||
CharSequence text = reelShare.getText();
|
||||
if (Utils.isEmpty(text)) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
binding.tvMessage.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (Utils.hasMentions(text)) text = Utils.getMentionText(text); // for mentions
|
||||
if (TextUtils.hasMentions(text)) text = TextUtils.getMentionText(text); // for mentions
|
||||
binding.tvMessage.setText(text);
|
||||
}
|
||||
final DirectItemModel.DirectItemMediaModel reelShareMedia = reelShare.getMedia();
|
||||
@ -41,8 +41,8 @@ public class DirectMessageReelShareViewHolder extends DirectMessageItemViewHolde
|
||||
binding.mediaExpiredIcon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO ||
|
||||
mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
getGlideRequestManager().load(reelShareMedia.getThumbUrl()).into(binding.ivMediaPreview);
|
||||
mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
binding.ivMediaPreview.setImageURI(reelShareMedia.getThumbUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmStoryShareBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT;
|
||||
|
||||
@ -34,15 +34,14 @@ public class DirectMessageStoryShareViewHolder extends DirectMessageItemViewHold
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
final String text = reelShare.getText();
|
||||
if (!Utils.isEmpty(text)) {
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
binding.tvMessage.setText(text);
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
final DirectItemModel.DirectItemMediaModel reelShareMedia = reelShare.getMedia();
|
||||
final MediaItemType mediaType = reelShareMedia.getMediaType();
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO ? View.VISIBLE : View.GONE);
|
||||
getGlideRequestManager().load(reelShareMedia.getThumbUrl()).into(binding.ivMediaPreview);
|
||||
binding.ivMediaPreview.setImageURI(reelShareMedia.getThumbUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectMessageTextViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
@ -32,8 +32,8 @@ public class DirectMessageTextViewHolder extends DirectMessageItemViewHolder {
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final Context context = itemView.getContext();
|
||||
CharSequence text = directItemModel.getText();
|
||||
text = Utils.getSpannableUrl(text.toString()); // for urls
|
||||
if (Utils.hasMentions(text)) text = Utils.getMentionText(text); // for mentions
|
||||
text = TextUtils.getSpannableUrl(text.toString()); // for urls
|
||||
if (TextUtils.hasMentions(text)) text = TextUtils.getMentionText(text); // for mentions
|
||||
if (text instanceof Spanned)
|
||||
binding.tvMessage.setText(text, TextView.BufferType.SPANNABLE);
|
||||
else if (text == "") {
|
||||
|
@ -9,7 +9,7 @@ import androidx.annotation.NonNull;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmVoiceMediaBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
|
||||
public class DirectMessageVoiceMediaViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
@ -61,13 +61,13 @@ public class DirectMessageVoiceMediaViewHolder extends DirectMessageItemViewHold
|
||||
if (waveformData != null) binding.waveformSeekBar.setSample(waveformData);
|
||||
|
||||
final long durationMs = voiceMediaModel.getDurationMs();
|
||||
binding.tvVoiceDuration.setText(Utils.millisToString(durationMs));
|
||||
binding.tvVoiceDuration.setText(NumberUtils.millisToString(durationMs));
|
||||
binding.waveformSeekBar.setProgress(voiceMediaModel.getProgress());
|
||||
binding.waveformSeekBar.setProgressChangeListener((waveformSeekBar, progress, fromUser) -> {
|
||||
// todo progress audio player
|
||||
voiceMediaModel.setProgress(progress);
|
||||
if (fromUser)
|
||||
binding.tvVoiceDuration.setText(Utils.millisToString(durationMs * progress / 100));
|
||||
binding.tvVoiceDuration.setText(NumberUtils.millisToString(durationMs * progress / 100));
|
||||
});
|
||||
binding.btnPlayVoice.setTag(voiceMediaModel);
|
||||
} else {
|
||||
|
@ -0,0 +1,138 @@
|
||||
package awais.instagrabber.adapters.viewholder.feed;
|
||||
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.customviews.CommentMentionClickSpan;
|
||||
import awais.instagrabber.customviews.RamboTextView;
|
||||
import awais.instagrabber.databinding.ItemFeedBottomBinding;
|
||||
import awais.instagrabber.databinding.ItemFeedTopBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public abstract class FeedItemViewHolder extends RecyclerView.ViewHolder {
|
||||
public static final int MAX_CHARS = 255;
|
||||
private final ItemFeedTopBinding topBinding;
|
||||
private final ItemFeedBottomBinding bottomBinding;
|
||||
private final MentionClickListener mentionClickListener;
|
||||
|
||||
public FeedItemViewHolder(@NonNull final View root,
|
||||
final ItemFeedTopBinding topBinding,
|
||||
final ItemFeedBottomBinding bottomBinding,
|
||||
final MentionClickListener mentionClickListener,
|
||||
final View.OnClickListener clickListener,
|
||||
final View.OnLongClickListener longClickListener) {
|
||||
super(root);
|
||||
this.topBinding = topBinding;
|
||||
this.bottomBinding = bottomBinding;
|
||||
this.mentionClickListener = mentionClickListener;
|
||||
// topBinding.title.setMovementMethod(new LinkMovementMethod());
|
||||
bottomBinding.btnComments.setOnClickListener(clickListener);
|
||||
topBinding.viewStoryPost.setOnClickListener(clickListener);
|
||||
topBinding.ivProfilePic.setOnClickListener(clickListener);
|
||||
bottomBinding.btnDownload.setOnClickListener(clickListener);
|
||||
bottomBinding.viewerCaption.setOnClickListener(clickListener);
|
||||
bottomBinding.viewerCaption.setOnLongClickListener(longClickListener);
|
||||
bottomBinding.viewerCaption.setMentionClickListener(mentionClickListener);
|
||||
}
|
||||
|
||||
public void bind(final FeedModel feedModel) {
|
||||
if (feedModel == null) {
|
||||
return;
|
||||
}
|
||||
topBinding.viewStoryPost.setTag(feedModel);
|
||||
topBinding.ivProfilePic.setTag(feedModel);
|
||||
bottomBinding.btnDownload.setTag(feedModel);
|
||||
bottomBinding.viewerCaption.setTag(feedModel);
|
||||
bottomBinding.btnComments.setTag(feedModel);
|
||||
final ProfileModel profileModel = feedModel.getProfileModel();
|
||||
if (profileModel != null) {
|
||||
topBinding.ivProfilePic.setImageURI(profileModel.getSdProfilePic());
|
||||
final int titleLen = profileModel.getUsername().length() + 1;
|
||||
final SpannableString spannableString = new SpannableString("@" + profileModel.getUsername());
|
||||
spannableString.setSpan(new CommentMentionClickSpan(), 0, titleLen, 0);
|
||||
topBinding.title.setText(spannableString);
|
||||
topBinding.title.setMentionClickListener(
|
||||
(view, text, isHashtag, isLocation) -> mentionClickListener.onClick(null, profileModel.getUsername(), false, false));
|
||||
}
|
||||
bottomBinding.tvPostDate.setText(feedModel.getPostDate());
|
||||
final long commentsCount = feedModel.getCommentsCount();
|
||||
bottomBinding.commentsCount.setText(String.valueOf(commentsCount));
|
||||
|
||||
final String locationName = feedModel.getLocationName();
|
||||
final String locationId = feedModel.getLocationId();
|
||||
setLocation(locationName, locationId);
|
||||
CharSequence postCaption = feedModel.getPostCaption();
|
||||
final boolean captionEmpty = TextUtils.isEmpty(postCaption);
|
||||
bottomBinding.viewerCaption.setVisibility(captionEmpty ? View.GONE : View.VISIBLE);
|
||||
if (!captionEmpty) {
|
||||
if (TextUtils.hasMentions(postCaption)) {
|
||||
postCaption = TextUtils.getMentionText(postCaption);
|
||||
feedModel.setPostCaption(postCaption);
|
||||
bottomBinding.viewerCaption.setText(postCaption, TextView.BufferType.SPANNABLE);
|
||||
} else {
|
||||
bottomBinding.viewerCaption.setText(postCaption);
|
||||
}
|
||||
}
|
||||
expandCollapseTextView(bottomBinding.viewerCaption, feedModel.getPostCaption());
|
||||
bindItem(feedModel);
|
||||
}
|
||||
|
||||
private void setLocation(final String locationName, final String locationId) {
|
||||
if (TextUtils.isEmpty(locationName)) {
|
||||
topBinding.location.setVisibility(View.GONE);
|
||||
topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
} else {
|
||||
topBinding.location.setVisibility(View.VISIBLE);
|
||||
topBinding.location.setText(locationName);
|
||||
topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
topBinding.location.setOnClickListener(v -> mentionClickListener.onClick(topBinding.location, locationId, false, true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* expands or collapses {@link RamboTextView} [stg idek why i wrote this documentation]
|
||||
*
|
||||
* @param textView the {@link RamboTextView} view, to expand and collapse
|
||||
* @param caption caption
|
||||
* @return isExpanded
|
||||
*/
|
||||
public static boolean expandCollapseTextView(@NonNull final RamboTextView textView, final CharSequence caption) {
|
||||
if (TextUtils.isEmpty(caption)) return false;
|
||||
|
||||
final TextView.BufferType bufferType = caption instanceof Spanned ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL;
|
||||
|
||||
if (textView.isCaptionExpanded()) {
|
||||
textView.setText(caption, bufferType);
|
||||
textView.setCaptionIsExpanded(false);
|
||||
return true;
|
||||
}
|
||||
int i = TextUtils.indexOfChar(caption, '\r', 0);
|
||||
if (i == -1) i = TextUtils.indexOfChar(caption, '\n', 0);
|
||||
if (i == -1) i = MAX_CHARS;
|
||||
|
||||
final int captionLen = caption.length();
|
||||
final int minTrim = Math.min(MAX_CHARS, i);
|
||||
if (captionLen <= minTrim) return false;
|
||||
|
||||
if (TextUtils.hasMentions(caption))
|
||||
textView.setText(TextUtils.getMentionText(caption), TextView.BufferType.SPANNABLE);
|
||||
textView.setCaptionIsExpandable(true);
|
||||
textView.setCaptionIsExpanded(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void bindItem(final FeedModel feedModel);
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package awais.instagrabber.adapters.viewholder.feed;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
import awais.instagrabber.databinding.ItemFeedPhotoBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class FeedPhotoViewHolder extends FeedItemViewHolder {
|
||||
private static final String TAG = "FeedPhotoViewHolder";
|
||||
|
||||
private final ItemFeedPhotoBinding binding;
|
||||
|
||||
public FeedPhotoViewHolder(@NonNull final ItemFeedPhotoBinding binding,
|
||||
final MentionClickListener mentionClickListener,
|
||||
final View.OnClickListener clickListener,
|
||||
final View.OnLongClickListener longClickListener) {
|
||||
super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, mentionClickListener, clickListener, longClickListener);
|
||||
this.binding = binding;
|
||||
binding.itemFeedBottom.videoViewsContainer.setVisibility(View.GONE);
|
||||
binding.itemFeedBottom.btnMute.setVisibility(View.GONE);
|
||||
binding.imageViewer.setAllowTouchInterceptionWhileZoomed(false);
|
||||
final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(itemView.getContext().getResources())
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
|
||||
.build();
|
||||
binding.imageViewer.setHierarchy(hierarchy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final FeedModel feedModel) {
|
||||
if (feedModel == null) {
|
||||
return;
|
||||
}
|
||||
final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams();
|
||||
final int requiredWidth = Utils.displayMetrics.widthPixels;
|
||||
layoutParams.width = feedModel.getImageWidth() == 0 ? requiredWidth : feedModel.getImageWidth();
|
||||
layoutParams.height = feedModel.getImageHeight() == 0 ? requiredWidth + 1 : feedModel.getImageHeight();
|
||||
binding.imageViewer.requestLayout();
|
||||
final String thumbnailUrl = feedModel.getThumbnailUrl();
|
||||
String url = feedModel.getDisplayUrl();
|
||||
if (TextUtils.isEmpty(url)) url = thumbnailUrl;
|
||||
final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
binding.imageViewer.setController(Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(requestBuilder)
|
||||
.setOldController(binding.imageViewer.getController())
|
||||
.setLowResImageRequest(ImageRequest.fromUri(thumbnailUrl))
|
||||
.build());
|
||||
// binding.imageViewer.setImageURI(url);
|
||||
// final RequestBuilder<Bitmap> thumbnailRequestBuilder = glide
|
||||
// .asBitmap()
|
||||
// .load(thumbnailUrl)
|
||||
// .diskCacheStrategy(DiskCacheStrategy.ALL);
|
||||
// glide.asBitmap()
|
||||
// .load(url)
|
||||
// .thumbnail(thumbnailRequestBuilder)
|
||||
// .diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
// .into(customTarget);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,341 @@
|
||||
package awais.instagrabber.adapters.viewholder.feed;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ViewSwitcher;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ItemFeedSliderBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class FeedSliderViewHolder extends FeedItemViewHolder {
|
||||
private static final String TAG = "FeedSliderViewHolder";
|
||||
private static final boolean shouldAutoPlay = settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS);
|
||||
|
||||
private final ItemFeedSliderBinding binding;
|
||||
private final DefaultDataSourceFactory dataSourceFactory;
|
||||
|
||||
private final PlayerChangeListener playerChangeListener = (position, player) -> {
|
||||
pagerPlayer = player;
|
||||
playerPosition = position;
|
||||
};
|
||||
|
||||
private CacheDataSourceFactory cacheDataSourceFactory;
|
||||
private SimpleExoPlayer pagerPlayer;
|
||||
private int playerPosition = 0;
|
||||
|
||||
public FeedSliderViewHolder(@NonNull final ItemFeedSliderBinding binding,
|
||||
final MentionClickListener mentionClickListener,
|
||||
final View.OnClickListener clickListener,
|
||||
final View.OnLongClickListener longClickListener) {
|
||||
super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, mentionClickListener, clickListener, longClickListener);
|
||||
this.binding = binding;
|
||||
binding.itemFeedBottom.videoViewsContainer.setVisibility(View.GONE);
|
||||
binding.itemFeedBottom.btnMute.setVisibility(View.GONE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.mediaList.getLayoutParams();
|
||||
layoutParams.height = Utils.displayMetrics.widthPixels + 1;
|
||||
binding.mediaList.setLayoutParams(layoutParams);
|
||||
final Context context = binding.getRoot().getContext();
|
||||
dataSourceFactory = new DefaultDataSourceFactory(context, "instagram");
|
||||
final SimpleCache simpleCache = Utils.getSimpleCacheInstance(context);
|
||||
if (simpleCache != null) {
|
||||
cacheDataSourceFactory = new CacheDataSourceFactory(simpleCache, dataSourceFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final FeedModel feedModel) {
|
||||
final ViewerPostModel[] sliderItems = feedModel.getSliderItems();
|
||||
final int sliderItemLen = sliderItems != null ? sliderItems.length : 0;
|
||||
if (sliderItemLen <= 0) {
|
||||
return;
|
||||
}
|
||||
final String text = "1/" + sliderItemLen;
|
||||
binding.mediaCounter.setText(text);
|
||||
binding.mediaList.setOffscreenPageLimit(Math.min(5, sliderItemLen));
|
||||
|
||||
final PagerAdapter adapter = binding.mediaList.getAdapter();
|
||||
if (adapter != null) {
|
||||
final int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
adapter.destroyItem(binding.mediaList, i, binding.mediaList.getChildAt(i));
|
||||
}
|
||||
}
|
||||
final ChildMediaItemsAdapter itemsAdapter = new ChildMediaItemsAdapter(sliderItems,
|
||||
cacheDataSourceFactory != null
|
||||
? cacheDataSourceFactory
|
||||
: dataSourceFactory,
|
||||
playerChangeListener);
|
||||
binding.mediaList.setAdapter(itemsAdapter);
|
||||
|
||||
//noinspection deprecation
|
||||
binding.mediaList.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||
private int prevPos = 0;
|
||||
|
||||
@Override
|
||||
public void onPageSelected(final int position) {
|
||||
ViewerPostModel sliderItem = sliderItems[prevPos];
|
||||
if (sliderItem != null) {
|
||||
sliderItem.setSelected(false);
|
||||
if (sliderItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
// stop playing prev video
|
||||
final ViewSwitcher prevChild = (ViewSwitcher) binding.mediaList.getChildAt(prevPos);
|
||||
if (prevChild == null || prevChild.getTag() == null || !(prevChild.getTag() instanceof SimpleExoPlayer)) {
|
||||
return;
|
||||
}
|
||||
((SimpleExoPlayer) prevChild.getTag()).setPlayWhenReady(false);
|
||||
}
|
||||
}
|
||||
sliderItem = sliderItems[position];
|
||||
if (sliderItem == null) return;
|
||||
sliderItem.setSelected(true);
|
||||
final String text = (position + 1) + "/" + sliderItemLen;
|
||||
binding.mediaCounter.setText(text);
|
||||
prevPos = position;
|
||||
if (sliderItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE);
|
||||
if (shouldAutoPlay) {
|
||||
autoPlay(position);
|
||||
}
|
||||
} else binding.itemFeedBottom.btnMute.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
final View.OnClickListener muteClickListener = v -> {
|
||||
final int currentItem = binding.mediaList.getCurrentItem();
|
||||
if (currentItem < 0 || currentItem >= binding.mediaList.getChildCount()) {
|
||||
return;
|
||||
}
|
||||
final ViewerPostModel sliderItem = sliderItems[currentItem];
|
||||
if (sliderItem.getItemType() != MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
return;
|
||||
}
|
||||
final View currentView = binding.mediaList.getChildAt(currentItem);
|
||||
if (!(currentView instanceof ViewSwitcher)) {
|
||||
return;
|
||||
}
|
||||
final ViewSwitcher viewSwitcher = (ViewSwitcher) currentView;
|
||||
final Object tag = viewSwitcher.getTag();
|
||||
if (!(tag instanceof SimpleExoPlayer)) {
|
||||
return;
|
||||
}
|
||||
final SimpleExoPlayer player = (SimpleExoPlayer) tag;
|
||||
final float intVol = player.getVolume() == 0f ? 1f : 0f;
|
||||
player.setVolume(intVol);
|
||||
binding.itemFeedBottom.btnMute.setImageResource(intVol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24);
|
||||
Utils.sessionVolumeFull = intVol == 1f;
|
||||
};
|
||||
final ViewerPostModel firstItem = sliderItems[0];
|
||||
if (firstItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE);
|
||||
}
|
||||
binding.itemFeedBottom.btnMute.setImageResource(Utils.sessionVolumeFull ? R.drawable.ic_volume_off_24 : R.drawable.ic_volume_up_24);
|
||||
binding.itemFeedBottom.btnMute.setOnClickListener(muteClickListener);
|
||||
}
|
||||
|
||||
private void autoPlay(final int position) {
|
||||
if (!shouldAutoPlay) {
|
||||
return;
|
||||
}
|
||||
final ChildMediaItemsAdapter adapter = (ChildMediaItemsAdapter) binding.mediaList.getAdapter();
|
||||
if (adapter == null) {
|
||||
return;
|
||||
}
|
||||
final ViewerPostModel sliderItem = adapter.getItemAtPosition(position);
|
||||
if (sliderItem.getItemType() != MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
return;
|
||||
}
|
||||
final ViewSwitcher viewSwitcher = (ViewSwitcher) binding.mediaList.getChildAt(position);
|
||||
loadPlayer(binding.getRoot().getContext(),
|
||||
position, sliderItem.getDisplayUrl(),
|
||||
viewSwitcher,
|
||||
cacheDataSourceFactory != null ? cacheDataSourceFactory : dataSourceFactory,
|
||||
playerChangeListener);
|
||||
}
|
||||
|
||||
public void startPlayingVideo() {
|
||||
autoPlay(playerPosition);
|
||||
}
|
||||
|
||||
public void stopPlayingVideo() {
|
||||
if (pagerPlayer == null) {
|
||||
return;
|
||||
}
|
||||
pagerPlayer.setPlayWhenReady(false);
|
||||
}
|
||||
|
||||
private interface PlayerChangeListener {
|
||||
void playerChanged(final int position, final SimpleExoPlayer player);
|
||||
}
|
||||
|
||||
private static void loadPlayer(final Context context,
|
||||
final int position, final String displayUrl,
|
||||
final ViewSwitcher viewSwitcher,
|
||||
final DataSource.Factory factory,
|
||||
final PlayerChangeListener playerChangeListener) {
|
||||
if (viewSwitcher == null) {
|
||||
return;
|
||||
}
|
||||
SimpleExoPlayer player = (SimpleExoPlayer) viewSwitcher.getTag();
|
||||
if (player != null) {
|
||||
player.setPlayWhenReady(true);
|
||||
return;
|
||||
}
|
||||
player = new SimpleExoPlayer.Builder(context).build();
|
||||
final PlayerView playerView = (PlayerView) viewSwitcher.getChildAt(1);
|
||||
playerView.setPlayer(player);
|
||||
if (viewSwitcher.getDisplayedChild() == 0) {
|
||||
viewSwitcher.showNext();
|
||||
}
|
||||
playerView.setControllerShowTimeoutMs(1000);
|
||||
float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
if (vol == 0f && Utils.sessionVolumeFull) vol = 1f;
|
||||
player.setVolume(vol);
|
||||
player.setPlayWhenReady(Utils.settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
|
||||
final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(factory).createMediaSource(Uri.parse(displayUrl));
|
||||
player.setRepeatMode(Player.REPEAT_MODE_ALL);
|
||||
player.prepare(mediaSource);
|
||||
player.setVolume(vol);
|
||||
playerChangeListener.playerChanged(position, player);
|
||||
viewSwitcher.setTag(player);
|
||||
}
|
||||
|
||||
private static final class ChildMediaItemsAdapter extends PagerAdapter {
|
||||
// private static final String TAG = "ChildMediaItemsAdapter";
|
||||
|
||||
private final ViewerPostModel[] sliderItems;
|
||||
private final DataSource.Factory factory;
|
||||
private final PlayerChangeListener playerChangeListener;
|
||||
private final ViewGroup.LayoutParams layoutParams;
|
||||
|
||||
private ChildMediaItemsAdapter(final ViewerPostModel[] sliderItems,
|
||||
final DataSource.Factory factory,
|
||||
final PlayerChangeListener playerChangeListener) {
|
||||
this.sliderItems = sliderItems;
|
||||
this.factory = factory;
|
||||
this.playerChangeListener = playerChangeListener;
|
||||
layoutParams = new ViewGroup.LayoutParams(Utils.displayMetrics.widthPixels, Utils.displayMetrics.widthPixels + 1);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object instantiateItem(@NonNull final ViewGroup container, final int position) {
|
||||
final Context context = container.getContext();
|
||||
final ViewerPostModel sliderItem = sliderItems[position];
|
||||
|
||||
final String displayUrl = sliderItem.getDisplayUrl();
|
||||
if (sliderItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
final ViewSwitcher viewSwitcher = createViewSwitcher(context, position, sliderItem.getSliderDisplayUrl(), displayUrl);
|
||||
container.addView(viewSwitcher);
|
||||
return viewSwitcher;
|
||||
}
|
||||
final GenericDraweeHierarchy hierarchy = GenericDraweeHierarchyBuilder.newInstance(container.getResources())
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
|
||||
.build();
|
||||
final SimpleDraweeView photoView = new SimpleDraweeView(context, hierarchy);
|
||||
photoView.setLayoutParams(layoutParams);
|
||||
final ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(displayUrl))
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
photoView.setImageRequest(imageRequest);
|
||||
container.addView(photoView);
|
||||
return photoView;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ViewSwitcher createViewSwitcher(final Context context, final int position, final String sliderDisplayUrl, final String displayUrl) {
|
||||
|
||||
final ViewSwitcher viewSwitcher = new ViewSwitcher(context);
|
||||
viewSwitcher.setLayoutParams(layoutParams);
|
||||
|
||||
final FrameLayout frameLayout = new FrameLayout(context);
|
||||
frameLayout.setLayoutParams(layoutParams);
|
||||
|
||||
final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(context.getResources())
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
|
||||
.build();
|
||||
final SimpleDraweeView simpleDraweeView = new SimpleDraweeView(context, hierarchy);
|
||||
simpleDraweeView.setLayoutParams(layoutParams);
|
||||
simpleDraweeView.setImageURI(sliderDisplayUrl);
|
||||
frameLayout.addView(simpleDraweeView);
|
||||
|
||||
final AppCompatImageView imageView = new AppCompatImageView(context);
|
||||
final int px = Utils.convertDpToPx(50);
|
||||
final FrameLayout.LayoutParams playButtonLayoutParams = new FrameLayout.LayoutParams(px, px);
|
||||
playButtonLayoutParams.gravity = Gravity.CENTER;
|
||||
imageView.setLayoutParams(playButtonLayoutParams);
|
||||
imageView.setImageResource(R.drawable.exo_icon_play);
|
||||
frameLayout.addView(imageView);
|
||||
|
||||
viewSwitcher.addView(frameLayout);
|
||||
|
||||
final PlayerView playerView = new PlayerView(context);
|
||||
viewSwitcher.addView(playerView);
|
||||
if (shouldAutoPlay && position == 0) {
|
||||
loadPlayer(context, position, displayUrl, viewSwitcher, factory, playerChangeListener);
|
||||
} else
|
||||
frameLayout.setOnClickListener(v -> loadPlayer(context, position, displayUrl, viewSwitcher, factory, playerChangeListener));
|
||||
return viewSwitcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(@NonNull final ViewGroup container, final int position, @NonNull final Object object) {
|
||||
final View view = container.getChildAt(position);
|
||||
// Log.d(TAG, "destroy position: " + position + ", view: " + view);
|
||||
if (view instanceof ViewSwitcher) {
|
||||
final Object tag = view.getTag();
|
||||
if (tag instanceof SimpleExoPlayer) {
|
||||
final SimpleExoPlayer player = (SimpleExoPlayer) tag;
|
||||
player.release();
|
||||
}
|
||||
}
|
||||
container.removeView((View) object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return sliderItems != null ? sliderItems.length : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(@NonNull final View view, @NonNull final Object object) {
|
||||
return view.equals(object);
|
||||
}
|
||||
|
||||
public ViewerPostModel getItemAtPosition(final int position) {
|
||||
return sliderItems[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
package awais.instagrabber.adapters.viewholder.feed;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.ItemFeedVideoBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class FeedVideoViewHolder extends FeedItemViewHolder {
|
||||
private static final String TAG = "FeedVideoViewHolder";
|
||||
|
||||
private final ItemFeedVideoBinding binding;
|
||||
private final Handler handler;
|
||||
private final DefaultDataSourceFactory dataSourceFactory;
|
||||
|
||||
private CacheDataSourceFactory cacheDataSourceFactory;
|
||||
private FeedModel feedModel;
|
||||
private SimpleExoPlayer player;
|
||||
|
||||
private final Runnable loadRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadPlayer(feedModel);
|
||||
}
|
||||
};
|
||||
|
||||
public FeedVideoViewHolder(@NonNull final ItemFeedVideoBinding binding,
|
||||
final MentionClickListener mentionClickListener,
|
||||
final View.OnClickListener clickListener,
|
||||
final View.OnLongClickListener longClickListener) {
|
||||
super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, mentionClickListener, clickListener, longClickListener);
|
||||
this.binding = binding;
|
||||
binding.itemFeedBottom.videoViewsContainer.setVisibility(View.VISIBLE);
|
||||
handler = new Handler(Looper.getMainLooper());
|
||||
final Context context = binding.getRoot().getContext();
|
||||
dataSourceFactory = new DefaultDataSourceFactory(context, "instagram");
|
||||
final SimpleCache simpleCache = Utils.getSimpleCacheInstance(context);
|
||||
if (simpleCache != null) {
|
||||
cacheDataSourceFactory = new CacheDataSourceFactory(simpleCache, dataSourceFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final FeedModel feedModel) {
|
||||
// Log.d(TAG, "Binding post: " + feedModel.getPostId());
|
||||
this.feedModel = feedModel;
|
||||
setThumbnail(feedModel);
|
||||
binding.itemFeedBottom.tvVideoViews.setText(String.valueOf(feedModel.getViewCount()));
|
||||
}
|
||||
|
||||
private void setThumbnail(final FeedModel feedModel) {
|
||||
final ViewGroup.LayoutParams layoutParams = binding.thumbnailParent.getLayoutParams();
|
||||
final int requiredWidth = Utils.displayMetrics.widthPixels;
|
||||
layoutParams.width = feedModel.getImageWidth() == 0 ? requiredWidth : feedModel.getImageWidth();
|
||||
layoutParams.height = feedModel.getImageHeight() == 0 ? requiredWidth + 1 : feedModel.getImageHeight();
|
||||
binding.thumbnailParent.requestLayout();
|
||||
final ImageRequest thumbnailRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(feedModel.getThumbnailUrl()))
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
final DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(thumbnailRequest)
|
||||
.build();
|
||||
binding.thumbnail.setController(controller);
|
||||
binding.thumbnailParent.setOnClickListener(v -> loadPlayer(feedModel));
|
||||
}
|
||||
|
||||
private void loadPlayer(final FeedModel feedModel) {
|
||||
if (feedModel == null) {
|
||||
return;
|
||||
}
|
||||
// Log.d(TAG, "playing post:" + feedModel.getPostId());
|
||||
if (binding.viewSwitcher.getDisplayedChild() == 0) {
|
||||
binding.viewSwitcher.showNext();
|
||||
}
|
||||
binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.playerView.getLayoutParams();
|
||||
final int requiredWidth = Utils.displayMetrics.widthPixels;
|
||||
final int resultingHeight = NumberUtils.getResultingHeight(requiredWidth, feedModel.getImageHeight(), feedModel.getImageWidth());
|
||||
layoutParams.width = requiredWidth;
|
||||
layoutParams.height = resultingHeight;
|
||||
binding.playerView.requestLayout();
|
||||
float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
if (vol == 0f && Utils.sessionVolumeFull) vol = 1f;
|
||||
setMuteIcon(vol);
|
||||
player = (SimpleExoPlayer) binding.playerView.getPlayer();
|
||||
if (player != null) {
|
||||
player.release();
|
||||
}
|
||||
player = new SimpleExoPlayer.Builder(itemView.getContext())
|
||||
.setLooper(Looper.getMainLooper())
|
||||
.build();
|
||||
player.setVolume(vol);
|
||||
player.setPlayWhenReady(true);
|
||||
final DataSource.Factory factory = cacheDataSourceFactory != null ? cacheDataSourceFactory : dataSourceFactory;
|
||||
final ProgressiveMediaSource.Factory sourceFactory = new ProgressiveMediaSource.Factory(factory);
|
||||
final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(Uri.parse(feedModel.getDisplayUrl()));
|
||||
player.setRepeatMode(Player.REPEAT_MODE_ALL);
|
||||
player.prepare(mediaSource);
|
||||
binding.playerView.setPlayer(player);
|
||||
final SimpleExoPlayer finalPlayer = player;
|
||||
binding.itemFeedBottom.btnMute.setOnClickListener(v -> {
|
||||
final float intVol = finalPlayer.getVolume() == 0f ? 1f : 0f;
|
||||
finalPlayer.setVolume(intVol);
|
||||
setMuteIcon(intVol);
|
||||
Utils.sessionVolumeFull = intVol == 1f;
|
||||
});
|
||||
binding.playerView.setOnClickListener(v -> finalPlayer.setPlayWhenReady(!finalPlayer.getPlayWhenReady()));
|
||||
}
|
||||
|
||||
private void setMuteIcon(final float vol) {
|
||||
binding.itemFeedBottom.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24);
|
||||
}
|
||||
|
||||
public FeedModel getCurrentFeedModel() {
|
||||
return feedModel;
|
||||
}
|
||||
|
||||
public void stopPlaying() {
|
||||
// Log.d(TAG, "Stopping post: " + feedModel.getPostId() + ", player: " + player + ", player.isPlaying: " + (player != null && player.isPlaying()));
|
||||
handler.removeCallbacks(loadRunnable);
|
||||
if (player != null) {
|
||||
player.release();
|
||||
}
|
||||
if (binding.viewSwitcher.getDisplayedChild() == 1) {
|
||||
binding.viewSwitcher.showPrevious();
|
||||
}
|
||||
}
|
||||
|
||||
public void startPlaying() {
|
||||
handler.removeCallbacks(loadRunnable);
|
||||
handler.postDelayed(loadRunnable, 800);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class CommentAction extends AsyncTask<String, Void, String> {
|
||||
private static final String TAG = "CommentAction";
|
||||
|
||||
private final String cookie;
|
||||
private final StoryModel storyModel;
|
||||
private final OnTaskCompleteListener onTaskCompleteListener;
|
||||
|
||||
public CommentAction(final String cookie, final StoryModel storyModel, final OnTaskCompleteListener onTaskCompleteListener) {
|
||||
this.cookie = cookie;
|
||||
this.storyModel = storyModel;
|
||||
this.onTaskCompleteListener = onTaskCompleteListener;
|
||||
}
|
||||
|
||||
protected String doInBackground(String... rawAction) {
|
||||
final String action = rawAction[0];
|
||||
final String url = "https://i.instagram.com/api/v1/direct_v2/create_group_thread/";
|
||||
HttpURLConnection urlConnection = null;
|
||||
try {
|
||||
urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
urlConnection.setUseCaches(false);
|
||||
final String urlParameters = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
|
||||
+ "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie)
|
||||
+ "\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
+ "\",\"recipient_users\":\"[" + storyModel.getUserId() // <- string of array of number (not joking)
|
||||
+ "]\"}");
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
if (urlParameters != null) {
|
||||
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) {
|
||||
return new JSONObject(NetworkUtils.readFromConnection(urlConnection)).getString("thread_id");
|
||||
}
|
||||
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, "reply (CT): " + ex);
|
||||
// Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
} finally {
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final String threadId) {
|
||||
if (threadId == null || onTaskCompleteListener == null) {
|
||||
return;
|
||||
}
|
||||
onTaskCompleteListener.onTaskComplete(threadId);
|
||||
}
|
||||
|
||||
public interface OnTaskCompleteListener {
|
||||
void onTaskComplete(final String threadId);
|
||||
}
|
||||
}
|
@ -19,7 +19,8 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.CommentModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
@ -57,7 +58,7 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]>
|
||||
final int childCommentsLen = childCommentModels.length;
|
||||
|
||||
final CommentModel lastChild = childCommentModels[childCommentsLen - 1];
|
||||
if (lastChild != null && lastChild.hasNextPage() && !Utils.isEmpty(lastChild.getEndCursor())) {
|
||||
if (lastChild != null && lastChild.hasNextPage() && !TextUtils.isEmpty(lastChild.getEndCursor())) {
|
||||
final CommentModel[] remoteChildComments = getChildComments(commentModel.getId());
|
||||
commentModel.setChildCommentModels(remoteChildComments);
|
||||
lastChild.setPageCursor(false, null);
|
||||
@ -94,12 +95,12 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]>
|
||||
|
||||
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) break;
|
||||
else {
|
||||
final JSONObject data = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject("comment").getJSONObject("edge_threaded_comments");
|
||||
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject("comment").getJSONObject("edge_threaded_comments");
|
||||
|
||||
final JSONObject pageInfo = data.getJSONObject("page_info");
|
||||
endCursor = pageInfo.getString("end_cursor");
|
||||
if (Utils.isEmpty(endCursor)) endCursor = null;
|
||||
if (TextUtils.isEmpty(endCursor)) endCursor = null;
|
||||
|
||||
final JSONArray childComments = data.optJSONArray("edges");
|
||||
if (childComments != null) {
|
||||
@ -158,12 +159,12 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]>
|
||||
|
||||
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) break;
|
||||
else {
|
||||
final JSONObject parentComments = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject("shortcode_media").getJSONObject("edge_media_to_parent_comment");
|
||||
final JSONObject parentComments = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject("shortcode_media").getJSONObject("edge_media_to_parent_comment");
|
||||
|
||||
final JSONObject pageInfo = parentComments.getJSONObject("page_info");
|
||||
endCursor = pageInfo.optString("end_cursor");
|
||||
if (Utils.isEmpty(endCursor)) endCursor = null;
|
||||
if (TextUtils.isEmpty(endCursor)) endCursor = null;
|
||||
|
||||
// final boolean containsToken = endCursor.contains("bifilter_token");
|
||||
// if (!Utils.isEmpty(endCursor) && (containsToken || endCursor.contains("cached_comments_cursor"))) {
|
||||
@ -216,7 +217,7 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, CommentModel[]>
|
||||
final boolean hasNextPage;
|
||||
if ((tempJsonObject = tempJsonObject.optJSONObject("page_info")) != null) {
|
||||
childEndCursor = tempJsonObject.optString("end_cursor");
|
||||
hasNextPage = tempJsonObject.optBoolean("has_next_page", !Utils.isEmpty(childEndCursor));
|
||||
hasNextPage = tempJsonObject.optBoolean("has_next_page", !TextUtils.isEmpty(childEndCursor));
|
||||
} else {
|
||||
childEndCursor = null;
|
||||
hasNextPage = false;
|
||||
|
@ -21,6 +21,10 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.DiscoverItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -67,7 +71,7 @@ public final class DiscoverFetcher extends AsyncTask<Void, Void, DiscoverItemMod
|
||||
private ArrayList<DiscoverItemModel> fetchItems(ArrayList<DiscoverItemModel> discoverItemModels, final String maxId) {
|
||||
try {
|
||||
final String url = "https://www.instagram.com/explore/grid/?is_prefetch=false&omit_cover_media=true&module=explore_popular" +
|
||||
"&use_sectional_payload=false&cluster_id="+cluster+"&include_fixed_destinations=true&session_id="+rankToken+maxId;
|
||||
"&use_sectional_payload=false&cluster_id=" + cluster + "&include_fixed_destinations=true&session_id=" + rankToken + maxId;
|
||||
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
|
||||
@ -75,7 +79,7 @@ public final class DiscoverFetcher extends AsyncTask<Void, Void, DiscoverItemMod
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject discoverResponse = new JSONObject(Utils.readFromConnection(urlConnection));
|
||||
final JSONObject discoverResponse = new JSONObject(NetworkUtils.readFromConnection(urlConnection));
|
||||
|
||||
moreAvailable = discoverResponse.getBoolean("more_available");
|
||||
nextMaxId = discoverResponse.optString("next_max_id");
|
||||
@ -130,10 +134,10 @@ public final class DiscoverFetcher extends AsyncTask<Void, Void, DiscoverItemMod
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_DISCOVER_FETCHER, "fetchItems",
|
||||
new Pair<>("maxId", maxId),
|
||||
new Pair<>("lastId", lastId),
|
||||
new Pair<>("isFirst", isFirst),
|
||||
new Pair<>("nextMaxId", nextMaxId));
|
||||
new Pair<>("maxId", maxId),
|
||||
new Pair<>("lastId", lastId),
|
||||
new Pair<>("isFirst", isFirst),
|
||||
new Pair<>("nextMaxId", nextMaxId));
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
|
||||
@ -160,25 +164,27 @@ public final class DiscoverFetcher extends AsyncTask<Void, Void, DiscoverItemMod
|
||||
// comment = caption instanceof JSONObject ? ((JSONObject) caption).getString("text") : null;
|
||||
// }
|
||||
|
||||
final MediaItemType mediaType = Utils.getMediaItemType(media.getInt("media_type"));
|
||||
final MediaItemType mediaType = ResponseBodyUtils.getMediaItemType(media.getInt("media_type"));
|
||||
|
||||
final DiscoverItemModel model = new DiscoverItemModel(mediaType,
|
||||
media.getString(Constants.EXTRAS_ID),
|
||||
media.getString("code"),
|
||||
Utils.getThumbnailUrl(media, mediaType));
|
||||
media.getString("pk"),
|
||||
media.getString("code"),
|
||||
ResponseBodyUtils.getThumbnailUrl(media, mediaType));
|
||||
|
||||
final File downloadDir = new File(Environment.getExternalStorageDirectory(), "Download" +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/" + username) : ""));
|
||||
|
||||
// to check if file exists
|
||||
File customDir = null;
|
||||
if (settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
|
||||
final String customPath = settingsHelper.getString(FOLDER_PATH);
|
||||
if (!Utils.isEmpty(customPath)) customDir = new File(customPath +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
if (!TextUtils.isEmpty(customPath)) customDir = new File(customPath +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER)
|
||||
? "/" + username
|
||||
: ""));
|
||||
}
|
||||
|
||||
Utils.checkExistence(downloadDir, customDir, mediaType == MediaItemType.MEDIA_TYPE_SLIDER, model);
|
||||
DownloadUtils.checkExistence(downloadDir, customDir, mediaType == MediaItemType.MEDIA_TYPE_SLIDER, model);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@ -28,25 +26,24 @@ import androidx.core.content.FileProvider;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.activities.ProfilePicViewer;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.CHANNEL_ID;
|
||||
import static awais.instagrabber.utils.Utils.CHANNEL_NAME;
|
||||
import static awais.instagrabber.utils.Utils.NOTIF_GROUP_NAME;
|
||||
import static awais.instagrabber.utils.Utils.isChannelCreated;
|
||||
import static awais.instagrabber.utils.Constants.NOTIF_GROUP_NAME;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
import static awais.instagrabber.utils.Utils.notificationManager;
|
||||
import static awaisomereport.LogCollector.LogFile;
|
||||
|
||||
public final class DownloadAsync extends AsyncTask<Void, Float, File> {
|
||||
private static final String TAG = "DownloadAsync";
|
||||
|
||||
private static int lastNotifId = 1;
|
||||
private final int currentNotifId;
|
||||
private final AtomicReference<Context> context;
|
||||
@ -56,8 +53,12 @@ public final class DownloadAsync extends AsyncTask<Void, Float, File> {
|
||||
private final Resources resources;
|
||||
private final NotificationCompat.Builder downloadNotif;
|
||||
private String shortCode, username;
|
||||
private final NotificationManagerCompat notificationManager;
|
||||
|
||||
public DownloadAsync(final Context context, final String url, final File outFile, final FetchListener<File> fetchListener) {
|
||||
public DownloadAsync(@NonNull final Context context,
|
||||
final String url,
|
||||
final File outFile,
|
||||
final FetchListener<File> fetchListener) {
|
||||
this.context = new AtomicReference<>(context);
|
||||
this.resources = context.getResources();
|
||||
this.url = url;
|
||||
@ -67,22 +68,18 @@ public final class DownloadAsync extends AsyncTask<Void, Float, File> {
|
||||
this.currentNotifId = ++lastNotifId;
|
||||
if (++lastNotifId + 1 == Integer.MAX_VALUE) lastNotifId = 1;
|
||||
|
||||
if (notificationManager == null)
|
||||
notificationManager = NotificationManagerCompat.from(context.getApplicationContext());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !isChannelCreated) {
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID,
|
||||
CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH));
|
||||
isChannelCreated = true;
|
||||
}
|
||||
|
||||
@StringRes final int titleRes = context instanceof ProfilePicViewer ? R.string.downloader_downloading_pfp : R.string.downloader_downloading_post;
|
||||
|
||||
downloadNotif = new NotificationCompat.Builder(context, CHANNEL_ID).setCategory(NotificationCompat.CATEGORY_STATUS)
|
||||
.setSmallIcon(R.mipmap.ic_launcher).setContentText(shortCode == null ? username : shortCode).setOngoing(true)
|
||||
.setProgress(100, 0, false).setAutoCancel(false).setOnlyAlertOnce(true)
|
||||
@StringRes final int titleRes = R.string.downloader_downloading_post;
|
||||
downloadNotif = new NotificationCompat.Builder(context, Constants.DOWNLOAD_CHANNEL_ID)
|
||||
.setCategory(NotificationCompat.CATEGORY_STATUS)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setContentText(shortCode == null ? username : shortCode)
|
||||
.setOngoing(true)
|
||||
.setProgress(100, 0, false)
|
||||
.setAutoCancel(false)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setContentTitle(resources.getString(titleRes));
|
||||
|
||||
notificationManager = NotificationManagerCompat.from(context.getApplicationContext());
|
||||
notificationManager.notify(currentNotifId, downloadNotif.build());
|
||||
}
|
||||
|
||||
@ -99,7 +96,7 @@ public final class DownloadAsync extends AsyncTask<Void, Float, File> {
|
||||
try {
|
||||
final URLConnection urlConnection = new URL(url).openConnection();
|
||||
final long fileSize = Build.VERSION.SDK_INT >= 24 ? urlConnection.getContentLengthLong() :
|
||||
urlConnection.getContentLength();
|
||||
urlConnection.getContentLength();
|
||||
float totalRead = 0;
|
||||
|
||||
try (final BufferedInputStream bis = new BufferedInputStream(urlConnection.getInputStream());
|
||||
@ -152,13 +149,13 @@ public final class DownloadAsync extends AsyncTask<Void, Float, File> {
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogFile.ASYNC_DOWNLOADER, "doInBackground",
|
||||
new Pair<>("context", context.get()),
|
||||
new Pair<>("resources", resources),
|
||||
new Pair<>("lastNotifId", lastNotifId),
|
||||
new Pair<>("downloadNotif", downloadNotif),
|
||||
new Pair<>("currentNotifId", currentNotifId),
|
||||
new Pair<>("notificationManager", notificationManager));
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
new Pair<>("context", context.get()),
|
||||
new Pair<>("resources", resources),
|
||||
new Pair<>("lastNotifId", lastNotifId),
|
||||
new Pair<>("downloadNotif", downloadNotif),
|
||||
new Pair<>("currentNotifId", currentNotifId),
|
||||
new Pair<>("notificationManager", notificationManager));
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -182,23 +179,23 @@ public final class DownloadAsync extends AsyncTask<Void, Float, File> {
|
||||
final Context context = this.context.get();
|
||||
|
||||
context.sendBroadcast(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ?
|
||||
new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(Environment.getExternalStorageDirectory())) :
|
||||
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(result.getAbsoluteFile()))
|
||||
new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(Environment.getExternalStorageDirectory())) :
|
||||
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(result.getAbsoluteFile()))
|
||||
);
|
||||
MediaScannerConnection.scanFile(context, new String[]{result.getAbsolutePath()}, null, null);
|
||||
|
||||
if (notificationManager != null) {
|
||||
final Uri uri = FileProvider.getUriForFile(context, "me.austinhuang.instagrabber.provider", result);
|
||||
final Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", result);
|
||||
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
Bitmap bitmap = null;
|
||||
if (Utils.isImage(uri, contentResolver)) {
|
||||
try {
|
||||
bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri));
|
||||
try (final InputStream inputStream = contentResolver.openInputStream(uri)) {
|
||||
bitmap = BitmapFactory.decodeStream(inputStream);
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogFile.ASYNC_DOWNLOADER, "onPostExecute::bitmap_1");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,15 +225,16 @@ public final class DownloadAsync extends AsyncTask<Void, Float, File> {
|
||||
final String downloadComplete = resources.getString(R.string.downloader_complete);
|
||||
|
||||
downloadNotif.setContentText(null).setContentTitle(downloadComplete).setProgress(0, 0, false)
|
||||
.setWhen(System.currentTimeMillis()).setOngoing(false).setOnlyAlertOnce(false).setAutoCancel(true)
|
||||
.setGroup(NOTIF_GROUP_NAME).setGroupSummary(true).setContentIntent(
|
||||
.setWhen(System.currentTimeMillis()).setOngoing(false).setOnlyAlertOnce(false).setAutoCancel(true)
|
||||
.setGroup(NOTIF_GROUP_NAME).setGroupSummary(true).setContentIntent(
|
||||
PendingIntent.getActivity(context, 2020, new Intent(Intent.ACTION_VIEW, uri)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
.addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_STREAM, uri), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT));
|
||||
|
||||
if (bitmap != null)
|
||||
downloadNotif.setStyle(new NotificationCompat.BigPictureStyle().setBigContentTitle(downloadComplete).bigPicture(bitmap))
|
||||
.setLargeIcon(bitmap).setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL);
|
||||
.setLargeIcon(bitmap).setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL);
|
||||
|
||||
notificationManager.cancel(currentNotifId);
|
||||
notificationManager.notify(currentNotifId + 1, downloadNotif.build());
|
||||
|
@ -19,12 +19,16 @@ import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> {
|
||||
private static final String TAG = "FeedFetcher";
|
||||
|
||||
private static final int maxItemsToLoad = 25; // max is 50, but that's too many posts, setting more than 30 is gay
|
||||
private final String endCursor;
|
||||
private final FetchListener<FeedModel[]> fetchListener;
|
||||
@ -61,8 +65,10 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> {
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject timelineFeed = new JSONObject(Utils.readFromConnection(urlConnection)).getJSONObject("data")
|
||||
.getJSONObject(Constants.EXTRAS_USER).getJSONObject("edge_web_feed_timeline");
|
||||
final String json = NetworkUtils.readFromConnection(urlConnection);
|
||||
// Log.d(TAG, json);
|
||||
final JSONObject timelineFeed = new JSONObject(json).getJSONObject("data")
|
||||
.getJSONObject(Constants.EXTRAS_USER).getJSONObject("edge_web_feed_timeline");
|
||||
|
||||
final String endCursor;
|
||||
final boolean hasNextPage;
|
||||
@ -83,30 +89,41 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> {
|
||||
for (int i = 0; i < feedLen; ++i) {
|
||||
final JSONObject feedItem = feedItems.getJSONObject(i).getJSONObject("node");
|
||||
final String mediaType = feedItem.optString("__typename");
|
||||
if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType)) continue;
|
||||
if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType))
|
||||
continue;
|
||||
|
||||
final boolean isVideo = feedItem.optBoolean("is_video");
|
||||
final long videoViews = feedItem.optLong("video_view_count", 0);
|
||||
|
||||
final String displayUrl = feedItem.optString("display_url");
|
||||
if (Utils.isEmpty(displayUrl)) continue;
|
||||
if (TextUtils.isEmpty(displayUrl)) continue;
|
||||
final String resourceUrl;
|
||||
|
||||
if (isVideo) resourceUrl = feedItem.getString("video_url");
|
||||
else resourceUrl = feedItem.has("display_resources") ? Utils.getHighQualityImage(feedItem) : displayUrl;
|
||||
else
|
||||
resourceUrl = feedItem.has("display_resources") ? ResponseBodyUtils.getHighQualityImage(feedItem) : displayUrl;
|
||||
|
||||
ProfileModel profileModel = null;
|
||||
if (feedItem.has("owner")) {
|
||||
final JSONObject owner = feedItem.getJSONObject("owner");
|
||||
profileModel = new ProfileModel(owner.optBoolean("is_private"),
|
||||
profileModel = new ProfileModel(
|
||||
owner.optBoolean("is_private"),
|
||||
false, // if you can see it then you def follow
|
||||
owner.optBoolean("is_verified"),
|
||||
owner.getString(Constants.EXTRAS_ID),
|
||||
owner.getString(Constants.EXTRAS_USERNAME),
|
||||
owner.optString("full_name"),
|
||||
null, null,
|
||||
null,
|
||||
null,
|
||||
owner.getString("profile_pic_url"),
|
||||
null, 0, 0, 0, false, false, false, false);
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
JSONObject tempJsonObject = feedItem.optJSONObject("edge_media_preview_comment");
|
||||
@ -122,7 +139,21 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> {
|
||||
captionText = tempJsonObject.getString("text");
|
||||
}
|
||||
|
||||
final FeedModel feedModel = new FeedModel(profileModel,
|
||||
final JSONObject location = feedItem.optJSONObject("location");
|
||||
// Log.d(TAG, "location: " + (location == null ? null : location.toString()));
|
||||
String locationId = null;
|
||||
String locationName = null;
|
||||
if (location != null) {
|
||||
locationName = location.optString("name");
|
||||
if (location.has("id")) {
|
||||
locationId = location.getString("id");
|
||||
} else if (location.has("pk")) {
|
||||
locationId = location.getString("pk");
|
||||
}
|
||||
// Log.d(TAG, "locationId: " + locationId);
|
||||
}
|
||||
final FeedModel feedModel = new FeedModel(
|
||||
profileModel,
|
||||
isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
videoViews,
|
||||
feedItem.getString(Constants.EXTRAS_ID),
|
||||
@ -135,7 +166,8 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> {
|
||||
feedItem.getBoolean("viewer_has_liked"),
|
||||
feedItem.getBoolean("viewer_has_saved"),
|
||||
feedItem.getJSONObject("edge_media_preview_like").getLong("count"),
|
||||
feedItem.optJSONObject("location"));
|
||||
locationName,
|
||||
locationId);
|
||||
|
||||
final boolean isSlider = "GraphSidecar".equals(mediaType) && feedItem.has("edge_sidecar_to_children");
|
||||
|
||||
@ -154,14 +186,17 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> {
|
||||
sliderItems[j] = new ViewerPostModel(
|
||||
isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
node.getString(Constants.EXTRAS_ID),
|
||||
isChildVideo ? node.getString("video_url") : Utils.getHighQualityImage(node),
|
||||
null, null, null,
|
||||
node.optLong("video_view_count", -1), -1, false, false,
|
||||
isChildVideo ? node.getString("video_url") : ResponseBodyUtils.getHighQualityImage(node),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
node.optLong("video_view_count", -1),
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
feedItem.getJSONObject("edge_media_preview_like").getLong("count"),
|
||||
feedItem.isNull("location") ? null : feedItem.getJSONObject("location").optString("name"),
|
||||
feedItem.isNull("location") ? null :
|
||||
(feedItem.getJSONObject("location").optString("id") + "/" +
|
||||
feedItem.getJSONObject("location").optString("slug")));
|
||||
locationName,
|
||||
locationId);
|
||||
|
||||
sliderItems[j].setSliderDisplayUrl(node.getString("display_url"));
|
||||
}
|
||||
@ -187,7 +222,9 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> {
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_FEED_FETCHER, "doInBackground");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -14,7 +14,7 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.FeedStoryModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awaisomereport.LogCollector.LogFile;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
@ -39,7 +39,7 @@ public final class FeedStoriesFetcher extends AsyncTask<Void, Void, FeedStoryMod
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONArray feedStoriesReel = new JSONObject(Utils.readFromConnection(conn))
|
||||
final JSONArray feedStoriesReel = new JSONObject(NetworkUtils.readFromConnection(conn))
|
||||
.getJSONObject("data")
|
||||
.getJSONObject(Constants.EXTRAS_USER)
|
||||
.getJSONObject("feed_reels_tray")
|
||||
|
@ -13,7 +13,7 @@ import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
@ -55,8 +55,8 @@ public final class FollowFetcher extends AsyncTask<Void, Void, FollowModel[]> {
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject data = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject(Constants.EXTRAS_USER).getJSONObject(isFollowers ? "edge_followed_by" : "edge_follow");
|
||||
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject(Constants.EXTRAS_USER).getJSONObject(isFollowers ? "edge_followed_by" : "edge_follow");
|
||||
|
||||
final String endCursor;
|
||||
final boolean hasNextPage;
|
||||
|
@ -9,24 +9,24 @@ import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class GetActivityAsyncTask extends AsyncTask<Void, Void, GetActivityAsyncTask.NotificationCounts> {
|
||||
public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsyncTask.NotificationCounts> {
|
||||
private static final String TAG = "GetActivityAsyncTask";
|
||||
private String uid;
|
||||
private String cookie;
|
||||
|
||||
private OnTaskCompleteListener onTaskCompleteListener;
|
||||
|
||||
public GetActivityAsyncTask(final String uid, final String cookie, final OnTaskCompleteListener onTaskCompleteListener) {
|
||||
this.uid = uid;
|
||||
this.cookie = cookie;
|
||||
public GetActivityAsyncTask(final OnTaskCompleteListener onTaskCompleteListener) {
|
||||
this.onTaskCompleteListener = onTaskCompleteListener;
|
||||
}
|
||||
|
||||
protected NotificationCounts doInBackground(Void... voids) {
|
||||
if (Utils.isEmpty(cookie)) {
|
||||
return null;
|
||||
}
|
||||
protected NotificationCounts doInBackground(final String... cookiesArray) {
|
||||
if (cookiesArray == null) return null;
|
||||
final String cookie = cookiesArray[0];
|
||||
if (TextUtils.isEmpty(cookie)) return null;
|
||||
final String uid = CookieUtils.getUserIdFromCookie(cookie);
|
||||
final String url = "https://www.instagram.com/graphql/query/?query_hash=0f318e8cfff9cc9ef09f88479ff571fb"
|
||||
+ "&variables={\"id\":\"" + uid + "\"}";
|
||||
HttpURLConnection urlConnection = null;
|
||||
@ -39,8 +39,12 @@ public class GetActivityAsyncTask extends AsyncTask<Void, Void, GetActivityAsync
|
||||
if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
return null;
|
||||
}
|
||||
final JSONObject data = new JSONObject(Utils.readFromConnection(urlConnection)).getJSONObject("data")
|
||||
.getJSONObject("user").getJSONObject("edge_activity_count").getJSONArray("edges").getJSONObject(0)
|
||||
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(urlConnection))
|
||||
.getJSONObject("data")
|
||||
.getJSONObject("user")
|
||||
.getJSONObject("edge_activity_count")
|
||||
.getJSONArray("edges")
|
||||
.getJSONObject(0)
|
||||
.getJSONObject("node");
|
||||
return new NotificationCounts(
|
||||
data.getInt("relationships"),
|
||||
@ -61,9 +65,7 @@ public class GetActivityAsyncTask extends AsyncTask<Void, Void, GetActivityAsync
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final NotificationCounts result) {
|
||||
if (onTaskCompleteListener == null) {
|
||||
return;
|
||||
}
|
||||
if (onTaskCompleteListener == null) return;
|
||||
onTaskCompleteListener.onTaskComplete(result);
|
||||
}
|
||||
|
||||
@ -105,6 +107,17 @@ public class GetActivityAsyncTask extends AsyncTask<Void, Void, GetActivityAsync
|
||||
public int getLikesCount() {
|
||||
return likesCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NotificationCounts{" +
|
||||
"relationshipsCount=" + relationshipsCount +
|
||||
", userTagsCount=" + userTagsCount +
|
||||
", commentsCount=" + commentsCount +
|
||||
", commentLikesCount=" + commentLikesCount +
|
||||
", likesCount=" + likesCount +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnTaskCompleteListener {
|
||||
|
@ -15,7 +15,7 @@ import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.HashtagModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
@ -40,7 +40,7 @@ public final class HashtagFetcher extends AsyncTask<Void, Void, HashtagModel> {
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject user = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("graphql").getJSONObject(Constants.EXTRAS_HASHTAG);
|
||||
final JSONObject user = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("graphql").getJSONObject(Constants.EXTRAS_HASHTAG);
|
||||
|
||||
final JSONObject timelineMedia = user.getJSONObject("edge_hashtag_to_media");
|
||||
if (timelineMedia.has("edges")) {
|
||||
|
@ -8,27 +8,29 @@ import org.json.JSONObject;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.HighlightModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
|
||||
public final class HighlightsFetcher extends AsyncTask<Void, Void, HighlightModel[]> {
|
||||
public final class HighlightsFetcher extends AsyncTask<Void, Void, List<HighlightModel>> {
|
||||
private final String id;
|
||||
private final boolean storiesig;
|
||||
private final FetchListener<HighlightModel[]> fetchListener;
|
||||
private final FetchListener<List<HighlightModel>> fetchListener;
|
||||
|
||||
public HighlightsFetcher(final String id, final boolean storiesig, final FetchListener<HighlightModel[]> fetchListener) {
|
||||
public HighlightsFetcher(final String id, final boolean storiesig, final FetchListener<List<HighlightModel>> fetchListener) {
|
||||
this.id = id;
|
||||
this.storiesig = storiesig;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HighlightModel[] doInBackground(final Void... voids) {
|
||||
HighlightModel[] result = null;
|
||||
protected List<HighlightModel> doInBackground(final Void... voids) {
|
||||
List<HighlightModel> result = null;
|
||||
String url = "https://" + (storiesig ? "storiesig" : "i.instagram") + ".com/api/v1/highlights/" + id + "/highlights_tray/";
|
||||
|
||||
try {
|
||||
@ -39,20 +41,21 @@ public final class HighlightsFetcher extends AsyncTask<Void, Void, HighlightMode
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONArray highlightsReel = new JSONObject(Utils.readFromConnection(conn)).getJSONArray("tray");
|
||||
final JSONArray highlightsReel = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONArray("tray");
|
||||
|
||||
final int length = highlightsReel.length();
|
||||
final HighlightModel[] highlightModels = new HighlightModel[length];
|
||||
final String[] highlightIds = new String[length];
|
||||
final List<HighlightModel> highlightModels = new ArrayList<>();
|
||||
// final String[] highlightIds = new String[length];
|
||||
for (int i = 0; i < length; ++i) {
|
||||
final JSONObject highlightNode = highlightsReel.getJSONObject(i);
|
||||
highlightModels[i] = new HighlightModel(
|
||||
highlightModels.add(new HighlightModel(
|
||||
highlightNode.getString("title"),
|
||||
highlightNode.getString(Constants.EXTRAS_ID),
|
||||
highlightNode.getJSONObject("cover_media").getJSONObject("cropped_image_version").getString("url")
|
||||
);
|
||||
highlightNode.getJSONObject("cover_media")
|
||||
.getJSONObject("cropped_image_version")
|
||||
.getString("url")
|
||||
));
|
||||
}
|
||||
|
||||
conn.disconnect();
|
||||
result = highlightModels;
|
||||
}
|
||||
@ -66,7 +69,7 @@ public final class HighlightsFetcher extends AsyncTask<Void, Void, HighlightMode
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final HighlightModel[] result) {
|
||||
protected void onPostExecute(final List<HighlightModel> result) {
|
||||
if (fetchListener != null) fetchListener.onResult(result);
|
||||
}
|
||||
}
|
@ -18,11 +18,11 @@ 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;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
|
||||
public class ImageUploader extends AsyncTask<ImageUploadOptions, Void, ImageUploader.ImageUploadResponse> {
|
||||
private static final String TAG = "ImageUploader";
|
||||
@ -52,7 +52,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 = NumberUtils.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");
|
||||
@ -69,7 +69,7 @@ public class ImageUploader extends AsyncTask<ImageUploadOptions, Void, ImageUplo
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoOutput(true);
|
||||
Utils.setConnectionHeaders(connection, headers);
|
||||
NetworkUtils.setConnectionHeaders(connection, headers);
|
||||
out = new BufferedOutputStream(connection.getOutputStream());
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
|
@ -5,7 +5,6 @@ import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -16,18 +15,20 @@ import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.LocationModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class LocationFetcher extends AsyncTask<Void, Void, LocationModel> {
|
||||
private final FetchListener<LocationModel> fetchListener;
|
||||
private final String idSlug;
|
||||
private static final String TAG = "LocationFetcher";
|
||||
|
||||
public LocationFetcher(String idSlug, FetchListener<LocationModel> fetchListener) {
|
||||
private final FetchListener<LocationModel> fetchListener;
|
||||
private final String id;
|
||||
|
||||
public LocationFetcher(final String id, final FetchListener<LocationModel> fetchListener) {
|
||||
// idSlug = id + "/" + slug UPDATE: slug can be ignored tbh
|
||||
this.idSlug = idSlug;
|
||||
this.id = id;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@ -37,27 +38,29 @@ public final class LocationFetcher extends AsyncTask<Void, Void, LocationModel>
|
||||
LocationModel result = null;
|
||||
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/explore/locations/" + idSlug + "/?__a=1").openConnection();
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/explore/locations/" + id + "/?__a=1")
|
||||
.openConnection();
|
||||
conn.setUseCaches(true);
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject user = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("graphql").getJSONObject(Constants.EXTRAS_LOCATION);
|
||||
|
||||
final JSONObject timelineMedia = user.getJSONObject("edge_location_to_media");
|
||||
if (timelineMedia.has("edges")) {
|
||||
final JSONArray edges = timelineMedia.getJSONArray("edges");
|
||||
}
|
||||
final JSONObject location = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("graphql")
|
||||
.getJSONObject(Constants.EXTRAS_LOCATION);
|
||||
|
||||
final JSONObject timelineMedia = location.getJSONObject("edge_location_to_media");
|
||||
// if (timelineMedia.has("edges")) {
|
||||
// final JSONArray edges = timelineMedia.getJSONArray("edges");
|
||||
// }
|
||||
result = new LocationModel(
|
||||
user.getString(Constants.EXTRAS_ID) + "/" + user.getString("slug"),
|
||||
user.getString("name"),
|
||||
user.getString("blurb"),
|
||||
user.getString("website"),
|
||||
user.getString("profile_pic_url"),
|
||||
location.getString(Constants.EXTRAS_ID),
|
||||
location.getString("slug"),
|
||||
location.getString("name"),
|
||||
location.getString("blurb"),
|
||||
location.getString("website"),
|
||||
location.getString("profile_pic_url"),
|
||||
timelineMedia.getLong("count"),
|
||||
BigDecimal.valueOf(user.optDouble("lat", 0d)).toString(),
|
||||
BigDecimal.valueOf(user.optDouble("lng", 0d)).toString()
|
||||
BigDecimal.valueOf(location.optDouble("lat", 0d)).toString(),
|
||||
BigDecimal.valueOf(location.optDouble("lng", 0d)).toString()
|
||||
);
|
||||
}
|
||||
|
||||
@ -65,9 +68,10 @@ public final class LocationFetcher extends AsyncTask<Void, Void, LocationModel>
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_LOCATION_FETCHER, "doInBackground");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
93
app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java
Executable file → Normal file
93
app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java
Executable file → Normal file
@ -8,31 +8,36 @@ import org.json.JSONObject;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.NotificationModel;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class NotificationsFetcher extends AsyncTask<Void, Void, NotificationModel[]> {
|
||||
private final FetchListener<NotificationModel[]> fetchListener;
|
||||
public final class NotificationsFetcher extends AsyncTask<Void, Void, List<NotificationModel>> {
|
||||
private static final String TAG = "NotificationsFetcher";
|
||||
|
||||
public NotificationsFetcher(final FetchListener<NotificationModel[]> fetchListener) {
|
||||
private final FetchListener<List<NotificationModel>> fetchListener;
|
||||
|
||||
public NotificationsFetcher(final FetchListener<List<NotificationModel>> fetchListener) {
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NotificationModel[] doInBackground(final Void... voids) {
|
||||
NotificationModel[] result = null;
|
||||
protected List<NotificationModel> doInBackground(final Void... voids) {
|
||||
List<NotificationModel> result = new ArrayList<>();
|
||||
final String url = "https://www.instagram.com/accounts/activity/?__a=1";
|
||||
Utils.setupCookies(settingsHelper.getString(Constants.COOKIE));
|
||||
CookieUtils.setupCookies(settingsHelper.getString(Constants.COOKIE));
|
||||
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
@ -42,56 +47,62 @@ public final class NotificationsFetcher extends AsyncTask<Void, Void, Notificati
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
JSONObject page = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("graphql").getJSONObject("user"),
|
||||
ewaf = page.getJSONObject("activity_feed").optJSONObject("edge_web_activity_feed"),
|
||||
efr = page.optJSONObject("edge_follow_requests"),
|
||||
data;
|
||||
final JSONObject page = new JSONObject(NetworkUtils.readFromConnection(conn))
|
||||
.getJSONObject("graphql")
|
||||
.getJSONObject("user");
|
||||
final JSONObject ewaf = page.getJSONObject("activity_feed")
|
||||
.optJSONObject("edge_web_activity_feed");
|
||||
final JSONObject efr = page.optJSONObject("edge_follow_requests");
|
||||
JSONObject data;
|
||||
JSONArray media;
|
||||
int totalLength = 0, mediaLen = 0, reqLen = 0;
|
||||
NotificationModel[] models = null, req = null;
|
||||
|
||||
if ((media = ewaf.optJSONArray("edges")) != null && media.length() > 0 &&
|
||||
(data = media.optJSONObject(0).optJSONObject("node")) != null) {
|
||||
mediaLen = media.length();
|
||||
models = new NotificationModel[mediaLen];
|
||||
for (int i = 0; i < mediaLen; ++i) {
|
||||
if (ewaf != null
|
||||
&& (media = ewaf.optJSONArray("edges")) != null
|
||||
&& media.length() > 0
|
||||
&& media.optJSONObject(0).optJSONObject("node") != null) {
|
||||
for (int i = 0; i < media.length(); ++i) {
|
||||
data = media.optJSONObject(i).optJSONObject("node");
|
||||
if (Utils.getNotifType(data.getString("__typename")) == null) continue;
|
||||
models[i] = new NotificationModel(data.getString(Constants.EXTRAS_ID),
|
||||
if (data == null) continue;
|
||||
final String type = data.getString("__typename");
|
||||
final NotificationType notificationType = NotificationType.valueOfType(type);
|
||||
if (notificationType == null) continue;
|
||||
final JSONObject user = data.getJSONObject("user");
|
||||
result.add(new NotificationModel(
|
||||
data.getString(Constants.EXTRAS_ID),
|
||||
data.optString("text"), // comments or mentions
|
||||
data.getLong("timestamp"),
|
||||
data.getJSONObject("user").getString("username"),
|
||||
data.getJSONObject("user").getString("profile_pic_url"),
|
||||
user.getString("id"),
|
||||
user.getString("username"),
|
||||
user.getString("profile_pic_url"),
|
||||
!data.isNull("media") ? data.getJSONObject("media").getString("shortcode") : null,
|
||||
!data.isNull("media") ? data.getJSONObject("media").getString("thumbnail_src") : null,
|
||||
Utils.getNotifType(data.getString("__typename")));
|
||||
!data.isNull("media") ? data.getJSONObject("media").getString("thumbnail_src") : null, notificationType));
|
||||
}
|
||||
}
|
||||
|
||||
if (efr != null && (media = efr.optJSONArray("edges")) != null && media.length() > 0 &&
|
||||
(data = media.optJSONObject(0).optJSONObject("node")) != null) {
|
||||
reqLen = media.length();
|
||||
req = new NotificationModel[reqLen];
|
||||
for (int i = 0; i < reqLen; ++i) {
|
||||
if (efr != null
|
||||
&& (media = efr.optJSONArray("edges")) != null
|
||||
&& media.length() > 0
|
||||
&& media.optJSONObject(0).optJSONObject("node") != null) {
|
||||
for (int i = 0; i < media.length(); ++i) {
|
||||
data = media.optJSONObject(i).optJSONObject("node");
|
||||
req[i] = new NotificationModel(data.getString(Constants.EXTRAS_ID),
|
||||
data.optString("full_name"), 0L, data.getString("username"),
|
||||
data.getString("profile_pic_url"), null, null, NotificationType.REQUEST);
|
||||
if (data == null) continue;
|
||||
result.add(new NotificationModel(
|
||||
data.getString(Constants.EXTRAS_ID),
|
||||
data.optString("full_name"),
|
||||
0L,
|
||||
data.getString(Constants.EXTRAS_ID),
|
||||
data.getString("username"),
|
||||
data.getString("profile_pic_url"),
|
||||
null,
|
||||
null, NotificationType.REQUEST));
|
||||
}
|
||||
}
|
||||
|
||||
result = new NotificationModel[mediaLen + reqLen];
|
||||
if (req != null) System.arraycopy(req, 0, result, 0, reqLen);
|
||||
if (models != null) System.arraycopy(models, 0, result, reqLen, mediaLen);
|
||||
}
|
||||
|
||||
conn.disconnect();
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_NOTIFICATION_FETCHER, "doInBackground");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -101,7 +112,7 @@ public final class NotificationsFetcher extends AsyncTask<Void, Void, Notificati
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final NotificationModel[] result) {
|
||||
protected void onPostExecute(final List<NotificationModel> result) {
|
||||
if (fetchListener != null) fetchListener.onResult(result);
|
||||
}
|
||||
}
|
@ -11,11 +11,16 @@ import java.io.File;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -25,6 +30,8 @@ import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]> {
|
||||
private static final String TAG = "PostFetcher";
|
||||
|
||||
private final String shortCode;
|
||||
private final FetchListener<ViewerPostModel[]> fetchListener;
|
||||
|
||||
@ -36,7 +43,7 @@ public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
@Override
|
||||
protected ViewerPostModel[] doInBackground(final Void... voids) {
|
||||
ViewerPostModel[] result = null;
|
||||
Utils.setupCookies(Utils.settingsHelper.getString(Constants.COOKIE)); // <- direct download
|
||||
CookieUtils.setupCookies(Utils.settingsHelper.getString(Constants.COOKIE)); // <- direct download
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/p/" + shortCode + "/?__a=1").openConnection();
|
||||
conn.setUseCaches(false);
|
||||
@ -44,19 +51,43 @@ public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
|
||||
final JSONObject media = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("graphql")
|
||||
.getJSONObject("shortcode_media");
|
||||
|
||||
final String username = media.has("owner") ? media.getJSONObject("owner").getString(Constants.EXTRAS_USERNAME) : null;
|
||||
final JSONObject media = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("graphql")
|
||||
.getJSONObject("shortcode_media");
|
||||
|
||||
ProfileModel profileModel = null;
|
||||
if (media.has("owner")) {
|
||||
final JSONObject owner = media.getJSONObject("owner");
|
||||
profileModel = new ProfileModel(
|
||||
owner.optBoolean("is_private"),
|
||||
owner.optBoolean("is_private"),
|
||||
owner.optBoolean("is_verified"),
|
||||
owner.optString("id"),
|
||||
owner.optString("username"),
|
||||
owner.optString("full_name"),
|
||||
null,
|
||||
null,
|
||||
owner.optString("profile_pic_url"),
|
||||
owner.optString("profile_pic_url"),
|
||||
owner.optInt("edge_owner_to_timeline_media"),
|
||||
owner.optInt("edge_followed_by"),
|
||||
-1,
|
||||
owner.optBoolean("followed_by_viewer"),
|
||||
owner.optBoolean("restricted_by_viewer"),
|
||||
owner.optBoolean("blocked_by_viewer"),
|
||||
owner.optBoolean("requested_by_viewer")
|
||||
);
|
||||
}
|
||||
final String username = profileModel == null ? "" : profileModel.getUsername();
|
||||
// to check if file exists
|
||||
final File downloadDir = new File(Environment.getExternalStorageDirectory(), "Download" +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/" + username) : ""));
|
||||
File customDir = null;
|
||||
if (Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
|
||||
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
if (!Utils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER)
|
||||
? ("/" + username)
|
||||
: ""));
|
||||
if (!TextUtils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
}
|
||||
|
||||
final long timestamp = media.getLong("taken_at_timestamp");
|
||||
@ -75,34 +106,36 @@ public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
else {
|
||||
final JSONArray captions = mediaToCaption.optJSONArray("edges");
|
||||
postCaption = captions != null && captions.length() > 0 ?
|
||||
captions.getJSONObject(0).getJSONObject("node").optString("text") : null;
|
||||
captions.getJSONObject(0).getJSONObject("node").optString("text") : null;
|
||||
}
|
||||
|
||||
JSONObject commentObject = media.optJSONObject("edge_media_to_parent_comment");
|
||||
final long commentsCount = commentObject != null ? commentObject.optLong("count") : 0;
|
||||
|
||||
String endCursor = null;
|
||||
if (commentObject != null && (commentObject = commentObject.optJSONObject("page_info")) != null)
|
||||
if (commentObject != null && (commentObject = commentObject.optJSONObject("page_info")) != null) {
|
||||
endCursor = commentObject.optString("end_cursor");
|
||||
}
|
||||
|
||||
if (mediaItemType != MediaItemType.MEDIA_TYPE_SLIDER) {
|
||||
final ViewerPostModel postModel = new ViewerPostModel(mediaItemType,
|
||||
final ViewerPostModel postModel = new ViewerPostModel(
|
||||
mediaItemType,
|
||||
media.getString(Constants.EXTRAS_ID),
|
||||
isVideo ? media.getString("video_url") : Utils.getHighQualityImage(media),
|
||||
isVideo ? media.getString("video_url") : ResponseBodyUtils.getHighQualityImage(media),
|
||||
shortCode,
|
||||
Utils.isEmpty(postCaption) ? null : postCaption,
|
||||
username,
|
||||
TextUtils.isEmpty(postCaption) ? null : postCaption,
|
||||
profileModel,
|
||||
isVideo && media.has("video_view_count") ? media.getLong("video_view_count") : -1,
|
||||
timestamp, media.getBoolean("viewer_has_liked"), media.getBoolean("viewer_has_saved"),
|
||||
media.getJSONObject("edge_media_preview_like").getLong("count"),
|
||||
media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
|
||||
media.isNull("location") ? null :
|
||||
(media.getJSONObject("location").optString("id") + "/" +
|
||||
(media.getJSONObject("location").optString("id") + "/" +
|
||||
media.getJSONObject("location").optString("slug")));
|
||||
|
||||
postModel.setCommentsCount(commentsCount);
|
||||
|
||||
Utils.checkExistence(downloadDir, customDir, false, postModel);
|
||||
DownloadUtils.checkExistence(downloadDir, customDir, false, postModel);
|
||||
|
||||
result = new ViewerPostModel[]{postModel};
|
||||
|
||||
@ -114,22 +147,23 @@ public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
final JSONObject node = children.getJSONObject(i).getJSONObject("node");
|
||||
final boolean isChildVideo = node.getBoolean("is_video");
|
||||
|
||||
postModels[i] = new ViewerPostModel(isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
postModels[i] = new ViewerPostModel(
|
||||
isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
media.getString(Constants.EXTRAS_ID),
|
||||
isChildVideo ? node.getString("video_url") : Utils.getHighQualityImage(node),
|
||||
isChildVideo ? node.getString("video_url") : ResponseBodyUtils.getHighQualityImage(node),
|
||||
node.getString(Constants.EXTRAS_SHORTCODE),
|
||||
postCaption,
|
||||
username,
|
||||
profileModel,
|
||||
isChildVideo && node.has("video_view_count") ? node.getLong("video_view_count") : -1,
|
||||
timestamp, media.getBoolean("viewer_has_liked"), media.getBoolean("viewer_has_saved"),
|
||||
media.getJSONObject("edge_media_preview_like").getLong("count"),
|
||||
media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
|
||||
media.isNull("location") ? null :
|
||||
(media.getJSONObject("location").optString("id") + "/" +
|
||||
media.getJSONObject("location").optString("slug")));
|
||||
(media.getJSONObject("location").optString("id") + "/" +
|
||||
media.getJSONObject("location").optString("slug")));
|
||||
postModels[i].setSliderDisplayUrl(node.getString("display_url"));
|
||||
|
||||
Utils.checkExistence(downloadDir, customDir, true, postModels[i]);
|
||||
DownloadUtils.checkExistence(downloadDir, customDir, true, postModels[i]);
|
||||
}
|
||||
|
||||
postModels[0].setCommentsCount(commentsCount);
|
||||
@ -140,9 +174,10 @@ public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
|
||||
conn.disconnect();
|
||||
} catch (Exception e) {
|
||||
if (logCollector != null)
|
||||
if (logCollector != null) {
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_POST_FETCHER, "doInBackground");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
Log.e(TAG, "Error fetching post", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -15,7 +15,11 @@ import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.models.enums.PostItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -25,19 +29,19 @@ import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
private static final String TAG = "PostsFetcher";
|
||||
private final PostItemType type;
|
||||
private final String endCursor;
|
||||
private final String id;
|
||||
private final FetchListener<PostModel[]> fetchListener;
|
||||
private String username = null;
|
||||
|
||||
public PostsFetcher(final String id, final FetchListener<PostModel[]> fetchListener) {
|
||||
this.id = id;
|
||||
this.endCursor = "";
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
public PostsFetcher(final String id, final String endCursor, final FetchListener<PostModel[]> fetchListener) {
|
||||
public PostsFetcher(final String id,
|
||||
final PostItemType type,
|
||||
final String endCursor,
|
||||
final FetchListener<PostModel[]> fetchListener) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.endCursor = endCursor == null ? "" : endCursor;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
@ -49,27 +53,32 @@ public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
|
||||
@Override
|
||||
protected PostModel[] doInBackground(final Void... voids) {
|
||||
final boolean isHashTag = id.charAt(0) == '#';
|
||||
final boolean isSaved = id.charAt(0) == '$';
|
||||
final boolean isTagged = id.charAt(0) == '%';
|
||||
final boolean isLocation = id.contains("/");
|
||||
// final boolean isHashTag = id.charAt(0) == '#';
|
||||
// final boolean isSaved = id.charAt(0) == '$';
|
||||
// final boolean isTagged = id.charAt(0) == '%';
|
||||
// final boolean isLocation = id.contains("/");
|
||||
|
||||
final String url;
|
||||
if (isHashTag)
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=9b498c08113f1e09617a1703c22b2f32&variables=" +
|
||||
"{\"tag_name\":\"" + id.substring(1).toLowerCase() + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
else if (isLocation)
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=36bd0f2bf5911908de389b8ceaa3be6d&variables=" +
|
||||
"{\"id\":\""+ id.split("/")[0] +"\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
else if (isSaved)
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=8c86fed24fa03a8a2eea2a70a80c7b6b&variables=" +
|
||||
"{\"id\":\""+ id.substring(1) +"\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
else if (isTagged)
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=ff260833edf142911047af6024eb634a&variables=" +
|
||||
"{\"id\":\""+ id.substring(1) +"\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
else
|
||||
url = "https://www.instagram.com/graphql/query/?query_id=17880160963012870&id=" + id + "&first=50&after=" + endCursor;
|
||||
|
||||
switch (type) {
|
||||
case HASHTAG:
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=9b498c08113f1e09617a1703c22b2f32&variables=" +
|
||||
"{\"tag_name\":\"" + id.toLowerCase() + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
break;
|
||||
case LOCATION:
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=36bd0f2bf5911908de389b8ceaa3be6d&variables=" +
|
||||
"{\"id\":\"" + id + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
break;
|
||||
case SAVED:
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=8c86fed24fa03a8a2eea2a70a80c7b6b&variables=" +
|
||||
"{\"id\":\"" + id + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
break;
|
||||
case TAGGED:
|
||||
url = "https://www.instagram.com/graphql/query/?query_hash=31fe64d9463cbbe58319dced405c6206&variables=" +
|
||||
"{\"id\":\"" + id + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||
break;
|
||||
default:
|
||||
url = "https://www.instagram.com/graphql/query/?query_id=17880160963012870&id=" + id + "&first=50&after=" + endCursor;
|
||||
}
|
||||
PostModel[] result = null;
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
@ -79,21 +88,30 @@ public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
// to check if file exists
|
||||
final File downloadDir = new File(Environment.getExternalStorageDirectory(), "Download" +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/" + username) : ""));
|
||||
File customDir = null;
|
||||
if (Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
|
||||
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
if (!Utils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER)
|
||||
? ("/" + username)
|
||||
: ""));
|
||||
if (!TextUtils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
}
|
||||
|
||||
final JSONObject mediaPosts = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject(isHashTag ? Constants.EXTRAS_HASHTAG :
|
||||
(isLocation ? Constants.EXTRAS_LOCATION : Constants.EXTRAS_USER))
|
||||
.getJSONObject(isHashTag ? "edge_hashtag_to_media" :
|
||||
(isLocation ? "edge_location_to_media" :
|
||||
(isSaved ? "edge_saved_media" :
|
||||
(isTagged ? "edge_user_to_photos_of_you" : "edge_owner_to_timeline_media"))));
|
||||
final boolean isHashtag = type == PostItemType.HASHTAG;
|
||||
final boolean isLocation = type == PostItemType.LOCATION;
|
||||
final boolean isSaved = type == PostItemType.SAVED;
|
||||
final boolean isTagged = type == PostItemType.TAGGED;
|
||||
final JSONObject mediaPosts = new JSONObject(NetworkUtils.readFromConnection(conn))
|
||||
.getJSONObject("data")
|
||||
.getJSONObject(isHashtag
|
||||
? Constants.EXTRAS_HASHTAG
|
||||
: (isLocation ? Constants.EXTRAS_LOCATION
|
||||
: Constants.EXTRAS_USER))
|
||||
.getJSONObject(isHashtag ? "edge_hashtag_to_media" :
|
||||
isLocation ? "edge_location_to_media" : isSaved ? "edge_saved_media"
|
||||
: isTagged ? "edge_user_to_photos_of_you"
|
||||
: "edge_owner_to_timeline_media");
|
||||
|
||||
final String endCursor;
|
||||
final boolean hasNextPage;
|
||||
@ -122,16 +140,16 @@ public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
else itemType = MediaItemType.MEDIA_TYPE_IMAGE;
|
||||
|
||||
models[i] = new PostModel(itemType, mediaNode.getString(Constants.EXTRAS_ID),
|
||||
mediaNode.getString("display_url"), mediaNode.getString("thumbnail_src"),
|
||||
mediaNode.getString(Constants.EXTRAS_SHORTCODE),
|
||||
captions.length() > 0 ? captions.getJSONObject(0).getJSONObject("node").getString("text") : null,
|
||||
mediaNode.getLong("taken_at_timestamp"), mediaNode.optBoolean("viewer_has_liked"),
|
||||
mediaNode.optBoolean("viewer_has_saved"), mediaNode.getJSONObject("edge_liked_by").getLong("count"));
|
||||
mediaNode.getString("display_url"), mediaNode.getString("thumbnail_src"),
|
||||
mediaNode.getString(Constants.EXTRAS_SHORTCODE),
|
||||
captions.length() > 0 ? captions.getJSONObject(0).getJSONObject("node").getString("text") : null,
|
||||
mediaNode.getLong("taken_at_timestamp"), mediaNode.optBoolean("viewer_has_liked"),
|
||||
mediaNode.optBoolean("viewer_has_saved"), mediaNode.getJSONObject("edge_liked_by").getLong("count"));
|
||||
|
||||
Utils.checkExistence(downloadDir, customDir, isSlider, models[i]);
|
||||
DownloadUtils.checkExistence(downloadDir, customDir, isSlider, models[i]);
|
||||
}
|
||||
|
||||
if (models.length > 0 && models[models.length - 1] != null)
|
||||
if (models.length != 0 && models[models.length - 1] != null)
|
||||
models[models.length - 1].setPageCursor(hasNextPage, endCursor);
|
||||
|
||||
result = models;
|
||||
@ -141,7 +159,7 @@ public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
} catch (Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_MAIN_POSTS_FETCHER, "doInBackground");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -15,7 +15,8 @@ import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
@ -40,7 +41,7 @@ public final class ProfileFetcher extends AsyncTask<Void, Void, ProfileModel> {
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject user = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("graphql").getJSONObject(Constants.EXTRAS_USER);
|
||||
final JSONObject user = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("graphql").getJSONObject(Constants.EXTRAS_USER);
|
||||
|
||||
boolean isPrivate = user.getBoolean("is_private");
|
||||
boolean reallyPrivate = isPrivate;
|
||||
@ -51,7 +52,7 @@ public final class ProfileFetcher extends AsyncTask<Void, Void, ProfileModel> {
|
||||
}
|
||||
|
||||
String url = user.optString("external_url");
|
||||
if (Utils.isEmpty(url)) url = null;
|
||||
if (TextUtils.isEmpty(url)) url = null;
|
||||
|
||||
result = new ProfileModel(isPrivate,
|
||||
reallyPrivate,
|
||||
|
@ -15,6 +15,8 @@ import java.net.URL;
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -45,26 +47,26 @@ public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> {
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("User-Agent", Constants.USER_AGENT);
|
||||
|
||||
final String result = conn.getResponseCode() == HttpURLConnection.HTTP_OK ? Utils.readFromConnection(conn) : null;
|
||||
final String result = conn.getResponseCode() == HttpURLConnection.HTTP_OK ? NetworkUtils.readFromConnection(conn) : null;
|
||||
conn.disconnect();
|
||||
|
||||
if (!Utils.isEmpty(result)) {
|
||||
if (!TextUtils.isEmpty(result)) {
|
||||
JSONObject data = new JSONObject(result).getJSONObject("user");
|
||||
if (data.has("hd_profile_pic_url_info"))
|
||||
out = data.getJSONObject("hd_profile_pic_url_info").optString("url");
|
||||
}
|
||||
|
||||
if (Utils.isEmpty(out) && Utils.settingsHelper.getBoolean(Constants.INSTADP)) {
|
||||
if (TextUtils.isEmpty(out) && Utils.settingsHelper.getBoolean(Constants.INSTADP)) {
|
||||
final HttpURLConnection backup =
|
||||
(HttpURLConnection) new URL("https://instadp.com/fullsize/" + userName).openConnection();
|
||||
backup.setUseCaches(false);
|
||||
backup.setRequestMethod("GET");
|
||||
backup.setRequestProperty("User-Agent", Constants.A_USER_AGENT);
|
||||
|
||||
final String instadp = backup.getResponseCode() == HttpURLConnection.HTTP_OK ? Utils.readFromConnection(backup) : null;
|
||||
final String instadp = backup.getResponseCode() == HttpURLConnection.HTTP_OK ? NetworkUtils.readFromConnection(backup) : null;
|
||||
backup.disconnect();
|
||||
|
||||
if (!Utils.isEmpty(instadp)) {
|
||||
if (!TextUtils.isEmpty(instadp)) {
|
||||
final Document doc = Jsoup.parse(instadp);
|
||||
boolean fallback = false;
|
||||
|
||||
@ -86,7 +88,7 @@ public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Utils.isEmpty(out)) out = picUrl;
|
||||
if (TextUtils.isEmpty(out)) out = picUrl;
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_PROFILE_PICTURE_FETCHER, "doInBackground");
|
||||
|
89
app/src/main/java/awais/instagrabber/asyncs/QuizAction.java
Normal file
89
app/src/main/java/awais/instagrabber/asyncs/QuizAction.java
Normal file
@ -0,0 +1,89 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.stickers.QuizModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class QuizAction extends AsyncTask<Integer, Void, Integer> {
|
||||
private static final String TAG = "QuizAction";
|
||||
|
||||
private final StoryModel storyModel;
|
||||
private final QuizModel quizModel;
|
||||
private final String cookie;
|
||||
private final OnTaskCompleteListener onTaskCompleteListener;
|
||||
|
||||
public QuizAction(final StoryModel storyModel,
|
||||
final QuizModel quizModel,
|
||||
final String cookie,
|
||||
final OnTaskCompleteListener onTaskCompleteListener) {
|
||||
this.storyModel = storyModel;
|
||||
this.quizModel = quizModel;
|
||||
this.cookie = cookie;
|
||||
this.onTaskCompleteListener = onTaskCompleteListener;
|
||||
}
|
||||
|
||||
protected Integer doInBackground(Integer... rawChoice) {
|
||||
int choice = rawChoice[0];
|
||||
final String url = "https://i.instagram.com/api/v1/media/" + storyModel.getStoryMediaId().split("_")[0] + "/" + quizModel.getId() + "/story_quiz_answer/";
|
||||
HttpURLConnection urlConnection = null;
|
||||
try {
|
||||
JSONObject ogBody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString()
|
||||
+ "\",\"mutation_token\":\"" + UUID.randomUUID().toString()
|
||||
+ "\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
|
||||
+ "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie)
|
||||
+ "\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
+ "\"}");
|
||||
ogBody.put("answer", String.valueOf(choice));
|
||||
String urlParameters = Utils.sign(ogBody.toString());
|
||||
urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
if (urlParameters != null) {
|
||||
urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
|
||||
}
|
||||
urlConnection.setDoOutput(true);
|
||||
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
|
||||
wr.writeBytes(urlParameters);
|
||||
wr.flush();
|
||||
wr.close();
|
||||
Log.d(TAG, "quiz: " + url + " " + cookie + " " + urlParameters);
|
||||
urlConnection.connect();
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
return choice;
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, "quiz: " + ex);
|
||||
} finally {
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Integer choice) {
|
||||
if (onTaskCompleteListener == null || choice == null) return;
|
||||
onTaskCompleteListener.onTaskComplete(choice);
|
||||
}
|
||||
|
||||
public interface OnTaskCompleteListener {
|
||||
void onTaskComplete(final int choice);
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.stickers.QuestionModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class RespondAction extends AsyncTask<String, Void, Boolean> {
|
||||
|
||||
private final StoryModel storyModel;
|
||||
private final QuestionModel questionModel;
|
||||
private final String cookie;
|
||||
private final OnTaskCompleteListener onTaskCompleteListener;
|
||||
|
||||
public RespondAction(final StoryModel storyModel,
|
||||
final QuestionModel questionModel,
|
||||
final String cookie,
|
||||
final OnTaskCompleteListener onTaskCompleteListener) {
|
||||
this.storyModel = storyModel;
|
||||
this.questionModel = questionModel;
|
||||
this.cookie = cookie;
|
||||
this.onTaskCompleteListener = onTaskCompleteListener;
|
||||
}
|
||||
|
||||
protected Boolean doInBackground(String... rawChoice) {
|
||||
final String url = "https://i.instagram.com/api/v1/media/"
|
||||
+ storyModel.getStoryMediaId().split("_")[0] + "/" + questionModel.getId() + "/story_question_response/";
|
||||
HttpURLConnection urlConnection = null;
|
||||
try {
|
||||
final JSONObject ogbody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString()
|
||||
+ "\",\"mutation_token\":\"" + UUID.randomUUID().toString()
|
||||
+ "\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
|
||||
+ "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie)
|
||||
+ "\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
+ "\"}");
|
||||
String choice = rawChoice[0].replaceAll("\"", ("\\\""));
|
||||
ogbody.put("response", choice);
|
||||
String urlParameters = Utils.sign(ogbody.toString());
|
||||
urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", Integer.toString(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) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (Throwable ex) {
|
||||
Log.e("austin_debug", "respond: " + ex);
|
||||
} finally {
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean ok) {
|
||||
if (onTaskCompleteListener == null) return;
|
||||
onTaskCompleteListener.onTaskComplete(ok);
|
||||
|
||||
}
|
||||
|
||||
public interface OnTaskCompleteListener {
|
||||
void onTaskComplete(final boolean result);
|
||||
}
|
||||
}
|
51
app/src/main/java/awais/instagrabber/asyncs/SeenAction.java
Normal file
51
app/src/main/java/awais/instagrabber/asyncs/SeenAction.java
Normal file
@ -0,0 +1,51 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
|
||||
public class SeenAction extends AsyncTask<Void, Void, Void> {
|
||||
private static final String TAG = "SeenAction";
|
||||
|
||||
private final String cookie;
|
||||
private final StoryModel storyModel;
|
||||
|
||||
public SeenAction(final String cookie, final StoryModel storyModel) {
|
||||
this.cookie = cookie;
|
||||
this.storyModel = storyModel;
|
||||
}
|
||||
|
||||
protected Void doInBackground(Void... voids) {
|
||||
final String url = "https://www.instagram.com/stories/reel/seen";
|
||||
try {
|
||||
final String urlParameters = "reelMediaId=" + storyModel.getStoryMediaId().split("_")[0]
|
||||
+ "&reelMediaOwnerId=" + storyModel.getUserId()
|
||||
+ "&reelId=" + storyModel.getUserId()
|
||||
+ "&reelMediaTakenAt=" + storyModel.getTimestamp()
|
||||
+ "&viewSeenAt=" + storyModel.getTimestamp();
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
|
||||
urlConnection.setDoOutput(true);
|
||||
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
|
||||
wr.writeBytes(urlParameters);
|
||||
wr.flush();
|
||||
wr.close();
|
||||
urlConnection.connect();
|
||||
Log.d(TAG, urlConnection.getResponseCode() + " " + NetworkUtils.readFromConnection(urlConnection));
|
||||
urlConnection.disconnect();
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, "Error", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -17,8 +17,8 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.SuggestionModel;
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.UrlEncoder;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public final class SuggestionsFetcher extends AsyncTask<String, String, SuggestionModel[]> {
|
||||
private final FetchListener<SuggestionModel[]> fetchListener;
|
||||
@ -43,7 +43,7 @@ public final class SuggestionsFetcher extends AsyncTask<String, String, Suggesti
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final String defaultHashTagPic = "https://www.instagram.com/static/images/hashtag/search-hashtag-default-avatar.png/1d8417c9a4f5.png";
|
||||
final JSONObject jsonObject = new JSONObject(Utils.readFromConnection(conn));
|
||||
final JSONObject jsonObject = new JSONObject(NetworkUtils.readFromConnection(conn));
|
||||
conn.disconnect();
|
||||
|
||||
final JSONArray usersArray = jsonObject.getJSONArray("users");
|
||||
@ -75,9 +75,9 @@ public final class SuggestionsFetcher extends AsyncTask<String, String, Suggesti
|
||||
|
||||
// name
|
||||
suggestionModels.add(new SuggestionModel(false,
|
||||
place.getJSONObject("location").getString("pk")+"/"+place.getString("slug"),
|
||||
place.getJSONObject("location").getString("pk"), // +"/"+place.getString("slug"),
|
||||
place.getString("title"),
|
||||
place.optString("profile_pic_url", null),
|
||||
place.optString("profile_pic_url"),
|
||||
SuggestionType.TYPE_LOCATION,
|
||||
placesArrayJSONObject.optInt("position", suggestionModels.size() - 1)));
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import java.net.URL;
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
|
||||
public final class UsernameFetcher extends AsyncTask<Void, Void, String> {
|
||||
private final FetchListener<String> fetchListener;
|
||||
@ -36,7 +36,7 @@ public final class UsernameFetcher extends AsyncTask<Void, Void, String> {
|
||||
|
||||
final JSONObject user;
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK &&
|
||||
(user = new JSONObject(Utils.readFromConnection(conn)).optJSONObject(Constants.EXTRAS_USER)) != null)
|
||||
(user = new JSONObject(NetworkUtils.readFromConnection(conn)).optJSONObject(Constants.EXTRAS_USER)) != null)
|
||||
result = user.getString(Constants.EXTRAS_USERNAME);
|
||||
|
||||
conn.disconnect();
|
||||
|
69
app/src/main/java/awais/instagrabber/asyncs/VoteAction.java
Normal file
69
app/src/main/java/awais/instagrabber/asyncs/VoteAction.java
Normal file
@ -0,0 +1,69 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.stickers.PollModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
|
||||
public class VoteAction extends AsyncTask<Integer, Void, Integer> {
|
||||
|
||||
private static final String TAG = "VoteAction";
|
||||
|
||||
private final StoryModel storyModel;
|
||||
private final PollModel pollModel;
|
||||
private final String cookie;
|
||||
private final OnTaskCompleteListener onTaskCompleteListener;
|
||||
|
||||
public VoteAction(final StoryModel storyModel,
|
||||
final PollModel pollModel,
|
||||
final String cookie,
|
||||
final OnTaskCompleteListener onTaskCompleteListener) {
|
||||
this.storyModel = storyModel;
|
||||
this.pollModel = pollModel;
|
||||
this.cookie = cookie;
|
||||
this.onTaskCompleteListener = onTaskCompleteListener;
|
||||
}
|
||||
|
||||
protected Integer doInBackground(Integer... rawChoice) {
|
||||
int choice = rawChoice[0];
|
||||
final String url = "https://www.instagram.com/media/" + storyModel.getStoryMediaId().split("_")[0] + "/" + pollModel.getId() + "/story_poll_vote/";
|
||||
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]);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", "6");
|
||||
urlConnection.setDoOutput(true);
|
||||
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
|
||||
wr.writeBytes("vote=" + choice);
|
||||
wr.flush();
|
||||
wr.close();
|
||||
urlConnection.connect();
|
||||
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
return choice;
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error", ex);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Integer result) {
|
||||
if (result == null || onTaskCompleteListener == null) return;
|
||||
onTaskCompleteListener.onTaskComplete(result);
|
||||
}
|
||||
|
||||
public interface OnTaskCompleteListener {
|
||||
void onTaskComplete(final int choice);
|
||||
}
|
||||
}
|
@ -18,7 +18,9 @@ import awais.instagrabber.models.direct_messages.InboxThreadModel;
|
||||
import awais.instagrabber.models.enums.UserInboxDirection;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
import static awaisomereport.LogCollector.LogFile;
|
||||
@ -48,10 +50,10 @@ public final class DirectMessageInboxThreadFetcher extends AsyncTask<Void, Void,
|
||||
final Map<String, String> queryParamsMap = new HashMap<>();
|
||||
queryParamsMap.put("visual_message_return_type", "unseen");
|
||||
if (direction != null) queryParamsMap.put("direction", direction.getValue());
|
||||
if (!Utils.isEmpty(endCursor)) {
|
||||
if (!TextUtils.isEmpty(endCursor)) {
|
||||
queryParamsMap.put("cursor", endCursor);
|
||||
}
|
||||
final String queryString = Utils.getQueryString(queryParamsMap);
|
||||
final String queryString = NetworkUtils.getQueryString(queryParamsMap);
|
||||
final String url = "https://i.instagram.com/api/v1/direct_v2/threads/" + id + "/?" + queryString;
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
@ -60,8 +62,8 @@ public final class DirectMessageInboxThreadFetcher extends AsyncTask<Void, Void,
|
||||
conn.setUseCaches(false);
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject data = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("thread");
|
||||
result = Utils.createInboxThreadModel(data, true);
|
||||
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("thread");
|
||||
result = ResponseBodyUtils.createInboxThreadModel(data, true);
|
||||
}
|
||||
|
||||
conn.disconnect();
|
||||
|
@ -19,6 +19,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
@ -43,8 +44,8 @@ public class DirectThreadBroadcaster extends AsyncTask<DirectThreadBroadcaster.B
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
final String cc = UUID.randomUUID().toString();
|
||||
final Map<String, String> form = new HashMap<>();
|
||||
form.put("_csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
|
||||
form.put("_uid", Utils.getUserIdFromCookie(cookie));
|
||||
form.put("_csrftoken", CookieUtils.getCsrfTokenFromCookie(cookie));
|
||||
form.put("_uid", CookieUtils.getUserIdFromCookie(cookie));
|
||||
form.put("__uuid", settingsHelper.getString(Constants.DEVICE_UUID));
|
||||
form.put("client_context", cc);
|
||||
form.put("mutation_token", cc);
|
||||
|
@ -8,6 +8,9 @@ import androidx.annotation.Nullable;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
@ -17,17 +20,21 @@ import awais.instagrabber.models.direct_messages.InboxModel;
|
||||
import awais.instagrabber.models.direct_messages.InboxThreadModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
import static awaisomereport.LogCollector.LogFile;
|
||||
|
||||
public final class InboxFetcher extends AsyncTask<Void, Void, InboxModel> {
|
||||
private static final String TAG = "InboxFetcher";
|
||||
|
||||
private final String endCursor;
|
||||
private final FetchListener<InboxModel> fetchListener;
|
||||
|
||||
public InboxFetcher(final String endCursor, final FetchListener<InboxModel> fetchListener) {
|
||||
this.endCursor = Utils.isEmpty(endCursor) ? "" : "?cursor=" + endCursor;
|
||||
this.endCursor = TextUtils.isEmpty(endCursor) ? "" : "?cursor=" + endCursor;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@ -43,46 +50,59 @@ public final class InboxFetcher extends AsyncTask<Void, Void, InboxModel> {
|
||||
conn.setRequestProperty("Accept-Language", LocaleUtils.getCurrentLocale().getLanguage() + ",en-US;q=0.8");
|
||||
conn.setUseCaches(false);
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
JSONObject data = new JSONObject(Utils.readFromConnection(conn));
|
||||
// try (FileWriter fileWriter = new FileWriter(new File("/sdcard/test.json"))) {
|
||||
// fileWriter.write(data.toString(2));
|
||||
// }
|
||||
|
||||
final long seqId = data.optLong("seq_id");
|
||||
final int pendingRequestsCount = data.optInt("pending_requests_total");
|
||||
final boolean hasPendingTopRequests = data.optBoolean("has_pending_top_requests");
|
||||
|
||||
data = data.getJSONObject("inbox");
|
||||
|
||||
final boolean blendedInboxEnabled = data.optBoolean("blended_inbox_enabled");
|
||||
final boolean hasOlder = data.optBoolean("has_older");
|
||||
final int unseenCount = data.optInt("unseen_count");
|
||||
final long unseenCountTimestamp = data.optLong("unseen_count_ts");
|
||||
final String oldestCursor = data.optString("oldest_cursor");
|
||||
|
||||
InboxThreadModel[] inboxThreadModels = null;
|
||||
|
||||
final JSONArray threadsArray = data.optJSONArray("threads");
|
||||
if (threadsArray != null) {
|
||||
final int threadsLen = threadsArray.length();
|
||||
inboxThreadModels = new InboxThreadModel[threadsLen];
|
||||
|
||||
for (int i = 0; i < threadsLen; ++i)
|
||||
inboxThreadModels[i] = Utils.createInboxThreadModel(threadsArray.getJSONObject(i), false);
|
||||
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
final InputStream responseInputStream = conn.getErrorStream();
|
||||
final BufferedReader r = new BufferedReader(new InputStreamReader(responseInputStream));
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (String line = r.readLine(); line != null; line = r.readLine()) {
|
||||
if (builder.length() != 0) {
|
||||
builder.append("\n");
|
||||
}
|
||||
builder.append(line);
|
||||
}
|
||||
|
||||
result = new InboxModel(hasOlder, hasPendingTopRequests,
|
||||
blendedInboxEnabled, unseenCount, pendingRequestsCount,
|
||||
seqId, unseenCountTimestamp, oldestCursor, inboxThreadModels);
|
||||
Log.e(TAG, "Error response: " + conn.getResponseCode() + ", " + builder.toString());
|
||||
r.close();
|
||||
conn.disconnect();
|
||||
return null;
|
||||
}
|
||||
JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn));
|
||||
// try (FileWriter fileWriter = new FileWriter(new File("/sdcard/test.json"))) {
|
||||
// fileWriter.write(data.toString(2));
|
||||
// }
|
||||
|
||||
final long seqId = data.optLong("seq_id");
|
||||
final int pendingRequestsCount = data.optInt("pending_requests_total");
|
||||
final boolean hasPendingTopRequests = data.optBoolean("has_pending_top_requests");
|
||||
|
||||
data = data.getJSONObject("inbox");
|
||||
|
||||
final boolean blendedInboxEnabled = data.optBoolean("blended_inbox_enabled");
|
||||
final boolean hasOlder = data.optBoolean("has_older");
|
||||
final int unseenCount = data.optInt("unseen_count");
|
||||
final long unseenCountTimestamp = data.optLong("unseen_count_ts");
|
||||
final String oldestCursor = data.optString("oldest_cursor");
|
||||
|
||||
InboxThreadModel[] inboxThreadModels = null;
|
||||
|
||||
final JSONArray threadsArray = data.optJSONArray("threads");
|
||||
if (threadsArray != null) {
|
||||
final int threadsLen = threadsArray.length();
|
||||
inboxThreadModels = new InboxThreadModel[threadsLen];
|
||||
|
||||
for (int i = 0; i < threadsLen; ++i)
|
||||
inboxThreadModels[i] = ResponseBodyUtils.createInboxThreadModel(threadsArray.getJSONObject(i), false);
|
||||
}
|
||||
|
||||
result = new InboxModel(hasOlder, hasPendingTopRequests,
|
||||
blendedInboxEnabled, unseenCount, pendingRequestsCount,
|
||||
seqId, unseenCountTimestamp, oldestCursor, inboxThreadModels);
|
||||
|
||||
conn.disconnect();
|
||||
} catch (final Exception e) {
|
||||
result = null;
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogFile.ASYNC_DMS, "doInBackground");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -16,6 +16,10 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -50,7 +54,7 @@ public final class iLikedFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject body = new JSONObject(Utils.readFromConnection(conn));
|
||||
final JSONObject body = new JSONObject(NetworkUtils.readFromConnection(conn));
|
||||
|
||||
final String endCursor;
|
||||
final boolean hasNextPage;
|
||||
@ -77,12 +81,12 @@ public final class iLikedFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
else itemType = MediaItemType.MEDIA_TYPE_IMAGE;
|
||||
|
||||
models[i] = new PostModel(itemType, mediaNode.getString(Constants.EXTRAS_ID),
|
||||
isSlider
|
||||
? Utils.getHighQualityImage(mediaNode.getJSONArray("carousel_media").getJSONObject(0))
|
||||
: Utils.getHighQualityImage(mediaNode),
|
||||
isSlider
|
||||
? Utils.getLowQualityImage(mediaNode.getJSONArray("carousel_media").getJSONObject(0))
|
||||
: Utils.getLowQualityImage(mediaNode),
|
||||
isSlider
|
||||
? ResponseBodyUtils.getHighQualityImage(mediaNode.getJSONArray("carousel_media").getJSONObject(0))
|
||||
: ResponseBodyUtils.getHighQualityImage(mediaNode),
|
||||
isSlider
|
||||
? ResponseBodyUtils.getLowQualityImage(mediaNode.getJSONArray("carousel_media").getJSONObject(0))
|
||||
: ResponseBodyUtils.getLowQualityImage(mediaNode),
|
||||
mediaNode.getString("code"),
|
||||
mediaNode.isNull("caption") ? null : mediaNode.getJSONObject("caption").optString("text"),
|
||||
mediaNode.getLong("taken_at"), true,
|
||||
@ -95,9 +99,9 @@ public final class iLikedFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
||||
if (Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
|
||||
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
if (!Utils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
if (!TextUtils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
}
|
||||
Utils.checkExistence(downloadDir, customDir, isSlider, models[i]);
|
||||
DownloadUtils.checkExistence(downloadDir, customDir, isSlider, models[i]);
|
||||
}
|
||||
|
||||
if (models[models.length - 1] != null)
|
||||
|
@ -13,9 +13,14 @@ import java.net.URL;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -25,6 +30,8 @@ import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class iPostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]> {
|
||||
private static final String TAG = "iPostFetcher";
|
||||
|
||||
private final String id;
|
||||
private final FetchListener<ViewerPostModel[]> fetchListener;
|
||||
|
||||
@ -43,19 +50,55 @@ public final class iPostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
|
||||
final JSONObject media = new JSONObject(Utils.readFromConnection(conn)).getJSONArray("items").getJSONObject(0);
|
||||
|
||||
final String username = media.has("user") ? media.getJSONObject("user").getString(Constants.EXTRAS_USERNAME) : null;
|
||||
final JSONObject media = new JSONObject(NetworkUtils.readFromConnection(conn))
|
||||
.getJSONArray("items")
|
||||
.getJSONObject(0);
|
||||
ProfileModel profileModel = null;
|
||||
if (media.has("user")) {
|
||||
final JSONObject user = media.getJSONObject("user");
|
||||
final JSONObject friendshipStatus = user.optJSONObject("friendship_status");
|
||||
boolean following = false;
|
||||
boolean isRestricted = false;
|
||||
boolean outgoingRequest = false;
|
||||
if (friendshipStatus != null) {
|
||||
following = friendshipStatus.optBoolean("following");
|
||||
isRestricted = friendshipStatus.optBoolean("is_restricted");
|
||||
outgoingRequest = friendshipStatus.optBoolean("outgoing_request");
|
||||
}
|
||||
profileModel = new ProfileModel(
|
||||
user.optBoolean("is_private"),
|
||||
user.optBoolean("is_private"),
|
||||
user.optBoolean("is_verified"),
|
||||
user.optString("pk"),
|
||||
user.getString(Constants.EXTRAS_USERNAME),
|
||||
user.optString("fullname"),
|
||||
null,
|
||||
null,
|
||||
user.getString("profile_pic_url"),
|
||||
null,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
following,
|
||||
isRestricted,
|
||||
false,
|
||||
outgoingRequest
|
||||
);
|
||||
}
|
||||
if (profileModel == null) {
|
||||
return new ViewerPostModel[]{};
|
||||
}
|
||||
|
||||
// to check if file exists
|
||||
final File downloadDir = new File(Environment.getExternalStorageDirectory(), "Download" +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
final boolean shouldDownloadToUserFolder = Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER);
|
||||
final File downloadDir = new File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
"Download" + (shouldDownloadToUserFolder ? "/" + profileModel.getUsername() : ""));
|
||||
File customDir = null;
|
||||
if (Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
|
||||
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH +
|
||||
(Utils.settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER) ? ("/"+username) : ""));
|
||||
if (!Utils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH)
|
||||
+ (shouldDownloadToUserFolder ? "/" + profileModel.getUsername() : "");
|
||||
if (!TextUtils.isEmpty(customPath)) customDir = new File(customPath);
|
||||
}
|
||||
|
||||
final long timestamp = media.getLong("taken_at");
|
||||
@ -75,26 +118,37 @@ public final class iPostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
|
||||
final long commentsCount = media.optLong("comment_count");
|
||||
|
||||
final JSONObject location = media.optJSONObject("location");
|
||||
String locationId = null;
|
||||
String locationName = null;
|
||||
if (location != null) {
|
||||
locationName = location.optString("name");
|
||||
if (location.has("id")) {
|
||||
locationId = location.getString("id");
|
||||
} else if (location.has("pk")) {
|
||||
locationId = location.getString("pk");
|
||||
}
|
||||
}
|
||||
// final String locationString = location.optString("id") + "/" + location.optString("slug");
|
||||
if (mediaItemType != MediaItemType.MEDIA_TYPE_SLIDER) {
|
||||
final ViewerPostModel postModel = new ViewerPostModel(mediaItemType,
|
||||
final ViewerPostModel postModel = new ViewerPostModel(
|
||||
mediaItemType,
|
||||
media.getString(Constants.EXTRAS_ID),
|
||||
isVideo
|
||||
? Utils.getHighQualityPost(media.optJSONArray("video_versions"), true, true, false)
|
||||
: Utils.getHighQualityImage(media),
|
||||
isVideo ? ResponseBodyUtils.getHighQualityPost(media.optJSONArray("video_versions"), true, true, false)
|
||||
: ResponseBodyUtils.getHighQualityImage(media),
|
||||
media.getString("code"),
|
||||
Utils.isEmpty(postCaption) ? null : postCaption,
|
||||
username,
|
||||
TextUtils.isEmpty(postCaption) ? null : postCaption,
|
||||
profileModel,
|
||||
isVideo && media.has("view_count") ? media.getLong("view_count") : -1,
|
||||
timestamp, media.optBoolean("has_liked"), media.optBoolean("has_viewer_saved"),
|
||||
timestamp, media.optBoolean("has_liked"),
|
||||
media.optBoolean("has_viewer_saved"),
|
||||
media.getLong("like_count"),
|
||||
media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
|
||||
media.isNull("location") ? null :
|
||||
(media.getJSONObject("location").optString("id") + "/" +
|
||||
media.getJSONObject("location").optString("slug")));
|
||||
locationName,
|
||||
locationId);
|
||||
|
||||
postModel.setCommentsCount(commentsCount);
|
||||
|
||||
Utils.checkExistence(downloadDir, customDir, false, postModel);
|
||||
DownloadUtils.checkExistence(downloadDir, customDir, false, postModel);
|
||||
|
||||
result = new ViewerPostModel[]{postModel};
|
||||
|
||||
@ -106,24 +160,23 @@ public final class iPostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
final JSONObject node = children.getJSONObject(i);
|
||||
final boolean isChildVideo = node.has("video_duration");
|
||||
|
||||
postModels[i] = new ViewerPostModel(isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
postModels[i] = new ViewerPostModel(
|
||||
isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO
|
||||
: MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
media.getString(Constants.EXTRAS_ID),
|
||||
isChildVideo
|
||||
? Utils.getHighQualityPost(node.optJSONArray("video_versions"), true, true, false)
|
||||
: Utils.getHighQualityImage(node),
|
||||
isChildVideo ? ResponseBodyUtils.getHighQualityPost(node.optJSONArray("video_versions"), true, true, false)
|
||||
: ResponseBodyUtils.getHighQualityImage(node),
|
||||
media.getString("code"),
|
||||
postCaption,
|
||||
username,
|
||||
profileModel,
|
||||
-1,
|
||||
timestamp, media.optBoolean("has_liked"), media.optBoolean("has_viewer_saved"),
|
||||
timestamp, media.optBoolean("has_liked"),
|
||||
media.optBoolean("has_viewer_saved"),
|
||||
media.getLong("like_count"),
|
||||
media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
|
||||
media.isNull("location") ? null :
|
||||
(media.getJSONObject("location").optString("id") + "/" +
|
||||
media.getJSONObject("location").optString("slug")));
|
||||
postModels[i].setSliderDisplayUrl(Utils.getHighQualityImage(node));
|
||||
|
||||
Utils.checkExistence(downloadDir, customDir, true, postModels[i]);
|
||||
locationName,
|
||||
locationId);
|
||||
postModels[i].setSliderDisplayUrl(ResponseBodyUtils.getHighQualityImage(node));
|
||||
DownloadUtils.checkExistence(downloadDir, customDir, true, postModels[i]);
|
||||
}
|
||||
|
||||
postModels[0].setCommentsCount(commentsCount);
|
||||
@ -135,7 +188,9 @@ public final class iPostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
|
||||
} catch (Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_POST_FETCHER, "doInBackground (i)");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ import awais.instagrabber.models.stickers.QuizModel;
|
||||
import awais.instagrabber.models.stickers.SwipeUpModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
@ -27,11 +28,18 @@ import static awais.instagrabber.utils.Utils.logCollector;
|
||||
public final class iStoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]> {
|
||||
private final String id;
|
||||
private String username;
|
||||
private final boolean isLoc, isHashtag, storiesig, highlight;
|
||||
private final boolean isLoc;
|
||||
private final boolean isHashtag;
|
||||
private final boolean storiesig;
|
||||
private final boolean highlight;
|
||||
private final FetchListener<StoryModel[]> fetchListener;
|
||||
|
||||
public iStoryStatusFetcher(final String id, final String username, final boolean isLoc,
|
||||
final boolean isHashtag, final boolean storiesig, final boolean highlight,
|
||||
public iStoryStatusFetcher(final String id,
|
||||
final String username,
|
||||
final boolean isLoc,
|
||||
final boolean isHashtag,
|
||||
final boolean storiesig,
|
||||
final boolean highlight,
|
||||
final FetchListener<StoryModel[]> fetchListener) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
@ -45,9 +53,35 @@ public final class iStoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[
|
||||
@Override
|
||||
protected StoryModel[] doInBackground(final Void... voids) {
|
||||
StoryModel[] result = null;
|
||||
final String url = "https://" + (storiesig ? "storiesig" : "i.instagram") + ".com/api/v1/"
|
||||
+ (isLoc ? "locations/" : (isHashtag ? "tags/" : (highlight ? "feed/reels_media?user_ids=" : "feed/user/")))
|
||||
+ id.replace(":", "%3A") + (highlight ? "" : (storiesig ? "/reel_media/" : "/story/"));
|
||||
final String userId = id.replace(":", "%3A");
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("https://");
|
||||
if (storiesig) {
|
||||
builder.append("storiesig");
|
||||
} else {
|
||||
builder.append("i.instagram");
|
||||
}
|
||||
builder.append(".com/api/v1/");
|
||||
if (isLoc) {
|
||||
builder.append("locations/");
|
||||
}
|
||||
if (isHashtag) {
|
||||
builder.append("tags/");
|
||||
}
|
||||
if (highlight) {
|
||||
builder.append("feed/reels_media?user_ids=");
|
||||
} else {
|
||||
builder.append("feed/user/");
|
||||
}
|
||||
builder.append(userId);
|
||||
if (!highlight) {
|
||||
if (storiesig) {
|
||||
builder.append("/reel_media/");
|
||||
} else {
|
||||
builder.append("/story/");
|
||||
}
|
||||
}
|
||||
final String url = builder.toString();
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setInstanceFollowRedirects(true);
|
||||
@ -57,11 +91,13 @@ public final class iStoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
JSONObject data = new JSONObject(Utils.readFromConnection(conn));
|
||||
if (!storiesig && !highlight) data = data.optJSONObject((isLoc || isHashtag) ? "story" : "reel");
|
||||
JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn));
|
||||
if (!storiesig && !highlight)
|
||||
data = data.optJSONObject((isLoc || isHashtag) ? "story" : "reel");
|
||||
else if (highlight) data = data.getJSONObject("reels").optJSONObject(id);
|
||||
|
||||
if (username == null && !isLoc && !isHashtag) username = data.getJSONObject("user").getString("username");
|
||||
if (username == null && !isLoc && !isHashtag)
|
||||
username = data.getJSONObject("user").getString("username");
|
||||
|
||||
JSONArray media;
|
||||
if (data != null && (media = data.optJSONArray("items")) != null
|
||||
@ -83,7 +119,7 @@ public final class iStoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[
|
||||
|
||||
final JSONArray videoResources = data.optJSONArray("video_versions");
|
||||
if (isVideo && videoResources != null)
|
||||
models[i].setVideoUrl(Utils.getHighQualityPost(videoResources, true, true, false));
|
||||
models[i].setVideoUrl(ResponseBodyUtils.getHighQualityPost(videoResources, true, true, false));
|
||||
|
||||
if (data.has("story_feed_media")) {
|
||||
models[i].setTappableShortCode(data.getJSONArray("story_feed_media").getJSONObject(0).optString("media_id"));
|
||||
@ -110,8 +146,8 @@ public final class iStoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[
|
||||
JSONObject tappableObject = data.getJSONArray("story_questions").getJSONObject(0).optJSONObject("question_sticker");
|
||||
if (tappableObject != null && !tappableObject.getString("question_type").equals("music"))
|
||||
models[i].setQuestion(new QuestionModel(
|
||||
String.valueOf(tappableObject.getLong("question_id")),
|
||||
tappableObject.getString("question")
|
||||
String.valueOf(tappableObject.getLong("question_id")),
|
||||
tappableObject.getString("question")
|
||||
));
|
||||
}
|
||||
|
||||
@ -123,7 +159,7 @@ public final class iStoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[
|
||||
for (int q = 0; q < choices.length; ++q) {
|
||||
JSONObject tempchoice = tappableObject.getJSONArray("tallies").getJSONObject(q);
|
||||
choices[q] = (q == tappableObject.getInt("correct_answer") ? "*** " : "")
|
||||
+tempchoice.getString("text");
|
||||
+ tempchoice.getString("text");
|
||||
counts[q] = tempchoice.getLong("count");
|
||||
}
|
||||
models[i].setQuiz(new QuizModel(
|
||||
@ -155,20 +191,20 @@ public final class iStoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[
|
||||
+ (locations == null ? 0 : locations.length())];
|
||||
if (hashtags != null) {
|
||||
for (int h = 0; h < hashtags.length(); ++h) {
|
||||
mentions[h] = "#"+hashtags.getJSONObject(h).getJSONObject("hashtag").getString("name");
|
||||
mentions[h] = "#" + hashtags.getJSONObject(h).getJSONObject("hashtag").getString("name");
|
||||
}
|
||||
}
|
||||
if (atmarks != null) {
|
||||
for (int h = 0; h < atmarks.length(); ++h) {
|
||||
mentions[h + (hashtags == null ? 0 : hashtags.length())] =
|
||||
"@"+atmarks.getJSONObject(h).getJSONObject("user").getString("username");
|
||||
"@" + atmarks.getJSONObject(h).getJSONObject("user").getString("username");
|
||||
}
|
||||
}
|
||||
if (locations != null) {
|
||||
for (int h = 0; h < locations.length(); ++h) {
|
||||
mentions[h + (hashtags == null ? 0 : hashtags.length()) + (atmarks == null ? 0 : atmarks.length())] =
|
||||
locations.getJSONObject(h).getJSONObject("location").getLong("pk")
|
||||
+"/ ("+locations.getJSONObject(h).getJSONObject("location").getString("short_name")+")";
|
||||
+ "/ (" + locations.getJSONObject(h).getJSONObject("location").getString("short_name") + ")";
|
||||
}
|
||||
}
|
||||
if (mentions.length != 0) models[i].setMentions(mentions);
|
||||
|
@ -14,7 +14,7 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.DiscoverTopicModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
@ -39,7 +39,7 @@ public final class iTopicFetcher extends AsyncTask<Void, Void, DiscoverTopicMode
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject body = new JSONObject(Utils.readFromConnection(conn));
|
||||
final JSONObject body = new JSONObject(NetworkUtils.readFromConnection(conn));
|
||||
|
||||
final JSONArray edges = body.getJSONArray("clusters");
|
||||
String[] names = new String[edges.length()], ids = new String[edges.length()];
|
||||
|
@ -1,22 +1,23 @@
|
||||
package awais.instagrabber.customviews;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public final class CircularImageView extends AppCompatImageView {
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyInflater;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
|
||||
public final class CircularImageView extends SimpleDraweeView {
|
||||
private final int borderSize = 8;
|
||||
private int color = Color.TRANSPARENT;
|
||||
private final Paint paint = new Paint();
|
||||
@ -24,82 +25,115 @@ public final class CircularImageView extends AppCompatImageView {
|
||||
private BitmapShader shader;
|
||||
private Bitmap bitmap;
|
||||
|
||||
public CircularImageView(Context context, GenericDraweeHierarchy hierarchy) {
|
||||
super(context);
|
||||
setHierarchy(hierarchy);
|
||||
setup();
|
||||
}
|
||||
|
||||
public CircularImageView(final Context context) {
|
||||
super(context);
|
||||
inflateHierarchy(context, null);
|
||||
setup();
|
||||
}
|
||||
|
||||
public CircularImageView(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
inflateHierarchy(context, attrs);
|
||||
setup();
|
||||
}
|
||||
|
||||
public CircularImageView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
inflateHierarchy(context, attrs);
|
||||
setup();
|
||||
}
|
||||
|
||||
protected void inflateHierarchy(Context context, @Nullable AttributeSet attrs) {
|
||||
Resources resources = context.getResources();
|
||||
final RoundingParams roundingParams = RoundingParams.asCircle();
|
||||
GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources)
|
||||
.setRoundingParams(roundingParams)
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER);
|
||||
GenericDraweeHierarchyInflater.updateBuilder(builder, context, attrs);
|
||||
setAspectRatio(builder.getDesiredAspectRatio());
|
||||
setHierarchy(builder.build());
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
paint.setAntiAlias(true);
|
||||
paintBorder.setColor(color);
|
||||
paintBorder.setAntiAlias(true);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
setOutlineProvider(new ViewOutlineProvider() {
|
||||
private int viewHeight;
|
||||
private int viewWidth;
|
||||
|
||||
@Override
|
||||
public void getOutline(final View view, final Outline outline) {
|
||||
if (viewHeight == 0) viewHeight = getHeight();
|
||||
if (viewWidth == 0) viewWidth = getWidth();
|
||||
outline.setRoundRect(borderSize, borderSize, viewWidth - borderSize, viewHeight - borderSize, viewHeight >> 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
// paint.setAntiAlias(true);
|
||||
// paintBorder.setColor(color);
|
||||
// paintBorder.setAntiAlias(true);
|
||||
//
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// setOutlineProvider(new ViewOutlineProvider() {
|
||||
// private int viewHeight;
|
||||
// private int viewWidth;
|
||||
//
|
||||
// @Override
|
||||
// public void getOutline(final View view, final Outline outline) {
|
||||
// if (viewHeight == 0) viewHeight = getHeight();
|
||||
// if (viewWidth == 0) viewWidth = getWidth();
|
||||
// outline.setRoundRect(borderSize, borderSize, viewWidth - borderSize, viewHeight - borderSize, viewHeight >> 1);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(getResources())
|
||||
// .setRoundingParams(RoundingParams.)
|
||||
// .build();
|
||||
// setHierarchy(hierarchy);
|
||||
// invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(final Canvas canvas) {
|
||||
final BitmapDrawable bitmapDrawable = (BitmapDrawable) getDrawable();
|
||||
if (bitmapDrawable != null) {
|
||||
final Bitmap prevBitmap = bitmap;
|
||||
bitmap = bitmapDrawable.getBitmap();
|
||||
final boolean changed = prevBitmap != bitmap;
|
||||
if (bitmap != null) {
|
||||
final int width = getWidth();
|
||||
final int height = getHeight();
|
||||
|
||||
if (shader == null || changed) {
|
||||
shader = new BitmapShader(Bitmap.createScaledBitmap(bitmap, width, height, true), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||
paint.setShader(shader);
|
||||
}
|
||||
|
||||
if (changed) color = 0;
|
||||
paintBorder.setColor(color);
|
||||
|
||||
final int circleCenter = (width - borderSize) / 2;
|
||||
final int position = circleCenter + (borderSize / 2);
|
||||
canvas.drawCircle(position, position, position - 4.0f, paintBorder);
|
||||
canvas.drawCircle(position, position, circleCenter - 4.0f, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
setLayerType(LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
setLayerType(LAYER_TYPE_NONE, null);
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
// @Override
|
||||
// public void onDraw(final Canvas canvas) {
|
||||
// final BitmapDrawable bitmapDrawable = (BitmapDrawable) getDrawable();
|
||||
// if (bitmapDrawable != null) {
|
||||
// final Bitmap prevBitmap = bitmap;
|
||||
// bitmap = bitmapDrawable.getBitmap();
|
||||
// final boolean changed = prevBitmap != bitmap;
|
||||
// if (bitmap != null) {
|
||||
// final int width = getWidth();
|
||||
// final int height = getHeight();
|
||||
//
|
||||
// if (shader == null || changed) {
|
||||
// shader = new BitmapShader(Bitmap.createScaledBitmap(bitmap, width, height, true), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||
// paint.setShader(shader);
|
||||
// }
|
||||
//
|
||||
// if (changed) color = 0;
|
||||
// paintBorder.setColor(color);
|
||||
//
|
||||
// final int circleCenter = (width - borderSize) / 2;
|
||||
// final int position = circleCenter + (borderSize / 2);
|
||||
// canvas.drawCircle(position, position, position - 4.0f, paintBorder);
|
||||
// canvas.drawCircle(position, position, circleCenter - 4.0f, paint);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onAttachedToWindow() {
|
||||
// super.onAttachedToWindow();
|
||||
// setLayerType(LAYER_TYPE_HARDWARE, null);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onDetachedFromWindow() {
|
||||
// setLayerType(LAYER_TYPE_NONE, null);
|
||||
// super.onDetachedFromWindow();
|
||||
// }
|
||||
|
||||
public void setStoriesBorder() {
|
||||
this.color = Color.GREEN;
|
||||
invalidate();
|
||||
// invalidate();
|
||||
// final RoundingParams roundingParams = RoundingParams.fromCornersRadius(5f);
|
||||
//
|
||||
RoundingParams roundingParams = getHierarchy().getRoundingParams();
|
||||
if (roundingParams == null) {
|
||||
roundingParams = RoundingParams.asCircle().setRoundingMethod(RoundingParams.RoundingMethod.BITMAP_ONLY);
|
||||
}
|
||||
roundingParams.setBorder(color, 5.0f);
|
||||
getHierarchy().setRoundingParams(roundingParams);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package awais.instagrabber.customviews;
|
||||
|
||||
import android.view.ActionMode;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
public class PrimaryActionModeCallback implements ActionMode.Callback {
|
||||
private ActionMode mode;
|
||||
private int menuRes;
|
||||
private final Callbacks callbacks;
|
||||
|
||||
public PrimaryActionModeCallback(final int menuRes, final Callbacks callbacks) {
|
||||
this.menuRes = menuRes;
|
||||
this.callbacks = callbacks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
|
||||
this.mode = mode;
|
||||
mode.getMenuInflater().inflate(menuRes, menu);
|
||||
if (callbacks != null) {
|
||||
callbacks.onCreate(mode, menu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
|
||||
if (callbacks != null) {
|
||||
return callbacks.onActionItemClicked(mode, item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(final ActionMode mode) {
|
||||
if (callbacks != null) {
|
||||
callbacks.onDestroy(mode);
|
||||
}
|
||||
this.mode = null;
|
||||
}
|
||||
|
||||
public abstract static class CallbacksHelper implements Callbacks {
|
||||
public void onCreate(final ActionMode mode, final Menu menu) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(final ActionMode mode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callbacks {
|
||||
void onCreate(final ActionMode mode, final Menu menu);
|
||||
|
||||
void onDestroy(final ActionMode mode);
|
||||
|
||||
boolean onActionItemClicked(final ActionMode mode, final MenuItem item);
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package awais.instagrabber.customviews;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Handler;
|
||||
import android.text.Layout;
|
||||
import android.text.Selection;
|
||||
import android.text.Spannable;
|
||||
@ -14,6 +15,7 @@ import android.text.style.ClickableSpan;
|
||||
import android.text.style.URLSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -23,14 +25,23 @@ import androidx.appcompat.widget.AppCompatTextView;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public final class RamboTextView extends AppCompatTextView {
|
||||
private static final String TAG = "RamboTextView";
|
||||
private static final int highlightBackgroundSpanKey = R.id.tvComment;
|
||||
private static final RectF touchedLineBounds = new RectF();
|
||||
private ClickableSpan clickableSpanUnderTouchOnActionDown;
|
||||
private MentionClickListener mentionClickListener;
|
||||
private boolean isUrlHighlighted, isExpandable, isExpanded;
|
||||
private boolean isUrlHighlighted;
|
||||
private boolean isExpandable;
|
||||
private boolean isExpanded;
|
||||
private OnLongClickListener longClickListener;
|
||||
|
||||
private final Handler handler = new Handler();
|
||||
private final Runnable longPressRunnable = () -> {
|
||||
if (longClickListener != null) longClickListener.onLongClick(this);
|
||||
};
|
||||
|
||||
public RamboTextView(final Context context) {
|
||||
super(context);
|
||||
@ -56,6 +67,12 @@ public final class RamboTextView extends AppCompatTextView {
|
||||
this.isExpanded = isExpanded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnLongClickListener(@Nullable final OnLongClickListener l) {
|
||||
if (l == null) return;
|
||||
this.longClickListener = l;
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(final MotionEvent event) {
|
||||
@ -71,33 +88,37 @@ public final class RamboTextView extends AppCompatTextView {
|
||||
final boolean isURLSpan = clickableSpanUnderTouch instanceof URLSpan;
|
||||
|
||||
// feed view caption hacks
|
||||
if (isExpandable && !touchStartedOverAClickableSpan)
|
||||
return !isExpanded | super.onTouchEvent(event); // short operator, because we want two shits to work
|
||||
// if (isExpandable && !touchStartedOverAClickableSpan)
|
||||
// return !isExpanded | super.onTouchEvent(event); // short operator, because we want two shits to work
|
||||
|
||||
final Object tag = getTag();
|
||||
final FeedModel feedModel = tag instanceof FeedModel ? (FeedModel) tag : null;
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
|
||||
handler.postDelayed(longPressRunnable, longPressTimeout);
|
||||
if (feedModel != null) feedModel.setMentionClicked(false);
|
||||
if (clickableSpanUnderTouch != null) highlightUrl(clickableSpanUnderTouch, spanText);
|
||||
return isURLSpan ? super.onTouchEvent(event) : touchStartedOverAClickableSpan;
|
||||
|
||||
if (clickableSpanUnderTouch != null) {
|
||||
highlightUrl(clickableSpanUnderTouch, spanText);
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
case MotionEvent.ACTION_UP:
|
||||
handler.removeCallbacks(longPressRunnable);
|
||||
if (touchStartedOverAClickableSpan && clickableSpanUnderTouch == clickableSpanUnderTouchOnActionDown) {
|
||||
dispatchUrlClick(spanText, clickableSpanUnderTouch);
|
||||
if (feedModel != null) feedModel.setMentionClicked(true);
|
||||
}
|
||||
cleanupOnTouchUp(spanText);
|
||||
return isURLSpan ? super.onTouchEvent(event) : touchStartedOverAClickableSpan;
|
||||
|
||||
return super.onTouchEvent(event);
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
// handler.removeCallbacks(longPressRunnable);
|
||||
if (feedModel != null) feedModel.setMentionClicked(false);
|
||||
if (clickableSpanUnderTouch != null) highlightUrl(clickableSpanUnderTouch, spanText);
|
||||
else removeUrlHighlightColor(spanText);
|
||||
return isURLSpan ? super.onTouchEvent(event) : touchStartedOverAClickableSpan;
|
||||
|
||||
return super.onTouchEvent(event);
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
handler.removeCallbacks(longPressRunnable);
|
||||
if (feedModel != null) feedModel.setMentionClicked(false);
|
||||
cleanupOnTouchUp(spanText);
|
||||
return super.onTouchEvent(event);
|
||||
@ -117,11 +138,11 @@ public final class RamboTextView extends AppCompatTextView {
|
||||
CharSequence subSequence = s.subSequence(start, s.getSpanEnd(clickableSpan));
|
||||
|
||||
// for feed ellipsize
|
||||
final int indexOfEllipsize = Utils.indexOfChar(subSequence, '…', 0);
|
||||
final int indexOfEllipsize = TextUtils.indexOfChar(subSequence, '…', 0);
|
||||
if (indexOfEllipsize != -1)
|
||||
subSequence = subSequence.subSequence(0, indexOfEllipsize - 1);
|
||||
|
||||
mentionClickListener.onClick(this, subSequence.toString(), ishHashtag);
|
||||
mentionClickListener.onClick(this, subSequence.toString(), ishHashtag, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +176,9 @@ public final class RamboTextView extends AppCompatTextView {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ClickableSpan findClickableSpanUnderTouch(@NonNull final TextView textView, final Spannable text, @NonNull final MotionEvent event) {
|
||||
private static ClickableSpan findClickableSpanUnderTouch(@NonNull final TextView textView,
|
||||
final Spanned text,
|
||||
@NonNull final MotionEvent event) {
|
||||
final int touchX = (int) (event.getX() - textView.getTotalPaddingLeft() + textView.getScrollX());
|
||||
final int touchY = (int) (event.getY() - textView.getTotalPaddingTop() + textView.getScrollY());
|
||||
|
||||
@ -176,4 +199,8 @@ public final class RamboTextView extends AppCompatTextView {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCaptionExpanded() {
|
||||
return isExpanded;
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package awais.instagrabber.customviews.drawee;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PointF;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
|
||||
/**
|
||||
* Abstract class for ZoomableController that adds animation capabilities to
|
||||
* DefaultZoomableController.
|
||||
*/
|
||||
public abstract class AbstractAnimatedZoomableController extends DefaultZoomableController {
|
||||
|
||||
private boolean mIsAnimating;
|
||||
private final float[] mStartValues = new float[9];
|
||||
private final float[] mStopValues = new float[9];
|
||||
private final float[] mCurrentValues = new float[9];
|
||||
private final Matrix mNewTransform = new Matrix();
|
||||
private final Matrix mWorkingTransform = new Matrix();
|
||||
|
||||
public AbstractAnimatedZoomableController(TransformGestureDetector transformGestureDetector) {
|
||||
super(transformGestureDetector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
FLog.v(getLogTag(), "reset");
|
||||
stopAnimation();
|
||||
mWorkingTransform.reset();
|
||||
mNewTransform.reset();
|
||||
super.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the zoomable transform is identity matrix, and the controller is idle.
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdentity() {
|
||||
return !isAnimating() && super.isIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zooms to the desired scale and positions the image so that the given image point corresponds to
|
||||
* the given view point.
|
||||
*
|
||||
* <p>If this method is called while an animation or gesture is already in progress, the current
|
||||
* animation or gesture will be stopped first.
|
||||
*
|
||||
* @param scale desired scale, will be limited to {min, max} scale factor
|
||||
* @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1)
|
||||
* @param viewPoint 2D point in view's absolute coordinate system
|
||||
*/
|
||||
@Override
|
||||
public void zoomToPoint(float scale, PointF imagePoint, PointF viewPoint) {
|
||||
zoomToPoint(scale, imagePoint, viewPoint, LIMIT_ALL, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zooms to the desired scale and positions the image so that the given image point corresponds to
|
||||
* the given view point.
|
||||
*
|
||||
* <p>If this method is called while an animation or gesture is already in progress, the current
|
||||
* animation or gesture will be stopped first.
|
||||
*
|
||||
* @param scale desired scale, will be limited to {min, max} scale factor
|
||||
* @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1)
|
||||
* @param viewPoint 2D point in view's absolute coordinate system
|
||||
* @param limitFlags whether to limit translation and/or scale.
|
||||
* @param durationMs length of animation of the zoom, or 0 if no animation desired
|
||||
* @param onAnimationComplete code to run when the animation completes. Ignored if durationMs=0
|
||||
*/
|
||||
public void zoomToPoint(
|
||||
float scale,
|
||||
PointF imagePoint,
|
||||
PointF viewPoint,
|
||||
@LimitFlag int limitFlags,
|
||||
long durationMs,
|
||||
@Nullable Runnable onAnimationComplete) {
|
||||
FLog.v(getLogTag(), "zoomToPoint: duration %d ms", durationMs);
|
||||
calculateZoomToPointTransform(mNewTransform, scale, imagePoint, viewPoint, limitFlags);
|
||||
setTransform(mNewTransform, durationMs, onAnimationComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new zoomable transformation and animates to it if desired.
|
||||
*
|
||||
* <p>If this method is called while an animation or gesture is already in progress, the current
|
||||
* animation or gesture will be stopped first.
|
||||
*
|
||||
* @param newTransform new transform to make active
|
||||
* @param durationMs duration of the animation, or 0 to not animate
|
||||
* @param onAnimationComplete code to run when the animation completes. Ignored if durationMs=0
|
||||
*/
|
||||
public void setTransform(
|
||||
Matrix newTransform, long durationMs, @Nullable Runnable onAnimationComplete) {
|
||||
FLog.v(getLogTag(), "setTransform: duration %d ms", durationMs);
|
||||
if (durationMs <= 0) {
|
||||
setTransformImmediate(newTransform);
|
||||
} else {
|
||||
setTransformAnimated(newTransform, durationMs, onAnimationComplete);
|
||||
}
|
||||
}
|
||||
|
||||
private void setTransformImmediate(final Matrix newTransform) {
|
||||
FLog.v(getLogTag(), "setTransformImmediate");
|
||||
stopAnimation();
|
||||
mWorkingTransform.set(newTransform);
|
||||
super.setTransform(newTransform);
|
||||
getDetector().restartGesture();
|
||||
}
|
||||
|
||||
protected boolean isAnimating() {
|
||||
return mIsAnimating;
|
||||
}
|
||||
|
||||
protected void setAnimating(boolean isAnimating) {
|
||||
mIsAnimating = isAnimating;
|
||||
}
|
||||
|
||||
protected float[] getStartValues() {
|
||||
return mStartValues;
|
||||
}
|
||||
|
||||
protected float[] getStopValues() {
|
||||
return mStopValues;
|
||||
}
|
||||
|
||||
protected Matrix getWorkingTransform() {
|
||||
return mWorkingTransform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGestureBegin(TransformGestureDetector detector) {
|
||||
FLog.v(getLogTag(), "onGestureBegin");
|
||||
stopAnimation();
|
||||
super.onGestureBegin(detector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGestureUpdate(TransformGestureDetector detector) {
|
||||
FLog.v(getLogTag(), "onGestureUpdate %s", isAnimating() ? "(ignored)" : "");
|
||||
if (isAnimating()) {
|
||||
return;
|
||||
}
|
||||
super.onGestureUpdate(detector);
|
||||
}
|
||||
|
||||
protected void calculateInterpolation(Matrix outMatrix, float fraction) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
mCurrentValues[i] = (1 - fraction) * mStartValues[i] + fraction * mStopValues[i];
|
||||
}
|
||||
outMatrix.setValues(mCurrentValues);
|
||||
}
|
||||
|
||||
public abstract void setTransformAnimated(
|
||||
final Matrix newTransform, long durationMs, @Nullable final Runnable onAnimationComplete);
|
||||
|
||||
protected abstract void stopAnimation();
|
||||
|
||||
protected abstract Class<?> getLogTag();
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package awais.instagrabber.customviews.drawee;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Matrix;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.common.internal.Preconditions;
|
||||
import com.facebook.common.logging.FLog;
|
||||
|
||||
|
||||
/**
|
||||
* ZoomableController that adds animation capabilities to DefaultZoomableController using standard
|
||||
* Android animation classes
|
||||
*/
|
||||
public class AnimatedZoomableController extends AbstractAnimatedZoomableController {
|
||||
|
||||
private static final Class<?> TAG = AnimatedZoomableController.class;
|
||||
|
||||
private final ValueAnimator mValueAnimator;
|
||||
|
||||
public static AnimatedZoomableController newInstance() {
|
||||
return new AnimatedZoomableController(TransformGestureDetector.newInstance());
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public AnimatedZoomableController(TransformGestureDetector transformGestureDetector) {
|
||||
super(transformGestureDetector);
|
||||
mValueAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
mValueAnimator.setInterpolator(new DecelerateInterpolator());
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void setTransformAnimated(
|
||||
final Matrix newTransform, long durationMs, @Nullable final Runnable onAnimationComplete) {
|
||||
FLog.v(getLogTag(), "setTransformAnimated: duration %d ms", durationMs);
|
||||
stopAnimation();
|
||||
Preconditions.checkArgument(durationMs > 0);
|
||||
Preconditions.checkState(!isAnimating());
|
||||
setAnimating(true);
|
||||
mValueAnimator.setDuration(durationMs);
|
||||
getTransform().getValues(getStartValues());
|
||||
newTransform.getValues(getStopValues());
|
||||
mValueAnimator.addUpdateListener(
|
||||
new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
calculateInterpolation(getWorkingTransform(), (float) valueAnimator.getAnimatedValue());
|
||||
AnimatedZoomableController.super.setTransform(getWorkingTransform());
|
||||
}
|
||||
});
|
||||
mValueAnimator.addListener(
|
||||
new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
FLog.v(getLogTag(), "setTransformAnimated: animation cancelled");
|
||||
onAnimationStopped();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
FLog.v(getLogTag(), "setTransformAnimated: animation finished");
|
||||
onAnimationStopped();
|
||||
}
|
||||
|
||||
private void onAnimationStopped() {
|
||||
if (onAnimationComplete != null) {
|
||||
onAnimationComplete.run();
|
||||
}
|
||||
setAnimating(false);
|
||||
getDetector().restartGesture();
|
||||
}
|
||||
});
|
||||
mValueAnimator.start();
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void stopAnimation() {
|
||||
if (!isAnimating()) {
|
||||
return;
|
||||
}
|
||||
FLog.v(getLogTag(), "stopAnimation");
|
||||
mValueAnimator.cancel();
|
||||
mValueAnimator.removeAllUpdateListeners();
|
||||
mValueAnimator.removeAllListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
@ -0,0 +1,720 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package awais.instagrabber.customviews.drawee;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Zoomable controller that calculates transformation based on touch events.
|
||||
*/
|
||||
public class DefaultZoomableController
|
||||
implements ZoomableController, TransformGestureDetector.Listener {
|
||||
|
||||
/**
|
||||
* Interface for handling call backs when the image bounds are set.
|
||||
*/
|
||||
public interface ImageBoundsListener {
|
||||
void onImageBoundsSet(RectF imageBounds);
|
||||
}
|
||||
|
||||
@IntDef(
|
||||
flag = true,
|
||||
value = {LIMIT_NONE, LIMIT_TRANSLATION_X, LIMIT_TRANSLATION_Y, LIMIT_SCALE, LIMIT_ALL})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface LimitFlag {}
|
||||
|
||||
public static final int LIMIT_NONE = 0;
|
||||
public static final int LIMIT_TRANSLATION_X = 1;
|
||||
public static final int LIMIT_TRANSLATION_Y = 2;
|
||||
public static final int LIMIT_SCALE = 4;
|
||||
public static final int LIMIT_ALL = LIMIT_TRANSLATION_X | LIMIT_TRANSLATION_Y | LIMIT_SCALE;
|
||||
|
||||
private static final float EPS = 1e-3f;
|
||||
|
||||
private static final Class<?> TAG = DefaultZoomableController.class;
|
||||
|
||||
private static final RectF IDENTITY_RECT = new RectF(0, 0, 1, 1);
|
||||
|
||||
private TransformGestureDetector mGestureDetector;
|
||||
|
||||
private @Nullable
|
||||
ImageBoundsListener mImageBoundsListener;
|
||||
|
||||
private @Nullable
|
||||
Listener mListener = null;
|
||||
|
||||
private boolean mIsEnabled = false;
|
||||
private boolean mIsRotationEnabled = false;
|
||||
private boolean mIsScaleEnabled = true;
|
||||
private boolean mIsTranslationEnabled = true;
|
||||
private boolean mIsGestureZoomEnabled = true;
|
||||
|
||||
private float mMinScaleFactor = 1.0f;
|
||||
private float mMaxScaleFactor = 2.0f;
|
||||
|
||||
// View bounds, in view-absolute coordinates
|
||||
private final RectF mViewBounds = new RectF();
|
||||
// Non-transformed image bounds, in view-absolute coordinates
|
||||
private final RectF mImageBounds = new RectF();
|
||||
// Transformed image bounds, in view-absolute coordinates
|
||||
private final RectF mTransformedImageBounds = new RectF();
|
||||
|
||||
private final Matrix mPreviousTransform = new Matrix();
|
||||
private final Matrix mActiveTransform = new Matrix();
|
||||
private final Matrix mActiveTransformInverse = new Matrix();
|
||||
private final float[] mTempValues = new float[9];
|
||||
private final RectF mTempRect = new RectF();
|
||||
private boolean mWasTransformCorrected;
|
||||
|
||||
public static DefaultZoomableController newInstance() {
|
||||
return new DefaultZoomableController(TransformGestureDetector.newInstance());
|
||||
}
|
||||
|
||||
public DefaultZoomableController(TransformGestureDetector gestureDetector) {
|
||||
mGestureDetector = gestureDetector;
|
||||
mGestureDetector.setListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rests the controller.
|
||||
*/
|
||||
public void reset() {
|
||||
FLog.v(TAG, "reset");
|
||||
mGestureDetector.reset();
|
||||
mPreviousTransform.reset();
|
||||
mActiveTransform.reset();
|
||||
onTransformChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the zoomable listener.
|
||||
*/
|
||||
@Override
|
||||
public void setListener(Listener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the controller is enabled or not.
|
||||
*/
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
mIsEnabled = enabled;
|
||||
if (!enabled) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the controller is enabled or not.
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mIsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the rotation gesture is enabled or not.
|
||||
*/
|
||||
public void setRotationEnabled(boolean enabled) {
|
||||
mIsRotationEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the rotation gesture is enabled or not.
|
||||
*/
|
||||
public boolean isRotationEnabled() {
|
||||
return mIsRotationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the scale gesture is enabled or not.
|
||||
*/
|
||||
public void setScaleEnabled(boolean enabled) {
|
||||
mIsScaleEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the scale gesture is enabled or not.
|
||||
*/
|
||||
public boolean isScaleEnabled() {
|
||||
return mIsScaleEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the translation gesture is enabled or not.
|
||||
*/
|
||||
public void setTranslationEnabled(boolean enabled) {
|
||||
mIsTranslationEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the translations gesture is enabled or not.
|
||||
*/
|
||||
public boolean isTranslationEnabled() {
|
||||
return mIsTranslationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum scale factor allowed.
|
||||
*
|
||||
* <p>Hierarchy's scaling (if any) is not taken into account.
|
||||
*/
|
||||
public void setMinScaleFactor(float minScaleFactor) {
|
||||
mMinScaleFactor = minScaleFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum scale factor allowed.
|
||||
*/
|
||||
public float getMinScaleFactor() {
|
||||
return mMinScaleFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum scale factor allowed.
|
||||
*
|
||||
* <p>Hierarchy's scaling (if any) is not taken into account.
|
||||
*/
|
||||
public void setMaxScaleFactor(float maxScaleFactor) {
|
||||
mMaxScaleFactor = maxScaleFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum scale factor allowed.
|
||||
*/
|
||||
public float getMaxScaleFactor() {
|
||||
return mMaxScaleFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether gesture zooms are enabled or not.
|
||||
*/
|
||||
public void setGestureZoomEnabled(boolean isGestureZoomEnabled) {
|
||||
mIsGestureZoomEnabled = isGestureZoomEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether gesture zooms are enabled or not.
|
||||
*/
|
||||
public boolean isGestureZoomEnabled() {
|
||||
return mIsGestureZoomEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current scale factor.
|
||||
*/
|
||||
@Override
|
||||
public float getScaleFactor() {
|
||||
return getMatrixScaleFactor(mActiveTransform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the image bounds, in view-absolute coordinates.
|
||||
*/
|
||||
@Override
|
||||
public void setImageBounds(RectF imageBounds) {
|
||||
if (!imageBounds.equals(mImageBounds)) {
|
||||
mImageBounds.set(imageBounds);
|
||||
onTransformChanged();
|
||||
if (mImageBoundsListener != null) {
|
||||
mImageBoundsListener.onImageBoundsSet(mImageBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the non-transformed image bounds, in view-absolute coordinates.
|
||||
*/
|
||||
public RectF getImageBounds() {
|
||||
return mImageBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transformed image bounds, in view-absolute coordinates
|
||||
*/
|
||||
private RectF getTransformedImageBounds() {
|
||||
return mTransformedImageBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the view bounds.
|
||||
*/
|
||||
@Override
|
||||
public void setViewBounds(RectF viewBounds) {
|
||||
mViewBounds.set(viewBounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the view bounds.
|
||||
*/
|
||||
public RectF getViewBounds() {
|
||||
return mViewBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the image bounds listener.
|
||||
*/
|
||||
public void setImageBoundsListener(@Nullable ImageBoundsListener imageBoundsListener) {
|
||||
mImageBoundsListener = imageBoundsListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the image bounds listener.
|
||||
*/
|
||||
public @Nullable
|
||||
ImageBoundsListener getImageBoundsListener() {
|
||||
return mImageBoundsListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the zoomable transform is identity matrix.
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdentity() {
|
||||
return isMatrixIdentity(mActiveTransform, 1e-3f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the transform was corrected during the last update.
|
||||
*
|
||||
* <p>We should rename this method to `wasTransformedWithoutCorrection` and just return the
|
||||
* internal flag directly. However, this requires interface change and negation of meaning.
|
||||
*/
|
||||
@Override
|
||||
public boolean wasTransformCorrected() {
|
||||
return mWasTransformCorrected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the matrix that transforms image-absolute coordinates to view-absolute coordinates. The
|
||||
* zoomable transformation is taken into account.
|
||||
*
|
||||
* <p>Internal matrix is exposed for performance reasons and is not to be modified by the callers.
|
||||
*/
|
||||
@Override
|
||||
public Matrix getTransform() {
|
||||
return mActiveTransform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the matrix that transforms image-relative coordinates to view-absolute coordinates. The
|
||||
* zoomable transformation is taken into account.
|
||||
*/
|
||||
public void getImageRelativeToViewAbsoluteTransform(Matrix outMatrix) {
|
||||
outMatrix.setRectToRect(IDENTITY_RECT, mTransformedImageBounds, Matrix.ScaleToFit.FILL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps point from view-absolute to image-relative coordinates. This takes into account the
|
||||
* zoomable transformation.
|
||||
*/
|
||||
public PointF mapViewToImage(PointF viewPoint) {
|
||||
float[] points = mTempValues;
|
||||
points[0] = viewPoint.x;
|
||||
points[1] = viewPoint.y;
|
||||
mActiveTransform.invert(mActiveTransformInverse);
|
||||
mActiveTransformInverse.mapPoints(points, 0, points, 0, 1);
|
||||
mapAbsoluteToRelative(points, points, 1);
|
||||
return new PointF(points[0], points[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps point from image-relative to view-absolute coordinates. This takes into account the
|
||||
* zoomable transformation.
|
||||
*/
|
||||
public PointF mapImageToView(PointF imagePoint) {
|
||||
float[] points = mTempValues;
|
||||
points[0] = imagePoint.x;
|
||||
points[1] = imagePoint.y;
|
||||
mapRelativeToAbsolute(points, points, 1);
|
||||
mActiveTransform.mapPoints(points, 0, points, 0, 1);
|
||||
return new PointF(points[0], points[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps array of 2D points from view-absolute to image-relative coordinates. This does NOT take
|
||||
* into account the zoomable transformation. Points are represented by a float array of [x0, y0,
|
||||
* x1, y1, ...].
|
||||
*
|
||||
* @param destPoints destination array (may be the same as source array)
|
||||
* @param srcPoints source array
|
||||
* @param numPoints number of points to map
|
||||
*/
|
||||
private void mapAbsoluteToRelative(float[] destPoints, float[] srcPoints, int numPoints) {
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
destPoints[i * 2 + 0] = (srcPoints[i * 2 + 0] - mImageBounds.left) / mImageBounds.width();
|
||||
destPoints[i * 2 + 1] = (srcPoints[i * 2 + 1] - mImageBounds.top) / mImageBounds.height();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps array of 2D points from image-relative to view-absolute coordinates. This does NOT take
|
||||
* into account the zoomable transformation. Points are represented by float array of [x0, y0, x1,
|
||||
* y1, ...].
|
||||
*
|
||||
* @param destPoints destination array (may be the same as source array)
|
||||
* @param srcPoints source array
|
||||
* @param numPoints number of points to map
|
||||
*/
|
||||
private void mapRelativeToAbsolute(float[] destPoints, float[] srcPoints, int numPoints) {
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
destPoints[i * 2 + 0] = srcPoints[i * 2 + 0] * mImageBounds.width() + mImageBounds.left;
|
||||
destPoints[i * 2 + 1] = srcPoints[i * 2 + 1] * mImageBounds.height() + mImageBounds.top;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zooms to the desired scale and positions the image so that the given image point corresponds to
|
||||
* the given view point.
|
||||
*
|
||||
* @param scale desired scale, will be limited to {min, max} scale factor
|
||||
* @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1)
|
||||
* @param viewPoint 2D point in view's absolute coordinate system
|
||||
*/
|
||||
public void zoomToPoint(float scale, PointF imagePoint, PointF viewPoint) {
|
||||
FLog.v(TAG, "zoomToPoint");
|
||||
calculateZoomToPointTransform(mActiveTransform, scale, imagePoint, viewPoint, LIMIT_ALL);
|
||||
onTransformChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the zoom transformation that would zoom to the desired scale and position the image
|
||||
* so that the given image point corresponds to the given view point.
|
||||
*
|
||||
* @param outTransform the matrix to store the result to
|
||||
* @param scale desired scale, will be limited to {min, max} scale factor
|
||||
* @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1)
|
||||
* @param viewPoint 2D point in view's absolute coordinate system
|
||||
* @param limitFlags whether to limit translation and/or scale.
|
||||
* @return whether or not the transform has been corrected due to limitation
|
||||
*/
|
||||
protected boolean calculateZoomToPointTransform(
|
||||
Matrix outTransform,
|
||||
float scale,
|
||||
PointF imagePoint,
|
||||
PointF viewPoint,
|
||||
@LimitFlag int limitFlags) {
|
||||
float[] viewAbsolute = mTempValues;
|
||||
viewAbsolute[0] = imagePoint.x;
|
||||
viewAbsolute[1] = imagePoint.y;
|
||||
mapRelativeToAbsolute(viewAbsolute, viewAbsolute, 1);
|
||||
float distanceX = viewPoint.x - viewAbsolute[0];
|
||||
float distanceY = viewPoint.y - viewAbsolute[1];
|
||||
boolean transformCorrected = false;
|
||||
outTransform.setScale(scale, scale, viewAbsolute[0], viewAbsolute[1]);
|
||||
transformCorrected |= limitScale(outTransform, viewAbsolute[0], viewAbsolute[1], limitFlags);
|
||||
outTransform.postTranslate(distanceX, distanceY);
|
||||
transformCorrected |= limitTranslation(outTransform, limitFlags);
|
||||
return transformCorrected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new zoom transformation.
|
||||
*/
|
||||
public void setTransform(Matrix newTransform) {
|
||||
FLog.v(TAG, "setTransform");
|
||||
mActiveTransform.set(newTransform);
|
||||
onTransformChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gesture detector.
|
||||
*/
|
||||
protected TransformGestureDetector getDetector() {
|
||||
return mGestureDetector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies controller of the received touch event.
|
||||
*/
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
FLog.v(TAG, "onTouchEvent: action: ", event.getAction());
|
||||
if (mIsEnabled && mIsGestureZoomEnabled) {
|
||||
return mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TransformGestureDetector.Listener methods */
|
||||
|
||||
@Override
|
||||
public void onGestureBegin(TransformGestureDetector detector) {
|
||||
FLog.v(TAG, "onGestureBegin");
|
||||
mPreviousTransform.set(mActiveTransform);
|
||||
onTransformBegin();
|
||||
// We only received a touch down event so far, and so we don't know yet in which direction a
|
||||
// future move event will follow. Therefore, if we can't scroll in all directions, we have to
|
||||
// assume the worst case where the user tries to scroll out of edge, which would cause
|
||||
// transformation to be corrected.
|
||||
mWasTransformCorrected = !canScrollInAllDirection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGestureUpdate(TransformGestureDetector detector) {
|
||||
FLog.v(TAG, "onGestureUpdate");
|
||||
boolean transformCorrected = calculateGestureTransform(mActiveTransform, LIMIT_ALL);
|
||||
onTransformChanged();
|
||||
if (transformCorrected) {
|
||||
mGestureDetector.restartGesture();
|
||||
}
|
||||
// A transformation happened, but was it without correction?
|
||||
mWasTransformCorrected = transformCorrected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGestureEnd(TransformGestureDetector detector) {
|
||||
FLog.v(TAG, "onGestureEnd");
|
||||
onTransformEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the zoom transformation based on the current gesture.
|
||||
*
|
||||
* @param outTransform the matrix to store the result to
|
||||
* @param limitTypes whether to limit translation and/or scale.
|
||||
* @return whether or not the transform has been corrected due to limitation
|
||||
*/
|
||||
protected boolean calculateGestureTransform(Matrix outTransform, @LimitFlag int limitTypes) {
|
||||
TransformGestureDetector detector = mGestureDetector;
|
||||
boolean transformCorrected = false;
|
||||
outTransform.set(mPreviousTransform);
|
||||
if (mIsRotationEnabled) {
|
||||
float angle = detector.getRotation() * (float) (180 / Math.PI);
|
||||
outTransform.postRotate(angle, detector.getPivotX(), detector.getPivotY());
|
||||
}
|
||||
if (mIsScaleEnabled) {
|
||||
float scale = detector.getScale();
|
||||
outTransform.postScale(scale, scale, detector.getPivotX(), detector.getPivotY());
|
||||
}
|
||||
transformCorrected |=
|
||||
limitScale(outTransform, detector.getPivotX(), detector.getPivotY(), limitTypes);
|
||||
if (mIsTranslationEnabled) {
|
||||
outTransform.postTranslate(detector.getTranslationX(), detector.getTranslationY());
|
||||
}
|
||||
transformCorrected |= limitTranslation(outTransform, limitTypes);
|
||||
return transformCorrected;
|
||||
}
|
||||
|
||||
private void onTransformBegin() {
|
||||
if (mListener != null && isEnabled()) {
|
||||
mListener.onTransformBegin(mActiveTransform);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTransformChanged() {
|
||||
mActiveTransform.mapRect(mTransformedImageBounds, mImageBounds);
|
||||
if (mListener != null && isEnabled()) {
|
||||
mListener.onTransformChanged(mActiveTransform);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTransformEnd() {
|
||||
if (mListener != null && isEnabled()) {
|
||||
mListener.onTransformEnd(mActiveTransform);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps the scaling factor within the specified limits.
|
||||
*
|
||||
* @param pivotX x coordinate of the pivot point
|
||||
* @param pivotY y coordinate of the pivot point
|
||||
* @param limitTypes whether to limit scale.
|
||||
* @return whether limiting has been applied or not
|
||||
*/
|
||||
private boolean limitScale(
|
||||
Matrix transform, float pivotX, float pivotY, @LimitFlag int limitTypes) {
|
||||
if (!shouldLimit(limitTypes, LIMIT_SCALE)) {
|
||||
return false;
|
||||
}
|
||||
float currentScale = getMatrixScaleFactor(transform);
|
||||
float targetScale = limit(currentScale, mMinScaleFactor, mMaxScaleFactor);
|
||||
if (targetScale != currentScale) {
|
||||
float scale = targetScale / currentScale;
|
||||
transform.postScale(scale, scale, pivotX, pivotY);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the translation so that there are no empty spaces on the sides if possible.
|
||||
*
|
||||
* <p>The image is attempted to be centered within the view bounds if the transformed image is
|
||||
* smaller. There will be no empty spaces within the view bounds if the transformed image is
|
||||
* bigger. This applies to each dimension (horizontal and vertical) independently.
|
||||
*
|
||||
* @param limitTypes whether to limit translation along the specific axis.
|
||||
* @return whether limiting has been applied or not
|
||||
*/
|
||||
private boolean limitTranslation(Matrix transform, @LimitFlag int limitTypes) {
|
||||
if (!shouldLimit(limitTypes, LIMIT_TRANSLATION_X | LIMIT_TRANSLATION_Y)) {
|
||||
return false;
|
||||
}
|
||||
RectF b = mTempRect;
|
||||
b.set(mImageBounds);
|
||||
transform.mapRect(b);
|
||||
float offsetLeft =
|
||||
shouldLimit(limitTypes, LIMIT_TRANSLATION_X)
|
||||
? getOffset(
|
||||
b.left, b.right, mViewBounds.left, mViewBounds.right, mImageBounds.centerX())
|
||||
: 0;
|
||||
float offsetTop =
|
||||
shouldLimit(limitTypes, LIMIT_TRANSLATION_Y)
|
||||
? getOffset(
|
||||
b.top, b.bottom, mViewBounds.top, mViewBounds.bottom, mImageBounds.centerY())
|
||||
: 0;
|
||||
if (offsetLeft != 0 || offsetTop != 0) {
|
||||
transform.postTranslate(offsetLeft, offsetTop);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specified limit flag is present in the limits provided.
|
||||
*
|
||||
* <p>If the flag contains multiple flags together using a bitwise OR, this only checks that at
|
||||
* least one of the flags is included.
|
||||
*
|
||||
* @param limits the limits to apply
|
||||
* @param flag the limit flag(s) to check for
|
||||
* @return true if the flag (or one of the flags) is included in the limits
|
||||
*/
|
||||
private static boolean shouldLimit(@LimitFlag int limits, @LimitFlag int flag) {
|
||||
return (limits & flag) != LIMIT_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset necessary to make sure that: - the image is centered within the limit if the
|
||||
* image is smaller than the limit - there is no empty space on left/right if the image is bigger
|
||||
* than the limit
|
||||
*/
|
||||
private float getOffset(
|
||||
float imageStart, float imageEnd, float limitStart, float limitEnd, float limitCenter) {
|
||||
float imageWidth = imageEnd - imageStart, limitWidth = limitEnd - limitStart;
|
||||
float limitInnerWidth = Math.min(limitCenter - limitStart, limitEnd - limitCenter) * 2;
|
||||
// center if smaller than limitInnerWidth
|
||||
if (imageWidth < limitInnerWidth) {
|
||||
return limitCenter - (imageEnd + imageStart) / 2;
|
||||
}
|
||||
// to the edge if in between and limitCenter is not (limitLeft + limitRight) / 2
|
||||
if (imageWidth < limitWidth) {
|
||||
if (limitCenter < (limitStart + limitEnd) / 2) {
|
||||
return limitStart - imageStart;
|
||||
} else {
|
||||
return limitEnd - imageEnd;
|
||||
}
|
||||
}
|
||||
// to the edge if larger than limitWidth and empty space visible
|
||||
if (imageStart > limitStart) {
|
||||
return limitStart - imageStart;
|
||||
}
|
||||
if (imageEnd < limitEnd) {
|
||||
return limitEnd - imageEnd;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the value to the given min and max range.
|
||||
*/
|
||||
private float limit(float value, float min, float max) {
|
||||
return Math.min(Math.max(min, value), max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scale factor for the given matrix. This method assumes the equal scaling factor for X
|
||||
* and Y axis.
|
||||
*/
|
||||
private float getMatrixScaleFactor(Matrix transform) {
|
||||
transform.getValues(mTempValues);
|
||||
return mTempValues[Matrix.MSCALE_X];
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@code Matrix.isIdentity()}, but with tolerance {@code eps}.
|
||||
*/
|
||||
private boolean isMatrixIdentity(Matrix transform, float eps) {
|
||||
// Checks whether the given matrix is close enough to the identity matrix:
|
||||
// 1 0 0
|
||||
// 0 1 0
|
||||
// 0 0 1
|
||||
// Or equivalently to the zero matrix, after subtracting 1.0f from the diagonal elements:
|
||||
// 0 0 0
|
||||
// 0 0 0
|
||||
// 0 0 0
|
||||
transform.getValues(mTempValues);
|
||||
mTempValues[0] -= 1.0f; // m00
|
||||
mTempValues[4] -= 1.0f; // m11
|
||||
mTempValues[8] -= 1.0f; // m22
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (Math.abs(mTempValues[i]) > eps) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the scroll can happen in all directions. I.e. the image is not on any edge.
|
||||
*/
|
||||
private boolean canScrollInAllDirection() {
|
||||
return mTransformedImageBounds.left < mViewBounds.left - EPS
|
||||
&& mTransformedImageBounds.top < mViewBounds.top - EPS
|
||||
&& mTransformedImageBounds.right > mViewBounds.right + EPS
|
||||
&& mTransformedImageBounds.bottom > mViewBounds.bottom + EPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeHorizontalScrollRange() {
|
||||
return (int) mTransformedImageBounds.width();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeHorizontalScrollOffset() {
|
||||
return (int) (mViewBounds.left - mTransformedImageBounds.left);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeHorizontalScrollExtent() {
|
||||
return (int) mViewBounds.width();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeVerticalScrollRange() {
|
||||
return (int) mTransformedImageBounds.height();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeVerticalScrollOffset() {
|
||||
return (int) (mViewBounds.top - mTransformedImageBounds.top);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeVerticalScrollExtent() {
|
||||
return (int) mViewBounds.height();
|
||||
}
|
||||
|
||||
public Listener getListener() {
|
||||
return mListener;
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package awais.instagrabber.customviews.drawee;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* Tap gesture listener for double tap to zoom / unzoom and double-tap-and-drag to zoom.
|
||||
*
|
||||
* @see ZoomableDraweeView#setTapListener(GestureDetector.SimpleOnGestureListener)
|
||||
*/
|
||||
public class DoubleTapGestureListener extends GestureDetector.SimpleOnGestureListener {
|
||||
private static final int DURATION_MS = 300;
|
||||
private static final int DOUBLE_TAP_SCROLL_THRESHOLD = 20;
|
||||
|
||||
private final ZoomableDraweeView mDraweeView;
|
||||
private final PointF mDoubleTapViewPoint = new PointF();
|
||||
private final PointF mDoubleTapImagePoint = new PointF();
|
||||
private float mDoubleTapScale = 1;
|
||||
private boolean mDoubleTapScroll = false;
|
||||
|
||||
public DoubleTapGestureListener(ZoomableDraweeView zoomableDraweeView) {
|
||||
mDraweeView = zoomableDraweeView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTapEvent(MotionEvent e) {
|
||||
AbstractAnimatedZoomableController zc =
|
||||
(AbstractAnimatedZoomableController) mDraweeView.getZoomableController();
|
||||
PointF vp = new PointF(e.getX(), e.getY());
|
||||
PointF ip = zc.mapViewToImage(vp);
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDoubleTapViewPoint.set(vp);
|
||||
mDoubleTapImagePoint.set(ip);
|
||||
mDoubleTapScale = zc.getScaleFactor();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mDoubleTapScroll = mDoubleTapScroll || shouldStartDoubleTapScroll(vp);
|
||||
if (mDoubleTapScroll) {
|
||||
float scale = calcScale(vp);
|
||||
zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mDoubleTapScroll) {
|
||||
float scale = calcScale(vp);
|
||||
zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
|
||||
} else {
|
||||
final float maxScale = zc.getMaxScaleFactor();
|
||||
final float minScale = zc.getMinScaleFactor();
|
||||
if (zc.getScaleFactor() < (maxScale + minScale) / 2) {
|
||||
zc.zoomToPoint(
|
||||
maxScale, ip, vp, DefaultZoomableController.LIMIT_ALL, DURATION_MS, null);
|
||||
} else {
|
||||
zc.zoomToPoint(
|
||||
minScale, ip, vp, DefaultZoomableController.LIMIT_ALL, DURATION_MS, null);
|
||||
}
|
||||
}
|
||||
mDoubleTapScroll = false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean shouldStartDoubleTapScroll(PointF viewPoint) {
|
||||
double dist =
|
||||
Math.hypot(viewPoint.x - mDoubleTapViewPoint.x, viewPoint.y - mDoubleTapViewPoint.y);
|
||||
return dist > DOUBLE_TAP_SCROLL_THRESHOLD;
|
||||
}
|
||||
|
||||
private float calcScale(PointF currentViewPoint) {
|
||||
float dy = (currentViewPoint.y - mDoubleTapViewPoint.y);
|
||||
float t = 1 + Math.abs(dy) * 0.001f;
|
||||
return (dy < 0) ? mDoubleTapScale / t : mDoubleTapScale * t;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package awais.instagrabber.customviews.drawee;
|
||||
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* Wrapper for SimpleOnGestureListener as GestureDetector does not allow changing its listener.
|
||||
*/
|
||||
public class GestureListenerWrapper extends GestureDetector.SimpleOnGestureListener {
|
||||
|
||||
private GestureDetector.SimpleOnGestureListener mDelegate;
|
||||
|
||||
public GestureListenerWrapper() {
|
||||
mDelegate = new GestureDetector.SimpleOnGestureListener();
|
||||
}
|
||||
|
||||
public void setListener(GestureDetector.SimpleOnGestureListener listener) {
|
||||
mDelegate = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
mDelegate.onLongPress(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
return mDelegate.onScroll(e1, e2, distanceX, distanceY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
return mDelegate.onFling(e1, e2, velocityX, velocityY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPress(MotionEvent e) {
|
||||
mDelegate.onShowPress(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return mDelegate.onDown(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent e) {
|
||||
return mDelegate.onDoubleTap(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTapEvent(MotionEvent e) {
|
||||
return mDelegate.onDoubleTapEvent(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
return mDelegate.onSingleTapConfirmed(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
return mDelegate.onSingleTapUp(e);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user