fileNames = new ArrayList<>();
for (final File f : contents) {
final String name = f.getName();
- if (f.isDirectory() || showZaAiConfigFiles && f.isFile() && name.toLowerCase().endsWith(".zaai"))
- fileNames.add(name);
+ final String nameLowerCase = name.toLowerCase();
+ final boolean isBackupFile = nameLowerCase.endsWith(".zaai") || nameLowerCase.endsWith(".backup");
+ if (f.isDirectory() || (showBackupFiles && f.isFile() && isBackupFile))
+ fileNames.add(f);
}
-
- Collections.sort(fileNames);
+ Collections.sort(fileNames, (o1, o2) -> {
+ if ((o1.isDirectory() && o2.isDirectory())
+ || (o1.isFile() && o2.isFile())) {
+ return o1.getName().compareToIgnoreCase(o2.getName());
+ }
+ if (o1.isDirectory()) return -1;
+ if (o2.isDirectory()) return 1;
+ return 0;
+ });
+ fileListViewModel.getList().postValue(fileNames);
selectedDir = dir;
- tvSelectedFolder.setText(path);
- listDirectoriesAdapter.notifyDataSetChanged();
fileObserver = new FileObserver(path, FileObserver.CREATE | FileObserver.DELETE | FileObserver.MOVED_FROM | FileObserver.MOVED_TO) {
private final Runnable currentDirRefresher = () -> changeDirectory(selectedDir);
@@ -222,15 +255,15 @@ public final class DirectoryChooser extends DialogFragment {
if (selectedDir != null) {
final String path = selectedDir.getAbsolutePath();
toggleUpButton(!path.equals(sdcardPathFile.getAbsolutePath()) && selectedDir != sdcardPathFile);
- btnConfirm.setEnabled(isValidFile(selectedDir));
+ binding.btnConfirm.setEnabled(isValidFile(selectedDir));
}
}
private void toggleUpButton(final boolean enable) {
- if (btnNavUp != null) {
- btnNavUp.setEnabled(enable);
- btnNavUp.setAlpha(enable ? 1f : 0.617f);
- }
+ binding.toolbar.setNavigationOnClickListener(enable ? navigationOnClickListener : null);
+ final Drawable navigationIcon = binding.toolbar.getNavigationIcon();
+ if (navigationIcon == null) return;
+ navigationIcon.setAlpha(enable ? 255 : (int) (255 * 0.617));
}
private boolean isValidFile(final File file) {
@@ -242,7 +275,17 @@ public final class DirectoryChooser extends DialogFragment {
return this;
}
+ public void setOnCancelListener(final OnCancelListener onCancelListener) {
+ if (onCancelListener != null) {
+ this.onCancelListener = onCancelListener;
+ }
+ }
+
+ public interface OnCancelListener {
+ void onCancel();
+ }
+
public interface OnFragmentInteractionListener {
- void onSelectDirectory(final String path);
+ void onSelectDirectory(final File file);
}
}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/utils/DirectoryUtils.java b/app/src/main/java/awais/instagrabber/utils/DirectoryUtils.java
new file mode 100644
index 00000000..710510a3
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/utils/DirectoryUtils.java
@@ -0,0 +1,76 @@
+package awais.instagrabber.utils;
+
+import android.os.Build;
+import android.os.Environment;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+public class DirectoryUtils {
+ private static final Pattern DIR_SEPORATOR = Pattern.compile("/");
+
+ /**
+ * From: https://stackoverflow.com/a/18871043/1436766
+ *
+ * Returns all available SD-Cards in the system (include emulated)
+ *
+ * Warning: Hack! Based on Android source code of version 4.3 (API 18)
+ * Because there is no standard way to get it.
+ * TODO: Test on future Android versions 4.4+
+ *
+ * @return paths to all available SD-Cards in the system (include emulated)
+ */
+ public static Set getStorageDirectories() {
+ // Final set of paths
+ final Set rv = new HashSet<>();
+ // Primary physical SD-CARD (not emulated)
+ final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
+ // All Secondary SD-CARDs (all exclude primary) separated by ":"
+ final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
+ // Primary emulated SD-CARD
+ final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
+ if (TextUtils.isEmpty(rawEmulatedStorageTarget)) {
+ // Device has physical external storage; use plain paths.
+ if (TextUtils.isEmpty(rawExternalStorage)) {
+ // EXTERNAL_STORAGE undefined; falling back to default.
+ rv.add("/storage/sdcard0");
+ } else {
+ rv.add(rawExternalStorage);
+ }
+ } else {
+ // Device has emulated storage; external storage paths should have
+ // userId burned into them.
+ final String rawUserId;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ rawUserId = "";
+ } else {
+ final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
+ final String[] folders = DIR_SEPORATOR.split(path);
+ final String lastFolder = folders[folders.length - 1];
+ boolean isDigit = false;
+ try {
+ Integer.valueOf(lastFolder);
+ isDigit = true;
+ } catch (NumberFormatException ignored) {
+ }
+ rawUserId = isDigit ? lastFolder : "";
+ }
+ // /storage/emulated/0[1,2,...]
+ if (TextUtils.isEmpty(rawUserId)) {
+ rv.add(rawEmulatedStorageTarget);
+ } else {
+ rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
+ }
+ }
+ // Add all secondary storages
+ if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) {
+ // All Secondary SD-CARDs splited into array
+ final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
+ Collections.addAll(rv, rawSecondaryStorages);
+ }
+ return rv;
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java
index 4b867f87..48576a98 100644
--- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java
+++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java
@@ -37,7 +37,9 @@ import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
public final class DownloadUtils {
public static final String[] PERMS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
- public static void batchDownload(@NonNull final Context context, @Nullable String username, final DownloadMethod method,
+ public static void batchDownload(@NonNull final Context context,
+ @Nullable String username,
+ final DownloadMethod method,
final List extends BasePostModel> itemsToDownload) {
if (Utils.settingsHelper == null) Utils.settingsHelper = new SettingsHelper(context);
diff --git a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
index 750e3b80..3770bd65 100755
--- a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
+++ b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
@@ -1,40 +1,40 @@
package awais.instagrabber.utils;
import android.content.Context;
-import android.text.InputFilter;
-import android.text.InputType;
+import android.content.SharedPreferences;
import android.util.Base64;
import android.util.Log;
+import android.util.Pair;
import android.widget.Toast;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.widget.AppCompatEditText;
import org.json.JSONArray;
+import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.util.ArrayList;
+import java.util.Date;
import java.util.Iterator;
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
+import java.util.List;
+import java.util.Map;
import awais.instagrabber.BuildConfig;
-import awais.instagrabber.R;
import awais.instagrabber.interfaces.FetchListener;
+import awais.instagrabber.models.enums.FavoriteType;
+import awais.instagrabber.utils.PasswordUtils.IncorrectPasswordException;
import awaisomereport.LogCollector.LogFile;
import static awais.instagrabber.utils.Utils.logCollector;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class ExportImportUtils {
+ private static final String TAG = "ExportImportUtils";
+
public static final int FLAG_COOKIES = 1;
public static final int FLAG_FAVORITES = 1 << 1;
public static final int FLAG_SETTINGS = 1 << 2;
@@ -42,292 +42,289 @@ public final class ExportImportUtils {
@IntDef(value = {FLAG_COOKIES, FLAG_FAVORITES, FLAG_SETTINGS}, flag = true)
@interface ExportImportFlags {}
- public static void Export(@Nullable final String password, @ExportImportFlags final int flags, @NonNull final File filePath,
- final FetchListener fetchListener) {
- final String exportString = ExportImportUtils.getExportString(flags);
- if (!TextUtils.isEmpty(exportString)) {
- final boolean isPass = !TextUtils.isEmpty(password);
- byte[] exportBytes = null;
-
- if (isPass) {
- final byte[] passwordBytes = password.getBytes();
- final byte[] bytes = new byte[32];
- System.arraycopy(passwordBytes, 0, bytes, 0, Math.min(passwordBytes.length, 32));
-
- try {
- exportBytes = PasswordUtils.enc(exportString, bytes);
- } catch (final Exception e) {
- if (fetchListener != null) fetchListener.onResult(false);
- if (logCollector != null)
- logCollector.appendException(e, LogFile.UTILS_EXPORT, "Export::isPass");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
- }
- } else {
- exportBytes = Base64.encode(exportString.getBytes(), Base64.DEFAULT | Base64.NO_WRAP | Base64.NO_PADDING);
+ public static void exportData(@Nullable final String password,
+ @ExportImportFlags final int flags,
+ @NonNull final File filePath,
+ final FetchListener fetchListener,
+ @NonNull final Context context) {
+ final String exportString = getExportString(flags, context);
+ if (TextUtils.isEmpty(exportString)) return;
+ final boolean isPass = !TextUtils.isEmpty(password);
+ byte[] exportBytes = null;
+ if (isPass) {
+ final byte[] passwordBytes = password.getBytes();
+ final byte[] bytes = new byte[32];
+ System.arraycopy(passwordBytes, 0, bytes, 0, Math.min(passwordBytes.length, 32));
+ try {
+ exportBytes = PasswordUtils.enc(exportString, bytes);
+ } catch (final Exception e) {
+ if (fetchListener != null) fetchListener.onResult(false);
+ if (logCollector != null)
+ logCollector.appendException(e, LogFile.UTILS_EXPORT, "Export::isPass");
+ if (BuildConfig.DEBUG) Log.e(TAG, "", e);
}
-
- if (exportBytes != null && exportBytes.length > 1) {
- try (final FileOutputStream fos = new FileOutputStream(filePath)) {
- fos.write(isPass ? 'A' : 'Z');
- fos.write(exportBytes);
- if (fetchListener != null) fetchListener.onResult(true);
- } catch (final Exception e) {
- if (fetchListener != null) fetchListener.onResult(false);
- if (logCollector != null)
- logCollector.appendException(e, LogFile.UTILS_EXPORT, "Export::notPass");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
- }
- } else if (fetchListener != null) fetchListener.onResult(false);
+ } else {
+ exportBytes = Base64.encode(exportString.getBytes(), Base64.DEFAULT | Base64.NO_WRAP | Base64.NO_PADDING);
}
+ if (exportBytes != null && exportBytes.length > 1) {
+ try (final FileOutputStream fos = new FileOutputStream(filePath)) {
+ fos.write(isPass ? 'A' : 'Z');
+ fos.write(exportBytes);
+ if (fetchListener != null) fetchListener.onResult(true);
+ } catch (final Exception e) {
+ if (fetchListener != null) fetchListener.onResult(false);
+ if (logCollector != null)
+ logCollector.appendException(e, LogFile.UTILS_EXPORT, "Export::notPass");
+ if (BuildConfig.DEBUG) Log.e(TAG, "", e);
+ }
+ } else if (fetchListener != null) fetchListener.onResult(false);
}
- public static void Import(@NonNull final Context context, @ExportImportFlags final int flags, @NonNull final File filePath,
- final FetchListener fetchListener) {
- try (final FileInputStream fis = new FileInputStream(filePath)) {
+ public static void importData(@NonNull final Context context,
+ @ExportImportFlags final int flags,
+ @NonNull final File file,
+ final String password,
+ final FetchListener fetchListener) throws IncorrectPasswordException {
+ try (final FileInputStream fis = new FileInputStream(file)) {
final int configType = fis.read();
-
final StringBuilder builder = new StringBuilder();
int c;
while ((c = fis.read()) != -1) {
builder.append((char) c);
}
-
if (configType == 'A') {
// password
- final AppCompatEditText editText = new AppCompatEditText(context);
- editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(32)});
- editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
- new AlertDialog.Builder(context).setView(editText).setTitle(R.string.password)
- .setPositiveButton(R.string.confirm, (dialog, which) -> {
- final CharSequence text = editText.getText();
- if (!TextUtils.isEmpty(text)) {
- try {
- final byte[] passwordBytes = text.toString().getBytes();
- final byte[] bytes = new byte[32];
- System.arraycopy(passwordBytes, 0, bytes, 0, Math.min(passwordBytes.length, 32));
- saveToSettings(new String(PasswordUtils.dec(builder.toString(), bytes)), flags,
- fetchListener);
- } catch (final Exception e) {
- if (fetchListener != null) fetchListener.onResult(false);
- if (logCollector != null)
- logCollector.appendException(e, LogFile.UTILS_IMPORT, "Import::pass");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
- }
-
- } else
- Toast.makeText(context, R.string.dialog_export_err_password_empty, Toast.LENGTH_SHORT).show();
- }).show();
-
+ if (TextUtils.isEmpty(password)) return;
+ try {
+ final byte[] passwordBytes = password.getBytes();
+ final byte[] bytes = new byte[32];
+ System.arraycopy(passwordBytes, 0, bytes, 0, Math.min(passwordBytes.length, 32));
+ importJson(new String(PasswordUtils.dec(builder.toString(), bytes)),
+ flags,
+ fetchListener);
+ } catch (final IncorrectPasswordException e) {
+ throw e;
+ } catch (final Exception e) {
+ if (fetchListener != null) fetchListener.onResult(false);
+ if (logCollector != null)
+ logCollector.appendException(e, LogFile.UTILS_IMPORT, "Import::pass");
+ if (BuildConfig.DEBUG) Log.e(TAG, "Error importing backup", e);
+ }
} else if (configType == 'Z') {
- saveToSettings(new String(Base64.decode(builder.toString(), Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP)),
- flags, fetchListener);
+ importJson(new String(Base64.decode(builder.toString(), Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP)),
+ flags,
+ fetchListener);
} else {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
+ Toast.makeText(context, "File is corrupted!", Toast.LENGTH_LONG).show();
if (fetchListener != null) fetchListener.onResult(false);
}
+ } catch (IncorrectPasswordException e) {
+ // separately handle incorrect password
+ throw e;
} catch (final Exception e) {
if (fetchListener != null) fetchListener.onResult(false);
if (logCollector != null) logCollector.appendException(e, LogFile.UTILS_IMPORT, "Import");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
+ if (BuildConfig.DEBUG) Log.e(TAG, "", e);
}
}
- private static void saveToSettings(final String json, @ExportImportFlags final int flags, final FetchListener fetchListener) {
+ private static void importJson(@NonNull final String json,
+ @ExportImportFlags final int flags,
+ final FetchListener fetchListener) {
try {
final JSONObject jsonObject = new JSONObject(json);
-
if ((flags & FLAG_SETTINGS) == FLAG_SETTINGS && jsonObject.has("settings")) {
- final JSONObject objSettings = jsonObject.getJSONObject("settings");
- final Iterator keys = objSettings.keys();
- while (keys.hasNext()) {
- final String key = keys.next();
- final Object val = objSettings.opt(key);
- if (val instanceof String) {
- settingsHelper.putString(key, (String) val);
- } else if (val instanceof Integer) {
- settingsHelper.putInteger(key, (int) val);
- } else if (val instanceof Boolean) {
- settingsHelper.putBoolean(key, (boolean) val);
- }
- }
+ importSettings(jsonObject);
}
-
if ((flags & FLAG_COOKIES) == FLAG_COOKIES && jsonObject.has("cookies")) {
- final JSONArray cookies = jsonObject.getJSONArray("cookies");
- final int cookiesLen = cookies.length();
- for (int i = 0; i < cookiesLen; ++i) {
- final JSONObject cookieObject = cookies.getJSONObject(i);
- // final DataBox.CookieModel cookieModel = new DataBox.CookieModel(cookieObject.getString("i"),
- // cookieObject.getString("u"),
- // cookieObject.getString("c"),
- // fullName,
- // profilePic);
- // Utils.dataBox.addOrUpdateUser(cookieModel.getUid(), cookieModel.getUserInfo(), cookieModel.getCookie());
- }
+ importAccounts(jsonObject);
}
-
if ((flags & FLAG_FAVORITES) == FLAG_FAVORITES && jsonObject.has("favs")) {
- final JSONArray favs = jsonObject.getJSONArray("favs");
- final int favsLen = favs.length();
- for (int i = 0; i < favsLen; ++i) {
- final JSONObject favsObject = favs.getJSONObject(i);
- Utils.dataBox.addFavorite(new DataBox.FavoriteModel(favsObject.getString("q"),
- favsObject.getLong("d"),
- favsObject.has("s") ? favsObject.getString("s") : favsObject.getString("q")));
- }
+ importFavorites(jsonObject);
}
-
if (fetchListener != null) fetchListener.onResult(true);
-
} catch (final Exception e) {
if (fetchListener != null) fetchListener.onResult(false);
- if (logCollector != null) logCollector.appendException(e, LogFile.UTILS_IMPORT, "saveToSettings");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
+ if (logCollector != null) logCollector.appendException(e, LogFile.UTILS_IMPORT, "importJson");
+ if (BuildConfig.DEBUG) Log.e(TAG, "", e);
}
}
+ private static void importFavorites(final JSONObject jsonObject) throws JSONException {
+ final JSONArray favs = jsonObject.getJSONArray("favs");
+ for (int i = 0; i < favs.length(); i++) {
+ final JSONObject favsObject = favs.getJSONObject(i);
+ final String queryText = favsObject.optString("q");
+ if (TextUtils.isEmpty(queryText)) continue;
+ final Pair favoriteTypeQueryPair;
+ String query = null;
+ FavoriteType favoriteType = null;
+ if (queryText.contains("@")
+ || queryText.contains("#")
+ || queryText.contains("/")) {
+ favoriteTypeQueryPair = Utils.migrateOldFavQuery(queryText);
+ if (favoriteTypeQueryPair != null) {
+ query = favoriteTypeQueryPair.second;
+ favoriteType = favoriteTypeQueryPair.first;
+ }
+ } else {
+ query = queryText;
+ favoriteType = FavoriteType.valueOf(favsObject.optString("type"));
+ }
+ if (query == null || favoriteType == null) {
+ continue;
+ }
+ final DataBox.FavoriteModel favoriteModel = new DataBox.FavoriteModel(
+ -1,
+ query,
+ favoriteType,
+ favsObject.optString("s"),
+ favoriteType == FavoriteType.HASHTAG ? null
+ : favsObject.optString("pic_url"),
+ new Date(favsObject.getLong("d")));
+ // Log.d(TAG, "importJson: favoriteModel: " + favoriteModel);
+ Utils.dataBox.addOrUpdateFavorite(favoriteModel);
+ }
+ }
+
+ private static void importAccounts(final JSONObject jsonObject) throws JSONException {
+ final JSONArray cookies = jsonObject.getJSONArray("cookies");
+ for (int i = 0; i < cookies.length(); i++) {
+ final JSONObject cookieObject = cookies.getJSONObject(i);
+ final DataBox.CookieModel cookieModel = new DataBox.CookieModel(
+ cookieObject.optString("i"),
+ cookieObject.optString("u"),
+ cookieObject.optString("c"),
+ cookieObject.optString("full_name"),
+ cookieObject.optString("profile_pic")
+ );
+ if (!cookieModel.isValid()) continue;
+ // Log.d(TAG, "importJson: cookieModel: " + cookieModel);
+ Utils.dataBox.addOrUpdateUser(cookieModel);
+ }
+ }
+
+ private static void importSettings(final JSONObject jsonObject) throws JSONException {
+ final JSONObject objSettings = jsonObject.getJSONObject("settings");
+ final Iterator keys = objSettings.keys();
+ while (keys.hasNext()) {
+ final String key = keys.next();
+ final Object val = objSettings.opt(key);
+ // Log.d(TAG, "importJson: key: " + key + ", val: " + val);
+ if (val instanceof String) {
+ settingsHelper.putString(key, (String) val);
+ } else if (val instanceof Integer) {
+ settingsHelper.putInteger(key, (int) val);
+ } else if (val instanceof Boolean) {
+ settingsHelper.putBoolean(key, (boolean) val);
+ }
+ }
+ }
+
+ public static boolean isEncrypted(final File file) {
+ try (final FileInputStream fis = new FileInputStream(file)) {
+ final int configType = fis.read();
+ if (configType == 'A') {
+ return true;
+ }
+ } catch (final Exception e) {
+ Log.e(TAG, "isEncrypted", e);
+ }
+ return false;
+ }
+
@Nullable
- private static String getExportString(@ExportImportFlags final int flags) {
+ private static String getExportString(@ExportImportFlags final int flags,
+ @NonNull final Context context) {
String result = null;
try {
final JSONObject jsonObject = new JSONObject();
-
- String str;
if ((flags & FLAG_SETTINGS) == FLAG_SETTINGS) {
- str = getSettings();
- if (str != null) jsonObject.put("settings", new JSONObject(str));
+ jsonObject.put("settings", getSettings(context));
}
-
if ((flags & FLAG_COOKIES) == FLAG_COOKIES) {
- str = getCookies();
- if (str != null) jsonObject.put("cookies", new JSONArray(str));
+ jsonObject.put("cookies", getCookies());
}
-
if ((flags & FLAG_FAVORITES) == FLAG_FAVORITES) {
- str = getFavorites();
- if (str != null) jsonObject.put("favs", new JSONArray(str));
+ jsonObject.put("favs", getFavorites());
}
result = jsonObject.toString();
} catch (final Exception e) {
if (logCollector != null) logCollector.appendException(e, LogFile.UTILS_EXPORT, "getExportString");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
+ if (BuildConfig.DEBUG) Log.e(TAG, "", e);
}
return result;
}
- @Nullable
- private static String getSettings() {
- String result = null;
+ @NonNull
+ private static JSONObject getSettings(@NonNull final Context context) {
+ final SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+ final Map allPrefs = sharedPreferences.getAll();
+ if (allPrefs == null) {
+ return new JSONObject();
+ }
+ try {
+ final JSONObject jsonObject = new JSONObject(allPrefs);
+ jsonObject.remove(Constants.COOKIE);
+ jsonObject.remove(Constants.DEVICE_UUID);
+ jsonObject.remove(Constants.PREV_INSTALL_VERSION);
+ return jsonObject;
+ } catch (Exception e) {
+ Log.e(TAG, "Error exporting settings", e);
+ }
+ return new JSONObject();
+ }
- if (settingsHelper != null) {
- try {
- final JSONObject json = new JSONObject();
- json.put(Constants.APP_THEME, settingsHelper.getString(Constants.APP_THEME));
- json.put(Constants.APP_LANGUAGE, settingsHelper.getString(Constants.APP_LANGUAGE));
-
- String str = settingsHelper.getString(Constants.FOLDER_PATH);
- if (!TextUtils.isEmpty(str)) json.put(Constants.FOLDER_PATH, str);
-
- str = settingsHelper.getString(Constants.DATE_TIME_FORMAT);
- if (!TextUtils.isEmpty(str)) json.put(Constants.DATE_TIME_FORMAT, str);
-
- str = settingsHelper.getString(Constants.DATE_TIME_SELECTION);
- if (!TextUtils.isEmpty(str)) json.put(Constants.DATE_TIME_SELECTION, str);
-
- str = settingsHelper.getString(Constants.CUSTOM_DATE_TIME_FORMAT);
- if (!TextUtils.isEmpty(str)) json.put(Constants.CUSTOM_DATE_TIME_FORMAT, str);
-
- json.put(Constants.DOWNLOAD_USER_FOLDER, settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER));
- json.put(Constants.MUTED_VIDEOS, settingsHelper.getBoolean(Constants.MUTED_VIDEOS));
- json.put(Constants.AUTOPLAY_VIDEOS, settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
- json.put(Constants.AUTOLOAD_POSTS, settingsHelper.getBoolean(Constants.AUTOLOAD_POSTS));
- json.put(Constants.FOLDER_SAVE_TO, settingsHelper.getBoolean(Constants.FOLDER_SAVE_TO));
-
- result = json.toString();
- } catch (final Exception e) {
- result = null;
- if (logCollector != null) logCollector.appendException(e, LogFile.UTILS_EXPORT, "getSettings");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
+ @NonNull
+ private static JSONArray getFavorites() {
+ if (Utils.dataBox == null) return new JSONArray();
+ try {
+ final List allFavorites = Utils.dataBox.getAllFavorites();
+ final JSONArray jsonArray = new JSONArray();
+ for (final DataBox.FavoriteModel favorite : allFavorites) {
+ final JSONObject jsonObject = new JSONObject();
+ jsonObject.put("q", favorite.getQuery());
+ jsonObject.put("type", favorite.getType().toString());
+ jsonObject.put("s", favorite.getDisplayName());
+ jsonObject.put("pic_url", favorite.getPicUrl());
+ jsonObject.put("d", favorite.getDateAdded().getTime());
+ jsonArray.put(jsonObject);
+ }
+ return jsonArray;
+ } catch (final Exception e) {
+ if (logCollector != null) {
+ logCollector.appendException(e, LogFile.UTILS_EXPORT, "getFavorites");
+ }
+ if (BuildConfig.DEBUG) {
+ Log.e(TAG, "Error exporting favorites", e);
}
}
-
- return result;
+ return new JSONArray();
}
- @Nullable
- private static String getFavorites() {
- String result = null;
- if (Utils.dataBox != null) {
- try {
- final ArrayList allFavorites = Utils.dataBox.getAllFavorites();
- final int allFavoritesSize;
- if (allFavorites != null && (allFavoritesSize = allFavorites.size()) > 0) {
- final JSONArray jsonArray = new JSONArray();
- for (int i = 0; i < allFavoritesSize; i++) {
- final DataBox.FavoriteModel favorite = allFavorites.get(i);
- final JSONObject jsonObject = new JSONObject();
- jsonObject.put("q", favorite.getQuery());
- jsonObject.put("d", favorite.getDate());
- jsonObject.put("s", favorite.getDisplayName());
- jsonArray.put(jsonObject);
- }
- result = jsonArray.toString();
- }
- } catch (final Exception e) {
- result = null;
- if (logCollector != null) logCollector.appendException(e, LogFile.UTILS_EXPORT, "getFavorites");
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
+ @NonNull
+ private static JSONArray getCookies() {
+ if (Utils.dataBox == null) return new JSONArray();
+ try {
+ final List allCookies = Utils.dataBox.getAllCookies();
+ final JSONArray jsonArray = new JSONArray();
+ for (final DataBox.CookieModel cookie : allCookies) {
+ final JSONObject jsonObject = new JSONObject();
+ jsonObject.put("i", cookie.getUid());
+ jsonObject.put("u", cookie.getUsername());
+ jsonObject.put("c", cookie.getCookie());
+ jsonObject.put("full_name", cookie.getFullName());
+ jsonObject.put("profile_pic", cookie.getProfilePic());
+ jsonArray.put(jsonObject);
+ }
+ return jsonArray;
+ } catch (final Exception e) {
+ if (BuildConfig.DEBUG) {
+ Log.e(TAG, "Error exporting accounts", e);
}
}
- return result;
- }
-
- @Nullable
- private static String getCookies() {
- String result = null;
- if (Utils.dataBox != null) {
- try {
- final ArrayList allCookies = Utils.dataBox.getAllCookies();
- final int allCookiesSize;
- if (allCookies != null && (allCookiesSize = allCookies.size()) > 0) {
- final JSONArray jsonArray = new JSONArray();
- for (int i = 0; i < allCookiesSize; i++) {
- final DataBox.CookieModel cookieModel = allCookies.get(i);
- final JSONObject jsonObject = new JSONObject();
- jsonObject.put("i", cookieModel.getUid());
- jsonObject.put("u", cookieModel.getUsername());
- jsonObject.put("c", cookieModel.getCookie());
- jsonArray.put(jsonObject);
- }
- result = jsonArray.toString();
- }
- } catch (final Exception e) {
- result = null;
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
- }
- }
- return result;
- }
-
- private final static class PasswordUtils {
- private static final String cipherAlgo = "AES";
- private static final String cipherTran = "AES/CBC/PKCS5Padding";
-
- private static byte[] dec(final String encrypted, final byte[] keyValue) throws Exception {
- final Cipher cipher = Cipher.getInstance(cipherTran);
- final SecretKeySpec secretKey = new SecretKeySpec(keyValue, cipherAlgo);
- cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new byte[16]));
- return cipher.doFinal(Base64.decode(encrypted, Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP));
- }
-
- private static byte[] enc(@NonNull final String str, final byte[] keyValue) throws Exception {
- final Cipher cipher = Cipher.getInstance(cipherTran);
- final SecretKeySpec secretKey = new SecretKeySpec(keyValue, cipherAlgo);
- cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new byte[16]));
- final byte[] bytes = cipher.doFinal(str.getBytes());
- return Base64.encode(bytes, Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP);
- }
+ return new JSONArray();
}
}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java b/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java
index 87c225a1..9af64d87 100644
--- a/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java
+++ b/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java
@@ -34,7 +34,7 @@ public class NavigationExtensions {
int firstFragmentGraphId = 0;
for (int i = 0; i < navGraphIds.size(); i++) {
final int navGraphId = navGraphIds.get(i);
- final String fragmentTag = getFragmentTag(i);
+ final String fragmentTag = getFragmentTag(navGraphId);
final NavHostFragment navHostFragment = obtainNavHostFragment(fragmentManager, fragmentTag, navGraphId, containerId);
final NavController navController = navHostFragment.getNavController();
final int graphId = navController.getGraph().getId();
@@ -57,7 +57,8 @@ public class NavigationExtensions {
return false;
}
String newlySelectedItemTag = graphIdToTagMap.get(item.getItemId());
- if (!selectedItemTag[0].equals(newlySelectedItemTag)) {
+ String tag = selectedItemTag[0];
+ if (tag != null && !tag.equals(newlySelectedItemTag)) {
fragmentManager.popBackStack(firstFragmentTag, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Fragment fragment = fragmentManager.findFragmentByTag(newlySelectedItemTag);
if (fragment == null) {
@@ -176,7 +177,7 @@ public class NavigationExtensions {
final Intent intent) {
for (int i = 0; i < navGraphIds.size(); i++) {
final int navGraphId = navGraphIds.get(i);
- final String fragmentTag = getFragmentTag(i);
+ final String fragmentTag = getFragmentTag(navGraphId);
final NavHostFragment navHostFragment = obtainNavHostFragment(fragmentManager, fragmentTag, navGraphId, containerId);
if (navHostFragment.getNavController().handleDeepLink(intent)) {
final int selectedItemId = bottomNavigationView.getSelectedItemId();
diff --git a/app/src/main/java/awais/instagrabber/utils/PasswordUtils.java b/app/src/main/java/awais/instagrabber/utils/PasswordUtils.java
new file mode 100644
index 00000000..2cc380bc
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/utils/PasswordUtils.java
@@ -0,0 +1,47 @@
+package awais.instagrabber.utils;
+
+import android.util.Base64;
+
+import androidx.annotation.NonNull;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public final class PasswordUtils {
+ private static final String cipherAlgo = "AES";
+ private static final String cipherTran = "AES/CBC/PKCS5Padding";
+
+ public static byte[] dec(final String encrypted, final byte[] keyValue) throws Exception {
+ try {
+ final Cipher cipher = Cipher.getInstance(cipherTran);
+ final SecretKeySpec secretKey = new SecretKeySpec(keyValue, cipherAlgo);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new byte[16]));
+ return cipher.doFinal(Base64.decode(encrypted, Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP));
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
+ throw new IncorrectPasswordException(e);
+ }
+ }
+
+ public static byte[] enc(@NonNull final String str, final byte[] keyValue) throws Exception {
+ final Cipher cipher = Cipher.getInstance(cipherTran);
+ final SecretKeySpec secretKey = new SecretKeySpec(keyValue, cipherAlgo);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new byte[16]));
+ final byte[] bytes = cipher.doFinal(str.getBytes());
+ return Base64.encode(bytes, Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP);
+ }
+
+ public static class IncorrectPasswordException extends Exception {
+ public IncorrectPasswordException(final GeneralSecurityException e) {
+ super(e);
+ }
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java
index a5610b22..658177d3 100644
--- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java
+++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java
@@ -232,8 +232,8 @@ public final class ResponseBodyUtils {
final String threadV2Id = data.getString("thread_v2_id");
final String threadTitle = data.getString("thread_title");
- final String threadNewestCursor = data.getString("newest_cursor");
- final String threadOldestCursor = data.getString("oldest_cursor");
+ final String threadNewestCursor = data.optString("newest_cursor");
+ final String threadOldestCursor = data.optString("oldest_cursor");
final String threadNextCursor = data.has("next_cursor") ? data.getString("next_cursor") : null;
final String threadPrevCursor = data.has("prev_cursor") ? data.getString("prev_cursor") : null;
diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
index aa39823e..34ad3102 100755
--- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
+++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
@@ -40,7 +40,7 @@ public final class SettingsHelper {
private final SharedPreferences sharedPreferences;
public SettingsHelper(@NonNull final Context context) {
- this.sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE);
+ this.sharedPreferences = context.getSharedPreferences(Constants.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
@NonNull
diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java
index 1fed5097..6e3b9ca6 100755
--- a/app/src/main/java/awais/instagrabber/utils/Utils.java
+++ b/app/src/main/java/awais/instagrabber/utils/Utils.java
@@ -1,28 +1,20 @@
package awais.instagrabber.utils;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.Uri;
-import android.os.Build;
-import android.text.Editable;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
+import android.util.Pair;
import android.webkit.MimeTypeMap;
import android.widget.Toast;
import androidx.annotation.NonNull;
-import androidx.annotation.StringRes;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.app.AppCompatDelegate;
-import androidx.fragment.app.FragmentManager;
+import androidx.annotation.Nullable;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
@@ -39,11 +31,9 @@ import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import awais.instagrabber.R;
-import awais.instagrabber.databinding.DialogImportExportBinding;
+import awais.instagrabber.models.enums.FavoriteType;
import awaisomereport.LogCollector;
-import static awais.instagrabber.utils.Constants.FOLDER_PATH;
-
public final class Utils {
private static final String TAG = "Utils";
private static final int VIDEO_CACHE_MAX_BYTES = 10 * 1024 * 1024;
@@ -64,19 +54,6 @@ public final class Utils {
return Math.round((dp * displayMetrics.densityDpi) / 160.0f);
}
- public static void setTooltipText(final View view, @StringRes final int tooltipTextRes) {
- if (view != null && tooltipTextRes != 0 && tooltipTextRes != -1) {
- final Context context = view.getContext();
- final String tooltipText = context.getResources().getString(tooltipTextRes);
-
- if (Build.VERSION.SDK_INT >= 26) view.setTooltipText(tooltipText);
- else view.setOnLongClickListener(v -> {
- Toast.makeText(context, tooltipText, Toast.LENGTH_SHORT).show();
- return true;
- });
- }
- }
-
public static void copyText(@NonNull final Context context, final CharSequence string) {
if (clipboardManager == null)
clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
@@ -89,100 +66,6 @@ public final class Utils {
Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show();
}
- public static void showImportExportDialog(final Context context) {
- final DialogImportExportBinding importExportBinding = DialogImportExportBinding.inflate(LayoutInflater.from(context));
-
- final View passwordParent = (View) importExportBinding.cbPassword.getParent();
- final View exportLoginsParent = (View) importExportBinding.cbExportLogins.getParent();
- final View exportFavoritesParent = (View) importExportBinding.cbExportFavorites.getParent();
- final View exportSettingsParent = (View) importExportBinding.cbExportSettings.getParent();
- final View importLoginsParent = (View) importExportBinding.cbImportLogins.getParent();
- final View importFavoritesParent = (View) importExportBinding.cbImportFavorites.getParent();
- final View importSettingsParent = (View) importExportBinding.cbImportSettings.getParent();
-
- importExportBinding.cbPassword.setOnCheckedChangeListener((buttonView, isChecked) ->
- importExportBinding.etPassword.etPassword.setEnabled(isChecked));
-
- final AlertDialog[] dialog = new AlertDialog[1];
- final View.OnClickListener onClickListener = v -> {
- if (v == passwordParent) importExportBinding.cbPassword.performClick();
-
- else if (v == exportLoginsParent) importExportBinding.cbExportLogins.performClick();
- else if (v == exportFavoritesParent)
- importExportBinding.cbExportFavorites.performClick();
-
- else if (v == importLoginsParent) importExportBinding.cbImportLogins.performClick();
- else if (v == importFavoritesParent)
- importExportBinding.cbImportFavorites.performClick();
-
- else if (v == exportSettingsParent) importExportBinding.cbExportSettings.performClick();
- else if (v == importSettingsParent) importExportBinding.cbImportSettings.performClick();
-
- else if (context instanceof AppCompatActivity) {
- final FragmentManager fragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
- final String folderPath = settingsHelper.getString(FOLDER_PATH);
-
- if (v == importExportBinding.btnSaveTo) {
- final Editable text = importExportBinding.etPassword.etPassword.getText();
- final boolean passwordChecked = importExportBinding.cbPassword.isChecked();
- if (passwordChecked && TextUtils.isEmpty(text))
- Toast.makeText(context, R.string.dialog_export_err_password_empty, Toast.LENGTH_SHORT).show();
- else {
- new DirectoryChooser().setInitialDirectory(folderPath).setInteractionListener(path -> {
- final File file = new File(path, "InstaGrabber_Settings_" + System.currentTimeMillis() + ".zaai");
- final String password = passwordChecked ? text.toString() : null;
- int flags = 0;
- if (importExportBinding.cbExportFavorites.isChecked())
- flags |= ExportImportUtils.FLAG_FAVORITES;
- if (importExportBinding.cbExportSettings.isChecked())
- flags |= ExportImportUtils.FLAG_SETTINGS;
- if (importExportBinding.cbExportLogins.isChecked())
- flags |= ExportImportUtils.FLAG_COOKIES;
-
- ExportImportUtils.Export(password, flags, file, result -> {
- Toast.makeText(context, result ? R.string.dialog_export_success : R.string.dialog_export_failed, Toast.LENGTH_SHORT)
- .show();
- if (dialog[0] != null && dialog[0].isShowing()) dialog[0].dismiss();
- });
-
- }).show(fragmentManager, null);
- }
-
- } else if (v == importExportBinding.btnImport) {
- new DirectoryChooser().setInitialDirectory(folderPath).setShowZaAiConfigFiles(true).setInteractionListener(path -> {
- int flags = 0;
- if (importExportBinding.cbImportFavorites.isChecked())
- flags |= ExportImportUtils.FLAG_FAVORITES;
- if (importExportBinding.cbImportSettings.isChecked())
- flags |= ExportImportUtils.FLAG_SETTINGS;
- if (importExportBinding.cbImportLogins.isChecked())
- flags |= ExportImportUtils.FLAG_COOKIES;
-
- ExportImportUtils.Import(context, flags, new File(path), result -> {
- ((AppCompatActivity) context).recreate();
- Toast.makeText(context, result ? R.string.dialog_import_success : R.string.dialog_import_failed, Toast.LENGTH_SHORT)
- .show();
- if (dialog[0] != null && dialog[0].isShowing()) dialog[0].dismiss();
- });
-
- }).show(fragmentManager, null);
- }
- }
- };
-
- passwordParent.setOnClickListener(onClickListener);
- exportLoginsParent.setOnClickListener(onClickListener);
- exportSettingsParent.setOnClickListener(onClickListener);
- exportFavoritesParent.setOnClickListener(onClickListener);
- importLoginsParent.setOnClickListener(onClickListener);
- importSettingsParent.setOnClickListener(onClickListener);
- importFavoritesParent.setOnClickListener(onClickListener);
- importExportBinding.btnSaveTo.setOnClickListener(onClickListener);
- importExportBinding.btnImport.setOnClickListener(onClickListener);
-
- dialog[0] = new AlertDialog.Builder(context).setView(importExportBinding.getRoot()).show();
- }
-
public static Map sign(final Map form) {
final String signed = sign(new JSONObject(form).toString());
if (signed == null) {
@@ -251,4 +134,16 @@ public final class Utils {
}
return simpleCache;
}
+
+ @Nullable
+ public static Pair migrateOldFavQuery(final String queryText) {
+ if (queryText.startsWith("@")) {
+ return new Pair<>(FavoriteType.USER, queryText.substring(1));
+ } else if (queryText.contains("/")) {
+ return new Pair<>(FavoriteType.LOCATION, queryText.substring(0, queryText.indexOf("/")));
+ } else if (queryText.startsWith("#")) {
+ return new Pair<>(FavoriteType.HASHTAG, queryText.substring(1));
+ }
+ return null;
+ }
}
diff --git a/app/src/main/java/awais/instagrabber/viewmodels/FavoritesViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/FavoritesViewModel.java
new file mode 100644
index 00000000..e30d4116
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/viewmodels/FavoritesViewModel.java
@@ -0,0 +1,19 @@
+package awais.instagrabber.viewmodels;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import java.util.List;
+
+import awais.instagrabber.utils.DataBox;
+
+public class FavoritesViewModel extends ViewModel {
+ private MutableLiveData> list;
+
+ public MutableLiveData> getList() {
+ if (list == null) {
+ list = new MutableLiveData<>();
+ }
+ return list;
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/viewmodels/FileListViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/FileListViewModel.java
new file mode 100644
index 00000000..c8ebcd5c
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/viewmodels/FileListViewModel.java
@@ -0,0 +1,18 @@
+package awais.instagrabber.viewmodels;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import java.io.File;
+import java.util.List;
+
+public class FileListViewModel extends ViewModel {
+ private MutableLiveData> list;
+
+ public MutableLiveData> getList() {
+ if (list == null) {
+ list = new MutableLiveData<>();
+ }
+ return list;
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java
index 14e3fc7e..fb5bba2c 100644
--- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java
@@ -98,14 +98,12 @@ public class StoriesService extends BaseService {
public void getUserStory(final String id,
final String username,
- final boolean storiesig,
final boolean isLoc,
final boolean isHashtag,
final boolean highlight,
final ServiceCallback> callback) {
- final String url = buildUrl(id, storiesig, isLoc, isHashtag, highlight);
- final String userAgent = storiesig ? Constants.A_USER_AGENT : Constants.I_USER_AGENT;
- final Call userStoryCall = repository.getUserStory(userAgent, url);
+ final String url = buildUrl(id, isLoc, isHashtag, highlight);
+ final Call userStoryCall = repository.getUserStory(Constants.I_USER_AGENT, url);
userStoryCall.enqueue(new Callback() {
@Override
public void onResponse(@NonNull final Call call, @NonNull final Response response) {
@@ -119,7 +117,7 @@ public class StoriesService extends BaseService {
}
data = new JSONObject(body);
- if (!storiesig && !highlight)
+ if (!highlight)
data = data.optJSONObject((isLoc || isHashtag) ? "story" : "reel");
else if (highlight) data = data.getJSONObject("reels").optJSONObject(id);
@@ -243,16 +241,10 @@ public class StoriesService extends BaseService {
});
}
- private String buildUrl(final String id, final boolean storiesig, final boolean isLoc, final boolean isHashtag, final boolean highlight) {
+ private String buildUrl(final String id, final boolean isLoc, final boolean isHashtag, final boolean highlight) {
final String userId = id.replace(":", "%3A");
final StringBuilder builder = new StringBuilder();
- builder.append("https://");
- if (storiesig) {
- builder.append("storiesig");
- } else {
- builder.append("i.instagram");
- }
- builder.append(".com/api/v1/");
+ builder.append("https://i.instagram.com/api/v1/");
if (isLoc) {
builder.append("locations/");
}
@@ -266,11 +258,7 @@ public class StoriesService extends BaseService {
}
builder.append(userId);
if (!highlight) {
- if (storiesig) {
- builder.append("/reel_media/");
- } else {
- builder.append("/story/");
- }
+ builder.append("/story/");
}
return builder.toString();
}
diff --git a/app/src/main/java/awais/instagrabber/webservices/TagsService.java b/app/src/main/java/awais/instagrabber/webservices/TagsService.java
new file mode 100644
index 00000000..2834a570
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/webservices/TagsService.java
@@ -0,0 +1,101 @@
+package awais.instagrabber.webservices;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import awais.instagrabber.repositories.TagsRepository;
+import awais.instagrabber.utils.Constants;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+
+public class TagsService extends BaseService {
+
+ private static final String TAG = "TagsService";
+
+ // web for www.instagram.com
+ private final TagsRepository webRepository;
+
+ private static TagsService instance;
+
+ private TagsService() {
+ final Retrofit webRetrofit = getRetrofitBuilder()
+ .baseUrl("https://www.instagram.com/")
+ .build();
+ webRepository = webRetrofit.create(TagsRepository.class);
+ }
+
+ public static TagsService getInstance() {
+ if (instance == null) {
+ instance = new TagsService();
+ }
+ return instance;
+ }
+
+ public void follow(@NonNull final String tag,
+ @NonNull final String csrfToken,
+ final ServiceCallback callback) {
+ final Call request = webRepository.follow(Constants.USER_AGENT,
+ csrfToken,
+ tag);
+ request.enqueue(new Callback() {
+ @Override
+ public void onResponse(@NonNull final Call call, @NonNull final Response response) {
+ final String body = response.body();
+ if (body == null) {
+ callback.onFailure(new RuntimeException("body is null"));
+ return;
+ }
+ try {
+ final JSONObject jsonObject = new JSONObject(body);
+ final String status = jsonObject.optString("status");
+ callback.onSuccess(status.equals("ok"));
+ } catch (JSONException e) {
+ Log.e(TAG, "onResponse: ", e);
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull final Call call, @NonNull final Throwable t) {
+ // Log.e(TAG, "onFailure: ", t);
+ callback.onFailure(t);
+ }
+ });
+ }
+
+ public void unfollow(@NonNull final String tag,
+ @NonNull final String csrfToken,
+ final ServiceCallback callback) {
+ final Call request = webRepository.unfollow(Constants.USER_AGENT,
+ csrfToken,
+ tag);
+ request.enqueue(new Callback() {
+ @Override
+ public void onResponse(@NonNull final Call call, @NonNull final Response response) {
+ final String body = response.body();
+ if (body == null) {
+ callback.onFailure(new RuntimeException("body is null"));
+ return;
+ }
+ try {
+ final JSONObject jsonObject = new JSONObject(body);
+ final String status = jsonObject.optString("status");
+ callback.onSuccess(status.equals("ok"));
+ } catch (JSONException e) {
+ Log.e(TAG, "onResponse: ", e);
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull final Call call, @NonNull final Throwable t) {
+ // Log.e(TAG, "onFailure: ", t);
+ callback.onFailure(t);
+ }
+ });
+ }
+}
diff --git a/app/src/main/res/drawable-night/expired.png b/app/src/main/res/drawable-night/expired.png
deleted file mode 100644
index 31da07c8..00000000
Binary files a/app/src/main/res/drawable-night/expired.png and /dev/null differ
diff --git a/app/src/main/res/drawable/expired.png b/app/src/main/res/drawable/expired.png
deleted file mode 100644
index 83f232d4..00000000
Binary files a/app/src/main/res/drawable/expired.png and /dev/null differ
diff --git a/app/src/main/res/drawable/ic_account_multiple_remove_24.xml b/app/src/main/res/drawable/ic_account_multiple_remove_24.xml
new file mode 100644
index 00000000..eb035e53
--- /dev/null
+++ b/app/src/main/res/drawable/ic_account_multiple_remove_24.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_block_24.xml b/app/src/main/res/drawable/ic_block_24.xml
new file mode 100644
index 00000000..9fefeec6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_block_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_clock_alert_outline_24.xml b/app/src/main/res/drawable/ic_clock_alert_outline_24.xml
new file mode 100644
index 00000000..731319fe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_clock_alert_outline_24.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_file_24.xml b/app/src/main/res/drawable/ic_file_24.xml
new file mode 100644
index 00000000..f404fbf7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_file_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_logout.xml b/app/src/main/res/drawable/ic_folder_24.xml
similarity index 68%
rename from app/src/main/res/drawable/ic_logout.xml
rename to app/src/main/res/drawable/ic_folder_24.xml
index bab545a7..dc6b0802 100644
--- a/app/src/main/res/drawable/ic_logout.xml
+++ b/app/src/main/res/drawable/ic_folder_24.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
+ android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
diff --git a/app/src/main/res/drawable/ic_highlight_off_24.xml b/app/src/main/res/drawable/ic_highlight_off_24.xml
new file mode 100644
index 00000000..6a21d0d7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_highlight_off_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_logout_24.xml b/app/src/main/res/drawable/ic_logout_24.xml
new file mode 100644
index 00000000..376bc7ce
--- /dev/null
+++ b/app/src/main/res/drawable/ic_logout_24.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_outline_class_24.xml b/app/src/main/res/drawable/ic_outline_class_24.xml
new file mode 100644
index 00000000..bace1783
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_class_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_map_24.xml b/app/src/main/res/drawable/ic_outline_map_24.xml
new file mode 100644
index 00000000..d0769b3e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_map_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_person_add_24.xml b/app/src/main/res/drawable/ic_outline_person_add_24.xml
new file mode 100644
index 00000000..a2a0572a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_person_add_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_person_add_disabled_24.xml b/app/src/main/res/drawable/ic_outline_person_add_disabled_24.xml
new file mode 100644
index 00000000..e230319e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_person_add_disabled_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_person_pin_24.xml b/app/src/main/res/drawable/ic_outline_person_pin_24.xml
new file mode 100644
index 00000000..13963ebf
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_person_pin_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_star_24.xml b/app/src/main/res/drawable/ic_outline_star_24.xml
new file mode 100644
index 00000000..b6d93cac
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_star_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_star_plus_24.xml b/app/src/main/res/drawable/ic_outline_star_plus_24.xml
new file mode 100644
index 00000000..2977b0e5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_star_plus_24.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_settings_backup_restore_24.xml b/app/src/main/res/drawable/ic_settings_backup_restore_24.xml
new file mode 100644
index 00000000..1772ed50
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings_backup_restore_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_star_check_24.xml b/app/src/main/res/drawable/ic_star_check_24.xml
new file mode 100644
index 00000000..b413c895
--- /dev/null
+++ b/app/src/main/res/drawable/ic_star_check_24.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/rounder_corner_semi_black_bg.xml b/app/src/main/res/drawable/rounder_corner_semi_black_bg.xml
index a0706c60..67e019e3 100644
--- a/app/src/main/res/drawable/rounder_corner_semi_black_bg.xml
+++ b/app/src/main/res/drawable/rounder_corner_semi_black_bg.xml
@@ -1,6 +1,6 @@
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 47477544..ad84f7a4 100755
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -28,7 +28,6 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="none"
- app:popupTheme="@style/Widget.AppTheme.Toolbar.PrimarySurface"
app:title="@string/app_name"
tools:menu="@menu/main_menu" />
diff --git a/app/src/main/res/layout/dialog_create_backup.xml b/app/src/main/res/layout/dialog_create_backup.xml
new file mode 100644
index 00000000..78df89d5
--- /dev/null
+++ b/app/src/main/res/layout/dialog_create_backup.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_import_export.xml b/app/src/main/res/layout/dialog_import_export.xml
deleted file mode 100755
index 0d6910f1..00000000
--- a/app/src/main/res/layout/dialog_import_export.xml
+++ /dev/null
@@ -1,230 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_profilepic.xml b/app/src/main/res/layout/dialog_profilepic.xml
index 0b5a4000..38db7201 100644
--- a/app/src/main/res/layout/dialog_profilepic.xml
+++ b/app/src/main/res/layout/dialog_profilepic.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/semi_transparent_black">
+ android:background="@color/black_a50">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_favorites.xml b/app/src/main/res/layout/fragment_favorites.xml
new file mode 100644
index 00000000..05a808d6
--- /dev/null
+++ b/app/src/main/res/layout/fragment_favorites.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_hashtag.xml b/app/src/main/res/layout/fragment_hashtag.xml
index 311ec733..262a2f22 100644
--- a/app/src/main/res/layout/fragment_hashtag.xml
+++ b/app/src/main/res/layout/fragment_hashtag.xml
@@ -17,47 +17,120 @@
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll">
-
+ android:padding="@dimen/profile_info_container_bottom_space">
+ android:background="?selectableItemBackgroundBorderless"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/mainTagPostCount"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:background="@mipmap/ic_launcher" />
+ app:layout_constraintBottom_toTopOf="@id/btnFollowTag"
+ app:layout_constraintStart_toEndOf="@id/mainHashtagImage"
+ app:layout_constraintTop_toTopOf="@id/mainHashtagImage"
+ tools:text="35 Posts" />
-
-
+ app:chipBackgroundColor="@null"
+ app:chipIcon="@drawable/ic_outline_person_add_24"
+ app:chipIconTint="@color/deep_purple_800"
+ app:layout_constraintBottom_toBottomOf="@id/mainHashtagImage"
+ app:layout_constraintStart_toEndOf="@id/mainHashtagImage"
+ app:layout_constraintTop_toBottomOf="@id/mainTagPostCount"
+ app:rippleColor="@color/purple_200" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_location.xml b/app/src/main/res/layout/fragment_location.xml
index 9ea5a610..8ae9ef80 100644
--- a/app/src/main/res/layout/fragment_location.xml
+++ b/app/src/main/res/layout/fragment_location.xml
@@ -17,101 +17,128 @@
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
-
+ android:padding="8dp">
-
+
+
+
+
+ android:layout_marginStart="8dp"
+ android:layout_marginLeft="8dp"
+ android:text="@string/map"
+ app:chipBackgroundColor="@null"
+ app:chipIcon="@drawable/ic_outline_map_24"
+ app:chipIconTint="@color/green_500"
+ app:layout_constraintBottom_toTopOf="@id/locationFullName"
+ app:layout_constraintStart_toEndOf="@id/mainLocationImage"
+ app:layout_constraintTop_toBottomOf="@id/mainLocPostCount"
+ app:rippleColor="@color/grey_500"
+ tools:visibility="visible" />
-
-
-
-
-
-
+
+ app:layout_constraintBottom_toTopOf="@id/locationUrl"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/locationFullName"
+ tools:text="IN THE MIDDLE OF OUR STREET"
+ tools:visibility="visible" />
-
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/locationBiography"
+ tools:text="https://austinhuang.me/"
+ tools:visibility="visible" />
+
diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml
index 2552fd7f..aedcbaaa 100644
--- a/app/src/main/res/layout/fragment_profile.xml
+++ b/app/src/main/res/layout/fragment_profile.xml
@@ -79,8 +79,10 @@
android:ellipsize="marquee"
android:paddingStart="8dp"
android:paddingLeft="8dp"
+ android:paddingTop="8dp"
android:paddingEnd="4dp"
android:paddingRight="4dp"
+ android:paddingBottom="8dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textStyle="bold"
@@ -102,15 +104,34 @@
app:srcCompat="@drawable/verified"
tools:visibility="visible" />
+
+
+
+
+ tools:visibility="gone" />
-
-
-
-
-
-
-
-
-
-
+
+
-
\ No newline at end of file
+ android:background="?attr/selectableItemBackground"
+ android:minHeight="56dp">
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_fav_section_header.xml b/app/src/main/res/layout/item_fav_section_header.xml
new file mode 100644
index 00000000..19f6fd40
--- /dev/null
+++ b/app/src/main/res/layout/item_fav_section_header.xml
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_feed_slider.xml b/app/src/main/res/layout/item_feed_slider.xml
index a6b31978..2267d089 100755
--- a/app/src/main/res/layout/item_feed_slider.xml
+++ b/app/src/main/res/layout/item_feed_slider.xml
@@ -18,7 +18,7 @@
android:id="@+id/media_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:background="@color/semi_transparent_black" />
+ tools:background="@color/black_a50" />
@@ -36,7 +36,6 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
- android:textColor="@color/feed_text_primary_color"
tools:text="username" />
diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml
index f2c344f1..9b2e4b11 100644
--- a/app/src/main/res/layout/item_notification.xml
+++ b/app/src/main/res/layout/item_notification.xml
@@ -20,37 +20,6 @@
app:roundAsCircle="true"
tools:placeholderImage="@mipmap/ic_launcher" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ tools:text="sub-comment long long long long long long long long long long" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_suggestion.xml b/app/src/main/res/layout/item_suggestion.xml
index 55425bb1..df114c34 100755
--- a/app/src/main/res/layout/item_suggestion.xml
+++ b/app/src/main/res/layout/item_suggestion.xml
@@ -7,7 +7,10 @@
android:background="?selectableItemBackground"
android:clickable="true"
android:focusable="true"
- android:padding="8dp">
+ android:paddingLeft="16dp"
+ android:paddingTop="8dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="8dp">
-
-
-
-
-
-
-
-
-
-
-
-
-
+ app:layout_constraintBottom_toTopOf="@id/directoryList"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
-
-
-
-
-
-
-
-
+ app:navigationIcon="@drawable/ic_arrow_upward_24"
+ tools:title="/this/that/thy" />
+
-
\ No newline at end of file
+ app:layout_constraintBottom_toTopOf="@id/bottom_horizontal_divider"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_dm_raven_media.xml b/app/src/main/res/layout/layout_dm_raven_media.xml
index 6eda3942..b5aa10a3 100644
--- a/app/src/main/res/layout/layout_dm_raven_media.xml
+++ b/app/src/main/res/layout/layout_dm_raven_media.xml
@@ -10,7 +10,7 @@
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:padding="8dp"
- android:src="@drawable/expired" />
+ app:srcCompat="@drawable/ic_clock_alert_outline_24" />
+ android:visibility="gone"
+ tools:visibility="visible">
\ No newline at end of file
diff --git a/app/src/main/res/navigation/more_nav_graph.xml b/app/src/main/res/navigation/more_nav_graph.xml
index 242d25a7..3f2ee769 100644
--- a/app/src/main/res/navigation/more_nav_graph.xml
+++ b/app/src/main/res/navigation/more_nav_graph.xml
@@ -34,6 +34,24 @@
app:nullable="true" />
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/profile_nav_graph.xml b/app/src/main/res/navigation/profile_nav_graph.xml
index 1af3b2bd..082a186d 100644
--- a/app/src/main/res/navigation/profile_nav_graph.xml
+++ b/app/src/main/res/navigation/profile_nav_graph.xml
@@ -36,7 +36,7 @@
+ app:destination="@id/profile_nav_graph">
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de/arrays.xml b/app/src/main/res/values-de/arrays.xml
index 088c4a46..ce2a1fbc 100644
--- a/app/src/main/res/values-de/arrays.xml
+++ b/app/src/main/res/values-de/arrays.xml
@@ -42,7 +42,6 @@
- Deaktivieren
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-es/arrays.xml b/app/src/main/res/values-es/arrays.xml
index 774dcb7b..135783ea 100755
--- a/app/src/main/res/values-es/arrays.xml
+++ b/app/src/main/res/values-es/arrays.xml
@@ -42,7 +42,6 @@
- Disable
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-fa/arrays.xml b/app/src/main/res/values-fa/arrays.xml
index 76e43ab5..7a46c80a 100644
--- a/app/src/main/res/values-fa/arrays.xml
+++ b/app/src/main/res/values-fa/arrays.xml
@@ -42,7 +42,6 @@
- ΨΊΫΨ±ΩΨΉΨ§Ω
- - Ψ§Ψ³ΨͺΩΨ±Ϋ ΩΨ§Ϋ ig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-fr/arrays.xml b/app/src/main/res/values-fr/arrays.xml
index 34fb31e8..d3873b53 100755
--- a/app/src/main/res/values-fr/arrays.xml
+++ b/app/src/main/res/values-fr/arrays.xml
@@ -42,7 +42,6 @@
- Disable
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-in/arrays.xml b/app/src/main/res/values-in/arrays.xml
index 9a8969fa..54736873 100644
--- a/app/src/main/res/values-in/arrays.xml
+++ b/app/src/main/res/values-in/arrays.xml
@@ -42,7 +42,6 @@
- Nonaktifkan
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-it/arrays.xml b/app/src/main/res/values-it/arrays.xml
index 0332b8d4..7c0d00d8 100755
--- a/app/src/main/res/values-it/arrays.xml
+++ b/app/src/main/res/values-it/arrays.xml
@@ -42,7 +42,6 @@
- Disattiva
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-mk/arrays.xml b/app/src/main/res/values-mk/arrays.xml
index e25cc849..3d671204 100644
--- a/app/src/main/res/values-mk/arrays.xml
+++ b/app/src/main/res/values-mk/arrays.xml
@@ -42,7 +42,6 @@
- Disable
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-night/color.xml b/app/src/main/res/values-night/color.xml
index 92e7892a..ce9cab02 100755
--- a/app/src/main/res/values-night/color.xml
+++ b/app/src/main/res/values-night/color.xml
@@ -1,6 +1,4 @@
- @color/text_color_dark
-
#353535
\ No newline at end of file
diff --git a/app/src/main/res/values-pl/arrays.xml b/app/src/main/res/values-pl/arrays.xml
index cb45f646..71a651d0 100644
--- a/app/src/main/res/values-pl/arrays.xml
+++ b/app/src/main/res/values-pl/arrays.xml
@@ -42,7 +42,6 @@
- Disable
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-pt/arrays.xml b/app/src/main/res/values-pt/arrays.xml
index 86a68b2e..c469e24c 100644
--- a/app/src/main/res/values-pt/arrays.xml
+++ b/app/src/main/res/values-pt/arrays.xml
@@ -42,7 +42,6 @@
- Disable
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-ru/arrays.xml b/app/src/main/res/values-ru/arrays.xml
index 995f1dbc..d9a71cac 100644
--- a/app/src/main/res/values-ru/arrays.xml
+++ b/app/src/main/res/values-ru/arrays.xml
@@ -42,7 +42,6 @@
- Disable
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-tr/arrays.xml b/app/src/main/res/values-tr/arrays.xml
index a801b947..576645a2 100644
--- a/app/src/main/res/values-tr/arrays.xml
+++ b/app/src/main/res/values-tr/arrays.xml
@@ -42,7 +42,6 @@
- DevredΔ±ΕΔ± BΔ±rak
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values-zh/arrays.xml b/app/src/main/res/values-zh/arrays.xml
index e2561ddb..e89bd427 100755
--- a/app/src/main/res/values-zh/arrays.xml
+++ b/app/src/main/res/values-zh/arrays.xml
@@ -42,7 +42,6 @@
- η¦η¨
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 3a65c322..5e8ca0b2 100755
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -42,7 +42,6 @@
- Disable
- - storiesig
- Aloinstagram
- Instadp
diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml
index 90ff3501..5d46cf57 100755
--- a/app/src/main/res/values/color.xml
+++ b/app/src/main/res/values/color.xml
@@ -28,15 +28,13 @@
#FFBB00
#FF000000
- @color/text_color_light
-
#efefef
- #80000000
#FFFFFF
#000000
#121212
+ #80000000
#FAFAFA
#F5F5F5
@@ -83,7 +81,67 @@
#bb86fc
#4b01d0
- #cf6679
+ #EDE7F6
+ #D1C4E9
+ #B39DDB
+ #9575CD
+ #7E57C2
+ #673AB7
+ #5E35B1
+ #512DA8
+ #4527A0
+ #311B92
+ #B388FF
+ #7C4DFF
+ #651FFF
+ #6200EA
+
+ #FFEBEE
+ #FFCDD2
+ #EF9A9A
+ #E57373
+ #EF5350
+ #F44336
+ #E53935
+ #D32F2F
+ #C62828
+ #B71C1C
+ #FF8A80
+ #FF5252
+ #FF1744
+ #D50000
+
+ #FBE9E7
+ #FFCCBC
+ #FFAB91
+ #FF8A65
+ #FF7043
+ #FF5722
+ #F4511E
+ #E64A19
+ #D84315
+ #BF360C
+ #FF9E80
+ #FF6E40
+ #FF3D00
+ #DD2C00
+
+ #FFFDE7
+ #FFF9C4
+ #FFF59D
+ #FFF176
+ #FFEE58
+ #FFEB3B
+ #FDD835
+ #FBC02D
+ #F9A825
+ #F57F17
+ #FFFF8D
+ #FFFF00
+ #FFEA00
+ #FFD600
+
+ #5CE362
#a86735
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c98f724a..fe5c3d78 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -18,6 +18,8 @@
Copied to clipboard!
Report
Password (Max 32 chars)
+ Set a password (max 32 chars)
+ Password
OK
Yes
Cancel
@@ -25,7 +27,7 @@
Confirm
Up
Don\'t Show Again
- Selected folder:
+ Current directory
Favorites
Discover
Comments
@@ -58,6 +60,7 @@
Language
What to do?
%s\nPosts
+ %s Posts
%s\nFollowers
%s\nFollowing
Video post
@@ -109,6 +112,7 @@
Liked
Saved
Tagged
+ Message
Like (%s)
Unlike (%s)
Bookmark
@@ -125,16 +129,18 @@
Export
Import
Export Logins
- Export Settings
- Export Favorites
- Import Settings
+ Accounts
+ Settings
+ Favorites
+ Import settings
Import Logins
- Import Favorites
+ Import accounts
+ Import favorites
Successfully imported!
Failed to import!
Successfully exported!
Failed to export!
- Password is empty! Password cannot be empt, dumbass!
+ Password is empty!
Refresh
Get cookies
Desktop Mode
@@ -146,7 +152,7 @@
Swap Time and Date positions
Favorites panel is for adding your favorite hashtags and/or usernames.\n\nAnd the Quick Access panel is for quickly switching between accounts.\n\nNote 1: Make sure to Login into each account [Settings > Login] to add account to the list!\n\nNote 2: Log out of the current account and then log into the other account.
Cannot delete currently in use account
- Are you sure you want to delete %s?
+ Are you sure you want to delete \'%s\'?
Width: %d\nHeight: %d
\nColor depth:
Select profile picture endpoint\n(Does not affect hashtags)
@@ -284,4 +290,17 @@
Barista
Bibliogram
Material Dark
+ Added to Favorites
+ Add to favorites
+ Accounts
+ Hashtags
+ Locations
+ Unknown
+ Removed from Favourites
+ Backup & Restore
+ Create
+ Restore
+ File:
+ Enter password
+ Select a backup file (.zaai/.backup)
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 459a3d33..54b6c291 100755
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -57,7 +57,11 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index d4358cfa..e1c4087a 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -19,6 +19,7 @@
- false
- @style/ThemeOverlay.MaterialComponents.ActionBar
+ - @style/ThemeOverlay.MaterialComponents.MaterialAlertDialog.Light