mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 22:57:29 +00:00
Merge branch 'master' into support-android-11
This commit is contained in:
commit
7848b60b97
@ -66,11 +66,13 @@ android {
|
|||||||
dimension "repo"
|
dimension "repo"
|
||||||
// versionNameSuffix "-github" // appended in assemble task
|
// versionNameSuffix "-github" // appended in assemble task
|
||||||
buildConfigField("String", "dsn", SENTRY_DSN)
|
buildConfigField("String", "dsn", SENTRY_DSN)
|
||||||
|
buildConfigField("boolean", "isPre", "false")
|
||||||
}
|
}
|
||||||
|
|
||||||
fdroid {
|
fdroid {
|
||||||
dimension "repo"
|
dimension "repo"
|
||||||
versionNameSuffix "-fdroid"
|
versionNameSuffix "-fdroid"
|
||||||
|
buildConfigField("boolean", "isPre", "false")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +86,7 @@ android {
|
|||||||
|
|
||||||
def suffix = "${versionName}-${flavor}_${builtType}" // eg. 19.1.0-github_debug or release
|
def suffix = "${versionName}-${flavor}_${builtType}" // eg. 19.1.0-github_debug or release
|
||||||
if (builtType.toString() == 'release' && project.hasProperty("pre")) {
|
if (builtType.toString() == 'release' && project.hasProperty("pre")) {
|
||||||
|
buildConfigField("boolean", "isPre", "true")
|
||||||
// append latest commit short hash for pre-release
|
// append latest commit short hash for pre-release
|
||||||
suffix = "${versionName}.${getGitHash()}-${flavor}" // eg. 19.1.0.b123456-github
|
suffix = "${versionName}.${getGitHash()}-${flavor}" // eg. 19.1.0.b123456-github
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package awais.instagrabber.utils;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class UpdateChecker {
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private static final String TAG = UpdateChecker.class.getSimpleName();
|
||||||
|
|
||||||
|
private static UpdateChecker instance;
|
||||||
|
|
||||||
|
public static UpdateChecker getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new UpdateChecker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needs to be called asynchronously
|
||||||
|
*
|
||||||
|
* @return the latest version from f-droid
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getLatestVersion() {
|
||||||
|
HttpURLConnection conn = null;
|
||||||
|
try {
|
||||||
|
conn = (HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection();
|
||||||
|
conn.setUseCaches(false);
|
||||||
|
conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me");
|
||||||
|
conn.connect();
|
||||||
|
final int responseCode = conn.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn));
|
||||||
|
return "v" + data.getJSONArray("packages").getJSONObject(0).getString("versionName");
|
||||||
|
// if (BuildConfig.VERSION_CODE < data.getInt("suggestedVersionCode")) {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
} finally {
|
||||||
|
if (conn != null) {
|
||||||
|
conn.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDownload(@NonNull final AppCompatActivity context) {
|
||||||
|
Utils.openURL(context, "https://f-droid.org/packages/me.austinhuang.instagrabber/");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package awais.instagrabber.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class UpdateChecker {
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private static final String TAG = UpdateChecker.class.getSimpleName();
|
||||||
|
|
||||||
|
private static UpdateChecker instance;
|
||||||
|
|
||||||
|
public static UpdateChecker getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new UpdateChecker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needs to be called asynchronously
|
||||||
|
*
|
||||||
|
* @return the latest version from Github
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getLatestVersion() {
|
||||||
|
HttpURLConnection conn = null;
|
||||||
|
try {
|
||||||
|
conn = (HttpURLConnection) new URL("https://github.com/austinhuang0131/barinsta/releases/latest").openConnection();
|
||||||
|
conn.setInstanceFollowRedirects(false);
|
||||||
|
conn.setUseCaches(false);
|
||||||
|
conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me");
|
||||||
|
conn.connect();
|
||||||
|
final int responseCode = conn.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
|
||||||
|
return "v" + conn.getHeaderField("Location").split("/v")[1];
|
||||||
|
// return !version.equals(BuildConfig.VERSION_NAME);
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
} finally {
|
||||||
|
if (conn != null) {
|
||||||
|
conn.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDownload(@NonNull final Context context) {
|
||||||
|
Utils.openURL(context, "https://github.com/austinhuang0131/instagrabber/releases/latest");
|
||||||
|
}
|
||||||
|
}
|
@ -130,6 +130,9 @@
|
|||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".activities.MainActivity" />
|
android:value=".activities.MainActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".utils.ProcessPhoenix"
|
||||||
|
android:theme="@style/Theme.AppCompat.Translucent" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
@ -27,6 +27,9 @@ import static awais.instagrabber.utils.Utils.clipboardManager;
|
|||||||
import static awais.instagrabber.utils.Utils.datetimeParser;
|
import static awais.instagrabber.utils.Utils.datetimeParser;
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
|
//import awaisomereport.LogCollector;
|
||||||
|
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
|
|
||||||
public final class InstaGrabberApplication extends Application {
|
public final class InstaGrabberApplication extends Application {
|
||||||
private static final String TAG = "InstaGrabberApplication";
|
private static final String TAG = "InstaGrabberApplication";
|
||||||
|
|
||||||
@ -53,7 +56,7 @@ public final class InstaGrabberApplication extends Application {
|
|||||||
Log.e(TAG, "Error", e);
|
Log.e(TAG, "Error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// final Set<RequestListener> requestListeners = new HashSet<>();
|
// final Set<RequestListener> requestListeners = new HashSet<>();
|
||||||
// requestListeners.add(new RequestLoggingListener());
|
// requestListeners.add(new RequestLoggingListener());
|
||||||
final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
|
final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
|
||||||
|
@ -13,7 +13,6 @@ import android.webkit.WebChromeClient;
|
|||||||
import android.webkit.WebSettings;
|
import android.webkit.WebSettings;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
import android.widget.CompoundButton;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -24,7 +23,7 @@ import awais.instagrabber.utils.Constants;
|
|||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
|
||||||
public final class Login extends BaseLanguageActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
public final class Login extends BaseLanguageActivity implements View.OnClickListener {
|
||||||
private final WebViewClient webViewClient = new WebViewClient() {
|
private final WebViewClient webViewClient = new WebViewClient() {
|
||||||
@Override
|
@Override
|
||||||
public void onPageStarted(final WebView view, final String url, final Bitmap favicon) {
|
public void onPageStarted(final WebView view, final String url, final Bitmap favicon) {
|
||||||
@ -53,7 +52,7 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final WebChromeClient webChromeClient = new WebChromeClient();
|
private final WebChromeClient webChromeClient = new WebChromeClient();
|
||||||
private String webViewUrl, defaultUserAgent;
|
private String webViewUrl;
|
||||||
private boolean ready = false;
|
private boolean ready = false;
|
||||||
private ActivityLoginBinding loginBinding;
|
private ActivityLoginBinding loginBinding;
|
||||||
|
|
||||||
@ -65,7 +64,6 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
|||||||
|
|
||||||
initWebView();
|
initWebView();
|
||||||
|
|
||||||
loginBinding.desktopMode.setOnCheckedChangeListener(this);
|
|
||||||
loginBinding.cookies.setOnClickListener(this);
|
loginBinding.cookies.setOnClickListener(this);
|
||||||
loginBinding.refresh.setOnClickListener(this);
|
loginBinding.refresh.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
@ -86,23 +84,6 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
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;
|
|
||||||
|
|
||||||
webSettings.setUserAgentString(newUserAgent);
|
|
||||||
webSettings.setUseWideViewPort(isChecked);
|
|
||||||
webSettings.setLoadWithOverviewMode(isChecked);
|
|
||||||
webSettings.setSupportZoom(isChecked);
|
|
||||||
webSettings.setBuiltInZoomControls(isChecked);
|
|
||||||
|
|
||||||
loginBinding.webView.loadUrl("https://instagram.com/");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
private void initWebView() {
|
private void initWebView() {
|
||||||
if (loginBinding != null) {
|
if (loginBinding != null) {
|
||||||
@ -110,7 +91,7 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis
|
|||||||
loginBinding.webView.setWebViewClient(webViewClient);
|
loginBinding.webView.setWebViewClient(webViewClient);
|
||||||
final WebSettings webSettings = loginBinding.webView.getSettings();
|
final WebSettings webSettings = loginBinding.webView.getSettings();
|
||||||
if (webSettings != null) {
|
if (webSettings != null) {
|
||||||
if (defaultUserAgent == null) defaultUserAgent = webSettings.getUserAgentString();
|
webSettings.setUserAgentString("Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36");
|
||||||
webSettings.setJavaScriptEnabled(true);
|
webSettings.setJavaScriptEnabled(true);
|
||||||
webSettings.setDomStorageEnabled(true);
|
webSettings.setDomStorageEnabled(true);
|
||||||
webSettings.setSupportZoom(true);
|
webSettings.setSupportZoom(true);
|
||||||
|
@ -8,7 +8,6 @@ import android.content.ComponentName;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@ -24,6 +23,7 @@ import android.view.WindowManager;
|
|||||||
import android.widget.AutoCompleteTextView;
|
import android.widget.AutoCompleteTextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.IdRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
@ -50,15 +50,16 @@ import com.google.android.material.appbar.CollapsingToolbarLayout;
|
|||||||
import com.google.android.material.badge.BadgeDrawable;
|
import com.google.android.material.badge.BadgeDrawable;
|
||||||
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior;
|
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior;
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Collections;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import awais.instagrabber.BuildConfig;
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.adapters.SuggestionsAdapter;
|
import awais.instagrabber.adapters.SuggestionsAdapter;
|
||||||
import awais.instagrabber.asyncs.PostFetcher;
|
import awais.instagrabber.asyncs.PostFetcher;
|
||||||
@ -69,6 +70,7 @@ import awais.instagrabber.fragments.directmessages.DirectMessageInboxFragmentDir
|
|||||||
import awais.instagrabber.fragments.main.FeedFragment;
|
import awais.instagrabber.fragments.main.FeedFragment;
|
||||||
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
||||||
import awais.instagrabber.models.IntentModel;
|
import awais.instagrabber.models.IntentModel;
|
||||||
|
import awais.instagrabber.models.Tab;
|
||||||
import awais.instagrabber.models.enums.SuggestionType;
|
import awais.instagrabber.models.enums.SuggestionType;
|
||||||
import awais.instagrabber.repositories.responses.search.SearchItem;
|
import awais.instagrabber.repositories.responses.search.SearchItem;
|
||||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
||||||
@ -84,6 +86,7 @@ import awais.instagrabber.utils.Utils;
|
|||||||
import awais.instagrabber.utils.emoji.EmojiParser;
|
import awais.instagrabber.utils.emoji.EmojiParser;
|
||||||
import awais.instagrabber.viewmodels.AppStateViewModel;
|
import awais.instagrabber.viewmodels.AppStateViewModel;
|
||||||
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
||||||
|
import awais.instagrabber.webservices.RetrofitFactory;
|
||||||
import awais.instagrabber.webservices.SearchService;
|
import awais.instagrabber.webservices.SearchService;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
@ -94,15 +97,8 @@ import static awais.instagrabber.utils.Utils.settingsHelper;
|
|||||||
|
|
||||||
public class MainActivity extends BaseLanguageActivity implements FragmentManager.OnBackStackChangedListener {
|
public class MainActivity extends BaseLanguageActivity implements FragmentManager.OnBackStackChangedListener {
|
||||||
private static final String TAG = "MainActivity";
|
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 Map<Integer, Integer> NAV_TO_MENU_ID_MAP = new HashMap<>();
|
|
||||||
private static final String FIRST_FRAGMENT_GRAPH_INDEX_KEY = "firstFragmentGraphIndex";
|
private static final String FIRST_FRAGMENT_GRAPH_INDEX_KEY = "firstFragmentGraphIndex";
|
||||||
|
private static final String LAST_SELECT_NAV_MENU_ID = "lastSelectedNavMenuId";
|
||||||
|
|
||||||
private ActivityMainBinding binding;
|
private ActivityMainBinding binding;
|
||||||
private LiveData<NavController> currentNavControllerLiveData;
|
private LiveData<NavController> currentNavControllerLiveData;
|
||||||
@ -114,10 +110,13 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
private boolean showSearch = true;
|
private boolean showSearch = true;
|
||||||
private Handler suggestionsFetchHandler;
|
private Handler suggestionsFetchHandler;
|
||||||
private int firstFragmentGraphIndex;
|
private int firstFragmentGraphIndex;
|
||||||
|
private int lastSelectedNavMenuId;
|
||||||
private boolean isActivityCheckerServiceBound = false;
|
private boolean isActivityCheckerServiceBound = false;
|
||||||
private boolean isBackStackEmpty = false;
|
private boolean isBackStackEmpty = false;
|
||||||
private boolean isLoggedIn;
|
private boolean isLoggedIn;
|
||||||
private HideBottomViewOnScrollBehavior<BottomNavigationView> behavior;
|
private HideBottomViewOnScrollBehavior<BottomNavigationView> behavior;
|
||||||
|
private List<Tab> currentTabs;
|
||||||
|
private List<Integer> showBottomViewDestinations = Collections.emptyList();
|
||||||
|
|
||||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
@ -133,16 +132,9 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
@Override
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
|
RetrofitFactory.setup(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
@ -165,8 +157,10 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
setupBottomNavigationBar(true);
|
setupBottomNavigationBar(true);
|
||||||
}
|
}
|
||||||
setupSuggestions();
|
setupSuggestions();
|
||||||
final boolean checkUpdates = settingsHelper.getBoolean(Constants.CHECK_UPDATES);
|
if (!BuildConfig.isPre) {
|
||||||
if (checkUpdates) FlavorTown.updateCheck(this);
|
final boolean checkUpdates = settingsHelper.getBoolean(Constants.CHECK_UPDATES);
|
||||||
|
if (checkUpdates) FlavorTown.updateCheck(this);
|
||||||
|
}
|
||||||
FlavorTown.changelogCheck(this);
|
FlavorTown.changelogCheck(this);
|
||||||
new ViewModelProvider(this).get(AppStateViewModel.class); // Just initiate the App state here
|
new ViewModelProvider(this).get(AppStateViewModel.class); // Just initiate the App state here
|
||||||
final Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
@ -227,6 +221,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
outState.putString(FIRST_FRAGMENT_GRAPH_INDEX_KEY, String.valueOf(firstFragmentGraphIndex));
|
outState.putString(FIRST_FRAGMENT_GRAPH_INDEX_KEY, String.valueOf(firstFragmentGraphIndex));
|
||||||
|
outState.putString(LAST_SELECT_NAV_MENU_ID, String.valueOf(binding.bottomNavView.getSelectedItemId()));
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,6 +234,12 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
firstFragmentGraphIndex = Integer.parseInt(key);
|
firstFragmentGraphIndex = Integer.parseInt(key);
|
||||||
} catch (NumberFormatException ignored) { }
|
} catch (NumberFormatException ignored) { }
|
||||||
}
|
}
|
||||||
|
final String lastSelected = (String) savedInstanceState.get(LAST_SELECT_NAV_MENU_ID);
|
||||||
|
if (lastSelected != null) {
|
||||||
|
try {
|
||||||
|
lastSelectedNavMenuId = Integer.parseInt(lastSelected);
|
||||||
|
} catch (NumberFormatException ignored) { }
|
||||||
|
}
|
||||||
setupBottomNavigationBar(false);
|
setupBottomNavigationBar(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +265,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
Log.e(TAG, "onDestroy: ", e);
|
Log.e(TAG, "onDestroy: ", e);
|
||||||
}
|
}
|
||||||
unbindActivityCheckerService();
|
unbindActivityCheckerService();
|
||||||
|
RetrofitFactory.getInstance().destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -273,9 +275,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
final NavController navController = currentNavControllerLiveData.getValue();
|
final NavController navController = currentNavControllerLiveData.getValue();
|
||||||
if (navController != null) {
|
if (navController != null) {
|
||||||
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
|
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
|
||||||
if (backStack != null) {
|
currentNavControllerBackStack = backStack.size();
|
||||||
currentNavControllerBackStack = backStack.size();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isTaskRoot() && isBackStackEmpty && currentNavControllerBackStack == 2) {
|
if (isTaskRoot() && isBackStackEmpty && currentNavControllerBackStack == 2) {
|
||||||
@ -328,7 +328,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_LOCATION:
|
case TYPE_LOCATION:
|
||||||
bundle.putLong("locationId", Long.valueOf(query));
|
bundle.putLong("locationId", Long.parseLong(query));
|
||||||
navController.navigate(R.id.action_global_locationFragment, bundle);
|
navController.navigate(R.id.action_global_locationFragment, bundle);
|
||||||
break;
|
break;
|
||||||
case TYPE_HASHTAG:
|
case TYPE_HASHTAG:
|
||||||
@ -378,14 +378,16 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
cursor = null;
|
cursor = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final List<SearchItem> result = new ArrayList<SearchItem>();
|
final List<SearchItem> result = new ArrayList<>();
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
if (body.getList() != null) result.addAll(searchHash ? body.getList()
|
if (body.getList() != null) {
|
||||||
.stream()
|
result.addAll(searchHash ? body.getList()
|
||||||
.filter(i -> i.getUser() == null)
|
.stream()
|
||||||
.collect(Collectors.toList()) : body.getList());
|
.filter(i -> i.getUser() == null)
|
||||||
}
|
.collect(Collectors.toList())
|
||||||
else {
|
: body.getList());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (body.getUsers() != null && !searchHash) result.addAll(body.getUsers());
|
if (body.getUsers() != null && !searchHash) result.addAll(body.getUsers());
|
||||||
if (body.getHashtags() != null) result.addAll(body.getHashtags());
|
if (body.getHashtags() != null) result.addAll(body.getHashtags());
|
||||||
if (body.getPlaces() != null) result.addAll(body.getPlaces());
|
if (body.getPlaces() != null) result.addAll(body.getPlaces());
|
||||||
@ -430,9 +432,10 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull final Call<SearchResponse> call,
|
public void onFailure(@NonNull final Call<SearchResponse> call,
|
||||||
Throwable t) {
|
@NonNull Throwable t) {
|
||||||
if (!call.isCanceled() && t != null)
|
if (!call.isCanceled()) {
|
||||||
Log.e(TAG, "Exception on search:", t);
|
Log.e(TAG, "Exception on search:", t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -454,7 +457,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
}
|
}
|
||||||
prevSuggestionAsync = searchService.search(isLoggedIn,
|
prevSuggestionAsync = searchService.search(isLoggedIn,
|
||||||
searchUser || searchHash ? currentSearchQuery.substring(1)
|
searchUser || searchHash ? currentSearchQuery.substring(1)
|
||||||
: currentSearchQuery,
|
: currentSearchQuery,
|
||||||
searchUser ? "user" : (searchHash ? "hashtag" : "blended"));
|
searchUser ? "user" : (searchHash ? "hashtag" : "blended"));
|
||||||
suggestionAdapter.changeCursor(null);
|
suggestionAdapter.changeCursor(null);
|
||||||
prevSuggestionAsync.enqueue(cb);
|
prevSuggestionAsync.enqueue(cb);
|
||||||
@ -484,36 +487,18 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupBottomNavigationBar(final boolean setDefaultFromSettings) {
|
private void setupBottomNavigationBar(final boolean setDefaultTabFromSettings) {
|
||||||
int main_nav_ids = R.array.main_nav_ids;
|
currentTabs = !isLoggedIn ? setupAnonBottomNav() : setupMainBottomNav();
|
||||||
if (!isLoggedIn) {
|
final List<Integer> mainNavList = currentTabs.stream()
|
||||||
main_nav_ids = R.array.logged_out_main_nav_ids;
|
.map(Tab::getNavigationResId)
|
||||||
final int selectedItemId = binding.bottomNavView.getSelectedItemId();
|
.collect(Collectors.toList());
|
||||||
binding.bottomNavView.getMenu().clear();
|
showBottomViewDestinations = currentTabs.stream()
|
||||||
binding.bottomNavView.inflateMenu(R.menu.logged_out_bottom_navigation_menu);
|
.map(Tab::getStartDestinationFragmentId)
|
||||||
if (selectedItemId == R.id.profile_nav_graph
|
.collect(Collectors.toList());
|
||||||
|| selectedItemId == R.id.more_nav_graph) {
|
if (setDefaultTabFromSettings) {
|
||||||
binding.bottomNavView.setSelectedItemId(selectedItemId);
|
setSelectedTab(currentTabs);
|
||||||
} else {
|
} else {
|
||||||
setBottomNavSelectedItem(R.navigation.profile_nav_graph);
|
binding.bottomNavView.setSelectedItemId(lastSelectedNavMenuId);
|
||||||
}
|
|
||||||
}
|
|
||||||
final List<Integer> mainNavList = getMainNavList(main_nav_ids);
|
|
||||||
if (setDefaultFromSettings) {
|
|
||||||
final String defaultTabResNameString = settingsHelper.getString(Constants.DEFAULT_TAB);
|
|
||||||
try {
|
|
||||||
int navId = 0;
|
|
||||||
if (!TextUtils.isEmpty(defaultTabResNameString)) {
|
|
||||||
navId = getResources().getIdentifier(defaultTabResNameString, "navigation", getPackageName());
|
|
||||||
}
|
|
||||||
final int defaultNavId = navId <= 0 ? R.navigation.profile_nav_graph
|
|
||||||
: navId;
|
|
||||||
final int index = mainNavList.indexOf(defaultNavId);
|
|
||||||
if (index >= 0) firstFragmentGraphIndex = index;
|
|
||||||
setBottomNavSelectedItem(defaultNavId);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "Error parsing id", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final LiveData<NavController> navControllerLiveData = setupWithNavController(
|
final LiveData<NavController> navControllerLiveData = setupWithNavController(
|
||||||
binding.bottomNavView,
|
binding.bottomNavView,
|
||||||
@ -536,27 +521,86 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBottomNavSelectedItem(final int navId) {
|
private void setSelectedTab(final List<Tab> tabs) {
|
||||||
final Integer menuId = NAV_TO_MENU_ID_MAP.get(navId);
|
final String defaultTabResNameString = settingsHelper.getString(Constants.DEFAULT_TAB);
|
||||||
if (menuId != null) {
|
try {
|
||||||
binding.bottomNavView.setSelectedItemId(menuId);
|
int navId = 0;
|
||||||
|
if (!TextUtils.isEmpty(defaultTabResNameString)) {
|
||||||
|
navId = getResources().getIdentifier(defaultTabResNameString, "navigation", getPackageName());
|
||||||
|
}
|
||||||
|
final int navGraph = isLoggedIn ? R.navigation.feed_nav_graph
|
||||||
|
: R.navigation.profile_nav_graph;
|
||||||
|
final int defaultNavId = navId <= 0 ? navGraph : navId;
|
||||||
|
int index = Iterators.indexOf(tabs.iterator(), tab -> {
|
||||||
|
if (tab == null) return false;
|
||||||
|
return tab.getNavigationResId() == defaultNavId;
|
||||||
|
});
|
||||||
|
if (index < 0 || index >= tabs.size()) index = 0;
|
||||||
|
firstFragmentGraphIndex = index;
|
||||||
|
setBottomNavSelectedTab(tabs.get(index));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error parsing id", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private List<Tab> setupAnonBottomNav() {
|
||||||
private List<Integer> getMainNavList(final int main_nav_ids) {
|
final int selectedItemId = binding.bottomNavView.getSelectedItemId();
|
||||||
final TypedArray navIds = getResources().obtainTypedArray(main_nav_ids);
|
final Tab profileTab = new Tab(R.drawable.ic_person_24,
|
||||||
final List<Integer> mainNavList = new ArrayList<>(navIds.length());
|
getString(R.string.profile),
|
||||||
final int length = navIds.length();
|
false,
|
||||||
for (int i = 0; i < length; i++) {
|
"profile_nav_graph",
|
||||||
final int resourceId = navIds.getResourceId(i, -1);
|
R.navigation.profile_nav_graph,
|
||||||
if (resourceId < 0) continue;
|
R.id.profile_nav_graph,
|
||||||
mainNavList.add(resourceId);
|
R.id.profileFragment);
|
||||||
|
final Tab moreTab = new Tab(R.drawable.ic_more_horiz_24,
|
||||||
|
getString(R.string.more),
|
||||||
|
false,
|
||||||
|
"more_nav_graph",
|
||||||
|
R.navigation.more_nav_graph,
|
||||||
|
R.id.more_nav_graph,
|
||||||
|
R.id.morePreferencesFragment);
|
||||||
|
final Menu menu = binding.bottomNavView.getMenu();
|
||||||
|
menu.clear();
|
||||||
|
menu.add(0, profileTab.getNavigationRootId(), 0, profileTab.getTitle()).setIcon(profileTab.getIconResId());
|
||||||
|
menu.add(0, moreTab.getNavigationRootId(), 0, moreTab.getTitle()).setIcon(moreTab.getIconResId());
|
||||||
|
if (selectedItemId != R.id.profile_nav_graph && selectedItemId != R.id.more_nav_graph) {
|
||||||
|
setBottomNavSelectedTab(profileTab);
|
||||||
}
|
}
|
||||||
navIds.recycle();
|
return ImmutableList.of(profileTab, moreTab);
|
||||||
return mainNavList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Tab> setupMainBottomNav() {
|
||||||
|
final Menu menu = binding.bottomNavView.getMenu();
|
||||||
|
menu.clear();
|
||||||
|
final List<Tab> navTabList = Utils.getNavTabList(this).first;
|
||||||
|
for (final Tab tab : navTabList) {
|
||||||
|
menu.add(0, tab.getNavigationRootId(), 0, tab.getTitle()).setIcon(tab.getIconResId());
|
||||||
|
}
|
||||||
|
return navTabList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setBottomNavSelectedTab(@NonNull final Tab tab) {
|
||||||
|
binding.bottomNavView.setSelectedItemId(tab.getNavigationRootId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setBottomNavSelectedTab(@SuppressWarnings("SameParameterValue") @IdRes final int navGraphRootId) {
|
||||||
|
binding.bottomNavView.setSelectedItemId(navGraphRootId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @NonNull
|
||||||
|
// private List<Integer> getMainNavList(final int main_nav_ids) {
|
||||||
|
// 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();
|
||||||
|
// return mainNavList;
|
||||||
|
// }
|
||||||
|
|
||||||
private void setupNavigation(final Toolbar toolbar, final NavController navController) {
|
private void setupNavigation(final Toolbar toolbar, final NavController navController) {
|
||||||
if (navController == null) return;
|
if (navController == null) return;
|
||||||
NavigationUI.setupWithNavController(toolbar, navController);
|
NavigationUI.setupWithNavController(toolbar, navController);
|
||||||
@ -574,7 +618,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
final int destinationId = destination.getId();
|
final int destinationId = destination.getId();
|
||||||
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
|
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
|
||||||
setupMenu(backStack.size(), destinationId);
|
setupMenu(backStack.size(), destinationId);
|
||||||
final boolean contains = SHOW_BOTTOM_VIEW_DESTINATIONS.contains(destinationId);
|
final boolean contains = showBottomViewDestinations.contains(destinationId);
|
||||||
binding.bottomNavView.setVisibility(contains ? View.VISIBLE : View.GONE);
|
binding.bottomNavView.setVisibility(contains ? View.VISIBLE : View.GONE);
|
||||||
if (contains && behavior != null) {
|
if (contains && behavior != null) {
|
||||||
behavior.slideUp(binding.bottomNavView);
|
behavior.slideUp(binding.bottomNavView);
|
||||||
@ -684,7 +728,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
});
|
});
|
||||||
final int selectedItemId = binding.bottomNavView.getSelectedItemId();
|
final int selectedItemId = binding.bottomNavView.getSelectedItemId();
|
||||||
if (selectedItemId != R.navigation.direct_messages_nav_graph) {
|
if (selectedItemId != R.navigation.direct_messages_nav_graph) {
|
||||||
setBottomNavSelectedItem(R.navigation.direct_messages_nav_graph);
|
setBottomNavSelectedTab(R.id.direct_messages_nav_graph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +800,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
final NavController navController = currentNavControllerLiveData.getValue();
|
final NavController navController = currentNavControllerLiveData.getValue();
|
||||||
if (navController == null) return;
|
if (navController == null) return;
|
||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
bundle.putLong("locationId", Long.valueOf(locationId));
|
bundle.putLong("locationId", Long.parseLong(locationId));
|
||||||
navController.navigate(R.id.action_global_locationFragment, bundle);
|
navController.navigate(R.id.action_global_locationFragment, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,6 +908,18 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
|||||||
return binding.toolbar;
|
return binding.toolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public View getRootView() {
|
||||||
|
return binding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Tab> getCurrentTabs() {
|
||||||
|
return currentTabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public boolean isNavRootInCurrentTabs(@IdRes final int navRootId) {
|
||||||
|
// return showBottomViewDestinations.stream().anyMatch(id -> id == navRootId);
|
||||||
|
// }
|
||||||
|
|
||||||
private void setNavBarDMUnreadCountBadge(final int unseenCount) {
|
private void setNavBarDMUnreadCountBadge(final int unseenCount) {
|
||||||
final BadgeDrawable badge = binding.bottomNavView.getOrCreateBadge(R.id.direct_messages_nav_graph);
|
final BadgeDrawable badge = binding.bottomNavView.getOrCreateBadge(R.id.direct_messages_nav_graph);
|
||||||
if (badge == null) return;
|
if (badge == null) return;
|
||||||
|
@ -10,7 +10,6 @@ import android.view.ViewGroup;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.cursoradapter.widget.CursorAdapter;
|
import androidx.cursoradapter.widget.CursorAdapter;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
|
||||||
import awais.instagrabber.databinding.ItemSuggestionBinding;
|
import awais.instagrabber.databinding.ItemSuggestionBinding;
|
||||||
import awais.instagrabber.models.enums.SuggestionType;
|
import awais.instagrabber.models.enums.SuggestionType;
|
||||||
|
|
||||||
|
156
app/src/main/java/awais/instagrabber/adapters/TabsAdapter.java
Normal file
156
app/src/main/java/awais/instagrabber/adapters/TabsAdapter.java
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package awais.instagrabber.adapters;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
|
import androidx.recyclerview.widget.ListAdapter;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.adapters.viewholder.TabViewHolder;
|
||||||
|
import awais.instagrabber.databinding.ItemFavSectionHeaderBinding;
|
||||||
|
import awais.instagrabber.databinding.ItemTabOrderPrefBinding;
|
||||||
|
import awais.instagrabber.models.Tab;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
|
|
||||||
|
public class TabsAdapter extends ListAdapter<TabsAdapter.TabOrHeader, RecyclerView.ViewHolder> {
|
||||||
|
private static final DiffUtil.ItemCallback<TabOrHeader> DIFF_CALLBACK = new DiffUtil.ItemCallback<TabOrHeader>() {
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(@NonNull final TabOrHeader oldItem, @NonNull final TabOrHeader newItem) {
|
||||||
|
if (oldItem.isHeader() && newItem.isHeader()) {
|
||||||
|
return oldItem.header == newItem.header;
|
||||||
|
}
|
||||||
|
if (!oldItem.isHeader() && !newItem.isHeader()) {
|
||||||
|
final Tab oldTab = oldItem.tab;
|
||||||
|
final Tab newTab = newItem.tab;
|
||||||
|
return oldTab.getIconResId() == newTab.getIconResId()
|
||||||
|
&& Objects.equals(oldTab.getTitle(), newTab.getTitle());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(@NonNull final TabOrHeader oldItem, @NonNull final TabOrHeader newItem) {
|
||||||
|
if (oldItem.isHeader() && newItem.isHeader()) {
|
||||||
|
return oldItem.header == newItem.header;
|
||||||
|
}
|
||||||
|
if (!oldItem.isHeader() && !newItem.isHeader()) {
|
||||||
|
final Tab oldTab = oldItem.tab;
|
||||||
|
final Tab newTab = newItem.tab;
|
||||||
|
return oldTab.getIconResId() == newTab.getIconResId()
|
||||||
|
&& Objects.equals(oldTab.getTitle(), newTab.getTitle());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final TabAdapterCallback tabAdapterCallback;
|
||||||
|
|
||||||
|
private List<Tab> current = new ArrayList<>();
|
||||||
|
private List<Tab> others = new ArrayList<>();
|
||||||
|
|
||||||
|
public TabsAdapter(@NonNull final TabAdapterCallback tabAdapterCallback) {
|
||||||
|
super(DIFF_CALLBACK);
|
||||||
|
this.tabAdapterCallback = tabAdapterCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||||
|
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||||
|
if (viewType == 1) {
|
||||||
|
final ItemTabOrderPrefBinding binding = ItemTabOrderPrefBinding.inflate(layoutInflater, parent, false);
|
||||||
|
return new TabViewHolder(binding, tabAdapterCallback);
|
||||||
|
}
|
||||||
|
final ItemFavSectionHeaderBinding headerBinding = ItemFavSectionHeaderBinding.inflate(layoutInflater, parent, false);
|
||||||
|
return new DirectUsersAdapter.HeaderViewHolder(headerBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
|
||||||
|
if (holder instanceof DirectUsersAdapter.HeaderViewHolder) {
|
||||||
|
((DirectUsersAdapter.HeaderViewHolder) holder).bind(R.string.other_tabs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (holder instanceof TabViewHolder) {
|
||||||
|
final Tab tab = getItem(position).tab;
|
||||||
|
((TabViewHolder) holder).bind(tab, others.contains(tab), current.size() == 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(final int position) {
|
||||||
|
return getItem(position).isHeader() ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void submitList(final List<Tab> current, final List<Tab> others, final Runnable commitCallback) {
|
||||||
|
final ImmutableList.Builder<TabOrHeader> builder = ImmutableList.builder();
|
||||||
|
if (current != null) {
|
||||||
|
builder.addAll(current.stream()
|
||||||
|
.map(TabOrHeader::new)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
builder.add(new TabOrHeader(R.string.other_tabs));
|
||||||
|
if (others != null) {
|
||||||
|
builder.addAll(others.stream()
|
||||||
|
.map(TabOrHeader::new)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
// Mutable non-null copies
|
||||||
|
this.current = current != null ? new ArrayList<>(current) : new ArrayList<>();
|
||||||
|
this.others = others != null ? new ArrayList<>(others) : new ArrayList<>();
|
||||||
|
submitList(builder.build(), commitCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void submitList(final List<Tab> current, final List<Tab> others) {
|
||||||
|
submitList(current, others, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveItem(final int from, final int to) {
|
||||||
|
final List<Tab> currentCopy = new ArrayList<>(current);
|
||||||
|
Utils.moveItem(from, to, currentCopy);
|
||||||
|
submitList(currentCopy, others);
|
||||||
|
tabAdapterCallback.onOrderChange(currentCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentCount() {
|
||||||
|
return current.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TabOrHeader {
|
||||||
|
Tab tab;
|
||||||
|
int header;
|
||||||
|
|
||||||
|
public TabOrHeader(final Tab tab) {
|
||||||
|
this.tab = tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TabOrHeader(@StringRes final int header) {
|
||||||
|
this.header = header;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isHeader() {
|
||||||
|
return header != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TabAdapterCallback {
|
||||||
|
void onStartDrag(TabViewHolder viewHolder);
|
||||||
|
|
||||||
|
void onOrderChange(List<Tab> newOrderTabs);
|
||||||
|
|
||||||
|
void onAdd(Tab tab);
|
||||||
|
|
||||||
|
void onRemove(Tab tab);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package awais.instagrabber.adapters.viewholder;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.widget.ImageViewCompat;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.color.MaterialColors;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.adapters.TabsAdapter;
|
||||||
|
import awais.instagrabber.databinding.ItemTabOrderPrefBinding;
|
||||||
|
import awais.instagrabber.models.Tab;
|
||||||
|
|
||||||
|
public class TabViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private final ItemTabOrderPrefBinding binding;
|
||||||
|
private final TabsAdapter.TabAdapterCallback tabAdapterCallback;
|
||||||
|
private final int highlightColor;
|
||||||
|
private final Drawable originalBgColor;
|
||||||
|
|
||||||
|
private boolean draggable = true;
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
public TabViewHolder(@NonNull final ItemTabOrderPrefBinding binding,
|
||||||
|
@NonNull final TabsAdapter.TabAdapterCallback tabAdapterCallback) {
|
||||||
|
super(binding.getRoot());
|
||||||
|
this.binding = binding;
|
||||||
|
this.tabAdapterCallback = tabAdapterCallback;
|
||||||
|
highlightColor = MaterialColors.getColor(itemView.getContext(), R.attr.colorControlHighlight, 0);
|
||||||
|
originalBgColor = itemView.getBackground();
|
||||||
|
binding.handle.setOnTouchListener((v, event) -> {
|
||||||
|
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||||
|
tabAdapterCallback.onStartDrag(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(@NonNull final Tab tab,
|
||||||
|
final boolean isInOthers,
|
||||||
|
final boolean isCurrentFull) {
|
||||||
|
draggable = !isInOthers;
|
||||||
|
binding.icon.setImageResource(tab.getIconResId());
|
||||||
|
binding.title.setText(tab.getTitle());
|
||||||
|
binding.handle.setVisibility(isInOthers ? View.GONE : View.VISIBLE);
|
||||||
|
binding.addRemove.setImageResource(isInOthers ? R.drawable.ic_round_add_circle_24
|
||||||
|
: R.drawable.ic_round_remove_circle_24);
|
||||||
|
final ColorStateList tintList = ColorStateList.valueOf(ContextCompat.getColor(
|
||||||
|
itemView.getContext(),
|
||||||
|
isInOthers ? R.color.green_500
|
||||||
|
: R.color.red_500));
|
||||||
|
ImageViewCompat.setImageTintList(binding.addRemove, tintList);
|
||||||
|
binding.addRemove.setOnClickListener(v -> {
|
||||||
|
if (isInOthers) {
|
||||||
|
tabAdapterCallback.onAdd(tab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tabAdapterCallback.onRemove(tab);
|
||||||
|
});
|
||||||
|
final boolean enabled = tab.isRemovable()
|
||||||
|
&& !(isInOthers && isCurrentFull); // All slots are full in current
|
||||||
|
binding.addRemove.setEnabled(enabled);
|
||||||
|
binding.addRemove.setAlpha(enabled ? 1 : 0.5F);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDraggable() {
|
||||||
|
return draggable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDragging(final boolean isDragging) {
|
||||||
|
if (isDragging) {
|
||||||
|
if (highlightColor != 0) {
|
||||||
|
itemView.setBackgroundColor(highlightColor);
|
||||||
|
} else {
|
||||||
|
itemView.setAlpha(0.5F);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
itemView.setAlpha(1);
|
||||||
|
itemView.setBackground(originalBgColor);
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,6 @@ import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
|||||||
import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
||||||
import awais.instagrabber.models.enums.MediaItemType;
|
import awais.instagrabber.models.enums.MediaItemType;
|
||||||
import awais.instagrabber.models.enums.RavenMediaViewMode;
|
import awais.instagrabber.models.enums.RavenMediaViewMode;
|
||||||
import awais.instagrabber.repositories.responses.ImageVersions2;
|
|
||||||
import awais.instagrabber.repositories.responses.Media;
|
import awais.instagrabber.repositories.responses.Media;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||||
|
@ -47,7 +47,7 @@ public class FavoriteDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void insertOrUpdateFavorite(@NonNull final Favorite favorite) {
|
public final void insertOrUpdateFavorite(@NonNull final Favorite favorite) {
|
||||||
if (favorite.getId() > 0) {
|
if (favorite.getId() != 0) {
|
||||||
favoriteDao.updateFavorites(favorite);
|
favoriteDao.updateFavorites(favorite);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -25,8 +24,10 @@ import awais.instagrabber.db.datasources.AccountDataSource;
|
|||||||
import awais.instagrabber.db.entities.Account;
|
import awais.instagrabber.db.entities.Account;
|
||||||
import awais.instagrabber.db.repositories.AccountRepository;
|
import awais.instagrabber.db.repositories.AccountRepository;
|
||||||
import awais.instagrabber.db.repositories.RepositoryCallback;
|
import awais.instagrabber.db.repositories.RepositoryCallback;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
|
import awais.instagrabber.utils.ProcessPhoenix;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
|
|
||||||
@ -55,9 +56,14 @@ public class AccountSwitcherDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
CookieUtils.setupCookies(model.getCookie());
|
CookieUtils.setupCookies(model.getCookie());
|
||||||
settingsHelper.putString(Constants.COOKIE, model.getCookie());
|
settingsHelper.putString(Constants.COOKIE, model.getCookie());
|
||||||
final FragmentActivity activity = getActivity();
|
// final FragmentActivity activity = getActivity();
|
||||||
if (activity != null) activity.recreate();
|
// if (activity != null) activity.recreate();
|
||||||
dismiss();
|
// dismiss();
|
||||||
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
ProcessPhoenix.triggerRebirth(context);
|
||||||
|
}, 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
private final AccountSwitcherAdapter.OnAccountLongClickListener accountLongClickListener = (model, isCurrent) -> {
|
private final AccountSwitcherAdapter.OnAccountLongClickListener accountLongClickListener = (model, isCurrent) -> {
|
||||||
|
@ -0,0 +1,275 @@
|
|||||||
|
package awais.instagrabber.dialogs;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper.SimpleCallback;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.adapters.DirectUsersAdapter;
|
||||||
|
import awais.instagrabber.adapters.TabsAdapter;
|
||||||
|
import awais.instagrabber.adapters.viewholder.TabViewHolder;
|
||||||
|
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
||||||
|
import awais.instagrabber.models.Tab;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
|
|
||||||
|
import static androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_DRAG;
|
||||||
|
import static androidx.recyclerview.widget.ItemTouchHelper.DOWN;
|
||||||
|
import static androidx.recyclerview.widget.ItemTouchHelper.UP;
|
||||||
|
|
||||||
|
public class TabOrderPreferenceDialogFragment extends DialogFragment {
|
||||||
|
private Callback callback;
|
||||||
|
private Context context;
|
||||||
|
private List<Tab> tabsInPref;
|
||||||
|
private ItemTouchHelper itemTouchHelper;
|
||||||
|
private AlertDialog dialog;
|
||||||
|
private List<Tab> newOrderTabs;
|
||||||
|
private List<Tab> newOtherTabs;
|
||||||
|
|
||||||
|
private final TabsAdapter.TabAdapterCallback tabAdapterCallback = new TabsAdapter.TabAdapterCallback() {
|
||||||
|
@Override
|
||||||
|
public void onStartDrag(final TabViewHolder viewHolder) {
|
||||||
|
if (itemTouchHelper == null || viewHolder == null) return;
|
||||||
|
itemTouchHelper.startDrag(viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOrderChange(final List<Tab> newOrderTabs) {
|
||||||
|
if (newOrderTabs == null || tabsInPref == null || dialog == null) return;
|
||||||
|
TabOrderPreferenceDialogFragment.this.newOrderTabs = newOrderTabs;
|
||||||
|
setSaveButtonState(newOrderTabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAdd(final Tab tab) {
|
||||||
|
// Add this tab to newOrderTabs
|
||||||
|
newOrderTabs = ImmutableList.<Tab>builder()
|
||||||
|
.addAll(newOrderTabs)
|
||||||
|
.add(tab)
|
||||||
|
.build();
|
||||||
|
// Remove this tab from newOtherTabs
|
||||||
|
if (newOtherTabs != null) {
|
||||||
|
newOtherTabs = newOtherTabs.stream()
|
||||||
|
.filter(t -> !t.equals(tab))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
setSaveButtonState(newOrderTabs);
|
||||||
|
// submit these tab lists to adapter
|
||||||
|
if (adapter == null) return;
|
||||||
|
adapter.submitList(newOrderTabs, newOtherTabs, () -> list.postDelayed(() -> adapter.notifyDataSetChanged(), 300));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(final Tab tab) {
|
||||||
|
// Remove this tab from newOrderTabs
|
||||||
|
newOrderTabs = newOrderTabs.stream()
|
||||||
|
.filter(t -> !t.equals(tab))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// Add this tab to newOtherTabs
|
||||||
|
if (newOtherTabs != null) {
|
||||||
|
newOtherTabs = ImmutableList.<Tab>builder()
|
||||||
|
.addAll(newOtherTabs)
|
||||||
|
.add(tab)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
setSaveButtonState(newOrderTabs);
|
||||||
|
// submit these tab lists to adapter
|
||||||
|
if (adapter == null) return;
|
||||||
|
adapter.submitList(newOrderTabs, newOtherTabs, () -> list.postDelayed(() -> {
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
if (tab.getNavigationRootId() == R.id.direct_messages_nav_graph) {
|
||||||
|
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
|
||||||
|
111, 0, R.string.dm_remove_warning, R.string.ok, 0, 0
|
||||||
|
);
|
||||||
|
dialogFragment.show(getChildFragmentManager(), "dm_warning_dialog");
|
||||||
|
}
|
||||||
|
}, 500));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSaveButtonState(final List<Tab> newOrderTabs) {
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
.setEnabled(!newOrderTabs.equals(tabsInPref));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final SimpleCallback simpleCallback = new SimpleCallback(UP | DOWN, 0) {
|
||||||
|
private int movePosition = RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMovementFlags(@NonNull final RecyclerView recyclerView, @NonNull final RecyclerView.ViewHolder viewHolder) {
|
||||||
|
if (viewHolder instanceof DirectUsersAdapter.HeaderViewHolder) return 0;
|
||||||
|
if (viewHolder instanceof TabViewHolder && !((TabViewHolder) viewHolder).isDraggable()) return 0;
|
||||||
|
return super.getMovementFlags(recyclerView, viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChildDraw(@NonNull final Canvas c,
|
||||||
|
@NonNull final RecyclerView recyclerView,
|
||||||
|
@NonNull final RecyclerView.ViewHolder viewHolder,
|
||||||
|
final float dX,
|
||||||
|
final float dY,
|
||||||
|
final int actionState,
|
||||||
|
final boolean isCurrentlyActive) {
|
||||||
|
if (actionState != ACTION_STATE_DRAG) {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final TabsAdapter adapter = (TabsAdapter) recyclerView.getAdapter();
|
||||||
|
if (adapter == null) {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Do not allow dragging into 'Other tabs' category
|
||||||
|
float edgeY = dY;
|
||||||
|
final int lastPosition = adapter.getCurrentCount() - 1;
|
||||||
|
final View view = viewHolder.itemView;
|
||||||
|
// final int topEdge = recyclerView.getTop();
|
||||||
|
final int bottomEdge = view.getHeight() * adapter.getCurrentCount() - view.getBottom();
|
||||||
|
// if (movePosition == 0 && dY < topEdge) {
|
||||||
|
// edgeY = topEdge;
|
||||||
|
// } else
|
||||||
|
if (movePosition >= lastPosition && dY >= bottomEdge) {
|
||||||
|
edgeY = bottomEdge;
|
||||||
|
}
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, edgeY, actionState, isCurrentlyActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMove(@NonNull final RecyclerView recyclerView,
|
||||||
|
@NonNull final RecyclerView.ViewHolder viewHolder,
|
||||||
|
@NonNull final RecyclerView.ViewHolder target) {
|
||||||
|
final TabsAdapter adapter = (TabsAdapter) recyclerView.getAdapter();
|
||||||
|
if (adapter == null) return false;
|
||||||
|
movePosition = target.getBindingAdapterPosition();
|
||||||
|
if (movePosition >= adapter.getCurrentCount()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final int from = viewHolder.getBindingAdapterPosition();
|
||||||
|
final int to = target.getBindingAdapterPosition();
|
||||||
|
adapter.moveItem(from, to);
|
||||||
|
// adapter.notifyItemMoved(from, to);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(@NonNull final RecyclerView.ViewHolder viewHolder, final int direction) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSelectedChanged(@Nullable final RecyclerView.ViewHolder viewHolder, final int actionState) {
|
||||||
|
super.onSelectedChanged(viewHolder, actionState);
|
||||||
|
if (!(viewHolder instanceof TabViewHolder)) {
|
||||||
|
movePosition = RecyclerView.NO_POSITION;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (actionState == ACTION_STATE_DRAG) {
|
||||||
|
((TabViewHolder) viewHolder).setDragging(true);
|
||||||
|
movePosition = viewHolder.getBindingAdapterPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearView(@NonNull final RecyclerView recyclerView,
|
||||||
|
@NonNull final RecyclerView.ViewHolder viewHolder) {
|
||||||
|
super.clearView(recyclerView, viewHolder);
|
||||||
|
((TabViewHolder) viewHolder).setDragging(false);
|
||||||
|
movePosition = RecyclerView.NO_POSITION;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private TabsAdapter adapter;
|
||||||
|
private RecyclerView list;
|
||||||
|
|
||||||
|
public static TabOrderPreferenceDialogFragment newInstance() {
|
||||||
|
final Bundle args = new Bundle();
|
||||||
|
final TabOrderPreferenceDialogFragment fragment = new TabOrderPreferenceDialogFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TabOrderPreferenceDialogFragment() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(@NonNull final Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
try {
|
||||||
|
callback = (Callback) getParentFragment();
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// throw new ClassCastException("Calling fragment must implement TabOrderPreferenceDialogFragment.Callback interface");
|
||||||
|
}
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
|
||||||
|
return new MaterialAlertDialogBuilder(context)
|
||||||
|
.setView(createView())
|
||||||
|
.setPositiveButton(R.string.save, (d, w) -> {
|
||||||
|
final boolean hasChanged = newOrderTabs != null && !newOrderTabs.equals(tabsInPref);
|
||||||
|
if (hasChanged) {
|
||||||
|
saveNewOrder();
|
||||||
|
}
|
||||||
|
if (callback == null) return;
|
||||||
|
callback.onSave(hasChanged);
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.cancel, (dialog, which) -> {
|
||||||
|
if (callback == null) return;
|
||||||
|
callback.onCancel();
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveNewOrder() {
|
||||||
|
final String newOrderString = newOrderTabs.stream()
|
||||||
|
.map(Tab::getGraphName)
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
Utils.settingsHelper.putString(PreferenceKeys.PREF_TAB_ORDER, newOrderString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
final Dialog dialog = getDialog();
|
||||||
|
if (!(dialog instanceof AlertDialog)) return;
|
||||||
|
this.dialog = (AlertDialog) dialog;
|
||||||
|
this.dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private View createView() {
|
||||||
|
list = new RecyclerView(context);
|
||||||
|
list.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
itemTouchHelper = new ItemTouchHelper(simpleCallback);
|
||||||
|
itemTouchHelper.attachToRecyclerView(list);
|
||||||
|
adapter = new TabsAdapter(tabAdapterCallback);
|
||||||
|
list.setAdapter(adapter);
|
||||||
|
final Pair<List<Tab>, List<Tab>> navTabListPair = Utils.getNavTabList(context);
|
||||||
|
tabsInPref = navTabListPair.first;
|
||||||
|
// initially set newOrderTabs and newOtherTabs same as current tabs
|
||||||
|
newOrderTabs = navTabListPair.first;
|
||||||
|
newOtherTabs = navTabListPair.second;
|
||||||
|
adapter.submitList(navTabListPair.first, navTabListPair.second);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Callback {
|
||||||
|
void onSave(final boolean orderHasChanged);
|
||||||
|
|
||||||
|
void onCancel();
|
||||||
|
}
|
||||||
|
}
|
@ -65,13 +65,14 @@ import awais.instagrabber.webservices.GraphQLService;
|
|||||||
import awais.instagrabber.webservices.LocationService;
|
import awais.instagrabber.webservices.LocationService;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.webservices.StoriesService;
|
import awais.instagrabber.webservices.StoriesService;
|
||||||
//import awaisomereport.LogCollector;
|
|
||||||
|
|
||||||
import static androidx.core.content.PermissionChecker.checkSelfPermission;
|
import static androidx.core.content.PermissionChecker.checkSelfPermission;
|
||||||
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
|
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
|
||||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
|
//import awaisomereport.LogCollector;
|
||||||
|
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
|
|
||||||
public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
||||||
private static final String TAG = "LocationFragment";
|
private static final String TAG = "LocationFragment";
|
||||||
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
|
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
|
||||||
|
@ -31,7 +31,6 @@ import awais.instagrabber.R;
|
|||||||
import awais.instagrabber.adapters.NotificationsAdapter;
|
import awais.instagrabber.adapters.NotificationsAdapter;
|
||||||
import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener;
|
import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener;
|
||||||
import awais.instagrabber.databinding.FragmentNotificationsViewerBinding;
|
import awais.instagrabber.databinding.FragmentNotificationsViewerBinding;
|
||||||
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
|
|
||||||
import awais.instagrabber.models.enums.NotificationType;
|
import awais.instagrabber.models.enums.NotificationType;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
|
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
|
||||||
@ -79,8 +78,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
try {
|
try {
|
||||||
binding.swipeRefreshLayout.setRefreshing(false);
|
binding.swipeRefreshLayout.setRefreshing(false);
|
||||||
Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
}
|
} catch (Throwable ignored) {}
|
||||||
catch(Throwable e) {}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -93,10 +91,10 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
@Override
|
@Override
|
||||||
public void onPreviewClick(final Notification model) {
|
public void onPreviewClick(final Notification model) {
|
||||||
final NotificationImage notificationImage = model.getArgs().getMedia().get(0);
|
final NotificationImage notificationImage = model.getArgs().getMedia().get(0);
|
||||||
final long mediaId = Long.valueOf(notificationImage.getId().split("_")[0]);
|
final long mediaId = Long.parseLong(notificationImage.getId().split("_")[0]);
|
||||||
if (model.getType() == NotificationType.RESPONDED_STORY) {
|
if (model.getType() == NotificationType.RESPONDED_STORY) {
|
||||||
final NavDirections action = NotificationsViewerFragmentDirections
|
final NavDirections action = NotificationsViewerFragmentDirections
|
||||||
.actionNotificationsViewerFragmentToStoryViewerFragment(
|
.actionNotificationsToStory(
|
||||||
StoryViewerOptions.forStory(
|
StoryViewerOptions.forStory(
|
||||||
mediaId,
|
mediaId,
|
||||||
model.getArgs().getUsername()));
|
model.getArgs().getUsername()));
|
||||||
@ -278,8 +276,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void openProfile(final String username) {
|
private void openProfile(final String username) {
|
||||||
final NavDirections action = MorePreferencesFragmentDirections
|
final NavDirections action = NotificationsViewerFragmentDirections.actionGlobalProfileFragment("@" + username);
|
||||||
.actionGlobalProfileFragment("@" + username);
|
|
||||||
NavHostFragment.findNavController(this).navigate(action);
|
NavHostFragment.findNavController(this).navigate(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,14 +2,12 @@ package awais.instagrabber.fragments;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -72,7 +70,6 @@ import awais.instagrabber.BuildConfig;
|
|||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.adapters.StoriesAdapter;
|
import awais.instagrabber.adapters.StoriesAdapter;
|
||||||
import awais.instagrabber.asyncs.CreateThreadAction;
|
import awais.instagrabber.asyncs.CreateThreadAction;
|
||||||
import awais.instagrabber.asyncs.PostFetcher;
|
|
||||||
import awais.instagrabber.customviews.helpers.SwipeGestureListener;
|
import awais.instagrabber.customviews.helpers.SwipeGestureListener;
|
||||||
import awais.instagrabber.databinding.FragmentStoryViewerBinding;
|
import awais.instagrabber.databinding.FragmentStoryViewerBinding;
|
||||||
import awais.instagrabber.fragments.main.ProfileFragmentDirections;
|
import awais.instagrabber.fragments.main.ProfileFragmentDirections;
|
||||||
@ -105,7 +102,6 @@ import awais.instagrabber.webservices.DirectMessagesService;
|
|||||||
import awais.instagrabber.webservices.MediaService;
|
import awais.instagrabber.webservices.MediaService;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.webservices.StoriesService;
|
import awais.instagrabber.webservices.StoriesService;
|
||||||
//import awaisomereport.LogCollector;
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
@ -113,9 +109,11 @@ import retrofit2.Response;
|
|||||||
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_THRESHOLD;
|
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_THRESHOLD;
|
||||||
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD;
|
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD;
|
||||||
import static awais.instagrabber.utils.Constants.MARK_AS_SEEN;
|
import static awais.instagrabber.utils.Constants.MARK_AS_SEEN;
|
||||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
|
//import awaisomereport.LogCollector;
|
||||||
|
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
|
|
||||||
public class StoryViewerFragment extends Fragment {
|
public class StoryViewerFragment extends Fragment {
|
||||||
private static final String TAG = "StoryViewerFragment";
|
private static final String TAG = "StoryViewerFragment";
|
||||||
|
|
||||||
@ -137,14 +135,14 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
private String[] mentions;
|
private String[] mentions;
|
||||||
private QuizModel quiz;
|
private QuizModel quiz;
|
||||||
private SliderModel slider;
|
private SliderModel slider;
|
||||||
private MenuItem menuDownload;
|
private MenuItem menuDownload, menuDm, menuProfile;
|
||||||
private MenuItem menuDm;
|
|
||||||
private SimpleExoPlayer player;
|
private SimpleExoPlayer player;
|
||||||
// private boolean isHashtag;
|
// private boolean isHashtag;
|
||||||
// private boolean isLoc;
|
// private boolean isLoc;
|
||||||
// private String highlight;
|
// private String highlight;
|
||||||
private String actionBarTitle;
|
private String actionBarTitle, actionBarSubtitle;
|
||||||
private boolean fetching = false, sticking = false, shouldRefresh = true;
|
private boolean fetching = false, sticking = false, shouldRefresh = true;
|
||||||
|
private boolean downloadVisible = false, dmVisible = false, profileVisible = true;
|
||||||
private int currentFeedStoryIndex;
|
private int currentFeedStoryIndex;
|
||||||
private double sliderValue;
|
private double sliderValue;
|
||||||
private StoriesViewModel storiesViewModel;
|
private StoriesViewModel storiesViewModel;
|
||||||
@ -195,8 +193,10 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
menuInflater.inflate(R.menu.story_menu, menu);
|
menuInflater.inflate(R.menu.story_menu, menu);
|
||||||
menuDownload = menu.findItem(R.id.action_download);
|
menuDownload = menu.findItem(R.id.action_download);
|
||||||
menuDm = menu.findItem(R.id.action_dms);
|
menuDm = menu.findItem(R.id.action_dms);
|
||||||
menuDownload.setVisible(false);
|
menuProfile = menu.findItem(R.id.action_profile);
|
||||||
menuDm.setVisible(false);
|
menuDownload.setVisible(downloadVisible);
|
||||||
|
menuDm.setVisible(dmVisible);
|
||||||
|
menuProfile.setVisible(profileVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -215,7 +215,8 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
else
|
else
|
||||||
ActivityCompat.requestPermissions(requireActivity(), DownloadUtils.PERMS, 8020);
|
ActivityCompat.requestPermissions(requireActivity(), DownloadUtils.PERMS, 8020);
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.action_dms) {
|
}
|
||||||
|
if (itemId == R.id.action_dms) {
|
||||||
final EditText input = new EditText(context);
|
final EditText input = new EditText(context);
|
||||||
input.setHint(R.string.reply_hint);
|
input.setHint(R.string.reply_hint);
|
||||||
new AlertDialog.Builder(context)
|
new AlertDialog.Builder(context)
|
||||||
@ -259,6 +260,9 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (itemId == R.id.action_profile) {
|
||||||
|
openProfile("@" + currentStory.getUsername());
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +285,9 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
|
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setTitle(actionBarTitle);
|
actionBar.setTitle(actionBarTitle);
|
||||||
|
actionBar.setSubtitle(actionBarSubtitle);
|
||||||
}
|
}
|
||||||
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -697,6 +703,10 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
lastSlidePos = 0;
|
lastSlidePos = 0;
|
||||||
if (menuDownload != null) menuDownload.setVisible(false);
|
if (menuDownload != null) menuDownload.setVisible(false);
|
||||||
if (menuDm != null) menuDm.setVisible(false);
|
if (menuDm != null) menuDm.setVisible(false);
|
||||||
|
if (menuProfile != null) menuProfile.setVisible(false);
|
||||||
|
downloadVisible = false;
|
||||||
|
dmVisible = false;
|
||||||
|
profileVisible = false;
|
||||||
binding.imageViewer.setController(null);
|
binding.imageViewer.setController(null);
|
||||||
releasePlayer();
|
releasePlayer();
|
||||||
String currentStoryMediaId = null;
|
String currentStoryMediaId = null;
|
||||||
@ -846,7 +856,6 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
|
|
||||||
final MediaItemType itemType = currentStory.getItemType();
|
final MediaItemType itemType = currentStory.getItemType();
|
||||||
|
|
||||||
if (menuDownload != null) menuDownload.setVisible(false);
|
|
||||||
url = itemType == MediaItemType.MEDIA_TYPE_IMAGE ? currentStory.getStoryUrl() : currentStory.getVideoUrl();
|
url = itemType == MediaItemType.MEDIA_TYPE_IMAGE ? currentStory.getStoryUrl() : currentStory.getVideoUrl();
|
||||||
|
|
||||||
if (itemType != MediaItemType.MEDIA_TYPE_LIVE) {
|
if (itemType != MediaItemType.MEDIA_TYPE_LIVE) {
|
||||||
@ -900,9 +909,10 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
else setupImage();
|
else setupImage();
|
||||||
|
|
||||||
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
|
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
|
||||||
|
actionBarSubtitle = Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L));
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
try {
|
try {
|
||||||
actionBar.setSubtitle(Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L)));
|
actionBar.setSubtitle(actionBarSubtitle);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "refreshStory: ", e);
|
Log.e(TAG, "refreshStory: ", e);
|
||||||
}
|
}
|
||||||
@ -948,11 +958,17 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
final ImageInfo imageInfo,
|
final ImageInfo imageInfo,
|
||||||
final Animatable animatable) {
|
final Animatable animatable) {
|
||||||
if (menuDownload != null) {
|
if (menuDownload != null) {
|
||||||
|
downloadVisible = true;
|
||||||
menuDownload.setVisible(true);
|
menuDownload.setVisible(true);
|
||||||
}
|
}
|
||||||
if (currentStory.canReply() && menuDm != null) {
|
if (currentStory.canReply() && menuDm != null) {
|
||||||
|
dmVisible = true;
|
||||||
menuDm.setVisible(true);
|
menuDm.setVisible(true);
|
||||||
}
|
}
|
||||||
|
if (!TextUtils.isEmpty(currentStory.getUsername())) {
|
||||||
|
profileVisible = true;
|
||||||
|
menuProfile.setVisible(true);
|
||||||
|
}
|
||||||
binding.progressView.setVisibility(View.GONE);
|
binding.progressView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -982,9 +998,18 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
|
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
|
||||||
@NonNull final LoadEventInfo loadEventInfo,
|
@NonNull final LoadEventInfo loadEventInfo,
|
||||||
@NonNull final MediaLoadData mediaLoadData) {
|
@NonNull final MediaLoadData mediaLoadData) {
|
||||||
if (menuDownload != null) menuDownload.setVisible(true);
|
if (menuDownload != null) {
|
||||||
if (currentStory.canReply() && menuDm != null)
|
downloadVisible = true;
|
||||||
|
menuDownload.setVisible(true);
|
||||||
|
}
|
||||||
|
if (currentStory.canReply() && menuDm != null) {
|
||||||
|
dmVisible = true;
|
||||||
menuDm.setVisible(true);
|
menuDm.setVisible(true);
|
||||||
|
}
|
||||||
|
if (!TextUtils.isEmpty(currentStory.getUsername()) && menuProfile != null) {
|
||||||
|
profileVisible = true;
|
||||||
|
menuProfile.setVisible(true);
|
||||||
|
}
|
||||||
binding.progressView.setVisibility(View.GONE);
|
binding.progressView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -993,9 +1018,18 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
|
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
|
||||||
@NonNull final LoadEventInfo loadEventInfo,
|
@NonNull final LoadEventInfo loadEventInfo,
|
||||||
@NonNull final MediaLoadData mediaLoadData) {
|
@NonNull final MediaLoadData mediaLoadData) {
|
||||||
if (menuDownload != null) menuDownload.setVisible(true);
|
if (menuDownload != null) {
|
||||||
if (currentStory.canReply() && menuDm != null)
|
downloadVisible = true;
|
||||||
|
menuDownload.setVisible(true);
|
||||||
|
}
|
||||||
|
if (currentStory.canReply() && menuDm != null) {
|
||||||
|
dmVisible = true;
|
||||||
menuDm.setVisible(true);
|
menuDm.setVisible(true);
|
||||||
|
}
|
||||||
|
if (!TextUtils.isEmpty(currentStory.getUsername()) && menuProfile != null) {
|
||||||
|
profileVisible = true;
|
||||||
|
menuProfile.setVisible(true);
|
||||||
|
}
|
||||||
binding.progressView.setVisibility(View.VISIBLE);
|
binding.progressView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1014,8 +1048,18 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
@NonNull final MediaLoadData mediaLoadData,
|
@NonNull final MediaLoadData mediaLoadData,
|
||||||
@NonNull final IOException error,
|
@NonNull final IOException error,
|
||||||
final boolean wasCanceled) {
|
final boolean wasCanceled) {
|
||||||
if (menuDownload != null) menuDownload.setVisible(false);
|
if (menuDownload != null) {
|
||||||
if (menuDm != null) menuDm.setVisible(false);
|
downloadVisible = false;
|
||||||
|
menuDownload.setVisible(false);
|
||||||
|
}
|
||||||
|
if (menuDm != null) {
|
||||||
|
dmVisible = false;
|
||||||
|
menuDm.setVisible(false);
|
||||||
|
}
|
||||||
|
if (menuProfile != null) {
|
||||||
|
profileVisible = false;
|
||||||
|
menuProfile.setVisible(false);
|
||||||
|
}
|
||||||
binding.progressView.setVisibility(View.GONE);
|
binding.progressView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -83,9 +83,12 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||||||
new FeedStoriesAdapter.OnFeedStoryClickListener() {
|
new FeedStoriesAdapter.OnFeedStoryClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFeedStoryClick(FeedStoryModel model, int position) {
|
public void onFeedStoryClick(FeedStoryModel model, int position) {
|
||||||
final NavDirections action = FeedFragmentDirections
|
final NavController navController = NavHostFragment.findNavController(FeedFragment.this);
|
||||||
.actionFeedFragmentToStoryViewerFragment(StoryViewerOptions.forFeedStoryPosition(position));
|
if (isSafeToNavigate(navController)) {
|
||||||
NavHostFragment.findNavController(FeedFragment.this).navigate(action);
|
final NavDirections action = FeedFragmentDirections
|
||||||
|
.actionFeedFragmentToStoryViewerFragment(StoryViewerOptions.forFeedStoryPosition(position));
|
||||||
|
navController.navigate(action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -437,4 +440,9 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||||||
binding.feedRecyclerView.smoothScrollToPosition(0);
|
binding.feedRecyclerView.smoothScrollToPosition(0);
|
||||||
// binding.storiesContainer.setExpanded(true);
|
// binding.storiesContainer.setExpanded(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSafeToNavigate(final NavController navController) {
|
||||||
|
return navController.getCurrentDestination() != null
|
||||||
|
&& navController.getCurrentDestination().getId() == R.id.feedFragment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,6 +306,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
private AccountRepository accountRepository;
|
private AccountRepository accountRepository;
|
||||||
private FavoriteRepository favoriteRepository;
|
private FavoriteRepository favoriteRepository;
|
||||||
private AppStateViewModel appStateViewModel;
|
private AppStateViewModel appStateViewModel;
|
||||||
|
private boolean disableDm = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
@ -321,8 +322,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
|
mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
|
||||||
userService = isLoggedIn ? UserService.getInstance() : null;
|
userService = isLoggedIn ? UserService.getInstance() : null;
|
||||||
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
||||||
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext()));
|
final Context context = getContext();
|
||||||
favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));
|
if (context == null) return;
|
||||||
|
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context));
|
||||||
|
favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context));
|
||||||
appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
|
appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
@ -577,6 +580,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
|
disableDm = !Utils.isNavRootInCurrentTabs("direct_messages_nav_graph");
|
||||||
if (getArguments() != null) {
|
if (getArguments() != null) {
|
||||||
final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments());
|
final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments());
|
||||||
username = fragmentArgs.getUsername();
|
username = fragmentArgs.getUsername();
|
||||||
@ -938,7 +942,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
}
|
}
|
||||||
profileDetailsBinding.btnSaved.setVisibility(View.GONE);
|
profileDetailsBinding.btnSaved.setVisibility(View.GONE);
|
||||||
profileDetailsBinding.btnLiked.setVisibility(View.GONE);
|
profileDetailsBinding.btnLiked.setVisibility(View.GONE);
|
||||||
profileDetailsBinding.btnDM.setVisibility(View.VISIBLE);
|
profileDetailsBinding.btnDM.setVisibility(disableDm ? View.GONE : View.VISIBLE);
|
||||||
profileDetailsBinding.btnFollow.setVisibility(View.VISIBLE);
|
profileDetailsBinding.btnFollow.setVisibility(View.VISIBLE);
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
@ -1116,23 +1120,25 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
PostItemType.TAGGED);
|
PostItemType.TAGGED);
|
||||||
NavHostFragment.findNavController(this).navigate(action);
|
NavHostFragment.findNavController(this).navigate(action);
|
||||||
});
|
});
|
||||||
profileDetailsBinding.btnDM.setOnClickListener(v -> {
|
if (!disableDm) {
|
||||||
profileDetailsBinding.btnDM.setEnabled(false);
|
profileDetailsBinding.btnDM.setOnClickListener(v -> {
|
||||||
new CreateThreadAction(cookie, profileModel.getPk(), thread -> {
|
profileDetailsBinding.btnDM.setEnabled(false);
|
||||||
if (thread == null) {
|
new CreateThreadAction(cookie, profileModel.getPk(), thread -> {
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
if (thread == null) {
|
||||||
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
|
profileDetailsBinding.btnDM.setEnabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager();
|
||||||
|
if (!inboxManager.containsThread(thread.getThreadId())) {
|
||||||
|
thread.setTemp(true);
|
||||||
|
inboxManager.addThread(thread, 0);
|
||||||
|
}
|
||||||
|
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
|
||||||
profileDetailsBinding.btnDM.setEnabled(true);
|
profileDetailsBinding.btnDM.setEnabled(true);
|
||||||
return;
|
}).execute();
|
||||||
}
|
});
|
||||||
final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager();
|
}
|
||||||
if (!inboxManager.containsThread(thread.getThreadId())) {
|
|
||||||
thread.setTemp(true);
|
|
||||||
inboxManager.addThread(thread, 0);
|
|
||||||
}
|
|
||||||
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
|
|
||||||
profileDetailsBinding.btnDM.setEnabled(true);
|
|
||||||
}).execute();
|
|
||||||
});
|
|
||||||
profileDetailsBinding.mainProfileImage.setOnClickListener(v -> {
|
profileDetailsBinding.mainProfileImage.setOnClickListener(v -> {
|
||||||
if (!hasStories) {
|
if (!hasStories) {
|
||||||
// show profile pic
|
// show profile pic
|
||||||
|
@ -38,6 +38,7 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
|||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
screen.addPreference(getDownloadUserFolderPreference(context));
|
screen.addPreference(getDownloadUserFolderPreference(context));
|
||||||
screen.addPreference(getSaveToCustomFolderPreference(context));
|
screen.addPreference(getSaveToCustomFolderPreference(context));
|
||||||
|
screen.addPreference(getPrependUsernameToFilenamePreference(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Preference getDownloadUserFolderPreference(@NonNull final Context context) {
|
private Preference getDownloadUserFolderPreference(@NonNull final Context context) {
|
||||||
@ -84,6 +85,14 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
|||||||
// Log.d(TAG, "onActivityResult: " + root);
|
// Log.d(TAG, "onActivityResult: " + root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Preference getPrependUsernameToFilenamePreference(@NonNull final Context context) {
|
||||||
|
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
||||||
|
preference.setKey(Constants.DOWNLOAD_PREPEND_USER_NAME);
|
||||||
|
preference.setTitle(R.string.download_prepend_username);
|
||||||
|
preference.setIconSpaceReserved(false);
|
||||||
|
return preference;
|
||||||
|
}
|
||||||
|
|
||||||
public static class SaveToCustomFolderPreference extends Preference {
|
public static class SaveToCustomFolderPreference extends Preference {
|
||||||
private AppCompatTextView customPathTextView;
|
private AppCompatTextView customPathTextView;
|
||||||
private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener;
|
private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package awais.instagrabber.fragments.settings;
|
package awais.instagrabber.fragments.settings;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.ListPreference;
|
import androidx.preference.ListPreference;
|
||||||
@ -12,13 +12,17 @@ import androidx.preference.SwitchPreferenceCompat;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.dialogs.ConfirmDialogFragment;
|
||||||
|
import awais.instagrabber.dialogs.TabOrderPreferenceDialogFragment;
|
||||||
|
import awais.instagrabber.models.Tab;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
public class GeneralPreferencesFragment extends BasePreferencesFragment {
|
public class GeneralPreferencesFragment extends BasePreferencesFragment implements TabOrderPreferenceDialogFragment.Callback {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setupPreferenceScreen(final PreferenceScreen screen) {
|
void setupPreferenceScreen(final PreferenceScreen screen) {
|
||||||
@ -28,12 +32,14 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment {
|
|||||||
final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
screen.addPreference(getDefaultTabPreference(context));
|
screen.addPreference(getDefaultTabPreference(context));
|
||||||
|
screen.addPreference(getTabOrderPreference(context));
|
||||||
}
|
}
|
||||||
screen.addPreference(getUpdateCheckPreference(context));
|
screen.addPreference(getUpdateCheckPreference(context));
|
||||||
screen.addPreference(getFlagSecurePreference(context));
|
screen.addPreference(getFlagSecurePreference(context));
|
||||||
final List<Preference> preferences = FlavorSettings.getInstance().getPreferences(context,
|
final List<Preference> preferences = FlavorSettings.getInstance()
|
||||||
getChildFragmentManager(),
|
.getPreferences(context,
|
||||||
SettingCategory.GENERAL);
|
getChildFragmentManager(),
|
||||||
|
SettingCategory.GENERAL);
|
||||||
if (preferences != null) {
|
if (preferences != null) {
|
||||||
for (final Preference preference : preferences) {
|
for (final Preference preference : preferences) {
|
||||||
screen.addPreference(preference);
|
screen.addPreference(preference);
|
||||||
@ -44,24 +50,36 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment {
|
|||||||
private Preference getDefaultTabPreference(@NonNull final Context context) {
|
private Preference getDefaultTabPreference(@NonNull final Context context) {
|
||||||
final ListPreference preference = new ListPreference(context);
|
final ListPreference preference = new ListPreference(context);
|
||||||
preference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
|
preference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
|
||||||
final TypedArray mainNavIds = getResources().obtainTypedArray(R.array.main_nav_ids);
|
final Pair<List<Tab>, List<Tab>> listPair = Utils.getNavTabList(context);
|
||||||
final int length = mainNavIds.length();
|
final List<Tab> tabs = listPair.first;
|
||||||
final String[] values = new String[length];
|
final String[] titles = tabs.stream()
|
||||||
for (int i = 0; i < length; i++) {
|
.map(Tab::getTitle)
|
||||||
final int resourceId = mainNavIds.getResourceId(i, -1);
|
.toArray(String[]::new);
|
||||||
if (resourceId < 0) continue;
|
final String[] navGraphFileNames = tabs.stream()
|
||||||
values[i] = getResources().getResourceEntryName(resourceId);
|
.map(Tab::getGraphName)
|
||||||
}
|
.toArray(String[]::new);
|
||||||
mainNavIds.recycle();
|
|
||||||
preference.setKey(Constants.DEFAULT_TAB);
|
preference.setKey(Constants.DEFAULT_TAB);
|
||||||
preference.setTitle(R.string.pref_start_screen);
|
preference.setTitle(R.string.pref_start_screen);
|
||||||
preference.setDialogTitle(R.string.pref_start_screen);
|
preference.setDialogTitle(R.string.pref_start_screen);
|
||||||
preference.setEntries(R.array.main_nav_ids_values);
|
preference.setEntries(titles);
|
||||||
preference.setEntryValues(values);
|
preference.setEntryValues(navGraphFileNames);
|
||||||
preference.setIconSpaceReserved(false);
|
preference.setIconSpaceReserved(false);
|
||||||
return preference;
|
return preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Preference getTabOrderPreference(@NonNull final Context context) {
|
||||||
|
final Preference preference = new Preference(context);
|
||||||
|
preference.setTitle(R.string.tab_order);
|
||||||
|
preference.setIconSpaceReserved(false);
|
||||||
|
preference.setOnPreferenceClickListener(preference1 -> {
|
||||||
|
final TabOrderPreferenceDialogFragment dialogFragment = TabOrderPreferenceDialogFragment.newInstance();
|
||||||
|
dialogFragment.show(getChildFragmentManager(), "tab_order_dialog");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return preference;
|
||||||
|
}
|
||||||
|
|
||||||
private Preference getUpdateCheckPreference(@NonNull final Context context) {
|
private Preference getUpdateCheckPreference(@NonNull final Context context) {
|
||||||
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
||||||
preference.setKey(Constants.CHECK_UPDATES);
|
preference.setKey(Constants.CHECK_UPDATES);
|
||||||
@ -82,4 +100,22 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSave(final boolean orderHasChanged) {
|
||||||
|
if (!orderHasChanged) return;
|
||||||
|
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
|
||||||
|
111,
|
||||||
|
0,
|
||||||
|
R.string.tab_order_start_next_launch,
|
||||||
|
R.string.ok,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
dialogFragment.show(getChildFragmentManager(), "tab_order_set_dialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,6 @@ import android.widget.Toast;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.navigation.NavController;
|
import androidx.navigation.NavController;
|
||||||
import androidx.navigation.NavDirections;
|
import androidx.navigation.NavDirections;
|
||||||
@ -27,6 +25,7 @@ import java.util.List;
|
|||||||
import awais.instagrabber.BuildConfig;
|
import awais.instagrabber.BuildConfig;
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.activities.Login;
|
import awais.instagrabber.activities.Login;
|
||||||
|
import awais.instagrabber.activities.MainActivity;
|
||||||
import awais.instagrabber.databinding.PrefAccountSwitcherBinding;
|
import awais.instagrabber.databinding.PrefAccountSwitcherBinding;
|
||||||
import awais.instagrabber.db.datasources.AccountDataSource;
|
import awais.instagrabber.db.datasources.AccountDataSource;
|
||||||
import awais.instagrabber.db.entities.Account;
|
import awais.instagrabber.db.entities.Account;
|
||||||
@ -34,10 +33,13 @@ import awais.instagrabber.db.repositories.AccountRepository;
|
|||||||
import awais.instagrabber.db.repositories.RepositoryCallback;
|
import awais.instagrabber.db.repositories.RepositoryCallback;
|
||||||
import awais.instagrabber.dialogs.AccountSwitcherDialogFragment;
|
import awais.instagrabber.dialogs.AccountSwitcherDialogFragment;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
import awais.instagrabber.utils.FlavorTown;
|
import awais.instagrabber.utils.FlavorTown;
|
||||||
|
import awais.instagrabber.utils.ProcessPhoenix;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.webservices.UserService;
|
import awais.instagrabber.webservices.UserService;
|
||||||
|
|
||||||
@ -55,8 +57,10 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
|
|||||||
void setupPreferenceScreen(final PreferenceScreen screen) {
|
void setupPreferenceScreen(final PreferenceScreen screen) {
|
||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
||||||
|
final MainActivity activity = (MainActivity) getActivity();
|
||||||
// screen.addPreference(new MoreHeaderPreference(getContext()));
|
// screen.addPreference(new MoreHeaderPreference(getContext()));
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
|
final Resources resources = context.getResources();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context));
|
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context));
|
||||||
final PreferenceCategory accountCategory = new PreferenceCategory(context);
|
final PreferenceCategory accountCategory = new PreferenceCategory(context);
|
||||||
@ -67,11 +71,15 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
|
|||||||
accountCategory.setSummary(R.string.account_hint);
|
accountCategory.setSummary(R.string.account_hint);
|
||||||
accountCategory.addPreference(getAccountSwitcherPreference(cookie, context));
|
accountCategory.addPreference(getAccountSwitcherPreference(cookie, context));
|
||||||
accountCategory.addPreference(getPreference(R.string.logout, R.string.logout_summary, R.drawable.ic_logout_24, preference -> {
|
accountCategory.addPreference(getPreference(R.string.logout, R.string.logout_summary, R.drawable.ic_logout_24, preference -> {
|
||||||
if (getContext() == null) return false;
|
final Context context1 = getContext();
|
||||||
|
if (context1 == null) return false;
|
||||||
CookieUtils.setupCookies("LOGOUT");
|
CookieUtils.setupCookies("LOGOUT");
|
||||||
shouldRecreate();
|
// shouldRecreate();
|
||||||
Toast.makeText(context, R.string.logout_success, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context1, R.string.logout_success, Toast.LENGTH_SHORT).show();
|
||||||
settingsHelper.putString(Constants.COOKIE, "");
|
settingsHelper.putString(Constants.COOKIE, "");
|
||||||
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
|
ProcessPhoenix.triggerRebirth(context1);
|
||||||
|
}, 200);
|
||||||
return true;
|
return true;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -99,9 +107,14 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
|
|||||||
CookieUtils.removeAllAccounts(context, new RepositoryCallback<Void>() {
|
CookieUtils.removeAllAccounts(context, new RepositoryCallback<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(final Void result) {
|
public void onSuccess(final Void result) {
|
||||||
shouldRecreate();
|
// shouldRecreate();
|
||||||
Toast.makeText(context, R.string.logout_success, Toast.LENGTH_SHORT).show();
|
final Context context1 = getContext();
|
||||||
|
if (context1 == null) return;
|
||||||
|
Toast.makeText(context1, R.string.logout_success, Toast.LENGTH_SHORT).show();
|
||||||
settingsHelper.putString(Constants.COOKIE, "");
|
settingsHelper.putString(Constants.COOKIE, "");
|
||||||
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
|
ProcessPhoenix.triggerRebirth(context1);
|
||||||
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -135,13 +148,30 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
|
|||||||
screen.addPreference(getDivider(context));
|
screen.addPreference(getDivider(context));
|
||||||
final NavController navController = NavHostFragment.findNavController(this);
|
final NavController navController = NavHostFragment.findNavController(this);
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
screen.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> {
|
boolean showActivity = true;
|
||||||
if (isSafeToNavigate(navController)) {
|
boolean showExplore = false;
|
||||||
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif");
|
if (activity != null) {
|
||||||
navController.navigate(navDirections);
|
showActivity = !Utils.isNavRootInCurrentTabs("notification_viewer_nav_graph");
|
||||||
}
|
showExplore = !Utils.isNavRootInCurrentTabs("discover_nav_graph");
|
||||||
return true;
|
}
|
||||||
}));
|
if (showActivity) {
|
||||||
|
screen.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> {
|
||||||
|
if (isSafeToNavigate(navController)) {
|
||||||
|
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif");
|
||||||
|
navController.navigate(navDirections);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (showExplore) {
|
||||||
|
screen.addPreference(getPreference(R.string.title_discover, R.drawable.ic_explore_24, preference -> {
|
||||||
|
if (isSafeToNavigate(navController)) {
|
||||||
|
navController.navigate(R.id.discover_nav_graph);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
screen.addPreference(getPreference(R.string.action_ayml, R.drawable.ic_suggested_users, preference -> {
|
screen.addPreference(getPreference(R.string.action_ayml, R.drawable.ic_suggested_users, preference -> {
|
||||||
if (isSafeToNavigate(navController)) {
|
if (isSafeToNavigate(navController)) {
|
||||||
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml");
|
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml");
|
||||||
@ -157,13 +187,21 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
|
|||||||
return true;
|
return true;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
screen.addPreference(getPreference(R.string.title_favorites, R.drawable.ic_star_24, preference -> {
|
|
||||||
if (isSafeToNavigate(navController)) {
|
// Check if favorites has been added as a tab. And if so, do not add in this list
|
||||||
final NavDirections navDirections = MorePreferencesFragmentDirections.actionMorePreferencesFragmentToFavoritesFragment();
|
boolean showFavorites = true;
|
||||||
navController.navigate(navDirections);
|
if (activity != null) {
|
||||||
}
|
showFavorites = !Utils.isNavRootInCurrentTabs("favorites_nav_graph");
|
||||||
return true;
|
}
|
||||||
}));
|
if (showFavorites) {
|
||||||
|
screen.addPreference(getPreference(R.string.title_favorites, R.drawable.ic_star_24, preference -> {
|
||||||
|
if (isSafeToNavigate(navController)) {
|
||||||
|
final NavDirections navDirections = MorePreferencesFragmentDirections.actionMorePreferencesFragmentToFavoritesFragment();
|
||||||
|
navController.navigate(navDirections);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
screen.addPreference(getDivider(context));
|
screen.addPreference(getDivider(context));
|
||||||
screen.addPreference(getPreference(R.string.action_settings, R.drawable.ic_outline_settings_24, preference -> {
|
screen.addPreference(getPreference(R.string.action_settings, R.drawable.ic_outline_settings_24, preference -> {
|
||||||
@ -193,7 +231,8 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
|
|||||||
BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")",
|
BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")",
|
||||||
-1,
|
-1,
|
||||||
preference -> {
|
preference -> {
|
||||||
FlavorTown.updateCheck((AppCompatActivity) requireActivity(), true);
|
if (BuildConfig.isPre) return true;
|
||||||
|
FlavorTown.updateCheck(activity, true);
|
||||||
return true;
|
return true;
|
||||||
}));
|
}));
|
||||||
screen.addPreference(getDivider(context));
|
screen.addPreference(getDivider(context));
|
||||||
@ -235,9 +274,14 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
|
|||||||
new RepositoryCallback<Account>() {
|
new RepositoryCallback<Account>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(final Account result) {
|
public void onSuccess(final Account result) {
|
||||||
final FragmentActivity activity = getActivity();
|
// final FragmentActivity activity = getActivity();
|
||||||
if (activity == null) return;
|
// if (activity == null) return;
|
||||||
activity.recreate();
|
// activity.recreate();
|
||||||
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
ProcessPhoenix.triggerRebirth(context);
|
||||||
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,4 +6,5 @@ public final class PreferenceKeys {
|
|||||||
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT = "enable_dm_auto_refresh_freq_unit";
|
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT = "enable_dm_auto_refresh_freq_unit";
|
||||||
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER = "enable_dm_auto_refresh_freq_number";
|
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER = "enable_dm_auto_refresh_freq_number";
|
||||||
public static final String PREF_ENABLE_SENTRY = "enable_sentry";
|
public static final String PREF_ENABLE_SENTRY = "enable_sentry";
|
||||||
|
public static final String PREF_TAB_ORDER = "tab_order";
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,14 @@ public class StoriesPreferencesFragment extends BasePreferencesFragment {
|
|||||||
return preference;
|
return preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Preference getHideMutedReelsPreference(@NonNull final Context context) {
|
||||||
|
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
||||||
|
preference.setKey(Constants.HIDE_MUTED_REELS);
|
||||||
|
preference.setTitle(R.string.hide_muted_reels_setting);
|
||||||
|
preference.setIconSpaceReserved(false);
|
||||||
|
return preference;
|
||||||
|
}
|
||||||
|
|
||||||
private Preference getMarkStoriesSeenPreference(@NonNull final Context context) {
|
private Preference getMarkStoriesSeenPreference(@NonNull final Context context) {
|
||||||
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
||||||
preference.setKey(Constants.MARK_AS_SEEN);
|
preference.setKey(Constants.MARK_AS_SEEN);
|
||||||
|
110
app/src/main/java/awais/instagrabber/models/Tab.java
Normal file
110
app/src/main/java/awais/instagrabber/models/Tab.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package awais.instagrabber.models;
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.annotation.IdRes;
|
||||||
|
import androidx.annotation.NavigationRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Tab {
|
||||||
|
private final int iconResId;
|
||||||
|
private final String title;
|
||||||
|
private final boolean removable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is name part of the navigation resource
|
||||||
|
* eg: @navigation/<b>graphName</b>
|
||||||
|
*/
|
||||||
|
private final String graphName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the actual resource id of the navigation resource (R.navigation.graphName = navigationResId)
|
||||||
|
*/
|
||||||
|
private final int navigationResId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the resource id of the root navigation tag of the navigation resource.
|
||||||
|
* <p>eg: inside R.navigation.direct_messages_nav_graph, the id of the root tag is R.id.direct_messages_nav_graph.
|
||||||
|
* <p>So this field would equal to the value of R.id.direct_messages_nav_graph
|
||||||
|
*/
|
||||||
|
private final int navigationRootId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the start destination of the nav graph
|
||||||
|
*/
|
||||||
|
private final int startDestinationFragmentId;
|
||||||
|
|
||||||
|
public Tab(@DrawableRes final int iconResId,
|
||||||
|
@NonNull final String title,
|
||||||
|
final boolean removable,
|
||||||
|
@NonNull final String graphName,
|
||||||
|
@NavigationRes final int navigationResId,
|
||||||
|
@IdRes final int navigationRootId,
|
||||||
|
@IdRes final int startDestinationFragmentId) {
|
||||||
|
this.iconResId = iconResId;
|
||||||
|
this.title = title;
|
||||||
|
this.removable = removable;
|
||||||
|
this.graphName = graphName;
|
||||||
|
this.navigationResId = navigationResId;
|
||||||
|
this.navigationRootId = navigationRootId;
|
||||||
|
this.startDestinationFragmentId = startDestinationFragmentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIconResId() {
|
||||||
|
return iconResId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRemovable() {
|
||||||
|
return removable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGraphName() {
|
||||||
|
return graphName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNavigationResId() {
|
||||||
|
return navigationResId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNavigationRootId() {
|
||||||
|
return navigationRootId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartDestinationFragmentId() {
|
||||||
|
return startDestinationFragmentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final Tab tab = (Tab) o;
|
||||||
|
return iconResId == tab.iconResId &&
|
||||||
|
removable == tab.removable &&
|
||||||
|
navigationResId == tab.navigationResId &&
|
||||||
|
navigationRootId == tab.navigationRootId &&
|
||||||
|
startDestinationFragmentId == tab.startDestinationFragmentId &&
|
||||||
|
Objects.equals(title, tab.title) &&
|
||||||
|
Objects.equals(graphName, tab.graphName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(iconResId, title, removable, graphName, navigationResId, navigationRootId, startDestinationFragmentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Tab{" +
|
||||||
|
"title='" + title + '\'' +
|
||||||
|
", removable=" + removable +
|
||||||
|
", graphName='" + graphName + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ package awais.instagrabber.repositories;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.GET;
|
import retrofit2.http.GET;
|
||||||
import retrofit2.http.QueryMap;
|
import retrofit2.http.QueryMap;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package awais.instagrabber.repositories.responses.notification;
|
package awais.instagrabber.repositories.responses.notification;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
public class NotificationCounts {
|
public class NotificationCounts {
|
||||||
private final int commentLikes;
|
private final int commentLikes;
|
||||||
private final int usertags;
|
private final int usertags;
|
||||||
|
@ -2,8 +2,6 @@ package awais.instagrabber.repositories.responses.search;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import awais.instagrabber.repositories.responses.User;
|
|
||||||
|
|
||||||
public class SearchResponse {
|
public class SearchResponse {
|
||||||
// app
|
// app
|
||||||
private final List<SearchItem> list;
|
private final List<SearchItem> list;
|
||||||
|
@ -20,6 +20,7 @@ public final class Constants {
|
|||||||
// boolean prefs
|
// boolean prefs
|
||||||
public static final String DOWNLOAD_USER_FOLDER = "download_user_folder";
|
public static final String DOWNLOAD_USER_FOLDER = "download_user_folder";
|
||||||
public static final String TOGGLE_KEYWORD_FILTER = "toggle_keyword_filter";
|
public static final String TOGGLE_KEYWORD_FILTER = "toggle_keyword_filter";
|
||||||
|
public static final String DOWNLOAD_PREPEND_USER_NAME = "download_user_name";
|
||||||
// deprecated: public static final String BOTTOM_TOOLBAR = "bottom_toolbar";
|
// deprecated: public static final String BOTTOM_TOOLBAR = "bottom_toolbar";
|
||||||
public static final String FOLDER_SAVE_TO = "saved_to";
|
public static final String FOLDER_SAVE_TO = "saved_to";
|
||||||
public static final String AUTOPLAY_VIDEOS = "autoplay_videos";
|
public static final String AUTOPLAY_VIDEOS = "autoplay_videos";
|
||||||
@ -28,6 +29,7 @@ public final class Constants {
|
|||||||
public static final String CUSTOM_DATE_TIME_FORMAT_ENABLED = "data_time_custom_enabled";
|
public static final String CUSTOM_DATE_TIME_FORMAT_ENABLED = "data_time_custom_enabled";
|
||||||
public static final String SWAP_DATE_TIME_FORMAT_ENABLED = "swap_date_time_enabled";
|
public static final String SWAP_DATE_TIME_FORMAT_ENABLED = "swap_date_time_enabled";
|
||||||
public static final String MARK_AS_SEEN = "mark_as_seen";
|
public static final String MARK_AS_SEEN = "mark_as_seen";
|
||||||
|
public static final String HIDE_MUTED_REELS = "hide_muted_reels";
|
||||||
public static final String DM_MARK_AS_SEEN = "dm_mark_as_seen";
|
public static final String DM_MARK_AS_SEEN = "dm_mark_as_seen";
|
||||||
// deprecated: public static final String INSTADP = "instadp";
|
// deprecated: public static final String INSTADP = "instadp";
|
||||||
// deprecated: public static final String STORIESIG = "storiesig";
|
// deprecated: public static final String STORIESIG = "storiesig";
|
||||||
@ -79,7 +81,6 @@ public final class Constants {
|
|||||||
// public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc";
|
// public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc";
|
||||||
public static final String BREADCRUMB_KEY = "iN4$aGr0m";
|
public static final String BREADCRUMB_KEY = "iN4$aGr0m";
|
||||||
public static final int LOGIN_RESULT_CODE = 5000;
|
public static final int LOGIN_RESULT_CODE = 5000;
|
||||||
public static final String FDROID_SHA1_FINGERPRINT = "C1661EB8FD09F618307E687786D5E5056F65084D";
|
|
||||||
public static final String SKIPPED_VERSION = "skipped_version";
|
public static final String SKIPPED_VERSION = "skipped_version";
|
||||||
public static final String DEFAULT_TAB = "default_tab";
|
public static final String DEFAULT_TAB = "default_tab";
|
||||||
public static final String PREF_DARK_THEME = "dark_theme";
|
public static final String PREF_DARK_THEME = "dark_theme";
|
||||||
@ -113,6 +114,7 @@ public final class Constants {
|
|||||||
public static final int SHOW_ACTIVITY_REQUEST_CODE = 1738;
|
public static final int SHOW_ACTIVITY_REQUEST_CODE = 1738;
|
||||||
public static final int SHOW_DM_THREAD = 2000;
|
public static final int SHOW_DM_THREAD = 2000;
|
||||||
public static final int DM_SYNC_SERVICE_REQUEST_CODE = 3000;
|
public static final int DM_SYNC_SERVICE_REQUEST_CODE = 3000;
|
||||||
|
public static final int GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE = 7777;
|
||||||
|
|
||||||
public static final String ACTION_SHOW_ACTIVITY = "show_activity";
|
public static final String ACTION_SHOW_ACTIVITY = "show_activity";
|
||||||
public static final String ACTION_SHOW_DM_THREAD = "show_dm_thread";
|
public static final String ACTION_SHOW_DM_THREAD = "show_dm_thread";
|
||||||
|
@ -157,12 +157,21 @@ public final class ExportImportUtils {
|
|||||||
query,
|
query,
|
||||||
favoriteType,
|
favoriteType,
|
||||||
favsObject.optString("s"),
|
favsObject.optString("s"),
|
||||||
favoriteType == FavoriteType.HASHTAG ? null
|
favoriteType == FavoriteType.USER ? favsObject.optString("pic_url") : null,
|
||||||
: favsObject.optString("pic_url"),
|
|
||||||
new Date(favsObject.getLong("d")));
|
new Date(favsObject.getLong("d")));
|
||||||
// Log.d(TAG, "importJson: favoriteModel: " + favoriteModel);
|
// Log.d(TAG, "importJson: favoriteModel: " + favoriteModel);
|
||||||
FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context))
|
final FavoriteRepository favRepo = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context));
|
||||||
.insertOrUpdateFavorite(favorite, null);
|
favRepo.getFavorite(query, favoriteType, new RepositoryCallback<Favorite>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final Favorite result) {
|
||||||
|
// local has priority since it's more frequently updated
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDataNotAvailable() {
|
||||||
|
favRepo.insertOrUpdateFavorite(favorite, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,104 +1,72 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.Signature;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
import java.util.Objects;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
import javax.security.cert.CertificateException;
|
import java.util.regex.Pattern;
|
||||||
import javax.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import awais.instagrabber.BuildConfig;
|
import awais.instagrabber.BuildConfig;
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.databinding.DialogUpdateBinding;
|
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
public final class FlavorTown {
|
public final class FlavorTown {
|
||||||
private static final String TAG = "FlavorTown";
|
private static final String TAG = "FlavorTown";
|
||||||
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
private static final UpdateChecker UPDATE_CHECKER = UpdateChecker.getInstance();
|
||||||
private static AlertDialog dialog;
|
private static final Pattern VERSION_NAME_PATTERN = Pattern.compile("v?(\\d+\\.\\d+\\.\\d+)(?:_?)(\\w*)(?:-?)(\\w*)");
|
||||||
|
|
||||||
|
private static boolean checking = false;
|
||||||
|
|
||||||
public static void updateCheck(@NonNull final AppCompatActivity context) {
|
public static void updateCheck(@NonNull final AppCompatActivity context) {
|
||||||
updateCheck(context, false);
|
updateCheck(context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("PackageManagerGetSignatures")
|
public static void updateCheck(@NonNull final AppCompatActivity context,
|
||||||
public static void updateCheck(@NonNull final AppCompatActivity context, final boolean force) {
|
final boolean force) {
|
||||||
boolean isInstalledFromFdroid = false;
|
if (checking) return;
|
||||||
final PackageInfo packageInfo;
|
checking = true;
|
||||||
try {
|
AppExecutors.getInstance().networkIO().execute(() -> {
|
||||||
packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
|
final String onlineVersionName = UPDATE_CHECKER.getLatestVersion();
|
||||||
for (Signature signature : packageInfo.signatures) {
|
if (onlineVersionName == null) return;
|
||||||
final X509Certificate cert = X509Certificate.getInstance(signature.toByteArray());
|
final String onlineVersion = getVersion(onlineVersionName);
|
||||||
final String fingerprint = bytesToHex(MessageDigest.getInstance("SHA-1").digest(cert.getEncoded()));
|
final String localVersion = getVersion(BuildConfig.VERSION_NAME);
|
||||||
isInstalledFromFdroid = fingerprint.equals(Constants.FDROID_SHA1_FINGERPRINT);
|
if (Objects.equals(onlineVersion, localVersion)) {
|
||||||
// Log.d(TAG, "fingerprint:" + fingerprint);
|
if (force) {
|
||||||
}
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
} catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException | CertificateException e) {
|
final Context applicationContext = context.getApplicationContext();
|
||||||
Log.e(TAG, "Error", e);
|
// Check if app was closed or crashed before reaching here
|
||||||
}
|
if (applicationContext == null) return;
|
||||||
if (isInstalledFromFdroid) return;
|
// Show toast if version number preference was tapped
|
||||||
final DialogUpdateBinding binding = DialogUpdateBinding.inflate(context.getLayoutInflater(), null, false);
|
Toast.makeText(applicationContext, R.string.on_latest_version, Toast.LENGTH_SHORT).show();
|
||||||
binding.skipUpdate.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
});
|
||||||
if (dialog == null) return;
|
}
|
||||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!isChecked);
|
|
||||||
});
|
|
||||||
Resources res = context.getResources();
|
|
||||||
new UpdateChecker(version -> {
|
|
||||||
if (force && version.equals(BuildConfig.VERSION_NAME)) {
|
|
||||||
Toast.makeText(context, "You're already on the latest version", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION);
|
final boolean shouldShowDialog = UpdateCheckCommon.shouldShowUpdateDialog(force, onlineVersionName);
|
||||||
final boolean shouldShowDialog = force || (!version.equals(BuildConfig.VERSION_NAME) && !BuildConfig.DEBUG && !skippedVersion
|
|
||||||
.equals(version));
|
|
||||||
if (!shouldShowDialog) return;
|
if (!shouldShowDialog) return;
|
||||||
dialog = new AlertDialog.Builder(context)
|
UpdateCheckCommon.showUpdateDialog(context, onlineVersionName, (dialog, which) -> {
|
||||||
.setTitle(res.getString(R.string.update_available, version))
|
UPDATE_CHECKER.onDownload(context);
|
||||||
.setView(binding.getRoot())
|
dialog.dismiss();
|
||||||
.setNeutralButton(R.string.cancel, (dialog, which) -> {
|
});
|
||||||
if (binding.skipUpdate.isChecked()) {
|
});
|
||||||
settingsHelper.putString(Constants.SKIPPED_VERSION, version);
|
}
|
||||||
}
|
|
||||||
dialog.dismiss();
|
private static String getVersion(@NonNull final String versionName) {
|
||||||
})
|
final Matcher matcher = VERSION_NAME_PATTERN.matcher(versionName);
|
||||||
.setPositiveButton(R.string.action_github, (dialog1, which) -> {
|
if (!matcher.matches()) return versionName;
|
||||||
try {
|
try {
|
||||||
context.startActivity(new Intent(Intent.ACTION_VIEW).setData(
|
return matcher.group(1);
|
||||||
Uri.parse("https://github.com/austinhuang0131/instagrabber/releases/latest")));
|
} catch (Exception e) {
|
||||||
} catch (final ActivityNotFoundException e) {
|
Log.e(TAG, "getVersion: ", e);
|
||||||
// do nothing
|
}
|
||||||
}
|
return versionName;
|
||||||
})
|
|
||||||
// if we don't show dialog for fdroid users, is the below required?
|
|
||||||
.setNegativeButton(R.string.action_fdroid, (dialog, which) -> {
|
|
||||||
try {
|
|
||||||
context.startActivity(new Intent(Intent.ACTION_VIEW).setData(
|
|
||||||
Uri.parse("https://f-droid.org/packages/me.austinhuang.instagrabber/")));
|
|
||||||
} catch (final ActivityNotFoundException e) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void changelogCheck(@NonNull final Context context) {
|
public static void changelogCheck(@NonNull final Context context) {
|
||||||
@ -121,14 +89,4 @@ public final class FlavorTown {
|
|||||||
settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE);
|
settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String bytesToHex(byte[] bytes) {
|
|
||||||
char[] hexChars = new char[bytes.length * 2];
|
|
||||||
for (int j = 0; j < bytes.length; j++) {
|
|
||||||
int v = bytes[j] & 0xFF;
|
|
||||||
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
|
|
||||||
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
|
||||||
}
|
|
||||||
return new String(hexChars);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -16,7 +16,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import awais.instagrabber.models.UploadPhotoOptions;
|
import awais.instagrabber.models.UploadPhotoOptions;
|
||||||
import awais.instagrabber.models.UploadVideoOptions;
|
import awais.instagrabber.models.UploadVideoOptions;
|
||||||
import awais.instagrabber.webservices.AddCookiesInterceptor;
|
import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Headers;
|
import okhttp3.Headers;
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
|
111
app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java
Normal file
111
app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Jake Wharton
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package awais.instagrabber.utils;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Process;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
||||||
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process Phoenix facilitates restarting your application process. This should only be used for
|
||||||
|
* things like fundamental state changes in your debug builds (e.g., changing from staging to
|
||||||
|
* production).
|
||||||
|
* <p>
|
||||||
|
* Trigger process recreation by calling {@link #triggerRebirth} with a {@link Context} instance.
|
||||||
|
*/
|
||||||
|
public final class ProcessPhoenix extends Activity {
|
||||||
|
private static final String KEY_RESTART_INTENTS = "phoenix_restart_intents";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call to restart the application process using the {@linkplain Intent#CATEGORY_DEFAULT default}
|
||||||
|
* activity as an intent.
|
||||||
|
* <p>
|
||||||
|
* Behavior of the current process after invoking this method is undefined.
|
||||||
|
*/
|
||||||
|
public static void triggerRebirth(Context context) {
|
||||||
|
triggerRebirth(context, getRestartIntent(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call to restart the application process using the specified intents.
|
||||||
|
* <p>
|
||||||
|
* Behavior of the current process after invoking this method is undefined.
|
||||||
|
*/
|
||||||
|
public static void triggerRebirth(Context context, Intent... nextIntents) {
|
||||||
|
Intent intent = new Intent(context, ProcessPhoenix.class);
|
||||||
|
intent.addFlags(FLAG_ACTIVITY_NEW_TASK); // In case we are called with non-Activity context.
|
||||||
|
intent.putParcelableArrayListExtra(KEY_RESTART_INTENTS, new ArrayList<>(Arrays.asList(nextIntents)));
|
||||||
|
context.startActivity(intent);
|
||||||
|
if (context instanceof Activity) {
|
||||||
|
((Activity) context).finish();
|
||||||
|
}
|
||||||
|
Runtime.getRuntime().exit(0); // Kill kill kill!
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Intent getRestartIntent(Context context) {
|
||||||
|
String packageName = context.getPackageName();
|
||||||
|
Intent defaultIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
|
||||||
|
if (defaultIntent != null) {
|
||||||
|
defaultIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
|
return defaultIntent;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Unable to determine default activity for "
|
||||||
|
+ packageName
|
||||||
|
+ ". Does an activity specify the DEFAULT category in its intent filter?");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
ArrayList<Intent> intents = getIntent().getParcelableArrayListExtra(KEY_RESTART_INTENTS);
|
||||||
|
startActivities(intents.toArray(new Intent[intents.size()]));
|
||||||
|
finish();
|
||||||
|
Runtime.getRuntime().exit(0); // Kill kill kill!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current process is a temporary Phoenix Process.
|
||||||
|
* This can be used to avoid initialisation of unused resources or to prevent running code that
|
||||||
|
* is not multi-process ready.
|
||||||
|
*
|
||||||
|
* @return true if the current process is a temporary Phoenix Process
|
||||||
|
*/
|
||||||
|
public static boolean isPhoenixProcess(Context context) {
|
||||||
|
int currentPid = Process.myPid();
|
||||||
|
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
List<ActivityManager.RunningAppProcessInfo> runningProcesses = manager.getRunningAppProcesses();
|
||||||
|
if (runningProcesses != null) {
|
||||||
|
for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
|
||||||
|
if (processInfo.pid == currentPid && processInfo.processName.endsWith(":phoenix")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -1089,12 +1089,19 @@ public final class ResponseBodyUtils {
|
|||||||
if (imageVersions2 == null) return null;
|
if (imageVersions2 == null) return null;
|
||||||
final List<MediaCandidate> candidates = imageVersions2.getCandidates();
|
final List<MediaCandidate> candidates = imageVersions2.getCandidates();
|
||||||
if (candidates == null || candidates.isEmpty()) return null;
|
if (candidates == null || candidates.isEmpty()) return null;
|
||||||
final List<MediaCandidate> sortedCandidates = candidates
|
final boolean isSquare = Integer.compare(media.getOriginalWidth(), media.getOriginalHeight()) == 0;
|
||||||
.stream()
|
final List<MediaCandidate> sortedCandidates = candidates.stream()
|
||||||
.sorted((c1, c2) -> Integer.compare(c2.getWidth(), c1.getWidth()))
|
.sorted((c1, c2) -> Integer.compare(c2.getWidth(), c1.getWidth()))
|
||||||
// .filter(c -> c.getWidth() < type.getValue())
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
final MediaCandidate candidate = sortedCandidates.get(0);
|
if (sortedCandidates.size() == 1) return sortedCandidates.get(0).getUrl();
|
||||||
|
final List<MediaCandidate> filteredCandidates = sortedCandidates.stream()
|
||||||
|
.filter(c ->
|
||||||
|
c.getWidth() <= media.getOriginalWidth()
|
||||||
|
&& c.getWidth() <= type.getValue()
|
||||||
|
&& (isSquare || Integer.compare(c.getWidth(), c.getHeight()) != 0)
|
||||||
|
)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
final MediaCandidate candidate = filteredCandidates.get(0);
|
||||||
if (candidate == null) return null;
|
if (candidate == null) return null;
|
||||||
return candidate.getUrl();
|
return candidate.getUrl();
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_D
|
|||||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT;
|
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT;
|
||||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_NOTIFICATIONS;
|
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_NOTIFICATIONS;
|
||||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY;
|
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY;
|
||||||
|
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_TAB_ORDER;
|
||||||
import static awais.instagrabber.utils.Constants.APP_LANGUAGE;
|
import static awais.instagrabber.utils.Constants.APP_LANGUAGE;
|
||||||
import static awais.instagrabber.utils.Constants.APP_THEME;
|
import static awais.instagrabber.utils.Constants.APP_THEME;
|
||||||
import static awais.instagrabber.utils.Constants.APP_UA;
|
import static awais.instagrabber.utils.Constants.APP_UA;
|
||||||
@ -33,16 +34,18 @@ import static awais.instagrabber.utils.Constants.DATE_TIME_SELECTION;
|
|||||||
import static awais.instagrabber.utils.Constants.DEFAULT_TAB;
|
import static awais.instagrabber.utils.Constants.DEFAULT_TAB;
|
||||||
import static awais.instagrabber.utils.Constants.DEVICE_UUID;
|
import static awais.instagrabber.utils.Constants.DEVICE_UUID;
|
||||||
import static awais.instagrabber.utils.Constants.DM_MARK_AS_SEEN;
|
import static awais.instagrabber.utils.Constants.DM_MARK_AS_SEEN;
|
||||||
|
import static awais.instagrabber.utils.Constants.DOWNLOAD_PREPEND_USER_NAME;
|
||||||
import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER;
|
import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER;
|
||||||
import static awais.instagrabber.utils.Constants.FLAG_SECURE;
|
import static awais.instagrabber.utils.Constants.FLAG_SECURE;
|
||||||
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
|
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
|
||||||
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
||||||
|
import static awais.instagrabber.utils.Constants.HIDE_MUTED_REELS;
|
||||||
|
import static awais.instagrabber.utils.Constants.KEYWORD_FILTERS;
|
||||||
import static awais.instagrabber.utils.Constants.MARK_AS_SEEN;
|
import static awais.instagrabber.utils.Constants.MARK_AS_SEEN;
|
||||||
import static awais.instagrabber.utils.Constants.MUTED_VIDEOS;
|
import static awais.instagrabber.utils.Constants.MUTED_VIDEOS;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_DARK_THEME;
|
import static awais.instagrabber.utils.Constants.PREF_DARK_THEME;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_EMOJI_VARIANTS;
|
import static awais.instagrabber.utils.Constants.PREF_EMOJI_VARIANTS;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_HASHTAG_POSTS_LAYOUT;
|
import static awais.instagrabber.utils.Constants.PREF_HASHTAG_POSTS_LAYOUT;
|
||||||
import static awais.instagrabber.utils.Constants.KEYWORD_FILTERS;
|
|
||||||
import static awais.instagrabber.utils.Constants.PREF_LIGHT_THEME;
|
import static awais.instagrabber.utils.Constants.PREF_LIGHT_THEME;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_LIKED_POSTS_LAYOUT;
|
import static awais.instagrabber.utils.Constants.PREF_LIKED_POSTS_LAYOUT;
|
||||||
import static awais.instagrabber.utils.Constants.PREF_LOCATION_POSTS_LAYOUT;
|
import static awais.instagrabber.utils.Constants.PREF_LOCATION_POSTS_LAYOUT;
|
||||||
@ -155,13 +158,13 @@ public final class SettingsHelper {
|
|||||||
CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME,
|
CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME,
|
||||||
PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT,
|
PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT,
|
||||||
PREF_LOCATION_POSTS_LAYOUT, PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT,
|
PREF_LOCATION_POSTS_LAYOUT, PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT,
|
||||||
STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT})
|
STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT, PREF_TAB_ORDER})
|
||||||
public @interface StringSettings {}
|
public @interface StringSettings {}
|
||||||
|
|
||||||
@StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
|
@StringDef({DOWNLOAD_USER_FOLDER, DOWNLOAD_PREPEND_USER_NAME, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
|
||||||
SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY,
|
SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY,
|
||||||
CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH,
|
CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH,
|
||||||
FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY})
|
FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY, HIDE_MUTED_REELS})
|
||||||
public @interface BooleanSettings {}
|
public @interface BooleanSettings {}
|
||||||
|
|
||||||
@StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER})
|
@StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER})
|
||||||
|
@ -2,8 +2,6 @@ package awais.instagrabber.utils;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.SpannableStringBuilder;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.style.URLSpan;
|
import android.text.style.URLSpan;
|
||||||
@ -11,17 +9,12 @@ import android.util.Patterns;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import awais.instagrabber.customviews.CommentMentionClickSpan;
|
|
||||||
|
|
||||||
public final class TextUtils {
|
public final class TextUtils {
|
||||||
// extracted from String class
|
// extracted from String class
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package awais.instagrabber.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
|
import awais.instagrabber.BuildConfig;
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
|
||||||
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
|
public final class UpdateCheckCommon {
|
||||||
|
|
||||||
|
public static boolean shouldShowUpdateDialog(final boolean force,
|
||||||
|
@NonNull final String version) {
|
||||||
|
final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION);
|
||||||
|
return force || (!BuildConfig.DEBUG && !skippedVersion.equals(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showUpdateDialog(@NonNull final Context context,
|
||||||
|
@NonNull final String version,
|
||||||
|
@NonNull final DialogInterface.OnClickListener onDownloadClickListener) {
|
||||||
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
|
new MaterialAlertDialogBuilder(context)
|
||||||
|
.setTitle(context.getString(R.string.update_available, version))
|
||||||
|
.setNeutralButton(R.string.skip_update, (dialog, which) -> {
|
||||||
|
settingsHelper.putString(Constants.SKIPPED_VERSION, version);
|
||||||
|
dialog.dismiss();
|
||||||
|
})
|
||||||
|
.setPositiveButton(R.string.action_download, onDownloadClickListener)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,58 +0,0 @@
|
|||||||
package awais.instagrabber.utils;
|
|
||||||
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import awais.instagrabber.BuildConfig;
|
|
||||||
import awais.instagrabber.interfaces.FetchListener;
|
|
||||||
|
|
||||||
public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
|
||||||
private final FetchListener<String> fetchListener;
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
public UpdateChecker(final FetchListener<String> fetchListener) {
|
|
||||||
this.fetchListener = fetchListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(final Void... voids) {
|
|
||||||
try {
|
|
||||||
version = "";
|
|
||||||
|
|
||||||
HttpURLConnection conn =
|
|
||||||
(HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection();
|
|
||||||
conn.setUseCaches(false);
|
|
||||||
conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me");
|
|
||||||
conn.connect();
|
|
||||||
|
|
||||||
final int responseCode = conn.getResponseCode();
|
|
||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
|
||||||
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn));
|
|
||||||
if (BuildConfig.VERSION_CODE < data.getInt("suggestedVersionCode")) {
|
|
||||||
version = data.getJSONArray("packages").getJSONObject(0).getString("versionName");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.disconnect();
|
|
||||||
} catch (final Exception e) {
|
|
||||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(final Boolean result) {
|
|
||||||
if (result != null && result && fetchListener != null)
|
|
||||||
fetchListener.onResult("v"+version);
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,6 +8,7 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@ -44,6 +45,8 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
|
|||||||
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
||||||
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
|
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
|
||||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Ordering;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -53,18 +56,25 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
||||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||||
|
import awais.instagrabber.models.Tab;
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
import awais.instagrabber.models.enums.FavoriteType;
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
private static final String TAG = "Utils";
|
private static final String TAG = "Utils";
|
||||||
private static final int VIDEO_CACHE_MAX_BYTES = 10 * 1024 * 1024;
|
private static final int VIDEO_CACHE_MAX_BYTES = 10 * 1024 * 1024;
|
||||||
|
|
||||||
// public static LogCollector logCollector;
|
// public static LogCollector logCollector;
|
||||||
public static SettingsHelper settingsHelper;
|
public static SettingsHelper settingsHelper;
|
||||||
public static boolean sessionVolumeFull = false;
|
public static boolean sessionVolumeFull = false;
|
||||||
public static final MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
|
public static final MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
|
||||||
@ -76,6 +86,7 @@ public final class Utils {
|
|||||||
private static int actionBarHeight;
|
private static int actionBarHeight;
|
||||||
public static Handler applicationHandler;
|
public static Handler applicationHandler;
|
||||||
public static String cacheDir;
|
public static String cacheDir;
|
||||||
|
public static String tabOrderString;
|
||||||
private static int defaultStatusBarColor;
|
private static int defaultStatusBarColor;
|
||||||
private static Object[] volumes;
|
private static Object[] volumes;
|
||||||
|
|
||||||
@ -375,6 +386,123 @@ public final class Utils {
|
|||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> void moveItem(int sourceIndex, int targetIndex, List<T> list) {
|
||||||
|
if (sourceIndex <= targetIndex) {
|
||||||
|
Collections.rotate(list.subList(sourceIndex, targetIndex + 1), -1);
|
||||||
|
} else {
|
||||||
|
Collections.rotate(list.subList(targetIndex, sourceIndex + 1), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final List<Integer> NON_REMOVABLE_NAV_ROOT_IDS = ImmutableList.of(R.id.profile_nav_graph, R.id.more_nav_graph);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static Pair<List<Tab>, List<Tab>> getNavTabList(@NonNull final Context context) {
|
||||||
|
final Resources resources = context.getResources();
|
||||||
|
final String[] titleArray = resources.getStringArray(R.array.main_nav_titles);
|
||||||
|
|
||||||
|
TypedArray typedArray = resources.obtainTypedArray(R.array.main_nav_graphs);
|
||||||
|
int length = typedArray.length();
|
||||||
|
final String[] navGraphNames = new String[length];
|
||||||
|
final int[] navigationResIds = new int[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final int resourceId = typedArray.getResourceId(i, 0);
|
||||||
|
if (resourceId == 0) continue;
|
||||||
|
navigationResIds[i] = resourceId;
|
||||||
|
navGraphNames[i] = resources.getResourceEntryName(resourceId);
|
||||||
|
}
|
||||||
|
typedArray.recycle();
|
||||||
|
|
||||||
|
typedArray = resources.obtainTypedArray(R.array.main_nav_graph_root_ids);
|
||||||
|
length = typedArray.length();
|
||||||
|
final int[] navRootIds = new int[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final int resourceId = typedArray.getResourceId(i, 0);
|
||||||
|
if (resourceId == 0) continue;
|
||||||
|
navRootIds[i] = resourceId;
|
||||||
|
}
|
||||||
|
typedArray.recycle();
|
||||||
|
|
||||||
|
typedArray = resources.obtainTypedArray(R.array.main_nav_drawables);
|
||||||
|
length = typedArray.length();
|
||||||
|
final int[] iconIds = new int[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final int resourceId = typedArray.getResourceId(i, 0);
|
||||||
|
if (resourceId == 0) continue;
|
||||||
|
iconIds[i] = resourceId;
|
||||||
|
}
|
||||||
|
typedArray.recycle();
|
||||||
|
|
||||||
|
typedArray = resources.obtainTypedArray(R.array.main_nav_start_dest_frag_ids);
|
||||||
|
length = typedArray.length();
|
||||||
|
final int[] startDestFragIds = new int[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final int resourceId = typedArray.getResourceId(i, 0);
|
||||||
|
if (resourceId == 0) continue;
|
||||||
|
startDestFragIds[i] = resourceId;
|
||||||
|
}
|
||||||
|
typedArray.recycle();
|
||||||
|
|
||||||
|
final List<String> currentOrderGraphNames = getCurrentOrderOfGraphNamesFromPref(navGraphNames);
|
||||||
|
|
||||||
|
if (titleArray.length != iconIds.length || titleArray.length != navGraphNames.length) {
|
||||||
|
throw new RuntimeException(String.format("Array lengths don't match!: titleArray%s, navGraphNames: %s, iconIds: %s",
|
||||||
|
Arrays.toString(titleArray), Arrays.toString(navGraphNames), Arrays.toString(iconIds)));
|
||||||
|
}
|
||||||
|
final List<Tab> tabs = new ArrayList<>();
|
||||||
|
final List<Tab> otherTabs = new ArrayList<>(); // Will contain tabs not in current list
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final String navGraphName = navGraphNames[i];
|
||||||
|
final int navRootId = navRootIds[i];
|
||||||
|
final Tab tab = new Tab(iconIds[i],
|
||||||
|
titleArray[i],
|
||||||
|
!NON_REMOVABLE_NAV_ROOT_IDS.contains(navRootId),
|
||||||
|
navGraphName,
|
||||||
|
navigationResIds[i],
|
||||||
|
navRootId,
|
||||||
|
startDestFragIds[i]);
|
||||||
|
if (!currentOrderGraphNames.contains(navGraphName)) {
|
||||||
|
otherTabs.add(tab);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tabs.add(tab);
|
||||||
|
}
|
||||||
|
Collections.sort(tabs, Ordering.explicit(currentOrderGraphNames).onResultOf(tab -> {
|
||||||
|
if (tab == null) return null;
|
||||||
|
return tab.getGraphName();
|
||||||
|
}));
|
||||||
|
return new Pair<>(tabs, otherTabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static List<String> getCurrentOrderOfGraphNamesFromPref(@NonNull final String[] navGraphNames) {
|
||||||
|
tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER);
|
||||||
|
final List<String> navGraphNameList = Arrays.asList(navGraphNames);
|
||||||
|
if (TextUtils.isEmpty(tabOrderString)) {
|
||||||
|
// Use top 5 entries for default list
|
||||||
|
final List<String> top5navGraphNames = navGraphNameList.subList(0, 5);
|
||||||
|
final String newOrderString = android.text.TextUtils.join(",", top5navGraphNames);
|
||||||
|
Utils.settingsHelper.putString(PreferenceKeys.PREF_TAB_ORDER, newOrderString);
|
||||||
|
tabOrderString = newOrderString;
|
||||||
|
return top5navGraphNames;
|
||||||
|
}
|
||||||
|
// Make sure that the list from preference does not contain any invalid values
|
||||||
|
final List<String> orderGraphNames = Arrays.stream(tabOrderString.split(","))
|
||||||
|
.filter(s -> !TextUtils.isEmpty(s))
|
||||||
|
.filter(navGraphNameList::contains)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (orderGraphNames.isEmpty()) {
|
||||||
|
// Use top 5 entries for default list
|
||||||
|
return navGraphNameList.subList(0, 5);
|
||||||
|
}
|
||||||
|
return orderGraphNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNavRootInCurrentTabs(final String navRootString) {
|
||||||
|
if (navRootString == null || tabOrderString == null) return false;
|
||||||
|
return tabOrderString.contains(navRootString);
|
||||||
|
}
|
||||||
|
|
||||||
public static void scanDocumentFile(@NonNull final Context context,
|
public static void scanDocumentFile(@NonNull final Context context,
|
||||||
@NonNull final DocumentFile documentFile,
|
@NonNull final DocumentFile documentFile,
|
||||||
@NonNull final OnScanCompletedListener callback) {
|
@NonNull final OnScanCompletedListener callback) {
|
||||||
|
@ -1,50 +1,8 @@
|
|||||||
package awais.instagrabber.webservices;
|
package awais.instagrabber.webservices;
|
||||||
|
|
||||||
import com.google.gson.FieldNamingPolicy;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import awais.instagrabber.BuildConfig;
|
|
||||||
import awais.instagrabber.repositories.responses.Caption;
|
|
||||||
import awais.instagrabber.utils.Utils;
|
|
||||||
import okhttp3.Cache;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import retrofit2.Retrofit;
|
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
|
||||||
import retrofit2.converter.scalars.ScalarsConverterFactory;
|
|
||||||
|
|
||||||
public abstract class BaseService {
|
public abstract class BaseService {
|
||||||
private static final String TAG = "BaseService";
|
private static final String TAG = "BaseService";
|
||||||
|
|
||||||
private Retrofit.Builder builder;
|
|
||||||
private final int cacheSize = 10 * 1024 * 1024; // 10 MB
|
|
||||||
private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize);
|
|
||||||
|
|
||||||
Retrofit.Builder getRetrofitBuilder() {
|
|
||||||
if (builder == null) {
|
|
||||||
final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
|
|
||||||
.addInterceptor(new AddCookiesInterceptor())
|
|
||||||
.followRedirects(false)
|
|
||||||
.followSslRedirects(false)
|
|
||||||
.cache(cache);
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
// clientBuilder.addInterceptor(new LoggingInterceptor());
|
|
||||||
}
|
|
||||||
final Gson gson = new GsonBuilder()
|
|
||||||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
|
||||||
.registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer())
|
|
||||||
.setLenient()
|
|
||||||
.create();
|
|
||||||
builder = new Retrofit.Builder()
|
|
||||||
.addConverterFactory(ScalarsConverterFactory.create())
|
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
|
||||||
.client(clientBuilder.build());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// protected String userBreadcrumb(final int size) {
|
// protected String userBreadcrumb(final int size) {
|
||||||
// final long term = (random(2, 4) * 1000) + size + (random(15, 21) * 1000);
|
// final long term = (random(2, 4) * 1000) + size + (random(15, 21) * 1000);
|
||||||
// final float div = (float) size / random(2, 4);
|
// final float div = (float) size / random(2, 4);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package awais.instagrabber.webservices;
|
package awais.instagrabber.webservices;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -14,7 +16,6 @@ import awais.instagrabber.utils.Utils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class CollectionService extends BaseService {
|
public class CollectionService extends BaseService {
|
||||||
private static final String TAG = "ProfileService";
|
private static final String TAG = "ProfileService";
|
||||||
@ -31,10 +32,9 @@ public class CollectionService extends BaseService {
|
|||||||
this.deviceUuid = deviceUuid;
|
this.deviceUuid = deviceUuid;
|
||||||
this.csrfToken = csrfToken;
|
this.csrfToken = csrfToken;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(CollectionRepository.class);
|
||||||
repository = retrofit.create(CollectionRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCsrfToken() {
|
public String getCsrfToken() {
|
||||||
@ -66,10 +66,10 @@ public class CollectionService extends BaseService {
|
|||||||
form.put("module_name", "feed_saved_add_to_collection");
|
form.put("module_name", "feed_saved_add_to_collection");
|
||||||
final List<String> ids;
|
final List<String> ids;
|
||||||
ids = posts.stream()
|
ids = posts.stream()
|
||||||
.map(Media::getPk)
|
.map(Media::getPk)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
form.put("added_media_ids", "[" + String.join(",", ids) + "]");
|
form.put("added_media_ids", "[" + TextUtils.join(",", ids) + "]");
|
||||||
changeCollection(collectionId, "edit", form, callback);
|
changeCollection(collectionId, "edit", form, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,6 @@ import awais.instagrabber.repositories.responses.giphy.GiphyGif;
|
|||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class DirectMessagesService extends BaseService {
|
public class DirectMessagesService extends BaseService {
|
||||||
private static final String TAG = "DiscoverService";
|
private static final String TAG = "DiscoverService";
|
||||||
@ -59,10 +58,9 @@ public class DirectMessagesService extends BaseService {
|
|||||||
this.csrfToken = csrfToken;
|
this.csrfToken = csrfToken;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.deviceUuid = deviceUuid;
|
this.deviceUuid = deviceUuid;
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(DirectMessagesRepository.class);
|
||||||
repository = retrofit.create(DirectMessagesRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCsrfToken() {
|
public String getCsrfToken() {
|
||||||
|
@ -12,7 +12,6 @@ import awais.instagrabber.utils.TextUtils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class DiscoverService extends BaseService {
|
public class DiscoverService extends BaseService {
|
||||||
|
|
||||||
@ -23,10 +22,9 @@ public class DiscoverService extends BaseService {
|
|||||||
private static DiscoverService instance;
|
private static DiscoverService instance;
|
||||||
|
|
||||||
private DiscoverService() {
|
private DiscoverService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(DiscoverRepository.class);
|
||||||
repository = retrofit.create(DiscoverRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DiscoverService getInstance() {
|
public static DiscoverService getInstance() {
|
||||||
|
@ -12,17 +12,16 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import awais.instagrabber.repositories.FeedRepository;
|
import awais.instagrabber.repositories.FeedRepository;
|
||||||
|
import awais.instagrabber.repositories.responses.Media;
|
||||||
|
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
||||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator;
|
import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator;
|
||||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroup;
|
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroup;
|
||||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroupSet;
|
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroupSet;
|
||||||
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse;
|
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse;
|
||||||
import awais.instagrabber.repositories.responses.Media;
|
|
||||||
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class FeedService extends BaseService {
|
public class FeedService extends BaseService {
|
||||||
private static final String TAG = "FeedService";
|
private static final String TAG = "FeedService";
|
||||||
@ -32,10 +31,9 @@ public class FeedService extends BaseService {
|
|||||||
private static FeedService instance;
|
private static FeedService instance;
|
||||||
|
|
||||||
private FeedService() {
|
private FeedService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(FeedRepository.class);
|
||||||
repository = retrofit.create(FeedRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FeedService getInstance() {
|
public static FeedService getInstance() {
|
||||||
|
@ -25,7 +25,6 @@ import awais.instagrabber.utils.Utils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class FriendshipService extends BaseService {
|
public class FriendshipService extends BaseService {
|
||||||
private static final String TAG = "FriendshipService";
|
private static final String TAG = "FriendshipService";
|
||||||
@ -42,10 +41,9 @@ public class FriendshipService extends BaseService {
|
|||||||
this.deviceUuid = deviceUuid;
|
this.deviceUuid = deviceUuid;
|
||||||
this.csrfToken = csrfToken;
|
this.csrfToken = csrfToken;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(FriendshipRepository.class);
|
||||||
repository = retrofit.create(FriendshipRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCsrfToken() {
|
public String getCsrfToken() {
|
||||||
@ -168,8 +166,8 @@ public class FriendshipService extends BaseService {
|
|||||||
form.put("_uuid", deviceUuid);
|
form.put("_uuid", deviceUuid);
|
||||||
form.put(story ? "target_reel_author_id" : "target_posts_author_id", String.valueOf(targetUserId));
|
form.put(story ? "target_reel_author_id" : "target_posts_author_id", String.valueOf(targetUserId));
|
||||||
final Call<FriendshipChangeResponse> request = repository.changeMute(unmute ?
|
final Call<FriendshipChangeResponse> request = repository.changeMute(unmute ?
|
||||||
"unmute_posts_or_story_from_follow" :
|
"unmute_posts_or_story_from_follow" :
|
||||||
"mute_posts_or_story_from_follow",
|
"mute_posts_or_story_from_follow",
|
||||||
form);
|
form);
|
||||||
request.enqueue(new Callback<FriendshipChangeResponse>() {
|
request.enqueue(new Callback<FriendshipChangeResponse>() {
|
||||||
@Override
|
@Override
|
||||||
@ -198,8 +196,8 @@ public class FriendshipService extends BaseService {
|
|||||||
if (maxId != null) queryMap.put("max_id", maxId);
|
if (maxId != null) queryMap.put("max_id", maxId);
|
||||||
final Call<String> request = repository.getList(
|
final Call<String> request = repository.getList(
|
||||||
targetUserId,
|
targetUserId,
|
||||||
follower ? "followers" : "following",
|
follower ? "followers" : "following",
|
||||||
queryMap);
|
queryMap);
|
||||||
request.enqueue(new Callback<String>() {
|
request.enqueue(new Callback<String>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||||
|
@ -3,7 +3,6 @@ package awais.instagrabber.webservices;
|
|||||||
import awais.instagrabber.repositories.GifRepository;
|
import awais.instagrabber.repositories.GifRepository;
|
||||||
import awais.instagrabber.repositories.responses.giphy.GiphyGifResponse;
|
import awais.instagrabber.repositories.responses.giphy.GiphyGifResponse;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class GifService extends BaseService {
|
public class GifService extends BaseService {
|
||||||
|
|
||||||
@ -12,10 +11,9 @@ public class GifService extends BaseService {
|
|||||||
private static GifService instance;
|
private static GifService instance;
|
||||||
|
|
||||||
private GifService() {
|
private GifService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(GifRepository.class);
|
||||||
repository = retrofit.create(GifRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GifService getInstance() {
|
public static GifService getInstance() {
|
||||||
|
@ -29,7 +29,6 @@ import awais.instagrabber.utils.TextUtils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class GraphQLService extends BaseService {
|
public class GraphQLService extends BaseService {
|
||||||
private static final String TAG = "GraphQLService";
|
private static final String TAG = "GraphQLService";
|
||||||
@ -40,10 +39,9 @@ public class GraphQLService extends BaseService {
|
|||||||
private static GraphQLService instance;
|
private static GraphQLService instance;
|
||||||
|
|
||||||
private GraphQLService() {
|
private GraphQLService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://www.instagram.com")
|
.getRetrofitWeb()
|
||||||
.build();
|
.create(GraphQLRepository.class);
|
||||||
repository = retrofit.create(GraphQLRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GraphQLService getInstance() {
|
public static GraphQLService getInstance() {
|
||||||
|
@ -13,7 +13,6 @@ import awais.instagrabber.utils.TextUtils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class LocationService extends BaseService {
|
public class LocationService extends BaseService {
|
||||||
private static final String TAG = "LocationService";
|
private static final String TAG = "LocationService";
|
||||||
@ -23,10 +22,9 @@ public class LocationService extends BaseService {
|
|||||||
private static LocationService instance;
|
private static LocationService instance;
|
||||||
|
|
||||||
private LocationService() {
|
private LocationService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(LocationRepository.class);
|
||||||
repository = retrofit.create(LocationRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocationService getInstance() {
|
public static LocationService getInstance() {
|
||||||
|
@ -31,7 +31,6 @@ import awais.instagrabber.utils.Utils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class MediaService extends BaseService {
|
public class MediaService extends BaseService {
|
||||||
private static final String TAG = "MediaService";
|
private static final String TAG = "MediaService";
|
||||||
@ -51,10 +50,9 @@ public class MediaService extends BaseService {
|
|||||||
this.deviceUuid = deviceUuid;
|
this.deviceUuid = deviceUuid;
|
||||||
this.csrfToken = csrfToken;
|
this.csrfToken = csrfToken;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(MediaRepository.class);
|
||||||
repository = retrofit.create(MediaRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCsrfToken() {
|
public String getCsrfToken() {
|
||||||
|
@ -12,17 +12,16 @@ import java.util.stream.Collectors;
|
|||||||
import awais.instagrabber.repositories.NewsRepository;
|
import awais.instagrabber.repositories.NewsRepository;
|
||||||
import awais.instagrabber.repositories.responses.AymlResponse;
|
import awais.instagrabber.repositories.responses.AymlResponse;
|
||||||
import awais.instagrabber.repositories.responses.AymlUser;
|
import awais.instagrabber.repositories.responses.AymlUser;
|
||||||
import awais.instagrabber.repositories.responses.notification.NotificationCounts;
|
|
||||||
import awais.instagrabber.repositories.responses.UserSearchResponse;
|
|
||||||
import awais.instagrabber.repositories.responses.NewsInboxResponse;
|
import awais.instagrabber.repositories.responses.NewsInboxResponse;
|
||||||
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
import awais.instagrabber.repositories.responses.UserSearchResponse;
|
||||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||||
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.notification.NotificationCounts;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class NewsService extends BaseService {
|
public class NewsService extends BaseService {
|
||||||
private static final String TAG = "NewsService";
|
private static final String TAG = "NewsService";
|
||||||
@ -32,10 +31,9 @@ public class NewsService extends BaseService {
|
|||||||
private static NewsService instance;
|
private static NewsService instance;
|
||||||
|
|
||||||
private NewsService() {
|
private NewsService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(NewsRepository.class);
|
||||||
repository = retrofit.create(NewsRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NewsService getInstance() {
|
public static NewsService getInstance() {
|
||||||
@ -56,9 +54,11 @@ public class NewsService extends BaseService {
|
|||||||
callback.onSuccess(null);
|
callback.onSuccess(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final List<Notification> result = new ArrayList<>();
|
final List<Notification> result = new ArrayList<Notification>();
|
||||||
result.addAll(body.getNewStories());
|
final List<Notification> newStories = body.getNewStories();
|
||||||
result.addAll(body.getOldStories());
|
if (newStories != null) result.addAll(newStories);
|
||||||
|
final List<Notification> oldStories = body.getOldStories();
|
||||||
|
if (oldStories != null) result.addAll(oldStories);
|
||||||
callback.onSuccess(result);
|
callback.onSuccess(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,8 @@ public class NewsService extends BaseService {
|
|||||||
aymlUsers.addAll(oldSuggestions);
|
aymlUsers.addAll(oldSuggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Notification> newsItems = aymlUsers.stream()
|
final List<Notification> newsItems = aymlUsers
|
||||||
|
.stream()
|
||||||
.map(i -> {
|
.map(i -> {
|
||||||
final User u = i.getUser();
|
final User u = i.getUser();
|
||||||
return new Notification(
|
return new Notification(
|
||||||
@ -162,7 +163,9 @@ public class NewsService extends BaseService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Notification> newsItems = body.getUsers().stream()
|
final List<Notification> newsItems = body
|
||||||
|
.getUsers()
|
||||||
|
.stream()
|
||||||
.map(u -> {
|
.map(u -> {
|
||||||
return new Notification(
|
return new Notification(
|
||||||
new NotificationArgs(
|
new NotificationArgs(
|
||||||
|
@ -23,7 +23,6 @@ import awais.instagrabber.utils.Utils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class ProfileService extends BaseService {
|
public class ProfileService extends BaseService {
|
||||||
private static final String TAG = "ProfileService";
|
private static final String TAG = "ProfileService";
|
||||||
@ -33,10 +32,9 @@ public class ProfileService extends BaseService {
|
|||||||
private static ProfileService instance;
|
private static ProfileService instance;
|
||||||
|
|
||||||
private ProfileService() {
|
private ProfileService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(ProfileRepository.class);
|
||||||
repository = retrofit.create(ProfileRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProfileService getInstance() {
|
public static ProfileService getInstance() {
|
||||||
@ -104,9 +102,9 @@ public class ProfileService extends BaseService {
|
|||||||
posts = Collections.emptyList();
|
posts = Collections.emptyList();
|
||||||
} else {
|
} else {
|
||||||
posts = items.stream()
|
posts = items.stream()
|
||||||
.map(WrappedMedia::getMedia)
|
.map(WrappedMedia::getMedia)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
callback.onSuccess(new PostsFetchResponse(
|
callback.onSuccess(new PostsFetchResponse(
|
||||||
posts,
|
posts,
|
||||||
|
@ -0,0 +1,112 @@
|
|||||||
|
package awais.instagrabber.webservices;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.gson.FieldNamingPolicy;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import awais.instagrabber.BuildConfig;
|
||||||
|
import awais.instagrabber.activities.MainActivity;
|
||||||
|
import awais.instagrabber.repositories.responses.Caption;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
|
import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor;
|
||||||
|
import awais.instagrabber.webservices.interceptors.IgErrorsInterceptor;
|
||||||
|
import okhttp3.Cache;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
import retrofit2.converter.scalars.ScalarsConverterFactory;
|
||||||
|
|
||||||
|
public final class RetrofitFactory {
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
|
||||||
|
private static RetrofitFactory instance;
|
||||||
|
|
||||||
|
private final int cacheSize = 10 * 1024 * 1024; // 10 MB
|
||||||
|
private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize);
|
||||||
|
|
||||||
|
private IgErrorsInterceptor igErrorsInterceptor;
|
||||||
|
private MainActivity mainActivity;
|
||||||
|
private Retrofit.Builder builder;
|
||||||
|
private Retrofit retrofit;
|
||||||
|
private Retrofit retrofitWeb;
|
||||||
|
|
||||||
|
public static void setup(@NonNull final MainActivity mainActivity) {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new RetrofitFactory(mainActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RetrofitFactory getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
throw new RuntimeException("Setup not done!");
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RetrofitFactory(@NonNull final MainActivity mainActivity) {
|
||||||
|
this.mainActivity = mainActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Retrofit.Builder getRetrofitBuilder() {
|
||||||
|
if (builder == null) {
|
||||||
|
igErrorsInterceptor = new IgErrorsInterceptor(mainActivity);
|
||||||
|
final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
|
||||||
|
.followRedirects(false)
|
||||||
|
.followSslRedirects(false)
|
||||||
|
.cache(cache);
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
// clientBuilder.addInterceptor(new LoggingInterceptor());
|
||||||
|
}
|
||||||
|
clientBuilder.addInterceptor(new AddCookiesInterceptor())
|
||||||
|
.addInterceptor(igErrorsInterceptor);
|
||||||
|
final Gson gson = new GsonBuilder()
|
||||||
|
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||||
|
.registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer())
|
||||||
|
.setLenient()
|
||||||
|
.create();
|
||||||
|
builder = new Retrofit.Builder()
|
||||||
|
.addConverterFactory(ScalarsConverterFactory.create())
|
||||||
|
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||||
|
.client(clientBuilder.build());
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Retrofit getRetrofit() {
|
||||||
|
if (retrofit == null) {
|
||||||
|
retrofit = getRetrofitBuilder()
|
||||||
|
.baseUrl("https://i.instagram.com")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return retrofit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Retrofit getRetrofitWeb() {
|
||||||
|
if (retrofitWeb == null) {
|
||||||
|
retrofitWeb = getRetrofitBuilder()
|
||||||
|
.baseUrl("https://www.instagram.com")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return retrofitWeb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
if (igErrorsInterceptor != null) {
|
||||||
|
igErrorsInterceptor.destroy();
|
||||||
|
}
|
||||||
|
igErrorsInterceptor = null;
|
||||||
|
mainActivity = null;
|
||||||
|
retrofit = null;
|
||||||
|
retrofitWeb = null;
|
||||||
|
builder = null;
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,10 @@
|
|||||||
package awais.instagrabber.webservices;
|
package awais.instagrabber.webservices;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import awais.instagrabber.repositories.SearchRepository;
|
import awais.instagrabber.repositories.SearchRepository;
|
||||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class SearchService extends BaseService {
|
public class SearchService extends BaseService {
|
||||||
private static final String TAG = "LocationService";
|
private static final String TAG = "LocationService";
|
||||||
@ -20,10 +14,9 @@ public class SearchService extends BaseService {
|
|||||||
private static SearchService instance;
|
private static SearchService instance;
|
||||||
|
|
||||||
private SearchService() {
|
private SearchService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://www.instagram.com")
|
.getRetrofitWeb()
|
||||||
.build();
|
.create(SearchRepository.class);
|
||||||
repository = retrofit.create(SearchRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SearchService getInstance() {
|
public static SearchService getInstance() {
|
||||||
@ -43,8 +36,8 @@ public class SearchService extends BaseService {
|
|||||||
builder.put("context", context);
|
builder.put("context", context);
|
||||||
builder.put("count", "50");
|
builder.put("count", "50");
|
||||||
return repository.search(isLoggedIn
|
return repository.search(isLoggedIn
|
||||||
? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/"
|
? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/"
|
||||||
: "https://www.instagram.com/web/search/topsearch/",
|
: "https://www.instagram.com/web/search/topsearch/",
|
||||||
builder.build());
|
builder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import awais.instagrabber.utils.Utils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class StoriesService extends BaseService {
|
public class StoriesService extends BaseService {
|
||||||
private static final String TAG = "StoriesService";
|
private static final String TAG = "StoriesService";
|
||||||
@ -50,10 +49,9 @@ public class StoriesService extends BaseService {
|
|||||||
this.csrfToken = csrfToken;
|
this.csrfToken = csrfToken;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.deviceUuid = deviceUuid;
|
this.deviceUuid = deviceUuid;
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(StoriesRepository.class);
|
||||||
repository = retrofit.create(StoriesRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCsrfToken() {
|
public String getCsrfToken() {
|
||||||
@ -137,7 +135,7 @@ public class StoriesService extends BaseService {
|
|||||||
final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray");
|
final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray");
|
||||||
for (int i = 0; i < feedStoriesReel.length(); ++i) {
|
for (int i = 0; i < feedStoriesReel.length(); ++i) {
|
||||||
final JSONObject node = feedStoriesReel.getJSONObject(i);
|
final JSONObject node = feedStoriesReel.getJSONObject(i);
|
||||||
if (node.optBoolean("hide_from_feed_unit")) continue;
|
if (node.optBoolean("hide_from_feed_unit") && Utils.settingsHelper.getBoolean(Constants.HIDE_MUTED_REELS)) continue;
|
||||||
final JSONObject userJson = node.getJSONObject(node.has("user") ? "user" : "owner");
|
final JSONObject userJson = node.getJSONObject(node.has("user") ? "user" : "owner");
|
||||||
try {
|
try {
|
||||||
final User user = new User(userJson.getLong("pk"),
|
final User user = new User(userJson.getLong("pk"),
|
||||||
@ -179,17 +177,22 @@ public class StoriesService extends BaseService {
|
|||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
final String id = node.getString("id");
|
|
||||||
final long timestamp = node.getLong("latest_reel_media");
|
final long timestamp = node.getLong("latest_reel_media");
|
||||||
final int mediaCount = node.getInt("media_count");
|
|
||||||
final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp;
|
final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp;
|
||||||
final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").optJSONObject(0) : null;
|
final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").optJSONObject(0) : null;
|
||||||
final boolean isBestie = node.optBoolean("has_besties_media", false);
|
|
||||||
StoryModel firstStoryModel = null;
|
StoryModel firstStoryModel = null;
|
||||||
if (itemJson != null) {
|
if (itemJson != null) {
|
||||||
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null);
|
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null);
|
||||||
}
|
}
|
||||||
feedStoryModels.add(new FeedStoryModel(id, user, fullyRead, timestamp, firstStoryModel, mediaCount, false, isBestie));
|
feedStoryModels.add(new FeedStoryModel(
|
||||||
|
node.getString("id"),
|
||||||
|
user,
|
||||||
|
fullyRead,
|
||||||
|
timestamp,
|
||||||
|
firstStoryModel,
|
||||||
|
node.getInt("media_count"),
|
||||||
|
false,
|
||||||
|
node.optBoolean("has_besties_media")));
|
||||||
}
|
}
|
||||||
catch (Exception e) {} // to cover promotional reels with non-long user pk's
|
catch (Exception e) {} // to cover promotional reels with non-long user pk's
|
||||||
}
|
}
|
||||||
@ -242,13 +245,16 @@ public class StoriesService extends BaseService {
|
|||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
final String id = node.getString("id");
|
feedStoryModels.add(new FeedStoryModel(
|
||||||
final long timestamp = node.getLong("published_time");
|
node.getString("id"),
|
||||||
// final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").getJSONObject(0) : null;
|
user,
|
||||||
final StoryModel firstStoryModel = ResponseBodyUtils.parseBroadcastItem(node);
|
false,
|
||||||
// if (itemJson != null) {
|
node.getLong("published_time"),
|
||||||
// }
|
ResponseBodyUtils.parseBroadcastItem(node),
|
||||||
feedStoryModels.add(new FeedStoryModel(id, user, false, timestamp, firstStoryModel, 1, true, false));
|
1,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
));
|
||||||
}
|
}
|
||||||
callback.onSuccess(sort(feedStoryModels));
|
callback.onSuccess(sort(feedStoryModels));
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
|
@ -21,7 +21,6 @@ import awais.instagrabber.utils.Utils;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class TagsService extends BaseService {
|
public class TagsService extends BaseService {
|
||||||
|
|
||||||
@ -32,10 +31,9 @@ public class TagsService extends BaseService {
|
|||||||
private final TagsRepository repository;
|
private final TagsRepository repository;
|
||||||
|
|
||||||
private TagsService() {
|
private TagsService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com/")
|
.getRetrofit()
|
||||||
.build();
|
.create(TagsRepository.class);
|
||||||
repository = retrofit.create(TagsRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TagsService getInstance() {
|
public static TagsService getInstance() {
|
||||||
|
@ -12,7 +12,6 @@ import awais.instagrabber.repositories.responses.WrappedUser;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
|
||||||
|
|
||||||
public class UserService extends BaseService {
|
public class UserService extends BaseService {
|
||||||
private static final String TAG = UserService.class.getSimpleName();
|
private static final String TAG = UserService.class.getSimpleName();
|
||||||
@ -22,10 +21,9 @@ public class UserService extends BaseService {
|
|||||||
private static UserService instance;
|
private static UserService instance;
|
||||||
|
|
||||||
private UserService() {
|
private UserService() {
|
||||||
final Retrofit retrofit = getRetrofitBuilder()
|
repository = RetrofitFactory.getInstance()
|
||||||
.baseUrl("https://i.instagram.com")
|
.getRetrofit()
|
||||||
.build();
|
.create(UserRepository.class);
|
||||||
repository = retrofit.create(UserRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserService getInstance() {
|
public static UserService getInstance() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package awais.instagrabber.webservices;
|
package awais.instagrabber.webservices.interceptors;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
@ -0,0 +1,136 @@
|
|||||||
|
package awais.instagrabber.webservices.interceptors;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.activities.MainActivity;
|
||||||
|
import awais.instagrabber.dialogs.ConfirmDialogFragment;
|
||||||
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
|
||||||
|
public class IgErrorsInterceptor implements Interceptor {
|
||||||
|
private static final String TAG = IgErrorsInterceptor.class.getSimpleName();
|
||||||
|
|
||||||
|
private MainActivity mainActivity;
|
||||||
|
|
||||||
|
public IgErrorsInterceptor(@NonNull final MainActivity mainActivity) {
|
||||||
|
this.mainActivity = mainActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Response intercept(@NonNull final Chain chain) throws IOException {
|
||||||
|
final Request request = chain.request();
|
||||||
|
final Response response = chain.proceed(request);
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
checkError(response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkError(@NonNull final Response response) {
|
||||||
|
final int errorCode = response.code();
|
||||||
|
switch (errorCode) {
|
||||||
|
case 429: // "429 Too Many Requests"
|
||||||
|
// ('Throttled by Instagram because of too many API requests.');
|
||||||
|
showErrorDialog(R.string.throttle_error);
|
||||||
|
return;
|
||||||
|
case 431: // "431 Request Header Fields Too Large"
|
||||||
|
// show dialog?
|
||||||
|
Log.e(TAG, "Network error: " + getMessage(errorCode, "The request start-line and/or headers are too large to process."));
|
||||||
|
return;
|
||||||
|
case 404:
|
||||||
|
showErrorDialog(R.string.not_found);
|
||||||
|
return;
|
||||||
|
case 302: // redirect
|
||||||
|
final String location = response.header("location");
|
||||||
|
if (location.equals("https://www.instagram.com/accounts/login/")) {
|
||||||
|
// rate limited
|
||||||
|
showErrorDialog(R.string.rate_limit);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ResponseBody body = response.body();
|
||||||
|
if (body == null) return;
|
||||||
|
try {
|
||||||
|
final String bodyString = body.string();
|
||||||
|
final JSONObject jsonObject = new JSONObject(bodyString);
|
||||||
|
String message = jsonObject.optString("message", null);
|
||||||
|
if (!TextUtils.isEmpty(message)) {
|
||||||
|
message = message.toLowerCase();
|
||||||
|
switch (message) {
|
||||||
|
case "user_has_logged_out":
|
||||||
|
showErrorDialog(R.string.account_logged_out);
|
||||||
|
return;
|
||||||
|
case "login_required":
|
||||||
|
showErrorDialog(R.string.login_required);
|
||||||
|
return;
|
||||||
|
case "execution failure":
|
||||||
|
showSnackbar(message);
|
||||||
|
return;
|
||||||
|
case "not authorized to view user": // Do we handle this in profile view fragment?
|
||||||
|
case "challenge_required": // Since we make users login using browser, we should not be getting this error in api requests
|
||||||
|
default:
|
||||||
|
showSnackbar(message);
|
||||||
|
Log.e(TAG, "checkError: " + bodyString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String errorType = jsonObject.optString("error_type", null);
|
||||||
|
if (TextUtils.isEmpty(errorType)) return;
|
||||||
|
if (errorType.equals("sentry_block")) {
|
||||||
|
showErrorDialog(R.string.sentry_block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (errorType.equals("inactive user")) {
|
||||||
|
showErrorDialog(R.string.inactive_user);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "checkError: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showSnackbar(final String message) {
|
||||||
|
final View view = mainActivity.getRootView();
|
||||||
|
if (view == null) return;
|
||||||
|
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private String getMessage(final int errorCode, final String message) {
|
||||||
|
return String.format("code: %s, internalMessage: %s", errorCode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showErrorDialog(@StringRes final int messageResId) {
|
||||||
|
if (mainActivity == null) return;
|
||||||
|
if (messageResId == 0) return;
|
||||||
|
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
|
||||||
|
Constants.GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE,
|
||||||
|
R.string.error,
|
||||||
|
messageResId,
|
||||||
|
R.string.ok,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
dialogFragment.show(mainActivity.getSupportFragmentManager(), "network_error_dialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
mainActivity = null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package awais.instagrabber.webservices;
|
package awais.instagrabber.webservices.interceptors;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z" />
|
|
||||||
</vector>
|
|
10
app/src/main/res/drawable/ic_explore_24.xml
Normal file
10
app/src/main/res/drawable/ic_explore_24.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,10.9c-0.61,0 -1.1,0.49 -1.1,1.1s0.49,1.1 1.1,1.1c0.61,0 1.1,-0.49 1.1,-1.1s-0.49,-1.1 -1.1,-1.1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM14.19,14.19L6,18l3.81,-8.19L18,6l-3.81,8.19z"/>
|
||||||
|
</vector>
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M13.5,0.67s0.74,2.65 0.74,4.8c0,2.06 -1.35,3.73 -3.41,3.73 -2.07,0 -3.63,-1.67 -3.63,-3.73l0.03,-0.36C5.21,7.51 4,10.62 4,14c0,4.42 3.58,8 8,8s8,-3.58 8,-8C20,8.61 17.41,3.8 13.5,0.67zM11.71,19c-1.78,0 -3.22,-1.4 -3.22,-3.14 0,-1.62 1.05,-2.76 2.81,-3.12 1.77,-0.36 3.6,-1.21 4.62,-2.58 0.39,1.29 0.59,2.65 0.59,4.04 0,2.65 -2.15,4.8 -4.8,4.8z" />
|
|
||||||
</vector>
|
|
10
app/src/main/res/drawable/ic_home_24.xml
Normal file
10
app/src/main/res/drawable/ic_home_24.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_message_24.xml
Normal file
10
app/src/main/res/drawable/ic_message_24.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_person_24.xml
Normal file
10
app/src/main/res/drawable/ic_person_24.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_round_add_circle_24.xml
Normal file
10
app/src/main/res/drawable/ic_round_add_circle_24.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM16,13h-3v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_round_drag_handle_24.xml
Normal file
10
app/src/main/res/drawable/ic_round_drag_handle_24.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M19,9H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM5,15h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_round_remove_circle_24.xml
Normal file
10
app/src/main/res/drawable/ic_round_remove_circle_24.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM16,13L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
|
||||||
|
</vector>
|
@ -47,7 +47,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
app:labelVisibilityMode="labeled"
|
app:labelVisibilityMode="auto"
|
||||||
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
|
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" />
|
||||||
app:menu="@menu/main_bottom_navigation_menu" />
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
45
app/src/main/res/layout/item_tab_order_pref.xml
Normal file
45
app/src/main/res/layout/item_tab_order_pref.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/add_remove"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
tools:srcCompat="@drawable/ic_round_add_circle_24"
|
||||||
|
tools:tint="@color/green_500" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
tools:srcCompat="@drawable/ic_home_24" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
tools:text="@string/feed" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/handle"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
app:srcCompat="@drawable/ic_round_drag_handle_24" />
|
||||||
|
</LinearLayout>
|
@ -326,6 +326,7 @@
|
|||||||
<androidx.constraintlayout.widget.Barrier
|
<androidx.constraintlayout.widget.Barrier
|
||||||
android:id="@+id/highlights_barrier"
|
android:id="@+id/highlights_barrier"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
app:constraint_referenced_ids="mainPostCount, mainFollowers, mainFollowing"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:barrierDirection="bottom" />
|
app:barrierDirection="bottom" />
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item
|
|
||||||
android:id="@+id/profile_nav_graph"
|
|
||||||
android:icon="@drawable/ic_profile_24"
|
|
||||||
android:title="@string/profile" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/more_nav_graph"
|
|
||||||
android:icon="@drawable/ic_more_horiz_24"
|
|
||||||
android:title="@string/more" />
|
|
||||||
</menu>
|
|
@ -1,30 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item
|
|
||||||
android:id="@+id/direct_messages_nav_graph"
|
|
||||||
android:icon="@drawable/ic_round_send_24"
|
|
||||||
android:title="@string/title_dm" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/feed_nav_graph"
|
|
||||||
android:icon="@drawable/ic_feed"
|
|
||||||
android:title="@string/feed" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/profile_nav_graph"
|
|
||||||
android:icon="@drawable/ic_profile_24"
|
|
||||||
android:title="@string/profile" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/discover_nav_graph"
|
|
||||||
android:icon="@drawable/ic_discover"
|
|
||||||
android:title="@string/title_discover" />
|
|
||||||
|
|
||||||
<!--<item-->
|
|
||||||
<!-- android:id="@+id/favouritesFragment"-->
|
|
||||||
<!-- android:icon="@drawable/ic_star_24"-->
|
|
||||||
<!-- android:title="@string/title_favorites"/>-->
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/more_nav_graph"
|
|
||||||
android:icon="@drawable/ic_more_horiz_24"
|
|
||||||
android:title="@string/more" />
|
|
||||||
</menu>
|
|
@ -5,13 +5,18 @@
|
|||||||
<item
|
<item
|
||||||
android:id="@+id/action_dms"
|
android:id="@+id/action_dms"
|
||||||
android:icon="@drawable/ic_round_send_24"
|
android:icon="@drawable/ic_round_send_24"
|
||||||
android:title="@string/action_dms"
|
android:title="@string/reply_story"
|
||||||
android:titleCondensed="@string/action_dms"
|
android:titleCondensed="@string/reply_story"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_profile"
|
||||||
|
android:title="@string/open_profile"
|
||||||
|
android:titleCondensed="@string/open_profile"
|
||||||
|
app:showAsAction="never" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_download"
|
android:id="@+id/action_download"
|
||||||
android:icon="@drawable/ic_download"
|
android:icon="@drawable/ic_download"
|
||||||
android:title="@string/action_download"
|
android:title="@string/action_download"
|
||||||
android:titleCondensed="@string/action_download"
|
android:titleCondensed="@string/action_download"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
43
app/src/main/res/navigation/favorites_nav_graph.xml
Normal file
43
app/src/main/res/navigation/favorites_nav_graph.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/favorites_nav_graph"
|
||||||
|
app:startDestination="@id/favoritesFragment">
|
||||||
|
|
||||||
|
<include app:graph="@navigation/profile_nav_graph" />
|
||||||
|
<include app:graph="@navigation/hashtag_nav_graph" />
|
||||||
|
<include app:graph="@navigation/location_nav_graph" />
|
||||||
|
<include app:graph="@navigation/comments_nav_graph" />
|
||||||
|
<include app:graph="@navigation/likes_nav_graph" />
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_profileFragment"
|
||||||
|
app:destination="@id/profile_nav_graph">
|
||||||
|
<argument
|
||||||
|
android:name="username"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="true" />
|
||||||
|
</action>
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_hashTagFragment"
|
||||||
|
app:destination="@id/hashtag_nav_graph">
|
||||||
|
<argument
|
||||||
|
android:name="hashtag"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
</action>
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_locationFragment"
|
||||||
|
app:destination="@id/location_nav_graph">
|
||||||
|
<argument
|
||||||
|
android:name="locationId"
|
||||||
|
app:argType="long" />
|
||||||
|
</action>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/favoritesFragment"
|
||||||
|
android:name="awais.instagrabber.fragments.FavoritesFragment"
|
||||||
|
android:label="@string/title_favorites" />
|
||||||
|
</navigation>
|
@ -11,6 +11,7 @@
|
|||||||
<include app:graph="@navigation/likes_nav_graph" />
|
<include app:graph="@navigation/likes_nav_graph" />
|
||||||
<include app:graph="@navigation/notification_viewer_nav_graph" />
|
<include app:graph="@navigation/notification_viewer_nav_graph" />
|
||||||
<include app:graph="@navigation/story_list_nav_graph" />
|
<include app:graph="@navigation/story_list_nav_graph" />
|
||||||
|
<include app:graph="@navigation/discover_nav_graph" />
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_profileFragment"
|
android:id="@+id/action_global_profileFragment"
|
||||||
|
@ -5,23 +5,16 @@
|
|||||||
android:id="@+id/notification_viewer_nav_graph"
|
android:id="@+id/notification_viewer_nav_graph"
|
||||||
app:startDestination="@id/notificationsViewer">
|
app:startDestination="@id/notificationsViewer">
|
||||||
|
|
||||||
<fragment
|
<include app:graph="@navigation/profile_nav_graph" />
|
||||||
android:id="@+id/notificationsViewer"
|
|
||||||
android:name="awais.instagrabber.fragments.NotificationsViewerFragment"
|
<action
|
||||||
android:label="@string/title_notifications"
|
android:id="@+id/action_global_profileFragment"
|
||||||
tools:layout="@layout/fragment_notifications_viewer">
|
app:destination="@id/profile_nav_graph">
|
||||||
<argument
|
<argument
|
||||||
android:name="type"
|
android:name="username"
|
||||||
app:argType="string"
|
app:argType="string"
|
||||||
app:nullable="false" />
|
app:nullable="true" />
|
||||||
<argument
|
</action>
|
||||||
android:name="targetId"
|
|
||||||
android:defaultValue="0L"
|
|
||||||
app:argType="long" />
|
|
||||||
<action
|
|
||||||
android:id="@+id/action_notificationsViewerFragment_to_storyViewerFragment"
|
|
||||||
app:destination="@id/storyViewerFragment" />
|
|
||||||
</fragment>
|
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_notificationsViewerFragment"
|
android:id="@+id/action_global_notificationsViewerFragment"
|
||||||
@ -88,4 +81,23 @@
|
|||||||
android:name="options"
|
android:name="options"
|
||||||
app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
|
app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/notificationsViewer"
|
||||||
|
android:name="awais.instagrabber.fragments.NotificationsViewerFragment"
|
||||||
|
android:label="@string/title_notifications"
|
||||||
|
tools:layout="@layout/fragment_notifications_viewer">
|
||||||
|
<argument
|
||||||
|
android:name="type"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false"
|
||||||
|
android:defaultValue="notif"/>
|
||||||
|
<argument
|
||||||
|
android:name="targetId"
|
||||||
|
android:defaultValue="0L"
|
||||||
|
app:argType="long" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_notifications_to_story"
|
||||||
|
app:destination="@id/storyViewerFragment" />
|
||||||
|
</fragment>
|
||||||
</navigation>
|
</navigation>
|
@ -71,11 +71,9 @@
|
|||||||
app:argType="long" />
|
app:argType="long" />
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
<include app:graph="@navigation/notification_viewer_nav_graph" />
|
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_notificationsViewerFragment"
|
android:id="@+id/action_global_notificationsViewerFragment"
|
||||||
app:destination="@id/notification_viewer_nav_graph">
|
app:destination="@id/notificationsViewer">
|
||||||
<argument
|
<argument
|
||||||
android:name="type"
|
android:name="type"
|
||||||
app:argType="string"
|
app:argType="string"
|
||||||
@ -86,6 +84,22 @@
|
|||||||
app:argType="long" />
|
app:argType="long" />
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/notificationsViewer"
|
||||||
|
android:name="awais.instagrabber.fragments.NotificationsViewerFragment"
|
||||||
|
android:label="@string/title_notifications"
|
||||||
|
tools:layout="@layout/fragment_notifications_viewer">
|
||||||
|
<argument
|
||||||
|
android:name="type"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false"
|
||||||
|
android:defaultValue="notif"/>
|
||||||
|
<argument
|
||||||
|
android:name="targetId"
|
||||||
|
android:defaultValue="0L"
|
||||||
|
app:argType="long" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
<include app:graph="@navigation/saved_nav_graph" />
|
<include app:graph="@navigation/saved_nav_graph" />
|
||||||
|
|
||||||
<action
|
<action
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Cerca actualitzacions a l\'inici</string>
|
<string name="update_check">Cerca actualitzacions a l\'inici</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Descarrega les publicacions a carpetes de nom d\'usuari</string>
|
<string name="download_user_folder">Descarrega les publicacions a carpetes de nom d\'usuari</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Marca les històries com a vistes després de visualitzar-es</string>
|
<string name="mark_as_seen_setting">Marca les històries com a vistes després de visualitzar-es</string>
|
||||||
<string name="mark_as_seen_setting_summary">L\'autor de la història sabrà que l\'has vista</string>
|
<string name="mark_as_seen_setting_summary">L\'autor de la història sabrà que l\'has vista</string>
|
||||||
<string name="dm_mark_as_seen_setting">Marca els missatges com a vists després de visualitzar-los</string>
|
<string name="dm_mark_as_seen_setting">Marca els missatges com a vists després de visualitzar-los</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Zkontrolovat aktualizace při spuštění</string>
|
<string name="update_check">Zkontrolovat aktualizace při spuštění</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Stáhnout příspěvky do složek s uživatelským jménem</string>
|
<string name="download_user_folder">Stáhnout příspěvky do složek s uživatelským jménem</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Označit příběhy po zhlédnutí jako zobrazené</string>
|
<string name="mark_as_seen_setting">Označit příběhy po zhlédnutí jako zobrazené</string>
|
||||||
<string name="mark_as_seen_setting_summary">Autor příběhu bude vědět, že jsi si ho zobrazili</string>
|
<string name="mark_as_seen_setting_summary">Autor příběhu bude vědět, že jsi si ho zobrazili</string>
|
||||||
<string name="dm_mark_as_seen_setting">Označovat přímou zprávu po zobrazení jako zobrazenou</string>
|
<string name="dm_mark_as_seen_setting">Označovat přímou zprávu po zobrazení jako zobrazenou</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Beim Start auf Aktualisierungen prüfen</string>
|
<string name="update_check">Beim Start auf Aktualisierungen prüfen</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Beiträge in Benutzernamen-Ordner herunterladen</string>
|
<string name="download_user_folder">Beiträge in Benutzernamen-Ordner herunterladen</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Stories nach dem Ansehen als gesehen markieren</string>
|
<string name="mark_as_seen_setting">Stories nach dem Ansehen als gesehen markieren</string>
|
||||||
<string name="mark_as_seen_setting_summary">Die Person wird wissen, dass du dir die Story angesehen hast</string>
|
<string name="mark_as_seen_setting_summary">Die Person wird wissen, dass du dir die Story angesehen hast</string>
|
||||||
<string name="dm_mark_as_seen_setting">Direktnachrichten nach dem Ansehen als gesehen markieren</string>
|
<string name="dm_mark_as_seen_setting">Direktnachrichten nach dem Ansehen als gesehen markieren</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Έλεγχος για ενημερώσεις στο ξεκίνημα</string>
|
<string name="update_check">Έλεγχος για ενημερώσεις στο ξεκίνημα</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Λήψη δημοσίευσης στους φακέλους με ονόματα χρηστών</string>
|
<string name="download_user_folder">Λήψη δημοσίευσης στους φακέλους με ονόματα χρηστών</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Επισήμανση ιστοριών ως προβληθέντων μετά την προβολή</string>
|
<string name="mark_as_seen_setting">Επισήμανση ιστοριών ως προβληθέντων μετά την προβολή</string>
|
||||||
<string name="mark_as_seen_setting_summary">Ο συντάκτης της ιστορίας θα ξέρει ότι την προβάλατε</string>
|
<string name="mark_as_seen_setting_summary">Ο συντάκτης της ιστορίας θα ξέρει ότι την προβάλατε</string>
|
||||||
<string name="dm_mark_as_seen_setting">Σήμανση ΠΜ ως αναγνωσμένου μετά την προβολή</string>
|
<string name="dm_mark_as_seen_setting">Σήμανση ΠΜ ως αναγνωσμένου μετά την προβολή</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Buscar actualizaciones al inicio</string>
|
<string name="update_check">Buscar actualizaciones al inicio</string>
|
||||||
<string name="flag_secure">Bloquea capturas de pantalla & vista previa de aplicaciones</string>
|
<string name="flag_secure">Bloquea capturas de pantalla & vista previa de aplicaciones</string>
|
||||||
<string name="download_user_folder">Usar subcarpetas con el nombre de usuario</string>
|
<string name="download_user_folder">Usar subcarpetas con el nombre de usuario</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Marcar historias como vistas después de verlas</string>
|
<string name="mark_as_seen_setting">Marcar historias como vistas después de verlas</string>
|
||||||
<string name="mark_as_seen_setting_summary">El autor de la historia sabrá que lo has visto</string>
|
<string name="mark_as_seen_setting_summary">El autor de la historia sabrá que lo has visto</string>
|
||||||
<string name="dm_mark_as_seen_setting">Marcar Mensaje Directo como visto después de verlo</string>
|
<string name="dm_mark_as_seen_setting">Marcar Mensaje Directo como visto después de verlo</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Bilatu eguneratzeak abioan</string>
|
<string name="update_check">Bilatu eguneratzeak abioan</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Deskargatu bidalketak erabiltzaile-izena duten karpetetara</string>
|
<string name="download_user_folder">Deskargatu bidalketak erabiltzaile-izena duten karpetetara</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Markatu istorioak ikusita gisa ikusi ondoren</string>
|
<string name="mark_as_seen_setting">Markatu istorioak ikusita gisa ikusi ondoren</string>
|
||||||
<string name="mark_as_seen_setting_summary">Istorioaren egileak ikusi duzula jakingo du</string>
|
<string name="mark_as_seen_setting_summary">Istorioaren egileak ikusi duzula jakingo du</string>
|
||||||
<string name="dm_mark_as_seen_setting">Markatu MZ ikusita gisa ikusi ondoren</string>
|
<string name="dm_mark_as_seen_setting">Markatu MZ ikusita gisa ikusi ondoren</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">بررسی بروزرسانی هنگام آغاز برنامه</string>
|
<string name="update_check">بررسی بروزرسانی هنگام آغاز برنامه</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">بارگیری پست ها در پوشه های به نام کاربر</string>
|
<string name="download_user_folder">بارگیری پست ها در پوشه های به نام کاربر</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">نشان کرد استوری ها به عنوان دیده شده بعد از دیدن</string>
|
<string name="mark_as_seen_setting">نشان کرد استوری ها به عنوان دیده شده بعد از دیدن</string>
|
||||||
<string name="mark_as_seen_setting_summary">نویسنده استوری می داند که شما آن را دیده اید</string>
|
<string name="mark_as_seen_setting_summary">نویسنده استوری می داند که شما آن را دیده اید</string>
|
||||||
<string name="dm_mark_as_seen_setting">نشان کردن پیام خصوصی بعنوان دیده شده بعد از دیدن</string>
|
<string name="dm_mark_as_seen_setting">نشان کردن پیام خصوصی بعنوان دیده شده بعد از دیدن</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Rechercher les mises à jours au démarrage</string>
|
<string name="update_check">Rechercher les mises à jours au démarrage</string>
|
||||||
<string name="flag_secure">Bloquer les captures d\'écran & l\'aperçu de l\'application</string>
|
<string name="flag_secure">Bloquer les captures d\'écran & l\'aperçu de l\'application</string>
|
||||||
<string name="download_user_folder">Télécharger les messages dans les dossiers des noms d\'utilisateurs</string>
|
<string name="download_user_folder">Télécharger les messages dans les dossiers des noms d\'utilisateurs</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Marquer les stories comme vues après consultation</string>
|
<string name="mark_as_seen_setting">Marquer les stories comme vues après consultation</string>
|
||||||
<string name="mark_as_seen_setting_summary">L\'auteur de la story saura que vous l\'avez vue</string>
|
<string name="mark_as_seen_setting_summary">L\'auteur de la story saura que vous l\'avez vue</string>
|
||||||
<string name="dm_mark_as_seen_setting">Marquer les messages privés comme vus après consultation</string>
|
<string name="dm_mark_as_seen_setting">Marquer les messages privés comme vus après consultation</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">खुलने पर अपडेट के लिए जाँच करें</string>
|
<string name="update_check">खुलने पर अपडेट के लिए जाँच करें</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">पोस्ट को ब्यबहारकारी के नाम पर किये फोल्डरस में रखें</string>
|
<string name="download_user_folder">पोस्ट को ब्यबहारकारी के नाम पर किये फोल्डरस में रखें</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">स्टोरि को दिखने के बाद \"दिखा गया\" दिखादें</string>
|
<string name="mark_as_seen_setting">स्टोरि को दिखने के बाद \"दिखा गया\" दिखादें</string>
|
||||||
<string name="mark_as_seen_setting_summary">सटोरि के लेखक जानेगा कि तुम देखे हो इसको</string>
|
<string name="mark_as_seen_setting_summary">सटोरि के लेखक जानेगा कि तुम देखे हो इसको</string>
|
||||||
<string name="dm_mark_as_seen_setting">तुम देखने के बाद सीधा संदेश को \"दिखागया\" लिखा जाएगा</string>
|
<string name="dm_mark_as_seen_setting">तुम देखने के बाद सीधा संदेश को \"दिखागया\" लिखा जाएगा</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Cek pembaruan saat memulai</string>
|
<string name="update_check">Cek pembaruan saat memulai</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Unduh kiriman ke folder nama pengguna</string>
|
<string name="download_user_folder">Unduh kiriman ke folder nama pengguna</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Tandai cerita dibaca setelah melihat</string>
|
<string name="mark_as_seen_setting">Tandai cerita dibaca setelah melihat</string>
|
||||||
<string name="mark_as_seen_setting_summary">Pembuat cerita akan tahu Anda melihatnya</string>
|
<string name="mark_as_seen_setting_summary">Pembuat cerita akan tahu Anda melihatnya</string>
|
||||||
<string name="dm_mark_as_seen_setting">Tandai DM dibaca setelah melihat</string>
|
<string name="dm_mark_as_seen_setting">Tandai DM dibaca setelah melihat</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Verifica per aggiornamenti all\'avvio</string>
|
<string name="update_check">Verifica per aggiornamenti all\'avvio</string>
|
||||||
<string name="flag_secure">Blocca screenshot & anteprima app</string>
|
<string name="flag_secure">Blocca screenshot & anteprima app</string>
|
||||||
<string name="download_user_folder">Scarica i post nelle cartelle del nome utente</string>
|
<string name="download_user_folder">Scarica i post nelle cartelle del nome utente</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Segna le storie come viste dopo la visualizzazione</string>
|
<string name="mark_as_seen_setting">Segna le storie come viste dopo la visualizzazione</string>
|
||||||
<string name="mark_as_seen_setting_summary">L\'autore della storia saprà che l\'hai visualizzata</string>
|
<string name="mark_as_seen_setting_summary">L\'autore della storia saprà che l\'hai visualizzata</string>
|
||||||
<string name="dm_mark_as_seen_setting">Segna il DM come visto dopo la visualizzazione</string>
|
<string name="dm_mark_as_seen_setting">Segna il DM come visto dopo la visualizzazione</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">起動時にアップデートを確認</string>
|
<string name="update_check">起動時にアップデートを確認</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">ユーザ名のフォルダに投稿をダウンロード</string>
|
<string name="download_user_folder">ユーザ名のフォルダに投稿をダウンロード</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">ストーリーズを表示後に既読にする</string>
|
<string name="mark_as_seen_setting">ストーリーズを表示後に既読にする</string>
|
||||||
<string name="mark_as_seen_setting_summary">ストーリーの作成者は、あなたが閲覧したことを知ることができます。</string>
|
<string name="mark_as_seen_setting_summary">ストーリーの作成者は、あなたが閲覧したことを知ることができます。</string>
|
||||||
<string name="dm_mark_as_seen_setting">DMを表示後に既読にする</string>
|
<string name="dm_mark_as_seen_setting">DMを表示後に既読にする</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Check for updates at startup</string>
|
<string name="update_check">Check for updates at startup</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Download posts to username folders</string>
|
<string name="download_user_folder">Download posts to username folders</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Mark stories as seen after viewing</string>
|
<string name="mark_as_seen_setting">Mark stories as seen after viewing</string>
|
||||||
<string name="mark_as_seen_setting_summary">Story author will know you viewed it</string>
|
<string name="mark_as_seen_setting_summary">Story author will know you viewed it</string>
|
||||||
<string name="dm_mark_as_seen_setting">Mark DM as seen after viewing</string>
|
<string name="dm_mark_as_seen_setting">Mark DM as seen after viewing</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Провери за ажурирање</string>
|
<string name="update_check">Провери за ажурирање</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Превземи објави во папката со кориснички имиња</string>
|
<string name="download_user_folder">Превземи објави во папката со кориснички имиња</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Означи ги приказните како видени</string>
|
<string name="mark_as_seen_setting">Означи ги приказните како видени</string>
|
||||||
<string name="mark_as_seen_setting_summary">Авторот на приказната ќе знае дека сте ја погледнале приказната</string>
|
<string name="mark_as_seen_setting_summary">Авторот на приказната ќе знае дека сте ја погледнале приказната</string>
|
||||||
<string name="dm_mark_as_seen_setting">Означи порака како видена</string>
|
<string name="dm_mark_as_seen_setting">Означи порака како видена</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Controleer op updates bij het opstarten</string>
|
<string name="update_check">Controleer op updates bij het opstarten</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Download berichten naar gebruikersnaam mappen</string>
|
<string name="download_user_folder">Download berichten naar gebruikersnaam mappen</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Markeer verhalen als gelezen na bekijken</string>
|
<string name="mark_as_seen_setting">Markeer verhalen als gelezen na bekijken</string>
|
||||||
<string name="mark_as_seen_setting_summary">Verhaalmaker zal het weten als je het bekeken hebt</string>
|
<string name="mark_as_seen_setting_summary">Verhaalmaker zal het weten als je het bekeken hebt</string>
|
||||||
<string name="dm_mark_as_seen_setting">Markeer privéberichten als gelezen na bekijken</string>
|
<string name="dm_mark_as_seen_setting">Markeer privéberichten als gelezen na bekijken</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">ଖୋଲିବା ସମୟରେ ଅପଡେଟ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ</string>
|
<string name="update_check">ଖୋଲିବା ସମୟରେ ଅପଡେଟ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">ଡାଉନଲୋଡ ପୋଷ୍ଟକୁ ବ୍ୟବହାରକାରୀଙ୍କ ନାମରେ ହୋଇଥିବା ସ୍ଥାନ ରେ ରଖ</string>
|
<string name="download_user_folder">ଡାଉନଲୋଡ ପୋଷ୍ଟକୁ ବ୍ୟବହାରକାରୀଙ୍କ ନାମରେ ହୋଇଥିବା ସ୍ଥାନ ରେ ରଖ</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">କାହାଣୀଗୁଡିକ ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |</string>
|
<string name="mark_as_seen_setting">କାହାଣୀଗୁଡିକ ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |</string>
|
||||||
<string name="mark_as_seen_setting_summary">କାହାଣୀ ପ୍ରେରକ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ</string>
|
<string name="mark_as_seen_setting_summary">କାହାଣୀ ପ୍ରେରକ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ</string>
|
||||||
<string name="dm_mark_as_seen_setting">ବାର୍ତା ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |</string>
|
<string name="dm_mark_as_seen_setting">ବାର୍ତା ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Sprawdź aktualizacje przy starcie</string>
|
<string name="update_check">Sprawdź aktualizacje przy starcie</string>
|
||||||
<string name="flag_secure">Blokuj zrzuty ekranu & podgląd aplikacji</string>
|
<string name="flag_secure">Blokuj zrzuty ekranu & podgląd aplikacji</string>
|
||||||
<string name="download_user_folder">Pobierz posty do folderów o nazwie użytkownika</string>
|
<string name="download_user_folder">Pobierz posty do folderów o nazwie użytkownika</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Oznacz relacje jako widoczne po wyświetleniu</string>
|
<string name="mark_as_seen_setting">Oznacz relacje jako widoczne po wyświetleniu</string>
|
||||||
<string name="mark_as_seen_setting_summary">Autor relacji będzie widział, że to wyświetliłeś</string>
|
<string name="mark_as_seen_setting_summary">Autor relacji będzie widział, że to wyświetliłeś</string>
|
||||||
<string name="dm_mark_as_seen_setting">Oznacz wiadomość jako przeczytaną</string>
|
<string name="dm_mark_as_seen_setting">Oznacz wiadomość jako przeczytaną</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Verificar se há atualizações ao iniciar</string>
|
<string name="update_check">Verificar se há atualizações ao iniciar</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Baixar publicações para pastas com o nome de usuário</string>
|
<string name="download_user_folder">Baixar publicações para pastas com o nome de usuário</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Marcar stories como vistos após a visualização</string>
|
<string name="mark_as_seen_setting">Marcar stories como vistos após a visualização</string>
|
||||||
<string name="mark_as_seen_setting_summary">O autor do story saberá que você viu</string>
|
<string name="mark_as_seen_setting_summary">O autor do story saberá que você viu</string>
|
||||||
<string name="dm_mark_as_seen_setting">Marcar DM como vista após a visualização</string>
|
<string name="dm_mark_as_seen_setting">Marcar DM como vista após a visualização</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Проверять наличие обновлений при запуске</string>
|
<string name="update_check">Проверять наличие обновлений при запуске</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Скачать публикации в папки с именем пользователя</string>
|
<string name="download_user_folder">Скачать публикации в папки с именем пользователя</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Отметить истории как увиденные после просмотра</string>
|
<string name="mark_as_seen_setting">Отметить истории как увиденные после просмотра</string>
|
||||||
<string name="mark_as_seen_setting_summary">Автор истории узнает, что вы просмотрели её</string>
|
<string name="mark_as_seen_setting_summary">Автор истории узнает, что вы просмотрели её</string>
|
||||||
<string name="dm_mark_as_seen_setting">Отметить ЛС как увиденные после просмотра</string>
|
<string name="dm_mark_as_seen_setting">Отметить ЛС как увиденные после просмотра</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Kontrolovať aktualizácie pri štarte</string>
|
<string name="update_check">Kontrolovať aktualizácie pri štarte</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Ukľadať do priečinkov podľa mena</string>
|
<string name="download_user_folder">Ukľadať do priečinkov podľa mena</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Označiť príbehy po videní ako videné</string>
|
<string name="mark_as_seen_setting">Označiť príbehy po videní ako videné</string>
|
||||||
<string name="mark_as_seen_setting_summary">Autor príbehu bude vedieť že ste ho videli</string>
|
<string name="mark_as_seen_setting_summary">Autor príbehu bude vedieť že ste ho videli</string>
|
||||||
<string name="dm_mark_as_seen_setting">Po prečítaní, označiť správu ako prečítanú</string>
|
<string name="dm_mark_as_seen_setting">Po prečítaní, označiť správu ako prečítanú</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Güncellemeleri başlangıçta kontrol et</string>
|
<string name="update_check">Güncellemeleri başlangıçta kontrol et</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">İndirmeleri kullanıcı adından oluşan bir alt klasörün içine yap</string>
|
<string name="download_user_folder">İndirmeleri kullanıcı adından oluşan bir alt klasörün içine yap</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Hikayeleri gördükten sonra görüldü olarak işaretle</string>
|
<string name="mark_as_seen_setting">Hikayeleri gördükten sonra görüldü olarak işaretle</string>
|
||||||
<string name="mark_as_seen_setting_summary">Hikayeyi paylaşan gördüğünüzü bilecek</string>
|
<string name="mark_as_seen_setting_summary">Hikayeyi paylaşan gördüğünüzü bilecek</string>
|
||||||
<string name="dm_mark_as_seen_setting">DM\'leri gördükten sonra görüldü olarak işaretle</string>
|
<string name="dm_mark_as_seen_setting">DM\'leri gördükten sonra görüldü olarak işaretle</string>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<string name="update_check">Kiểm tra cập nhật khi khởi động</string>
|
<string name="update_check">Kiểm tra cập nhật khi khởi động</string>
|
||||||
<string name="flag_secure">Block screenshots & app preview</string>
|
<string name="flag_secure">Block screenshots & app preview</string>
|
||||||
<string name="download_user_folder">Tải bài viết xuống theo thư mục tên người dùng trong Downloads</string>
|
<string name="download_user_folder">Tải bài viết xuống theo thư mục tên người dùng trong Downloads</string>
|
||||||
|
<string name="download_prepend_username">Prepend Username to Filename</string>
|
||||||
<string name="mark_as_seen_setting">Đánh dấu story là đã xem sau khi xem</string>
|
<string name="mark_as_seen_setting">Đánh dấu story là đã xem sau khi xem</string>
|
||||||
<string name="mark_as_seen_setting_summary">Người đăng story sẽ biết bạn đã xem nó</string>
|
<string name="mark_as_seen_setting_summary">Người đăng story sẽ biết bạn đã xem nó</string>
|
||||||
<string name="dm_mark_as_seen_setting">Đánh dấu DM là đã xem sau khi xem</string>
|
<string name="dm_mark_as_seen_setting">Đánh dấu DM là đã xem sau khi xem</string>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user