diff --git a/app/build.gradle b/app/build.gradle index 7295a592..62743e0e 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,6 +39,7 @@ android { dependencies { def appcompat_version = "1.2.0" def nav_version = "2.3.0" + def preference_version = "1.1.1" implementation "androidx.appcompat:appcompat:$appcompat_version" // For loading and tinting drawables on older versions of the platform @@ -50,6 +51,8 @@ dependencies { implementation "androidx.navigation:navigation-fragment:$nav_version" implementation "androidx.navigation:navigation-ui:$nav_version" implementation "androidx.constraintlayout:constraintlayout:2.0.0" + implementation "androidx.preference:preference:$preference_version" + implementation 'org.jsoup:jsoup:1.13.1' implementation 'com.github.bumptech.glide:glide:4.11.0' @@ -59,6 +62,7 @@ dependencies { implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' } diff --git a/app/src/main/java/awais/instagrabber/MainHelper.java b/app/src/main/java/awais/instagrabber/MainHelper.java index a5d66116..d67a4fee 100755 --- a/app/src/main/java/awais/instagrabber/MainHelper.java +++ b/app/src/main/java/awais/instagrabber/MainHelper.java @@ -1372,12 +1372,15 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { public void onClick(final View v) { final String userIdFromCookie = Utils.getUserIdFromCookie(MainHelper.this.cookie); final boolean isSelf = (isLoggedIn && mainActivity.profileModel != null) && userIdFromCookie != null && userIdFromCookie.equals(mainActivity.profileModel.getId()); - if (!isLoggedIn && Utils.dataBox.getFavorite(mainActivity.userQuery) != null && v == mainActivity.mainBinding.profileView.btnFollow) { + if (!isLoggedIn + && Utils.dataBox.getFavorite(mainActivity.userQuery) != null + && v == mainActivity.mainBinding.profileView.btnFollow) { Utils.dataBox.delFavorite(new DataBox.FavoriteModel(mainActivity.userQuery, Long.parseLong(Utils.dataBox.getFavorite(mainActivity.userQuery).split("/")[1]), mainActivity.locationModel != null ? mainActivity.locationModel.getName() : mainActivity.userQuery.replaceAll("^@", ""))); onRefresh(); - } else if (!isLoggedIn && (v == mainActivity.mainBinding.profileView.btnFollow || v == mainActivity.mainBinding.profileView.btnFollowTag)) { + } else if (!isLoggedIn + && (v == mainActivity.mainBinding.profileView.btnFollow || v == mainActivity.mainBinding.profileView.btnFollowTag)) { Utils.dataBox.addFavorite(new DataBox.FavoriteModel(mainActivity.userQuery, System.currentTimeMillis(), mainActivity.locationModel != null ? mainActivity.locationModel.getName() : mainActivity.userQuery.replaceAll("^@", ""))); onRefresh(); @@ -1389,7 +1392,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { new ProfileAction().execute("block"); } else if (v == mainActivity.mainBinding.profileView.btnFollowTag) { new ProfileAction().execute("followtag"); - } else if (v == mainActivity.mainBinding.profileView.btnTagged || (v == mainActivity.mainBinding.profileView.btnRestrict && !isLoggedIn)) { + } else if (v == mainActivity.mainBinding.profileView.btnTagged || v == mainActivity.mainBinding.profileView.btnRestrict) { mainActivity.startActivity(new Intent(mainActivity, SavedViewer.class) .putExtra(Constants.EXTRAS_INDEX, "%" + mainActivity.profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + mainActivity.profileModel.getUsername()) diff --git a/app/src/main/java/awais/instagrabber/activities/BaseLanguageActivity.java b/app/src/main/java/awais/instagrabber/activities/BaseLanguageActivity.java index 81dc4bf8..1d19ae71 100755 --- a/app/src/main/java/awais/instagrabber/activities/BaseLanguageActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/BaseLanguageActivity.java @@ -15,7 +15,7 @@ public abstract class BaseLanguageActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { - Utils.changeTheme(this); + Utils.changeTheme(getApplicationContext()); super.onCreate(savedInstanceState); } } diff --git a/app/src/main/java/awais/instagrabber/activities/Login.java b/app/src/main/java/awais/instagrabber/activities/Login.java index 55c30ca6..ee13138a 100755 --- a/app/src/main/java/awais/instagrabber/activities/Login.java +++ b/app/src/main/java/awais/instagrabber/activities/Login.java @@ -1,7 +1,9 @@ package awais.instagrabber.activities; import android.annotation.SuppressLint; +import android.content.Intent; import android.graphics.Bitmap; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.view.View; @@ -36,9 +38,9 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis final String mainCookie = Utils.getCookie(url); if (Utils.isEmpty(mainCookie) || !mainCookie.contains("; ds_user_id=")) ready = true; else if (mainCookie.contains("; ds_user_id=") && ready) { - Utils.setupCookies(mainCookie); - settingsHelper.putString(Constants.COOKIE, mainCookie); - Toast.makeText(getApplicationContext(), R.string.login_success_loading_cookies, Toast.LENGTH_SHORT).show(); + final Intent intent = new Intent(); + intent.putExtra("cookie", mainCookie); + setResult(Constants.LOGIN_RESULT_CODE, intent); finish(); } } @@ -95,7 +97,6 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis } @SuppressLint("SetJavaScriptEnabled") - @SuppressWarnings("deprecation") private void initWebView() { if (loginBinding != null) { loginBinding.webView.setWebChromeClient(webChromeClient); diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 70b61dba..36043e98 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -31,6 +31,19 @@ import static awais.instagrabber.utils.Utils.settingsHelper; public class MainActivity extends BaseLanguageActivity { private static final String TAG = "MainActivity"; + private static final List SHOW_BOTTOM_VIEW_DESTINATIONS = Arrays.asList( + R.id.directMessagesInboxFragment, + R.id.feedFragment, + R.id.profileFragment, + R.id.discoverFragment, + R.id.morePreferencesFragment); + private static final List KEEP_SCROLL_BEHAVIOUR_DESTINATIONS = Arrays.asList( + R.id.directMessagesInboxFragment, + R.id.feedFragment, + R.id.profileFragment, + R.id.discoverFragment, + R.id.morePreferencesFragment, + R.id.settingsPreferencesFragment); private ActivityMainBinding binding; private LiveData currentNavControllerLiveData; @@ -69,17 +82,16 @@ public class MainActivity extends BaseLanguageActivity { R.navigation.direct_messages_nav_graph, R.navigation.feed_nav_graph, R.navigation.profile_nav_graph, - R.navigation.discover_nav_graph + R.navigation.discover_nav_graph, + R.navigation.more_nav_graph )); - - binding.bottomNavView.setSelectedItemId(R.id.feed_nav_graph); final LiveData navControllerLiveData = setupWithNavController( binding.bottomNavView, navList, getSupportFragmentManager(), R.id.main_nav_host, getIntent(), - 1); + 0); navControllerLiveData.observe(this, this::setupNavigation); currentNavControllerLiveData = navControllerLiveData; } @@ -89,19 +101,12 @@ public class MainActivity extends BaseLanguageActivity { navController.addOnDestinationChangedListener((controller, destination, arguments) -> { binding.appBarLayout.setExpanded(true, true); final int destinationId = destination.getId(); - final List showBottomView = Arrays.asList( - R.id.directMessagesInboxFragment, - R.id.feedFragment, - R.id.profileFragment, - R.id.discoverFragment); - - if (showBottomView.contains(destinationId)) { + binding.bottomNavView.setVisibility(SHOW_BOTTOM_VIEW_DESTINATIONS.contains(destinationId) ? View.VISIBLE : View.GONE); + if (KEEP_SCROLL_BEHAVIOUR_DESTINATIONS.contains(destinationId)) { setScrollingBehaviour(); - binding.bottomNavView.setVisibility(View.VISIBLE); - return; + } else { + removeScrollingBehaviour(); } - removeScrollingBehaviour(); - binding.bottomNavView.setVisibility(View.GONE); }); } diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivityBackup.java b/app/src/main/java/awais/instagrabber/activities/MainActivityBackup.java index e1ea8536..6946a0c1 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivityBackup.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivityBackup.java @@ -41,7 +41,6 @@ import awais.instagrabber.asyncs.SuggestionsFetcher; import awais.instagrabber.asyncs.UsernameFetcher; import awais.instagrabber.asyncs.i.iStoryStatusFetcher; import awais.instagrabber.customviews.MouseDrawer; -import awais.instagrabber.databinding.ActivityMainBinding; import awais.instagrabber.databinding.ActivityMainbackupBinding; import awais.instagrabber.dialogs.AboutDialog; import awais.instagrabber.dialogs.QuickAccessDialog; @@ -95,8 +94,7 @@ public final class MainActivityBackup extends BaseLanguageActivity { // .putExtra(Constants.EXTRAS_HIGHLIGHT, highlightModel.getTitle()) // .putExtra(Constants.EXTRAS_STORIES, result) // ); - } - else + } else Toast.makeText(MainActivityBackup.this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -105,7 +103,8 @@ public final class MainActivityBackup extends BaseLanguageActivity { private SuggestionsAdapter suggestionAdapter; private MenuItem searchAction; - public @NonNull ActivityMainbackupBinding mainBinding; + public @NonNull + ActivityMainbackupBinding mainBinding; public SearchView searchView; public MenuItem downloadAction, settingsAction, dmsAction, notifAction; public StoryModel[] storyModels; @@ -253,7 +252,7 @@ public final class MainActivityBackup extends BaseLanguageActivity { final boolean isQueryNull = userQuery == null; if (isQueryNull) { allItems.clear(); - mainBinding.profileView.privatePage1.setImageResource(R.drawable.ic_info); + mainBinding.profileView.privatePage1.setImageResource(R.drawable.ic_outline_info_24); mainBinding.profileView.privatePage2.setTextSize(20); mainBinding.profileView.privatePage2.setText(isLoggedIn ? R.string.no_acc_logged_in : R.string.no_acc); mainBinding.profileView.privatePage.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/awais/instagrabber/adapters/DirectMessageInboxAdapter.java b/app/src/main/java/awais/instagrabber/adapters/DirectMessageInboxAdapter.java index dfe6af2c..c6701afc 100644 --- a/app/src/main/java/awais/instagrabber/adapters/DirectMessageInboxAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/DirectMessageInboxAdapter.java @@ -8,7 +8,7 @@ import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.ListAdapter; import awais.instagrabber.adapters.viewholder.DirectMessageInboxItemViewHolder; -import awais.instagrabber.databinding.LayoutIncludeSimpleItemBinding; +import awais.instagrabber.databinding.LayoutDmInboxItemBinding; import awais.instagrabber.models.direct_messages.InboxThreadModel; public final class DirectMessageInboxAdapter extends ListAdapter { @@ -35,7 +35,7 @@ public final class DirectMessageInboxAdapter extends ListAdapter 1) { binding.ivProfilePic.setVisibility(View.GONE); multipleProfilePicsContainer.setVisibility(View.VISIBLE); - for (int i = 0; i < Math.min(3, users.length); ++i) - glideRequestManager.load(users[i].getSdProfilePic()).into(multipleProfilePics[i]); + for (int i = 0; i < Math.min(3, users.length); ++i) { + multipleProfilePics[i].setImageURI(users[i].getSdProfilePic()); + } } else { binding.ivProfilePic.setVisibility(View.VISIBLE); multipleProfilePicsContainer.setVisibility(View.GONE); - glideRequestManager.load(users.length == 1 ? users[0].getSdProfilePic() : null).into(binding.ivProfilePic); + binding.ivProfilePic.setImageURI(users.length == 1 ? users[0].getSdProfilePic() : null); } binding.tvUsername.setText(model.getThreadTitle()); final DirectItemModel lastItemModel = itemModels[itemModels.length - 1]; diff --git a/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java index 793d3574..2f6af28d 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java @@ -25,6 +25,8 @@ import awaisomereport.LogCollector; import static awais.instagrabber.utils.Utils.logCollector; public final class FeedFetcher extends AsyncTask { + private static final String TAG = "FeedFetcher"; + private static final int maxItemsToLoad = 25; // max is 50, but that's too many posts, setting more than 30 is gay private final String endCursor; private final FetchListener fetchListener; @@ -61,8 +63,10 @@ public final class FeedFetcher extends AsyncTask { final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - final JSONObject timelineFeed = new JSONObject(Utils.readFromConnection(urlConnection)).getJSONObject("data") - .getJSONObject(Constants.EXTRAS_USER).getJSONObject("edge_web_feed_timeline"); + final String json = Utils.readFromConnection(urlConnection); + Log.d(TAG, json); + final JSONObject timelineFeed = new JSONObject(json).getJSONObject("data") + .getJSONObject(Constants.EXTRAS_USER).getJSONObject("edge_web_feed_timeline"); final String endCursor; final boolean hasNextPage; @@ -83,7 +87,8 @@ public final class FeedFetcher extends AsyncTask { for (int i = 0; i < feedLen; ++i) { final JSONObject feedItem = feedItems.getJSONObject(i).getJSONObject("node"); final String mediaType = feedItem.optString("__typename"); - if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType)) continue; + if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType)) + continue; final boolean isVideo = feedItem.optBoolean("is_video"); final long videoViews = feedItem.optLong("video_view_count", 0); @@ -93,7 +98,8 @@ public final class FeedFetcher extends AsyncTask { final String resourceUrl; if (isVideo) resourceUrl = feedItem.getString("video_url"); - else resourceUrl = feedItem.has("display_resources") ? Utils.getHighQualityImage(feedItem) : displayUrl; + else + resourceUrl = feedItem.has("display_resources") ? Utils.getHighQualityImage(feedItem) : displayUrl; ProfileModel profileModel = null; if (feedItem.has("owner")) { diff --git a/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java index f0255178..c875fd61 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java @@ -8,6 +8,9 @@ import androidx.annotation.Nullable; import org.json.JSONArray; import org.json.JSONObject; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; @@ -23,6 +26,8 @@ import static awais.instagrabber.utils.Utils.logCollector; import static awaisomereport.LogCollector.LogFile; public final class InboxFetcher extends AsyncTask { + private static final String TAG = "InboxFetcher"; + private final String endCursor; private final FetchListener fetchListener; @@ -43,46 +48,59 @@ public final class InboxFetcher extends AsyncTask { conn.setRequestProperty("Accept-Language", LocaleUtils.getCurrentLocale().getLanguage() + ",en-US;q=0.8"); conn.setUseCaches(false); - if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - JSONObject data = new JSONObject(Utils.readFromConnection(conn)); - // try (FileWriter fileWriter = new FileWriter(new File("/sdcard/test.json"))) { - // fileWriter.write(data.toString(2)); - // } - - final long seqId = data.optLong("seq_id"); - final int pendingRequestsCount = data.optInt("pending_requests_total"); - final boolean hasPendingTopRequests = data.optBoolean("has_pending_top_requests"); + if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { + final InputStream responseInputStream = conn.getErrorStream(); + final BufferedReader r = new BufferedReader(new InputStreamReader(responseInputStream)); + final StringBuilder builder = new StringBuilder(); + for (String line = r.readLine(); line != null; line = r.readLine()) { + if (builder.length() != 0) { + builder.append("\n"); + } + builder.append(line); + } + Log.e(TAG, "Error response: " + conn.getResponseCode() + ", " + builder.toString()); + r.close(); + conn.disconnect(); + return null; + } + JSONObject data = new JSONObject(Utils.readFromConnection(conn)); + // try (FileWriter fileWriter = new FileWriter(new File("/sdcard/test.json"))) { + // fileWriter.write(data.toString(2)); + // } - data = data.getJSONObject("inbox"); + final long seqId = data.optLong("seq_id"); + final int pendingRequestsCount = data.optInt("pending_requests_total"); + final boolean hasPendingTopRequests = data.optBoolean("has_pending_top_requests"); - final boolean blendedInboxEnabled = data.optBoolean("blended_inbox_enabled"); - final boolean hasOlder = data.optBoolean("has_older"); - final int unseenCount = data.optInt("unseen_count"); - final long unseenCountTimestamp = data.optLong("unseen_count_ts"); - final String oldestCursor = data.optString("oldest_cursor"); + data = data.getJSONObject("inbox"); - InboxThreadModel[] inboxThreadModels = null; + final boolean blendedInboxEnabled = data.optBoolean("blended_inbox_enabled"); + final boolean hasOlder = data.optBoolean("has_older"); + final int unseenCount = data.optInt("unseen_count"); + final long unseenCountTimestamp = data.optLong("unseen_count_ts"); + final String oldestCursor = data.optString("oldest_cursor"); - final JSONArray threadsArray = data.optJSONArray("threads"); - if (threadsArray != null) { - final int threadsLen = threadsArray.length(); - inboxThreadModels = new InboxThreadModel[threadsLen]; + InboxThreadModel[] inboxThreadModels = null; - for (int i = 0; i < threadsLen; ++i) - inboxThreadModels[i] = Utils.createInboxThreadModel(threadsArray.getJSONObject(i), false); - } + final JSONArray threadsArray = data.optJSONArray("threads"); + if (threadsArray != null) { + final int threadsLen = threadsArray.length(); + inboxThreadModels = new InboxThreadModel[threadsLen]; - result = new InboxModel(hasOlder, hasPendingTopRequests, - blendedInboxEnabled, unseenCount, pendingRequestsCount, - seqId, unseenCountTimestamp, oldestCursor, inboxThreadModels); + for (int i = 0; i < threadsLen; ++i) + inboxThreadModels[i] = Utils.createInboxThreadModel(threadsArray.getJSONObject(i), false); } + result = new InboxModel(hasOlder, hasPendingTopRequests, + blendedInboxEnabled, unseenCount, pendingRequestsCount, + seqId, unseenCountTimestamp, oldestCursor, inboxThreadModels); + conn.disconnect(); } catch (final Exception e) { result = null; if (logCollector != null) logCollector.appendException(e, LogFile.ASYNC_DMS, "doInBackground"); - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); + if (BuildConfig.DEBUG) Log.e(TAG, "", e); } return result; diff --git a/app/src/main/java/awais/instagrabber/dialogs/SettingsDialog.java b/app/src/main/java/awais/instagrabber/dialogs/SettingsDialog.java index 56812a54..4707bab8 100755 --- a/app/src/main/java/awais/instagrabber/dialogs/SettingsDialog.java +++ b/app/src/main/java/awais/instagrabber/dialogs/SettingsDialog.java @@ -24,6 +24,8 @@ import androidx.fragment.app.FragmentManager; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import java.text.SimpleDateFormat; + import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.activities.Login; @@ -50,6 +52,7 @@ import static awais.instagrabber.utils.Constants.MUTED_VIDEOS; import static awais.instagrabber.utils.Constants.STORIESIG; import static awais.instagrabber.utils.Utils.settingsHelper; +@Deprecated public final class SettingsDialog extends BottomSheetDialogFragment implements View.OnClickListener, AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener { private Activity activity; @@ -65,7 +68,8 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { if (requestCode != 6200) return; if (grantResults[0] == PackageManager.PERMISSION_GRANTED) showDirectoryChooser(); - else Toast.makeText(activity, R.string.direct_download_perms_ask, Toast.LENGTH_SHORT).show(); + else + Toast.makeText(activity, R.string.direct_download_perms_ask, Toast.LENGTH_SHORT).show(); } private void showDirectoryChooser() { @@ -73,10 +77,10 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V if (fragmentManager == null) fragmentManager = getChildFragmentManager(); new DirectoryChooser().setInitialDirectory(settingsHelper.getString(FOLDER_PATH)) - .setInteractionListener(path -> { - settingsHelper.putString(FOLDER_PATH, path); - somethingChanged = true; - }).show(fragmentManager, null); + .setInteractionListener(path -> { + settingsHelper.putString(FOLDER_PATH, path); + somethingChanged = true; + }).show(fragmentManager, null); } @NonNull @@ -115,12 +119,12 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V if (Utils.isEmpty(settingsHelper.getString(Constants.COOKIE))) btnLogout.setEnabled(false); spAppTheme = contentView.findViewById(R.id.spAppTheme); - currentTheme = settingsHelper.getInteger(APP_THEME); + currentTheme = Integer.parseInt(settingsHelper.getString(APP_THEME)); spAppTheme.setSelection(currentTheme); spAppTheme.setOnItemSelectedListener(this); spLanguage = contentView.findViewById(R.id.spLanguage); - currentLanguage = settingsHelper.getInteger(APP_LANGUAGE); + currentLanguage = Integer.parseInt(settingsHelper.getString(APP_LANGUAGE)); spLanguage.setSelection(currentLanguage); spLanguage.setOnItemSelectedListener(this); @@ -178,13 +182,13 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V public void onItemSelected(final AdapterView spinner, final View view, final int position, final long id) { if (spinner == spAppTheme) { if (position != currentTheme) { - settingsHelper.putInteger(APP_THEME, position); + settingsHelper.putString(APP_THEME, String.valueOf(position)); somethingChanged = true; } } else if (spinner == spLanguage) { selectedLanguage = position; if (position != currentLanguage) { - settingsHelper.putInteger(APP_LANGUAGE, position); + settingsHelper.putString(APP_LANGUAGE, String.valueOf(position)); somethingChanged = true; } } @@ -205,7 +209,28 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V requestPermissions(Utils.PERMS, 6007); else Utils.showImportExportDialog(activity); } else if (v == btnTimeSettings) { - new TimeSettingsDialog().show(fragmentManager, null); + new TimeSettingsDialog(settingsHelper.getBoolean(Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED), + settingsHelper.getString(Constants.CUSTOM_DATE_TIME_FORMAT), + settingsHelper.getString(Constants.DATE_TIME_SELECTION), + (isCustomFormat, + formatSelection, + spTimeFormatSelectedItemPosition, + spSeparatorSelectedItemPosition, + spDateFormatSelectedItemPosition, + selectedFormat, currentFormat) -> { + if (isCustomFormat) { + settingsHelper.putString(Constants.CUSTOM_DATE_TIME_FORMAT, formatSelection); + } else { + final String formatSelectionUpdated = spTimeFormatSelectedItemPosition + ";" + + spSeparatorSelectedItemPosition + ';' + + spDateFormatSelectedItemPosition; // time;separator;date + settingsHelper.putString(Constants.DATE_TIME_FORMAT, selectedFormat); + settingsHelper.putString(Constants.DATE_TIME_SELECTION, formatSelectionUpdated); + } + settingsHelper.putBoolean(Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED, isCustomFormat); + Utils.datetimeParser = (SimpleDateFormat) currentFormat.clone(); + } + ).show(fragmentManager, null); } else if (v == btnReport) { CrashReporter.get(activity.getApplication()).zipLogs().startCrashEmailIntent(activity, true); } else if (v == btnSaveTo) { diff --git a/app/src/main/java/awais/instagrabber/dialogs/TimeSettingsDialog.java b/app/src/main/java/awais/instagrabber/dialogs/TimeSettingsDialog.java index f9225d9f..b0a9aa85 100755 --- a/app/src/main/java/awais/instagrabber/dialogs/TimeSettingsDialog.java +++ b/app/src/main/java/awais/instagrabber/dialogs/TimeSettingsDialog.java @@ -6,6 +6,9 @@ import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; import android.widget.AdapterView; import android.widget.CompoundButton; @@ -19,38 +22,42 @@ import java.util.Date; import java.util.GregorianCalendar; import awais.instagrabber.databinding.DialogTimeSettingsBinding; -import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.LocaleUtils; import awais.instagrabber.utils.Utils; -import static awais.instagrabber.utils.Utils.settingsHelper; - public final class TimeSettingsDialog extends DialogFragment implements AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener, View.OnClickListener, TextWatcher { private DialogTimeSettingsBinding timeSettingsBinding; private final Date magicDate; private SimpleDateFormat currentFormat; private String selectedFormat; - - public TimeSettingsDialog() { - super(); + private boolean customDateTimeFormatEnabled; + private String customDateTimeFormat; + private String dateTimeSelection; + private final OnConfirmListener onConfirmListener; + + public TimeSettingsDialog(final boolean customDateTimeFormatEnabled, + final String customDateTimeFormat, + final String dateTimeSelection, + final OnConfirmListener onConfirmListener) { + this.customDateTimeFormatEnabled = customDateTimeFormatEnabled; + this.customDateTimeFormat = customDateTimeFormat; + this.dateTimeSelection = dateTimeSelection; + this.onConfirmListener = onConfirmListener; final Calendar instance = GregorianCalendar.getInstance(); instance.set(2020, 5, 22, 8, 17, 13); magicDate = instance.getTime(); } - @NonNull @Override - public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { - final Dialog dialog = super.onCreateDialog(savedInstanceState); - timeSettingsBinding = DialogTimeSettingsBinding.inflate(LayoutInflater.from(getContext())); + public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { + timeSettingsBinding = DialogTimeSettingsBinding.inflate(inflater, container, false); timeSettingsBinding.cbCustomFormat.setOnCheckedChangeListener(this); + timeSettingsBinding.cbCustomFormat.setChecked(customDateTimeFormatEnabled); + timeSettingsBinding.etCustomFormat.setText(customDateTimeFormat); - timeSettingsBinding.cbCustomFormat.setChecked(settingsHelper.getBoolean(Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED)); - timeSettingsBinding.etCustomFormat.setText(settingsHelper.getString(Constants.CUSTOM_DATE_TIME_FORMAT)); - - final String[] dateTimeFormat = settingsHelper.getString(Constants.DATE_TIME_SELECTION).split(";"); // output = time;separator;date + final String[] dateTimeFormat = dateTimeSelection.split(";"); // output = time;separator;date timeSettingsBinding.spTimeFormat.setSelection(Integer.parseInt(dateTimeFormat[0])); timeSettingsBinding.spSeparator.setSelection(Integer.parseInt(dateTimeFormat[1])); timeSettingsBinding.spDateFormat.setSelection(Integer.parseInt(dateTimeFormat[2])); @@ -67,8 +74,7 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV timeSettingsBinding.btnConfirm.setOnClickListener(this); timeSettingsBinding.btnInfo.setOnClickListener(this); - dialog.setContentView(timeSettingsBinding.getRoot()); - return dialog; + return timeSettingsBinding.getRoot(); } private void refreshTimeFormat() { @@ -87,7 +93,8 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV + (isSwapTime ? dateStr : timeStr); timeSettingsBinding.btnConfirm.setEnabled(true); - timeSettingsBinding.timePreview.setText((currentFormat = new SimpleDateFormat(selectedFormat, LocaleUtils.getCurrentLocale())).format(magicDate)); + currentFormat = new SimpleDateFormat(selectedFormat, LocaleUtils.getCurrentLocale()); + timeSettingsBinding.timePreview.setText(currentFormat.format(magicDate)); } } @@ -96,8 +103,8 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV //noinspection ConstantConditions final String string = timeSettingsBinding.etCustomFormat.getText().toString(); if (Utils.isEmpty(string)) throw new NullPointerException(); - - final String format = (currentFormat = new SimpleDateFormat(string, LocaleUtils.getCurrentLocale())).format(magicDate); + currentFormat = new SimpleDateFormat(string, LocaleUtils.getCurrentLocale()); + final String format = currentFormat.format(magicDate); timeSettingsBinding.timePreview.setText(format); timeSettingsBinding.btnConfirm.setEnabled(true); @@ -115,6 +122,8 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { if (buttonView == timeSettingsBinding.cbCustomFormat) { + final View parent = (View) timeSettingsBinding.etCustomFormat.getParent(); + parent.setVisibility(isChecked ? View.VISIBLE : View.GONE); timeSettingsBinding.etCustomFormat.setEnabled(isChecked); timeSettingsBinding.btnInfo.setEnabled(isChecked); @@ -134,26 +143,16 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV @Override public void onClick(final View v) { if (v == timeSettingsBinding.btnConfirm) { - final String formatSelection; - - final boolean isCustomFormat = timeSettingsBinding.cbCustomFormat.isChecked(); - - if (isCustomFormat) { - //noinspection ConstantConditions - formatSelection = timeSettingsBinding.etCustomFormat.getText().toString(); - settingsHelper.putString(Constants.CUSTOM_DATE_TIME_FORMAT, formatSelection); - } else { - formatSelection = timeSettingsBinding.spTimeFormat.getSelectedItemPosition() + ";" - + timeSettingsBinding.spSeparator.getSelectedItemPosition() + ';' - + timeSettingsBinding.spDateFormat.getSelectedItemPosition(); // time;separator;date - - settingsHelper.putString(Constants.DATE_TIME_FORMAT, selectedFormat); - settingsHelper.putString(Constants.DATE_TIME_SELECTION, formatSelection); + final Editable etCustomFormatText = timeSettingsBinding.etCustomFormat.getText(); + if (onConfirmListener != null) { + onConfirmListener.onConfirm(timeSettingsBinding.cbCustomFormat.isChecked(), + etCustomFormatText == null ? null : etCustomFormatText.toString(), + timeSettingsBinding.spTimeFormat.getSelectedItemPosition(), + timeSettingsBinding.spSeparator.getSelectedItemPosition(), + timeSettingsBinding.spDateFormat.getSelectedItemPosition(), + selectedFormat, + currentFormat); } - - settingsHelper.putBoolean(Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED, isCustomFormat); - - Utils.datetimeParser = (SimpleDateFormat) currentFormat.clone(); dismiss(); } else if (v == timeSettingsBinding.btnInfo) { timeSettingsBinding.customPanel.setVisibility(timeSettingsBinding.customPanel @@ -162,6 +161,14 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV } } + public interface OnConfirmListener { + void onConfirm(boolean isCustomFormat, + String formatSelection, + int spTimeFormatSelectedItemPosition, + int spSeparatorSelectedItemPosition, + int spDateFormatSelectedItemPosition, final String selectedFormat, final SimpleDateFormat currentFormat); + } + @Override public void onNothingSelected(final AdapterView parent) { } @@ -170,4 +177,17 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV @Override public void afterTextChanged(final Editable s) { } + + @Override + public void onResume() { + super.onResume(); + final Dialog dialog = getDialog(); + if (dialog == null) return; + final Window window = dialog.getWindow(); + if (window == null) return; + final WindowManager.LayoutParams params = window.getAttributes(); + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.height = ViewGroup.LayoutParams.WRAP_CONTENT; + window.setAttributes(params); + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java index 70b9f8a8..5ca4531e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -11,6 +11,8 @@ import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@ -19,11 +21,11 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.AppCompatImageView; -import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentContainerView; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; @@ -49,7 +51,6 @@ import java.util.List; import awais.instagrabber.R; import awais.instagrabber.activities.PostViewer; -import awais.instagrabber.activities.ProfileViewer; import awais.instagrabber.adapters.DirectMessageItemsAdapter; import awais.instagrabber.asyncs.ImageUploader; import awais.instagrabber.asyncs.direct_messages.DirectMessageInboxThreadFetcher; @@ -61,7 +62,6 @@ import awais.instagrabber.interfaces.MentionClickListener; import awais.instagrabber.models.ImageUploadOptions; import awais.instagrabber.models.PostModel; import awais.instagrabber.models.ProfileModel; -import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.direct_messages.DirectItemModel; import awais.instagrabber.models.direct_messages.InboxThreadModel; import awais.instagrabber.models.enums.DirectItemType; @@ -74,7 +74,7 @@ public class DirectMessageThreadFragment extends Fragment { private static final String TAG = "DirectMessagesThreadFmt"; private static final int PICK_IMAGE = 100; - private FragmentActivity fragmentActivity; + private AppCompatActivity fragmentActivity; private String threadId, threadTitle; private String cursor; private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); @@ -83,7 +83,7 @@ public class DirectMessageThreadFragment extends Fragment { private DirectItemModelListViewModel listViewModel; private DirectItemModel directItemModel; private RecyclerView messageList; - private AppCompatImageView dmInfo; + // private AppCompatImageView dmInfo; private boolean hasSentSomething, hasDeletedSomething; private boolean hasOlder = true; @@ -157,7 +157,8 @@ public class DirectMessageThreadFragment extends Fragment { @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - fragmentActivity = requireActivity(); + fragmentActivity = (AppCompatActivity) requireActivity(); + setHasOptionsMenu(true); } @Override @@ -165,8 +166,8 @@ public class DirectMessageThreadFragment extends Fragment { final ViewGroup container, final Bundle savedInstanceState) { binding = FragmentDirectMessagesThreadBinding.inflate(inflater, container, false); - CoordinatorLayout containerTwo = (CoordinatorLayout) container.getParent(); - dmInfo = containerTwo.findViewById(R.id.dmInfo); + final FragmentContainerView containerTwo = (FragmentContainerView) container.getParent(); + // dmInfo = containerTwo.findViewById(R.id.dmInfo); final LinearLayout root = binding.getRoot(); listViewModel = new ViewModelProvider(fragmentActivity).get(DirectItemModelListViewModel.class); if (getArguments() == null) { @@ -177,6 +178,10 @@ public class DirectMessageThreadFragment extends Fragment { threadId = DirectMessageThreadFragmentArgs.fromBundle(getArguments()).getThreadId(); } threadTitle = DirectMessageThreadFragmentArgs.fromBundle(getArguments()).getTitle(); + final ActionBar actionBar = fragmentActivity.getSupportActionBar(); + if (actionBar != null) { + actionBar.setTitle(threadTitle); + } binding.swipeRefreshLayout.setEnabled(false); messageList = binding.messageList; messageList.setHasFixedSize(true); @@ -192,11 +197,11 @@ public class DirectMessageThreadFragment extends Fragment { } new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, cursor, fetchListener).execute(); // serial because we don't want messages to be randomly ordered })); - dmInfo.setOnClickListener(v -> { - final NavDirections action = - DirectMessageThreadFragmentDirections.actionDMThreadFragmentToDMSettingsFragment(threadId, threadTitle); - NavHostFragment.findNavController(DirectMessageThreadFragment.this).navigate(action); - }); + // dmInfo.setOnClickListener(v -> { + // final NavDirections action = + // DirectMessageThreadFragmentDirections.actionDMThreadFragmentToDMSettingsFragment(threadId, threadTitle); + // NavHostFragment.findNavController(DirectMessageThreadFragment.this).navigate(action); + // }); final DialogInterface.OnClickListener onDialogListener = (dialogInterface, which) -> { if (which == 0) { @@ -250,12 +255,11 @@ public class DirectMessageThreadFragment extends Fragment { default: Log.d("austin_debug", "unsupported type " + itemType); } - } - else if (which == 1) { + } else if (which == 1) { sendText(null, directItemModel.getItemId(), directItemModel.isLiked()); - } - else if (which == 2) { - if (String.valueOf(directItemModel.getUserId()).equals(myId)) new Unsend().execute(); + } else if (which == 2) { + if (String.valueOf(directItemModel.getUserId()).equals(myId)) + new Unsend().execute(); else searchUsername(getUser(directItemModel.getUserId()).getUsername()); } }; @@ -320,6 +324,12 @@ public class DirectMessageThreadFragment extends Fragment { return root; } + @Override + public void onPrepareOptionsMenu(@NonNull final Menu menu) { + final MenuItem item = menu.findItem(R.id.favourites); + item.setVisible(false); + } + @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -423,7 +433,9 @@ public class DirectMessageThreadFragment extends Fragment { } private void searchUsername(final String text) { - startActivity(new Intent(requireContext(), ProfileViewer.class).putExtra(Constants.EXTRAS_USERNAME, text)); + // startActivity(new Intent(requireContext(), ProfileViewer.class).putExtra(Constants.EXTRAS_USERNAME, text)); + final NavDirections action = DirectMessageThreadFragmentDirections.actionDirectMessagesThreadFragmentToProfileFragment("@" + text); + NavHostFragment.findNavController(this).navigate(action); } public static class DirectItemModelListViewModel extends ViewModel { @@ -434,8 +446,7 @@ public class DirectMessageThreadFragment extends Fragment { if (list == null) { list = new MutableLiveData<>(); isEmpty = true; - } - else isEmpty = false; + } else isEmpty = false; return list; } @@ -451,10 +462,10 @@ public class DirectMessageThreadFragment extends Fragment { class Unsend extends AsyncTask { protected Void doInBackground(Void... lmao) { - final String url = "https://i.instagram.com/api/v1/direct_v2/threads/"+threadId+"/items/"+directItemModel.getItemId()+"/delete/"; + final String url = "https://i.instagram.com/api/v1/direct_v2/threads/" + threadId + "/items/" + directItemModel.getItemId() + "/delete/"; try { String urlParameters = "_csrftoken=" + cookie.split("csrftoken=")[1].split(";")[0] - +"&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID); + + "&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID); final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setUseCaches(false); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java index 2ddb607a..846fa53d 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java @@ -60,6 +60,7 @@ public class DiscoverFragment extends Fragment { private String discoverEndMaxId; private ActionMode actionMode; private DiscoverItemViewModel discoverItemViewModel; + private boolean shouldRefresh = true; private final FetchListener topicFetchListener = new FetchListener() { @Override @@ -154,14 +155,20 @@ public class DiscoverFragment extends Fragment { final ViewGroup container, final Bundle savedInstanceState) { if (root != null) { + shouldRefresh = false; return root; } binding = FragmentDiscoverBinding.inflate(inflater, container, false); root = binding.getRoot(); - setupExplore(); return root; } + @Override + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + if (!shouldRefresh) return; + setupExplore(); + } + private void setupExplore() { discoverItemViewModel = new ViewModelProvider(fragmentActivity).get(DiscoverItemViewModel.class); final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(requireContext(), Utils.convertDpToPx(110)); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index 1add9834..4d7f6e4f 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -80,6 +80,7 @@ public class FeedFragment extends Fragment { private String feedEndCursor = null; private FeedViewModel feedViewModel; private VideoAwareRecyclerScroller videoAwareRecyclerScroller; + private boolean shouldRefresh = true; private final FetchListener feedFetchListener = new FetchListener() { @Override @@ -164,14 +165,21 @@ public class FeedFragment extends Fragment { final ViewGroup container, final Bundle savedInstanceState) { if (root != null) { + shouldRefresh = false; return root; } binding = FragmentFeedBinding.inflate(inflater, container, false); root = binding.getRoot(); + return root; + } + + @Override + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + if (!shouldRefresh) return; // setupActionBar(); setupFeedStories(); setupFeed(); - return root; + shouldRefresh = false; } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 3013c7c9..6908da18 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -10,6 +10,7 @@ import android.os.Looper; import android.text.SpannableStringBuilder; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; +import android.util.Log; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.MenuItem; @@ -29,8 +30,10 @@ import androidx.core.view.ViewCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import awais.instagrabber.R; import awais.instagrabber.activities.FollowViewer; @@ -47,17 +50,24 @@ import awais.instagrabber.customviews.PrimaryActionModeCallback; import awais.instagrabber.customviews.PrimaryActionModeCallback.CallbacksHelper; import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager; import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; +import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.FragmentProfileBinding; import awais.instagrabber.fragments.main.viewmodels.ProfilePostsViewModel; import awais.instagrabber.interfaces.FetchListener; +import awais.instagrabber.models.PostModel; import awais.instagrabber.models.ProfileModel; +import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.DownloadMethod; import awais.instagrabber.models.enums.ItemGetType; -import awais.instagrabber.services.ProfileService; +import awais.instagrabber.repositories.responses.FriendshipRepositoryChangeResponseRootObject; +import awais.instagrabber.services.FriendshipService; +import awais.instagrabber.services.ServiceCallback; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.DataBox; import awais.instagrabber.utils.Utils; +import awaisomereport.LogCollector; +import static awais.instagrabber.utils.Utils.logCollector; import static awais.instagrabber.utils.Utils.settingsHelper; public class ProfileFragment extends Fragment { @@ -74,8 +84,13 @@ public class ProfileFragment extends Fragment { private PostsAdapter postsAdapter; private ActionMode actionMode; private Handler usernameSettingHandler; - private ProfileService profileService; - + private FriendshipService friendshipService; + private boolean shouldRefresh = true; + private StoryModel[] storyModels; + private boolean hasNextPage; + private String endCursor; + private AsyncTask currentlyExecuting; + ; private final Runnable usernameSettingRunnable = () -> { final ActionBar actionBar = fragmentActivity.getSupportActionBar(); if (actionBar != null) { @@ -118,11 +133,38 @@ public class ProfileFragment extends Fragment { } }); + private final FetchListener postsFetchListener = new FetchListener() { + @Override + public void onResult(final PostModel[] result) { + binding.swipeRefreshLayout.setRefreshing(false); + if (result != null) { + binding.mainPosts.post(() -> binding.mainPosts.setVisibility(View.VISIBLE)); + // final int oldSize = mainActivity.allItems.size(); + final List postModels = profilePostsViewModel.getList().getValue(); + final List finalList = postModels == null || postModels.isEmpty() ? new ArrayList<>() : new ArrayList<>(postModels); + finalList.addAll(Arrays.asList(result)); + profilePostsViewModel.getList().postValue(finalList); + PostModel model = null; + if (result.length != 0) { + model = result[result.length - 1]; + } + if (model == null) return; + endCursor = model.getEndCursor(); + hasNextPage = model.hasNextPage(); + model.setPageCursor(false, null); + return; + } + binding.privatePage1.setImageResource(R.drawable.ic_cancel); + binding.privatePage2.setText(R.string.empty_acc); + binding.privatePage.setVisibility(View.VISIBLE); + } + }; + @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); fragmentActivity = (MainActivity) requireActivity(); - profileService = ProfileService.getInstance(); + friendshipService = FriendshipService.getInstance(); } @Override @@ -130,6 +172,15 @@ public class ProfileFragment extends Fragment { final ViewGroup container, final Bundle savedInstanceState) { if (root != null) { + if (getArguments() != null) { + final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments()); + if (!fragmentArgs.getUsername().equals(username)) { + shouldRefresh = true; + return root; + } + } + setUsernameDelayed(); + shouldRefresh = false; return root; } binding = FragmentProfileBinding.inflate(inflater, container, false); @@ -139,7 +190,9 @@ public class ProfileFragment extends Fragment { @Override public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + if (!shouldRefresh) return; init(); + shouldRefresh = false; } @Override @@ -162,12 +215,13 @@ public class ProfileFragment extends Fragment { setUsernameDelayed(); } if (!isLoggedIn) { - binding.privatePage1.setImageResource(R.drawable.ic_info); + binding.privatePage1.setImageResource(R.drawable.ic_outline_info_24); binding.privatePage2.setText(R.string.no_acc); binding.privatePage.setVisibility(View.VISIBLE); return; } setupPosts(); + setupCommonListeners(); fetchProfile(); } @@ -205,18 +259,12 @@ public class ProfileFragment extends Fragment { private void fetchProfileDetails() { new ProfileFetcher(username.substring(1), profileModel -> { this.profileModel = profileModel; - new PostsFetcher(profileModel.getId(), - null, - result -> profilePostsViewModel.getList().postValue(Arrays.asList(result))) - .setUsername(profileModel.getUsername()) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); setProfileDetails(); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } private void setProfileDetails() { - setupCommonListeners(); if (profileModel == null) { binding.swipeRefreshLayout.setRefreshing(false); Toast.makeText(requireContext(), R.string.error_loading_profile, Toast.LENGTH_SHORT).show(); @@ -225,12 +273,18 @@ public class ProfileFragment extends Fragment { binding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE); final String profileId = profileModel.getId(); if (settingsHelper.getBoolean(Constants.STORIESIG)) { - new iStoryStatusFetcher(profileId, profileModel.getUsername(), false, false, - (!isLoggedIn && settingsHelper.getBoolean(Constants.STORIESIG)), false, + new iStoryStatusFetcher( + profileId, + profileModel.getUsername(), + false, + false, + (!isLoggedIn && settingsHelper.getBoolean(Constants.STORIESIG)), + false, result -> { - // mainActivity.storyModels = result; - // if (result != null && result.length > 0) - // binding.mainProfileImage.setStoriesBorder(); + storyModels = result; + if (result != null && result.length > 0) { + binding.mainProfileImage.setStoriesBorder(); + } }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new HighlightsFetcher(profileId, (!isLoggedIn && settingsHelper.getBoolean(Constants.STORIESIG)), result -> { @@ -412,9 +466,7 @@ public class ProfileFragment extends Fragment { } else { binding.swipeRefreshLayout.setRefreshing(true); binding.mainPosts.setVisibility(View.VISIBLE); - // currentlyExecuting = new PostsFetcher(profileId, postsFetchListener) - // .setUsername(profileModel.getUsername()) - // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + fetchPosts(); } } else { binding.mainFollowers.setClickable(false); @@ -451,14 +503,53 @@ public class ProfileFragment extends Fragment { new DataBox.FavoriteModel(username, System.currentTimeMillis(), username.replaceAll("^@", ""))); } - // onRefresh(); + fetchProfileDetails(); return; } - profileService.followProfile(username); + if (profileModel.getFollowing() || profileModel.getRequested()) { + friendshipService.unfollow( + userIdFromCookie, + profileModel.getId(), + Utils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepositoryChangeResponseRootObject result) { + Log.d(TAG, "Unfollow success: " + result); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error unfollowing", t); + } + }); + } else { + friendshipService.follow( + userIdFromCookie, + profileModel.getId(), + Utils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepositoryChangeResponseRootObject result) { + Log.d(TAG, "Follow success: " + result); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error following", t); + } + }); + } }); - // binding.btnRestrict.setOnClickListener(profileActionListener); - // binding.btnBlock.setOnClickListener(profileActionListener); + binding.btnRestrict.setOnClickListener(v -> { + if (!isLoggedIn) return; + // restrict + // new ProfileAction().execute("restrict"); + }); + binding.btnBlock.setOnClickListener(v -> { + if (!isLoggedIn) return; + // new MainHelper.ProfileAction().execute("block"); + }); binding.btnSaved.setOnClickListener(v -> startActivity(new Intent(requireContext(), SavedViewer.class) .putExtra(Constants.EXTRAS_INDEX, "$" + profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + profileModel.getUsername()) @@ -516,8 +607,34 @@ public class ProfileFragment extends Fragment { onBackPressedDispatcher.addCallback(onBackPressedCallback); return true; }); - binding.mainPosts.setAdapter(postsAdapter); profilePostsViewModel.getList().observe(fragmentActivity, postsAdapter::submitList); + binding.mainPosts.setAdapter(postsAdapter); + final RecyclerLazyLoader lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { + if (!hasNextPage) return; + binding.swipeRefreshLayout.setRefreshing(true); + fetchPosts(); + endCursor = null; + }); + binding.mainPosts.addOnScrollListener(lazyLoader); + } + + private void fetchPosts() { + stopCurrentExecutor(); + currentlyExecuting = new PostsFetcher(profileModel.getId(), endCursor, postsFetchListener) + .setUsername(profileModel.getUsername()) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + public void stopCurrentExecutor() { + if (currentlyExecuting != null) { + try { + currentlyExecuting.cancel(true); + } catch (final Exception e) { + if (logCollector != null) + logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor"); + Log.e(TAG, "", e); + } + } } private boolean checkAndResetAction() { diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/BasePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/BasePreferencesFragment.java new file mode 100644 index 00000000..a73a387e --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/settings/BasePreferencesFragment.java @@ -0,0 +1,44 @@ +package awais.instagrabber.fragments.settings; + +import android.content.SharedPreferences; +import android.os.Bundle; + +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +import awais.instagrabber.activities.MainActivity; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.LocaleUtils; + +public abstract class BasePreferencesFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + private boolean shouldRecreate = false; + + @Override + public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { + final PreferenceManager preferenceManager = getPreferenceManager(); + preferenceManager.setSharedPreferencesName("settings"); + preferenceManager.getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + final PreferenceScreen screen = preferenceManager.createPreferenceScreen(requireContext()); + setupPreferenceScreen(screen); + setPreferenceScreen(screen); + } + + abstract void setupPreferenceScreen(PreferenceScreen screen); + + protected void shouldRecreate() { + this.shouldRecreate = true; + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { + if (!shouldRecreate) return; + final MainActivity activity = (MainActivity) getActivity(); + if (activity == null) return; + if (key.equals(Constants.APP_LANGUAGE)) { + LocaleUtils.setLocale(activity.getBaseContext()); + } + shouldRecreate = false; + activity.recreate(); + } +} diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java new file mode 100644 index 00000000..738a75dc --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -0,0 +1,105 @@ +package awais.instagrabber.fragments.settings; + +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.navigation.NavDirections; +import androidx.navigation.fragment.NavHostFragment; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; + +import awais.instagrabber.R; +import awais.instagrabber.activities.Login; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.Utils; + +import static awais.instagrabber.utils.Utils.settingsHelper; + +public class MorePreferencesFragment extends BasePreferencesFragment { + private final String cookie = settingsHelper.getString(Constants.COOKIE); + + @Override + void setupPreferenceScreen(final PreferenceScreen screen) { + screen.addPreference(new MoreHeaderPreference(requireContext())); + + final PreferenceCategory accountCategory = new PreferenceCategory(requireContext()); + accountCategory.setTitle("Account"); + accountCategory.setIconSpaceReserved(false); + screen.addPreference(accountCategory); + final boolean isLoggedIn = !Utils.isEmpty(cookie) && Utils.getUserIdFromCookie(cookie) != null; + screen.addPreference(getPreference(isLoggedIn ? R.string.relogin : R.string.login, + isLoggedIn ? R.string.relogin_summary : -1, + -1, + preference -> { + startActivityForResult(new Intent(requireContext(), Login.class), Constants.LOGIN_RESULT_CODE); + return true; + })); + if (isLoggedIn) { + screen.addPreference(getPreference(R.string.logout, -1, preference -> { + Utils.setupCookies("LOGOUT"); + shouldRecreate(); + Toast.makeText(requireContext(), R.string.logout_success, Toast.LENGTH_SHORT).show(); + settingsHelper.putString(Constants.COOKIE, ""); + return true; + })); + } + + final PreferenceCategory defaultCategory = new PreferenceCategory(requireContext()); + screen.addPreference(defaultCategory); + defaultCategory.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> false)); + defaultCategory.addPreference(getPreference(R.string.action_settings, R.drawable.ic_outline_settings_24, preference -> { + final NavDirections navDirections = MorePreferencesFragmentDirections.actionMorePreferencesFragmentToSettingsPreferencesFragment(); + NavHostFragment.findNavController(this).navigate(navDirections); + return true; + })); + defaultCategory.addPreference(getPreference(R.string.action_about, R.drawable.ic_outline_info_24, preference -> false)); + } + + @Override + public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { + if (resultCode == Constants.LOGIN_RESULT_CODE) { + if (data == null) return; + final String cookie = data.getStringExtra("cookie"); + Utils.setupCookies(cookie); + shouldRecreate(); + Toast.makeText(requireContext(), R.string.login_success_loading_cookies, Toast.LENGTH_SHORT).show(); + settingsHelper.putString(Constants.COOKIE, cookie); + } + } + + @NonNull + private Preference getPreference(final int title, + final int icon, + final Preference.OnPreferenceClickListener clickListener) { + return getPreference(title, -1, icon, clickListener); + } + + @NonNull + private Preference getPreference(final int title, + final int summary, + final int icon, + final Preference.OnPreferenceClickListener clickListener) { + final Preference preference = new Preference(requireContext()); + if (icon <= 0) preference.setIconSpaceReserved(false); + if (icon > 0) preference.setIcon(icon); + preference.setTitle(title); + if (summary > 0) { + preference.setSummary(summary); + } + preference.setOnPreferenceClickListener(clickListener); + return preference; + } + + public static class MoreHeaderPreference extends Preference { + + public MoreHeaderPreference(final Context context) { + super(context); + setLayoutResource(R.layout.pref_more_header); + setSelectable(false); + } + } +} diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/SettingsPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/SettingsPreferencesFragment.java new file mode 100644 index 00000000..b828618e --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/settings/SettingsPreferencesFragment.java @@ -0,0 +1,285 @@ +package awais.instagrabber.fragments.settings; + +import android.content.Context; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.preference.DropDownPreference; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; +import androidx.preference.PreferenceViewHolder; +import androidx.preference.SwitchPreferenceCompat; + +import com.google.android.material.switchmaterial.SwitchMaterial; + +import java.text.SimpleDateFormat; + +import awais.instagrabber.R; +import awais.instagrabber.dialogs.TimeSettingsDialog; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.DirectoryChooser; +import awais.instagrabber.utils.Utils; + +import static awais.instagrabber.utils.Constants.FOLDER_PATH; +import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO; +import static awais.instagrabber.utils.Utils.settingsHelper; + +public class SettingsPreferencesFragment extends BasePreferencesFragment { + private static final String TAG = "SettingsPrefsFrag"; + private static AppCompatTextView customPathTextView; + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onPrepareOptionsMenu(@NonNull final Menu menu) { + super.onPrepareOptionsMenu(menu); + final MenuItem item = menu.findItem(R.id.favourites); + item.setVisible(false); + } + + @Override + void setupPreferenceScreen(final PreferenceScreen screen) { + screen.addPreference(getLanguagePreference()); + screen.addPreference(getThemePreference()); + screen.addPreference(getAmoledThemePreference()); + screen.addPreference(getDownloadUserFolderPreference()); + screen.addPreference(getSaveToCustomFolderPreference()); + screen.addPreference(getAutoPlayVideosPreference()); + screen.addPreference(getAlwaysMuteVideosPreference()); + screen.addPreference(getPostTimePreference()); + + final PreferenceCategory loggedInUsersPreferenceCategory = new PreferenceCategory(requireContext()); + loggedInUsersPreferenceCategory.setIconSpaceReserved(false); + screen.addPreference(loggedInUsersPreferenceCategory); + loggedInUsersPreferenceCategory.setTitle(R.string.login_settings); + loggedInUsersPreferenceCategory.addPreference(getMarkStoriesSeenPreference()); + loggedInUsersPreferenceCategory.addPreference(getEnableActivityNotificationsPreference()); + + final PreferenceCategory anonUsersPreferenceCategory = new PreferenceCategory(requireContext()); + anonUsersPreferenceCategory.setIconSpaceReserved(false); + screen.addPreference(anonUsersPreferenceCategory); + anonUsersPreferenceCategory.setTitle(R.string.anonymous_settings); + anonUsersPreferenceCategory.addPreference(getUseInstaDpPreference()); + anonUsersPreferenceCategory.addPreference(getUseStoriesIgPreference()); + + } + + @NonNull + private DropDownPreference getLanguagePreference() { + final DropDownPreference preference = new DropDownPreference(requireContext()); + preference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance()); + final int length = getResources().getStringArray(R.array.languages).length; + final String[] values = new String[length]; + for (int i = 0; i < length; i++) { + values[i] = String.valueOf(i); + } + preference.setKey(Constants.APP_LANGUAGE); + preference.setTitle(R.string.select_language); + preference.setEntries(R.array.languages); + preference.setIconSpaceReserved(false); + preference.setEntryValues(values); + preference.setOnPreferenceChangeListener((preference1, newValue) -> { + shouldRecreate(); + return true; + }); + return preference; + } + + @NonNull + private DropDownPreference getThemePreference() { + final DropDownPreference preference = new DropDownPreference(requireContext()); + preference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance()); + final int length = getResources().getStringArray(R.array.theme_presets).length; + final String[] values = new String[length]; + for (int i = 0; i < length; i++) { + values[i] = String.valueOf(i); + } + preference.setKey(Constants.APP_THEME); + preference.setTitle(R.string.theme_settings); + preference.setEntries(R.array.theme_presets); + preference.setIconSpaceReserved(false); + preference.setEntryValues(values); + preference.setOnPreferenceChangeListener((preference1, newValue) -> { + shouldRecreate(); + return true; + }); + return preference; + } + + private SwitchPreferenceCompat getAmoledThemePreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.AMOLED_THEME); + preference.setTitle(R.string.use_amoled_dark_theme); + preference.setIconSpaceReserved(false); + preference.setOnPreferenceChangeListener((preference1, newValue) -> { + final boolean isNight = Utils.isNight(requireContext(), settingsHelper.getThemeCode(true)); + if (isNight) shouldRecreate(); + return true; + }); + return preference; + } + + private Preference getDownloadUserFolderPreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.DOWNLOAD_USER_FOLDER); + preference.setTitle("Download to username folder"); + preference.setSummary(R.string.download_user_folder); + preference.setIconSpaceReserved(false); + return preference; + } + + private Preference getSaveToCustomFolderPreference() { + return new SaveToCustomFolderPreference(requireContext(), (resultCallback) -> { + new DirectoryChooser() + .setInitialDirectory(settingsHelper.getString(FOLDER_PATH)) + .setInteractionListener(path -> { + settingsHelper.putString(FOLDER_PATH, path); + resultCallback.onResult(path); + }) + .show(getParentFragmentManager(), null); + }); + } + + private Preference getAutoPlayVideosPreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.AUTOPLAY_VIDEOS); + preference.setTitle(R.string.post_viewer_autoplay_video); + preference.setIconSpaceReserved(false); + return preference; + } + + private Preference getAlwaysMuteVideosPreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.MUTED_VIDEOS); + preference.setTitle(R.string.post_viewer_muted_autoplay); + preference.setIconSpaceReserved(false); + return preference; + } + + private Preference getMarkStoriesSeenPreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.MARK_AS_SEEN); + preference.setTitle(R.string.mark_as_seen_setting); + preference.setSummary(R.string.mark_as_seen_setting_summary); + preference.setIconSpaceReserved(false); + return preference; + } + + private Preference getEnableActivityNotificationsPreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.CHECK_ACTIVITY); + preference.setTitle(R.string.activity_setting); + preference.setIconSpaceReserved(false); + return preference; + } + + private Preference getUseInstaDpPreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.INSTADP); + preference.setTitle(R.string.instadp_settings); + preference.setIconSpaceReserved(false); + return preference; + } + + private Preference getUseStoriesIgPreference() { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(requireContext()); + preference.setKey(Constants.STORIESIG); + preference.setTitle(R.string.storiesig_settings); + preference.setIconSpaceReserved(false); + return preference; + } + + private Preference getPostTimePreference() { + final Preference preference = new Preference(requireContext()); + preference.setTitle(R.string.time_settings); + preference.setIconSpaceReserved(false); + preference.setOnPreferenceClickListener(preference1 -> { + new TimeSettingsDialog(settingsHelper.getBoolean(Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED), + settingsHelper.getString(Constants.CUSTOM_DATE_TIME_FORMAT), + settingsHelper.getString(Constants.DATE_TIME_SELECTION), + (isCustomFormat, + formatSelection, + spTimeFormatSelectedItemPosition, + spSeparatorSelectedItemPosition, + spDateFormatSelectedItemPosition, + selectedFormat, currentFormat) -> { + if (isCustomFormat) { + settingsHelper.putString(Constants.CUSTOM_DATE_TIME_FORMAT, formatSelection); + } else { + final String formatSelectionUpdated = spTimeFormatSelectedItemPosition + ";" + + spSeparatorSelectedItemPosition + ';' + + spDateFormatSelectedItemPosition; // time;separator;date + settingsHelper.putString(Constants.DATE_TIME_FORMAT, selectedFormat); + settingsHelper.putString(Constants.DATE_TIME_SELECTION, formatSelectionUpdated); + } + settingsHelper.putBoolean(Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED, isCustomFormat); + Utils.datetimeParser = (SimpleDateFormat) currentFormat.clone(); + } + ).show(getParentFragmentManager(), null); + return true; + }); + return preference; + } + + public static class SaveToCustomFolderPreference extends Preference { + + private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener; + private String key; + + public SaveToCustomFolderPreference(final Context context, final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener) { + super(context); + this.onSelectFolderButtonClickListener = onSelectFolderButtonClickListener; + key = Constants.FOLDER_SAVE_TO; + setLayoutResource(R.layout.pref_custom_folder); + setKey(key); + setTitle(R.string.save_to_folder); + setIconSpaceReserved(false); + } + + @Override + public void onBindViewHolder(final PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + final SwitchMaterial cbSaveTo = (SwitchMaterial) holder.findViewById(R.id.cbSaveTo); + final View buttonContainer = holder.findViewById(R.id.button_container); + customPathTextView = (AppCompatTextView) holder.findViewById(R.id.custom_path); + cbSaveTo.setOnCheckedChangeListener((buttonView, isChecked) -> { + settingsHelper.putBoolean(FOLDER_SAVE_TO, isChecked); + buttonContainer.setVisibility(isChecked ? View.VISIBLE : View.GONE); + final String customPath = settingsHelper.getString(FOLDER_PATH); + customPathTextView.setText(customPath); + }); + final boolean savedToEnabled = settingsHelper.getBoolean(key); + holder.itemView.setOnClickListener(v -> cbSaveTo.toggle()); + cbSaveTo.setChecked(savedToEnabled); + buttonContainer.setVisibility(savedToEnabled ? View.VISIBLE : View.GONE); + final AppCompatButton btnSaveTo = (AppCompatButton) holder.findViewById(R.id.btnSaveTo); + btnSaveTo.setOnClickListener(v -> { + if (onSelectFolderButtonClickListener == null) return; + onSelectFolderButtonClickListener.onClick(result -> { + if (Utils.isEmpty(result)) return; + customPathTextView.setText(result); + }); + }); + } + + public interface ResultCallback { + void onResult(String result); + } + + public interface OnSelectFolderButtonClickListener { + void onClick(ResultCallback resultCallback); + } + } +} diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/helpers/AutoSummaryDropDownPreference.java b/app/src/main/java/awais/instagrabber/fragments/settings/helpers/AutoSummaryDropDownPreference.java new file mode 100644 index 00000000..1ab0142e --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/settings/helpers/AutoSummaryDropDownPreference.java @@ -0,0 +1,4 @@ +package awais.instagrabber.fragments.settings.helpers; + +public class AutoSummaryDropDownPreference { +} diff --git a/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.java b/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.java new file mode 100644 index 00000000..96935721 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.java @@ -0,0 +1,19 @@ +package awais.instagrabber.repositories; + +import java.util.Map; + +import awais.instagrabber.repositories.responses.FriendshipRepositoryChangeResponseRootObject; +import retrofit2.Call; +import retrofit2.http.FieldMap; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.POST; +import retrofit2.http.Path; + +public interface FriendshipRepository { + + @FormUrlEncoded + @POST("/api/v1/friendships/{action}/{id}/") + Call change(@Path("action") String action, + @Path("id") String id, + @FieldMap Map form); +} diff --git a/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java b/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java deleted file mode 100644 index b7167ce2..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java +++ /dev/null @@ -1,4 +0,0 @@ -package awais.instagrabber.repositories; - -public interface ProfileRepository { -} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/FriendshipRepositoryChangeResponseFriendshipStatus.java b/app/src/main/java/awais/instagrabber/repositories/responses/FriendshipRepositoryChangeResponseFriendshipStatus.java new file mode 100644 index 00000000..b34e914f --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/FriendshipRepositoryChangeResponseFriendshipStatus.java @@ -0,0 +1,76 @@ +package awais.instagrabber.repositories.responses; + +public class FriendshipRepositoryChangeResponseFriendshipStatus { + private boolean following; + private boolean followedBy; + private boolean blocking; + private boolean muting; + private boolean isPrivate; + private boolean incomingRequest; + private boolean outgoingRequest; + private boolean isBestie; + + public FriendshipRepositoryChangeResponseFriendshipStatus(final boolean following, + final boolean followedBy, + final boolean blocking, + final boolean muting, + final boolean isPrivate, + final boolean incomingRequest, + final boolean outgoingRequest, + final boolean isBestie) { + this.following = following; + this.followedBy = followedBy; + this.blocking = blocking; + this.muting = muting; + this.isPrivate = isPrivate; + this.incomingRequest = incomingRequest; + this.outgoingRequest = outgoingRequest; + this.isBestie = isBestie; + } + + public boolean isFollowing() { + return following; + } + + public boolean isFollowedBy() { + return followedBy; + } + + public boolean isBlocking() { + return blocking; + } + + public boolean isMuting() { + return muting; + } + + public boolean isPrivate() { + return isPrivate; + } + + public boolean isIncomingRequest() { + return incomingRequest; + } + + public boolean isOutgoingRequest() { + return outgoingRequest; + } + + public boolean isBestie() { + return isBestie; + } + + @Override + public String toString() { + return "FriendshipRepositoryChangeResponseFriendshipStatus{" + + "following=" + following + + ", followedBy=" + followedBy + + ", blocking=" + blocking + + ", muting=" + muting + + ", isPrivate=" + isPrivate + + ", incomingRequest=" + incomingRequest + + ", outgoingRequest=" + outgoingRequest + + ", isBestie=" + isBestie + + '}'; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/FriendshipRepositoryChangeResponseRootObject.java b/app/src/main/java/awais/instagrabber/repositories/responses/FriendshipRepositoryChangeResponseRootObject.java new file mode 100644 index 00000000..ebfdc39e --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/FriendshipRepositoryChangeResponseRootObject.java @@ -0,0 +1,27 @@ +package awais.instagrabber.repositories.responses; + +public class FriendshipRepositoryChangeResponseRootObject { + private FriendshipRepositoryChangeResponseFriendshipStatus friendshipStatus; + private String status; + + public FriendshipRepositoryChangeResponseRootObject(final FriendshipRepositoryChangeResponseFriendshipStatus friendshipStatus, final String status) { + this.friendshipStatus = friendshipStatus; + this.status = status; + } + + public FriendshipRepositoryChangeResponseFriendshipStatus getFriendshipStatus() { + return friendshipStatus; + } + + public String getStatus() { + return status; + } + + @Override + public String toString() { + return "FriendshipRepositoryChangeResponseRootObject{" + + "friendshipStatus=" + friendshipStatus + + ", status='" + status + '\'' + + '}'; + } +} diff --git a/app/src/main/java/awais/instagrabber/services/BaseService.java b/app/src/main/java/awais/instagrabber/services/BaseService.java index bbf7c28f..dd1a822e 100644 --- a/app/src/main/java/awais/instagrabber/services/BaseService.java +++ b/app/src/main/java/awais/instagrabber/services/BaseService.java @@ -2,6 +2,7 @@ package awais.instagrabber.services; import okhttp3.OkHttpClient; import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory; public abstract class BaseService { @@ -17,6 +18,7 @@ public abstract class BaseService { .build(); builder = new Retrofit.Builder() .addConverterFactory(ScalarsConverterFactory.create()) + .addConverterFactory(GsonConverterFactory.create()) .client(client); } return builder; diff --git a/app/src/main/java/awais/instagrabber/services/FriendshipService.java b/app/src/main/java/awais/instagrabber/services/FriendshipService.java new file mode 100644 index 00000000..8eb8aaaa --- /dev/null +++ b/app/src/main/java/awais/instagrabber/services/FriendshipService.java @@ -0,0 +1,82 @@ +package awais.instagrabber.services; + +import androidx.annotation.NonNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import awais.instagrabber.repositories.FriendshipRepository; +import awais.instagrabber.repositories.responses.FriendshipRepositoryChangeResponseRootObject; +import awais.instagrabber.utils.Utils; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +public class FriendshipService extends BaseService { + private static final String TAG = "ProfileService"; + + private final FriendshipRepository repository; + + private static FriendshipService instance; + + private FriendshipService() { + final Retrofit retrofit = getRetrofitBuilder() + .baseUrl("https://i.instagram.com") + .build(); + repository = retrofit.create(FriendshipRepository.class); + } + + public static FriendshipService getInstance() { + if (instance == null) { + instance = new FriendshipService(); + } + return instance; + } + + public void follow(final String userId, + final String targetUserId, + final String crsfToken, + final ServiceCallback callback) { + change("create", userId, targetUserId, crsfToken, callback); + } + + public void unfollow(final String userId, + final String targetUserId, + final String crsfToken, + final ServiceCallback callback) { + change("destroy", userId, targetUserId, crsfToken, callback); + } + + private void change(final String action, + final String userId, + final String targetUserId, + final String crsfToken, + final ServiceCallback callback) { + final Map form = new HashMap<>(5); + form.put("_csrftoken", crsfToken); + form.put("_uid", userId); + form.put("_uuid", UUID.randomUUID().toString()); + form.put("user_id", targetUserId); + final Map signedForm = Utils.sign(form); + final Call request = repository.change(action, targetUserId, signedForm); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, + @NonNull final Response response) { + if (callback != null) { + callback.onSuccess(response.body()); + } + } + + @Override + public void onFailure(@NonNull final Call call, + @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); + } +} diff --git a/app/src/main/java/awais/instagrabber/services/ProfileService.java b/app/src/main/java/awais/instagrabber/services/ProfileService.java deleted file mode 100644 index d5be7b17..00000000 --- a/app/src/main/java/awais/instagrabber/services/ProfileService.java +++ /dev/null @@ -1,35 +0,0 @@ -package awais.instagrabber.services; - -import awais.instagrabber.repositories.ProfileRepository; -import retrofit2.Retrofit; - -public class ProfileService extends BaseService { - private static final String TAG = "ProfileService"; - - private final ProfileRepository repository; - - private static ProfileService instance; - - private ProfileService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(ProfileRepository.class); - } - - public static ProfileService getInstance() { - if (instance == null) { - instance = new ProfileService(); - } - return instance; - } - - public void followProfile(final String username) { - // final String url = "https://www.instagram.com/web/" + (action.equals("followtag") && mainActivity.hashtagModel != null ? "tags/" + (mainActivity.hashtagModel.getFollowing() ? "unfollow/" : "follow/") + mainActivity.hashtagModel.getName() + "/" : (action.equals("restrict") && mainActivity.profileModel != null ? "restrict_action" : "friendships/" + mainActivity.profileModel.getId()) + "/" + (action.equals("follow") ? - // mainActivity.profileModel.getFollowing() || mainActivity.profileModel.getRequested() - // ? "unfollow/" : "follow/" : - // action.equals("restrict") ? - // mainActivity.profileModel.getRestricted() ? "unrestrict/" : "restrict/" : - // mainActivity.profileModel.getBlocked() ? "unblock/" : "block/")); - } -} diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index 692342d9..7d34d894 100755 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -64,4 +64,5 @@ public final class Constants { "\"gyroscope\", \"value\": \"gyroscope_enabled\" } ]"; public static final String SIGNATURE_VERSION = "4"; public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc"; + public static final int LOGIN_RESULT_CODE = 5000; } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java index 28ad6d9f..0ba66f32 100755 --- a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java @@ -217,8 +217,8 @@ public final class ExportImportUtils { if (settingsHelper != null) { try { final JSONObject json = new JSONObject(); - json.put(Constants.APP_THEME, settingsHelper.getInteger(Constants.APP_THEME)); - json.put(Constants.APP_LANGUAGE, settingsHelper.getInteger(Constants.APP_LANGUAGE)); + 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 (!Utils.isEmpty(str)) json.put(Constants.FOLDER_PATH, str); diff --git a/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java b/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java index 3eddb197..a3d7216e 100755 --- a/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java @@ -55,7 +55,7 @@ public final class LocaleUtils { if (Utils.settingsHelper == null) Utils.settingsHelper = new SettingsHelper(baseContext); - final int appLanguageIndex = Utils.settingsHelper.getInteger(Constants.APP_LANGUAGE); + final int appLanguageIndex = Integer.parseInt(Utils.settingsHelper.getString(Constants.APP_LANGUAGE)); if (appLanguageIndex == 1) return "en"; if (appLanguageIndex == 2) return "fr"; diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index d6b22b5b..cd4ffc3f 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -1,5 +1,6 @@ package awais.instagrabber.utils; +import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; @@ -83,10 +84,18 @@ public final class SettingsHelper { int themeCode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM; if (!fromHelper && sharedPreferences != null) { - themeCode = sharedPreferences.getInt(APP_THEME, themeCode); - if (themeCode == 1) themeCode = AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY; - else if (themeCode == 3) themeCode = AppCompatDelegate.MODE_NIGHT_NO; - else if (themeCode == 0) themeCode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM; + themeCode = Integer.parseInt(sharedPreferences.getString(APP_THEME, String.valueOf(themeCode))); + switch (themeCode) { + case 1: + themeCode = AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY; + break; + case 3: + themeCode = AppCompatDelegate.MODE_NIGHT_NO; + break; + case 0: + themeCode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM; + break; + } } if (themeCode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM && Build.VERSION.SDK_INT < 29) @@ -107,13 +116,13 @@ public final class SettingsHelper { if (sharedPreferences != null) sharedPreferences.edit().putBoolean(key, val).apply(); } - @StringDef({COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID}) + @StringDef({APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID}) public @interface StringSettings {} @StringDef({DOWNLOAD_USER_FOLDER, BOTTOM_TOOLBAR, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, AUTOLOAD_POSTS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, INSTADP, STORIESIG, AMOLED_THEME, CHECK_ACTIVITY}) public @interface BooleanSettings {} - @StringDef({APP_THEME, APP_LANGUAGE, PREV_INSTALL_VERSION}) + @StringDef({PREV_INSTALL_VERSION}) public @interface IntegerSettings {} } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index 64c7985a..8c60d98f 100755 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -59,6 +59,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -820,24 +821,26 @@ public final class Utils { } AppCompatDelegate.setDefaultNightMode(themeCode); // use amoled theme only if enabled in settings - if (isAmoledEnabled) { - // check if setting is set to 'Dark' - boolean isNight = themeCode == AppCompatDelegate.MODE_NIGHT_YES; - // if not dark check if themeCode is MODE_NIGHT_FOLLOW_SYSTEM or MODE_NIGHT_AUTO_BATTERY - if (!isNight && (themeCode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM || themeCode == AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)) { - // check if resulting theme would be NIGHT - final int uiMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; - isNight = uiMode == Configuration.UI_MODE_NIGHT_YES; - } - if (isNight) { - // set amoled theme - Log.d("InstaGrabber", "settings amoled theme"); - context.setTheme(R.style.Theme_Amoled); - return; - } + if (isAmoledEnabled && isNight(context, themeCode)) { + // set amoled theme + Log.d(TAG, "settings amoled theme"); + context.setTheme(R.style.Theme_Amoled); + } + } + + public static boolean isNight(final Context context, final int themeCode) { + // check if setting is set to 'Dark' + boolean isNight = themeCode == AppCompatDelegate.MODE_NIGHT_YES; + // if not dark check if themeCode is MODE_NIGHT_FOLLOW_SYSTEM or MODE_NIGHT_AUTO_BATTERY + if (!isNight && (themeCode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM || themeCode == AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)) { + // check if resulting theme would be NIGHT + final int uiMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + isNight = uiMode == Configuration.UI_MODE_NIGHT_YES; } + return isNight; } + public static void setTooltipText(final View view, @StringRes final int tooltipTextRes) { if (view != null && tooltipTextRes != 0 && tooltipTextRes != -1) { final Context context = view.getContext(); @@ -1208,6 +1211,20 @@ public final class Utils { 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) { + return null; + } + final String[] parts = signed.split("&"); + final Map map = new HashMap<>(); + for (final String part : parts) { + final String[] partSplit = part.split("="); + map.put(partSplit[0], partSplit[1]); + } + return map; + } + public static String sign(final String message) { try { final Mac hasher = Mac.getInstance("HmacSHA256"); @@ -1440,4 +1457,11 @@ public final class Utils { public static int getResultingWidth(final int requiredHeight, final int height, final int width) { return requiredHeight * width / height; } + + public static String getCsrfTokenFromCookie(final String cookie) { + if (cookie == null) { + return null; + } + return cookie.split("csrftoken=")[1].split(";")[0]; + } } \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_info.png b/app/src/main/res/drawable-hdpi/ic_info.png deleted file mode 100644 index 884ee57b..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_info.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_like.png b/app/src/main/res/drawable-hdpi/ic_like.png deleted file mode 100644 index 3984ecbb..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_like.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_not_liked.png b/app/src/main/res/drawable-hdpi/ic_not_liked.png deleted file mode 100644 index 9b69873a..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_not_liked.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_info.png b/app/src/main/res/drawable-mdpi/ic_info.png deleted file mode 100644 index 40f84825..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_info.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_like.png b/app/src/main/res/drawable-mdpi/ic_like.png deleted file mode 100644 index ebc88607..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_like.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_not_liked.png b/app/src/main/res/drawable-mdpi/ic_not_liked.png deleted file mode 100644 index 9ce1c759..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_not_liked.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_info.png b/app/src/main/res/drawable-xhdpi/ic_info.png deleted file mode 100644 index b3d8e89d..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_info.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_like.png b/app/src/main/res/drawable-xhdpi/ic_like.png deleted file mode 100644 index eadf8e7b..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_like.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_not_liked.png b/app/src/main/res/drawable-xhdpi/ic_not_liked.png deleted file mode 100644 index c7af44c5..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_not_liked.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_info.png b/app/src/main/res/drawable-xxhdpi/ic_info.png deleted file mode 100644 index 4c9ddff5..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_info.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_like.png b/app/src/main/res/drawable-xxhdpi/ic_like.png deleted file mode 100644 index ac66ff42..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_like.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_not_liked.png b/app/src/main/res/drawable-xxhdpi/ic_not_liked.png deleted file mode 100644 index 16ee4db9..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_not_liked.png and /dev/null differ diff --git a/app/src/main/res/drawable-anydpi/ic_like.xml b/app/src/main/res/drawable/ic_like.xml similarity index 100% rename from app/src/main/res/drawable-anydpi/ic_like.xml rename to app/src/main/res/drawable/ic_like.xml diff --git a/app/src/main/res/drawable-anydpi/ic_not_liked.xml b/app/src/main/res/drawable/ic_not_liked.xml similarity index 100% rename from app/src/main/res/drawable-anydpi/ic_not_liked.xml rename to app/src/main/res/drawable/ic_not_liked.xml diff --git a/app/src/main/res/drawable-anydpi/ic_info.xml b/app/src/main/res/drawable/ic_outline_info_24.xml similarity index 80% rename from app/src/main/res/drawable-anydpi/ic_info.xml rename to app/src/main/res/drawable/ic_outline_info_24.xml index 28e2af78..35f7f5f6 100644 --- a/app/src/main/res/drawable-anydpi/ic_info.xml +++ b/app/src/main/res/drawable/ic_outline_info_24.xml @@ -1,10 +1,9 @@ + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> diff --git a/app/src/main/res/drawable/ic_outline_settings_24.xml b/app/src/main/res/drawable/ic_outline_settings_24.xml new file mode 100644 index 00000000..0d7a0a66 --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_settings_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_direct_messages.xml b/app/src/main/res/layout/activity_direct_messages.xml index 459fadaa..5e0a0cc3 100644 --- a/app/src/main/res/layout/activity_direct_messages.xml +++ b/app/src/main/res/layout/activity_direct_messages.xml @@ -63,7 +63,7 @@ android:paddingEnd="8dp" android:paddingRight="8dp" android:paddingBottom="4dp" - app:srcCompat="@drawable/ic_info" /> + app:srcCompat="@drawable/ic_outline_info_24" /> diff --git a/app/src/main/res/layout/dialog_time_settings.xml b/app/src/main/res/layout/dialog_time_settings.xml index 14f44a52..f95af99f 100755 --- a/app/src/main/res/layout/dialog_time_settings.xml +++ b/app/src/main/res/layout/dialog_time_settings.xml @@ -1,13 +1,10 @@ + android:padding="16dp"> + android:orientation="horizontal" + android:visibility="gone"> + app:srcCompat="@drawable/ic_outline_info_24" /> + android:orientation="vertical"> + android:orientation="horizontal"> + android:orientation="horizontal"> + android:orientation="horizontal"> + + - - - - - - + android:layout_gravity="bottom" + android:text="@string/time_settings_title_preview" /> + tools:listitem="@layout/layout_dm_inbox_item" /> diff --git a/app/src/main/res/layout/item_comment.xml b/app/src/main/res/layout/item_comment.xml index 4b727c3e..064a50bc 100755 --- a/app/src/main/res/layout/item_comment.xml +++ b/app/src/main/res/layout/item_comment.xml @@ -9,7 +9,7 @@ + layout="@layout/layout_dm_inbox_item" /> + android:background="@android:color/darker_gray" /> + android:background="@android:color/darker_gray" /> -