Preferences! Check description
1. Added preferences screens. 2. Some DM changes. 3. Init profile actions using services
| @ -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' | ||||
| } | ||||
|  | ||||
| @ -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()) | ||||
|  | ||||
| @ -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); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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<Integer> SHOW_BOTTOM_VIEW_DESTINATIONS = Arrays.asList( | ||||
|             R.id.directMessagesInboxFragment, | ||||
|             R.id.feedFragment, | ||||
|             R.id.profileFragment, | ||||
|             R.id.discoverFragment, | ||||
|             R.id.morePreferencesFragment); | ||||
|     private static final List<Integer> KEEP_SCROLL_BEHAVIOUR_DESTINATIONS = Arrays.asList( | ||||
|             R.id.directMessagesInboxFragment, | ||||
|             R.id.feedFragment, | ||||
|             R.id.profileFragment, | ||||
|             R.id.discoverFragment, | ||||
|             R.id.morePreferencesFragment, | ||||
|             R.id.settingsPreferencesFragment); | ||||
|     private ActivityMainBinding binding; | ||||
|     private LiveData<NavController> 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<NavController> 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<Integer> 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(); | ||||
|             binding.bottomNavView.setVisibility(View.GONE); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -8,7 +8,7 @@ import androidx.recyclerview.widget.DiffUtil; | ||||
| import androidx.recyclerview.widget.ListAdapter; | ||||
| 
 | ||||
| import awais.instagrabber.adapters.viewholder.DirectMessageInboxItemViewHolder; | ||||
| import awais.instagrabber.databinding.LayoutIncludeSimpleItemBinding; | ||||
| import awais.instagrabber.databinding.LayoutDmInboxItemBinding; | ||||
| import awais.instagrabber.models.direct_messages.InboxThreadModel; | ||||
| 
 | ||||
| public final class DirectMessageInboxAdapter extends ListAdapter<InboxThreadModel, DirectMessageInboxItemViewHolder> { | ||||
| @ -35,7 +35,7 @@ public final class DirectMessageInboxAdapter extends ListAdapter<InboxThreadMode | ||||
|     @Override | ||||
|     public DirectMessageInboxItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) { | ||||
|         final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); | ||||
|         final LayoutIncludeSimpleItemBinding binding = LayoutIncludeSimpleItemBinding.inflate(layoutInflater, parent, false); | ||||
|         final LayoutDmInboxItemBinding binding = LayoutDmInboxItemBinding.inflate(layoutInflater, parent, false); | ||||
|         return new DirectMessageInboxItemViewHolder(binding); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -2,18 +2,16 @@ package awais.instagrabber.adapters.viewholder; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.view.View; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.LinearLayout; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.core.text.HtmlCompat; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import com.bumptech.glide.Glide; | ||||
| import com.bumptech.glide.RequestManager; | ||||
| import com.facebook.drawee.view.SimpleDraweeView; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.databinding.LayoutIncludeSimpleItemBinding; | ||||
| import awais.instagrabber.databinding.LayoutDmInboxItemBinding; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.models.direct_messages.DirectItemModel; | ||||
| import awais.instagrabber.models.direct_messages.InboxThreadModel; | ||||
| @ -21,19 +19,18 @@ import awais.instagrabber.models.enums.DirectItemType; | ||||
| 
 | ||||
| public final class DirectMessageInboxItemViewHolder extends RecyclerView.ViewHolder { | ||||
|     private final LinearLayout multipleProfilePicsContainer; | ||||
|     private final ImageView[] multipleProfilePics; | ||||
|     private final LayoutIncludeSimpleItemBinding binding; | ||||
|     private final SimpleDraweeView[] multipleProfilePics; | ||||
|     private final LayoutDmInboxItemBinding binding; | ||||
| 
 | ||||
|     public DirectMessageInboxItemViewHolder(@NonNull final LayoutIncludeSimpleItemBinding binding) { | ||||
|     public DirectMessageInboxItemViewHolder(@NonNull final LayoutDmInboxItemBinding binding) { | ||||
|         super(binding.getRoot()); | ||||
|         this.binding = binding; | ||||
|         binding.tvLikes.setVisibility(View.GONE); | ||||
|         multipleProfilePicsContainer = binding.container; | ||||
|         multipleProfilePicsContainer = binding.multiPicContainer; | ||||
|         final LinearLayout containerChild = (LinearLayout) multipleProfilePicsContainer.getChildAt(1); | ||||
|         multipleProfilePics = new ImageView[]{ | ||||
|                 (ImageView) multipleProfilePicsContainer.getChildAt(0), | ||||
|                 (ImageView) containerChild.getChildAt(0), | ||||
|                 (ImageView) containerChild.getChildAt(1) | ||||
|         multipleProfilePics = new SimpleDraweeView[]{ | ||||
|                 (SimpleDraweeView) multipleProfilePicsContainer.getChildAt(0), | ||||
|                 (SimpleDraweeView) containerChild.getChildAt(0), | ||||
|                 (SimpleDraweeView) containerChild.getChildAt(1) | ||||
|         }; | ||||
|         binding.tvDate.setSelected(true); | ||||
|         binding.tvUsername.setSelected(true); | ||||
| @ -45,17 +42,17 @@ public final class DirectMessageInboxItemViewHolder extends RecyclerView.ViewHol | ||||
|             return; | ||||
|         } | ||||
|         itemView.setTag(model); | ||||
|         final RequestManager glideRequestManager = Glide.with(itemView); | ||||
|         final ProfileModel[] users = model.getUsers(); | ||||
|         if (users.length > 1) { | ||||
|             binding.ivProfilePic.setVisibility(View.GONE); | ||||
|             multipleProfilePicsContainer.setVisibility(View.VISIBLE); | ||||
|             for (int i = 0; i < Math.min(3, users.length); ++i) | ||||
|                 glideRequestManager.load(users[i].getSdProfilePic()).into(multipleProfilePics[i]); | ||||
|             for (int i = 0; i < Math.min(3, users.length); ++i) { | ||||
|                 multipleProfilePics[i].setImageURI(users[i].getSdProfilePic()); | ||||
|             } | ||||
|         } else { | ||||
|             binding.ivProfilePic.setVisibility(View.VISIBLE); | ||||
|             multipleProfilePicsContainer.setVisibility(View.GONE); | ||||
|             glideRequestManager.load(users.length == 1 ? users[0].getSdProfilePic() : null).into(binding.ivProfilePic); | ||||
|             binding.ivProfilePic.setImageURI(users.length == 1 ? users[0].getSdProfilePic() : null); | ||||
|         } | ||||
|         binding.tvUsername.setText(model.getThreadTitle()); | ||||
|         final DirectItemModel lastItemModel = itemModels[itemModels.length - 1]; | ||||
|  | ||||
| @ -25,6 +25,8 @@ import awaisomereport.LogCollector; | ||||
| import static awais.instagrabber.utils.Utils.logCollector; | ||||
| 
 | ||||
| public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> { | ||||
|     private static final String TAG = "FeedFetcher"; | ||||
| 
 | ||||
|     private static final int maxItemsToLoad = 25; // max is 50, but that's too many posts, setting more than 30 is gay | ||||
|     private final String endCursor; | ||||
|     private final FetchListener<FeedModel[]> fetchListener; | ||||
| @ -61,7 +63,9 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> { | ||||
|             final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); | ||||
| 
 | ||||
|             if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { | ||||
|                 final JSONObject timelineFeed = new JSONObject(Utils.readFromConnection(urlConnection)).getJSONObject("data") | ||||
|                 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; | ||||
| @ -83,7 +87,8 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> { | ||||
|                 for (int i = 0; i < feedLen; ++i) { | ||||
|                     final JSONObject feedItem = feedItems.getJSONObject(i).getJSONObject("node"); | ||||
|                     final String mediaType = feedItem.optString("__typename"); | ||||
|                     if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType)) continue; | ||||
|                     if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType)) | ||||
|                         continue; | ||||
| 
 | ||||
|                     final boolean isVideo = feedItem.optBoolean("is_video"); | ||||
|                     final long videoViews = feedItem.optLong("video_view_count", 0); | ||||
| @ -93,7 +98,8 @@ public final class FeedFetcher extends AsyncTask<Void, Void, FeedModel[]> { | ||||
|                     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")) { | ||||
|  | ||||
| @ -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<Void, Void, InboxModel> { | ||||
|     private static final String TAG = "InboxFetcher"; | ||||
| 
 | ||||
|     private final String endCursor; | ||||
|     private final FetchListener<InboxModel> fetchListener; | ||||
| 
 | ||||
| @ -43,7 +48,21 @@ public final class InboxFetcher extends AsyncTask<Void, Void, InboxModel> { | ||||
|             conn.setRequestProperty("Accept-Language", LocaleUtils.getCurrentLocale().getLanguage() + ",en-US;q=0.8"); | ||||
|             conn.setUseCaches(false); | ||||
| 
 | ||||
|             if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { | ||||
|             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)); | ||||
| @ -75,14 +94,13 @@ public final class InboxFetcher extends AsyncTask<Void, Void, InboxModel> { | ||||
|             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; | ||||
|  | ||||
| @ -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() { | ||||
| @ -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) { | ||||
|  | ||||
| @ -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; | ||||
|     private boolean customDateTimeFormatEnabled; | ||||
|     private String customDateTimeFormat; | ||||
|     private String dateTimeSelection; | ||||
|     private final OnConfirmListener onConfirmListener; | ||||
| 
 | ||||
|     public TimeSettingsDialog() { | ||||
|         super(); | ||||
|     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); | ||||
|     } | ||||
| } | ||||
| @ -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<Void, Void, Void> { | ||||
|         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); | ||||
|  | ||||
| @ -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<DiscoverTopicModel> topicFetchListener = new FetchListener<DiscoverTopicModel>() { | ||||
|         @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)); | ||||
|  | ||||
| @ -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<FeedModel[]> feedFetchListener = new FetchListener<FeedModel[]>() { | ||||
|         @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 | ||||
|  | ||||
| @ -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<Void, Void, PostModel[]> 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<PostModel[]> postsFetchListener = new FetchListener<PostModel[]>() { | ||||
|         @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<PostModel> postModels = profilePostsViewModel.getList().getValue(); | ||||
|                 final List<PostModel> 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<FriendshipRepositoryChangeResponseRootObject>() { | ||||
|                             @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<FriendshipRepositoryChangeResponseRootObject>() { | ||||
|                             @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() { | ||||
|  | ||||
| @ -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(); | ||||
|     } | ||||
| } | ||||
| @ -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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,4 @@ | ||||
| package awais.instagrabber.fragments.settings.helpers; | ||||
| 
 | ||||
| public class AutoSummaryDropDownPreference { | ||||
| } | ||||
| @ -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<FriendshipRepositoryChangeResponseRootObject> change(@Path("action") String action, | ||||
|                                                               @Path("id") String id, | ||||
|                                                               @FieldMap Map<String, String> form); | ||||
| } | ||||
| @ -1,4 +0,0 @@ | ||||
| package awais.instagrabber.repositories; | ||||
| 
 | ||||
| public interface ProfileRepository { | ||||
| } | ||||
| @ -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 + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -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 + '\'' + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
|  | ||||
| @ -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<FriendshipRepositoryChangeResponseRootObject> callback) { | ||||
|         change("create", userId, targetUserId, crsfToken, callback); | ||||
|     } | ||||
| 
 | ||||
|     public void unfollow(final String userId, | ||||
|                          final String targetUserId, | ||||
|                          final String crsfToken, | ||||
|                          final ServiceCallback<FriendshipRepositoryChangeResponseRootObject> callback) { | ||||
|         change("destroy", userId, targetUserId, crsfToken, callback); | ||||
|     } | ||||
| 
 | ||||
|     private void change(final String action, | ||||
|                         final String userId, | ||||
|                         final String targetUserId, | ||||
|                         final String crsfToken, | ||||
|                         final ServiceCallback<FriendshipRepositoryChangeResponseRootObject> callback) { | ||||
|         final Map<String, Object> 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<String, String> signedForm = Utils.sign(form); | ||||
|         final Call<FriendshipRepositoryChangeResponseRootObject> request = repository.change(action, targetUserId, signedForm); | ||||
|         request.enqueue(new Callback<FriendshipRepositoryChangeResponseRootObject>() { | ||||
|             @Override | ||||
|             public void onResponse(@NonNull final Call<FriendshipRepositoryChangeResponseRootObject> call, | ||||
|                                    @NonNull final Response<FriendshipRepositoryChangeResponseRootObject> response) { | ||||
|                 if (callback != null) { | ||||
|                     callback.onSuccess(response.body()); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onFailure(@NonNull final Call<FriendshipRepositoryChangeResponseRootObject> call, | ||||
|                                   @NonNull final Throwable t) { | ||||
|                 if (callback != null) { | ||||
|                     callback.onFailure(t); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @ -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/")); | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
| @ -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); | ||||
|  | ||||
| @ -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"; | ||||
|  | ||||
| @ -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 {} | ||||
| } | ||||
| @ -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,7 +821,14 @@ public final class Utils { | ||||
|         } | ||||
|         AppCompatDelegate.setDefaultNightMode(themeCode); | ||||
|         // use amoled theme only if enabled in settings | ||||
|         if (isAmoledEnabled) { | ||||
|         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 | ||||
| @ -829,15 +837,10 @@ public final class Utils { | ||||
|             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; | ||||
|             } | ||||
|         } | ||||
|         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<String, String> sign(final Map<String, Object> form) { | ||||
|         final String signed = sign(new JSONObject(form).toString()); | ||||
|         if (signed == null) { | ||||
|             return null; | ||||
|         } | ||||
|         final String[] parts = signed.split("&"); | ||||
|         final Map<String, String> 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]; | ||||
|     } | ||||
| } | ||||
| Before Width: | Height: | Size: 451 B | 
| Before Width: | Height: | Size: 333 B | 
| Before Width: | Height: | Size: 435 B | 
| Before Width: | Height: | Size: 253 B | 
| Before Width: | Height: | Size: 239 B | 
| Before Width: | Height: | Size: 311 B | 
| Before Width: | Height: | Size: 597 B | 
| Before Width: | Height: | Size: 415 B | 
| Before Width: | Height: | Size: 560 B | 
| Before Width: | Height: | Size: 811 B | 
| Before Width: | Height: | Size: 570 B | 
| Before Width: | Height: | Size: 815 B | 
| @ -1,10 +1,9 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:alpha="0.8" | ||||
|     android:tint="?attr/colorControlNormal" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="?attr/colorControlNormal"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/> | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_outline_settings_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="?attr/colorControlNormal"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/> | ||||
| </vector> | ||||
| @ -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" /> | ||||
|             </androidx.appcompat.widget.Toolbar> | ||||
|         </com.google.android.material.appbar.CollapsingToolbarLayout> | ||||
|     </com.google.android.material.appbar.AppBarLayout> | ||||
|  | ||||
| @ -1,13 +1,10 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:paddingStart="4dp" | ||||
|     android:paddingLeft="4dp" | ||||
|     android:paddingTop="12dp" | ||||
|     android:paddingEnd="4dp" | ||||
|     android:paddingRight="4dp"> | ||||
|     android:padding="16dp"> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:layout_width="match_parent" | ||||
| @ -25,9 +22,8 @@ | ||||
|                 android:orientation="horizontal"> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_weight="1" | ||||
|                     android:text="@string/time_settings_title_custom" /> | ||||
| 
 | ||||
|                 <CheckBox | ||||
| @ -40,7 +36,8 @@ | ||||
|             <LinearLayout | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:orientation="horizontal"> | ||||
|                 android:orientation="horizontal" | ||||
|                 android:visibility="gone"> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatEditText | ||||
|                     android:id="@+id/etCustomFormat" | ||||
| @ -55,7 +52,7 @@ | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_gravity="start" | ||||
|                     android:src="@android:drawable/ic_menu_info_details" /> | ||||
|                     app:srcCompat="@drawable/ic_outline_info_24" /> | ||||
|             </LinearLayout> | ||||
| 
 | ||||
|             <FrameLayout | ||||
| @ -73,63 +70,72 @@ | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:baselineAligned="false" | ||||
|             android:orientation="horizontal"> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="0dp" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_weight="0.84" | ||||
|             android:orientation="vertical"> | ||||
| 
 | ||||
|                 <TextView | ||||
|             <LinearLayout | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:orientation="horizontal"> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_weight="1" | ||||
|                     android:text="@string/time_settings_title_time_format" /> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatSpinner | ||||
|                     android:id="@+id/spTimeFormat" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="36dp" | ||||
|                     android:layout_weight="1" | ||||
|                     android:entries="@array/time_presets" /> | ||||
|             </LinearLayout> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="0dp" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_weight="0.7" | ||||
|                 android:orientation="vertical"> | ||||
| 
 | ||||
|                 <TextView | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:orientation="horizontal"> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_weight="1" | ||||
|                     android:text="@string/time_settings_title_separator" /> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatSpinner | ||||
|                     android:id="@+id/spSeparator" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="36dp" | ||||
|                     android:layout_weight="1" | ||||
|                     android:entries="@array/separator_presets" /> | ||||
|             </LinearLayout> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:orientation="horizontal"> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_weight="1" | ||||
|                 android:orientation="vertical"> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:text="@string/time_settings_title_date_format" /> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatSpinner | ||||
|                     android:id="@+id/spDateFormat" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="36dp" | ||||
|                     android:layout_weight="1" | ||||
|                     android:entries="@array/date_presets" /> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
| 
 | ||||
|         <CheckBox | ||||
|             android:id="@+id/cbSwapTimeDate" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="@string/time_settings_swap_time" /> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
| @ -137,25 +143,11 @@ | ||||
|             android:baselineAligned="false" | ||||
|             android:orientation="vertical"> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:orientation="horizontal"> | ||||
| 
 | ||||
|             <TextView | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_gravity="bottom" | ||||
|                     android:layout_weight="1" | ||||
|                     android:text="@string/time_settings_title_preview" /> | ||||
| 
 | ||||
|                 <CheckBox | ||||
|                     android:id="@+id/cbSwapTimeDate" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                     android:gravity="center" | ||||
|                     android:text="@string/time_settings_swap_time" /> | ||||
|             </LinearLayout> | ||||
|                 android:layout_gravity="bottom" | ||||
|                 android:text="@string/time_settings_title_preview" /> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@+id/timePreview" | ||||
|  | ||||
| @ -16,6 +16,6 @@ | ||||
|             android:id="@+id/inbox_list" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             tools:listitem="@layout/layout_include_simple_item" /> | ||||
|             tools:listitem="@layout/layout_dm_inbox_item" /> | ||||
|     </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | ||||
| </awais.instagrabber.customviews.helpers.NestedCoordinatorLayout> | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/container" | ||||
|         layout="@layout/layout_include_simple_item" /> | ||||
|         layout="@layout/layout_dm_inbox_item" /> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/rvChildComments" | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="1dip" | ||||
|             android:layout_alignParentTop="true" | ||||
|             android:background="?android:attr/dividerVertical" /> | ||||
|             android:background="@android:color/darker_gray" /> | ||||
| 
 | ||||
|         <View | ||||
|             android:id="@+id/horizontalDivider" | ||||
| @ -23,9 +23,9 @@ | ||||
|             android:layout_centerHorizontal="true" | ||||
|             android:layout_marginTop="4dp" | ||||
|             android:layout_marginBottom="4dp" | ||||
|             android:background="?android:attr/dividerVertical" /> | ||||
|             android:background="@android:color/darker_gray" /> | ||||
| 
 | ||||
|         <Button | ||||
|         <androidx.appcompat.widget.AppCompatButton | ||||
|             android:id="@+id/btnCancel" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
| @ -38,7 +38,7 @@ | ||||
|             android:background="?android:selectableItemBackground" | ||||
|             android:text="@string/cancel" /> | ||||
| 
 | ||||
|         <Button | ||||
|         <androidx.appcompat.widget.AppCompatButton | ||||
|             android:id="@+id/btnConfirm" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
| @ -103,7 +103,7 @@ | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="1dp" | ||||
|             android:layout_below="@id/btnNavUp" | ||||
|             android:background="#33B5E5" /> | ||||
|             android:background="@android:color/darker_gray" /> | ||||
|     </RelativeLayout> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|  | ||||
							
								
								
									
										121
									
								
								app/src/main/res/layout/layout_dm_inbox_item.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,121 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:background="?android:selectableItemBackground" | ||||
|     android:orientation="horizontal"> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|         android:layout_width="@dimen/simple_item_picture_size" | ||||
|         android:layout_height="@dimen/simple_item_picture_size" | ||||
|         android:gravity="center" | ||||
|         android:padding="4dp"> | ||||
| 
 | ||||
|         <com.facebook.drawee.view.SimpleDraweeView | ||||
|             android:id="@+id/ivProfilePic" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             app:roundAsCircle="true" /> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:id="@+id/multi_pic_container" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:orientation="horizontal"> | ||||
| 
 | ||||
|             <com.facebook.drawee.view.SimpleDraweeView | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" | ||||
|                 app:roundAsCircle="true" /> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:orientation="vertical"> | ||||
| 
 | ||||
|                 <com.facebook.drawee.view.SimpleDraweeView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" | ||||
|                     app:roundAsCircle="true" /> | ||||
| 
 | ||||
|                 <com.facebook.drawee.view.SimpleDraweeView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" | ||||
|                     app:roundAsCircle="true" /> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
|     </FrameLayout> | ||||
| 
 | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_gravity="center" | ||||
|         android:padding="8dp" | ||||
|         android:orientation="vertical"> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvUsername" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="0dp" | ||||
|             android:ellipsize="marquee" | ||||
|             android:gravity="center_vertical" | ||||
|             android:singleLine="true" | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat.Medium" | ||||
|             android:textColor="?android:textColorPrimary" | ||||
|             android:textStyle="bold" | ||||
|             app:layout_constraintEnd_toStartOf="@id/tvDate" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" | ||||
|             tools:text="username" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvDate" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="0dp" | ||||
|             android:ellipsize="marquee" | ||||
|             android:gravity="center_vertical|end" | ||||
|             android:singleLine="true" | ||||
|             android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|             android:textStyle="italic" | ||||
|             app:layout_constraintBottom_toTopOf="@id/comment_container" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toEndOf="@id/tvUsername" | ||||
|             app:layout_constraintTop_toTopOf="parent" | ||||
|             tools:text="long date................................" /> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:id="@+id/comment_container" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:orientation="horizontal" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toBottomOf="@id/tvUsername"> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageView | ||||
|                 android:id="@+id/notTextType" | ||||
|                 android:layout_width="4dp" | ||||
|                 android:layout_height="4dp" | ||||
|                 android:layout_gravity="center_vertical" | ||||
|                 android:layout_marginEnd="4dp" | ||||
|                 android:layout_marginRight="4dp" | ||||
|                 android:visibility="gone" | ||||
|                 app:srcCompat="@android:drawable/ic_notification_overlay" | ||||
|                 app:tint="@color/feed_text_primary_color" /> | ||||
| 
 | ||||
|             <awais.instagrabber.customviews.RamboTextView | ||||
|                 android:id="@+id/tvComment" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:layout_gravity="center_vertical" | ||||
|                 android:autoLink="web|email" | ||||
|                 android:ellipsize="end" | ||||
|                 android:linksClickable="true" | ||||
|                 android:textAppearance="@style/TextAppearance.AppCompat.Caption" | ||||
|                 tools:text="comment" /> | ||||
|         </LinearLayout> | ||||
|     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| </LinearLayout> | ||||
| @ -1,138 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:background="?android:selectableItemBackground" | ||||
|     android:orientation="horizontal" | ||||
|     android:paddingStart="0dp" | ||||
|     android:paddingLeft="0dp" | ||||
|     android:paddingEnd="4dp" | ||||
|     android:paddingRight="4dp"> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|         android:layout_width="@dimen/simple_item_picture_size" | ||||
|         android:layout_height="@dimen/simple_item_picture_size" | ||||
|         android:gravity="center"> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatImageView | ||||
|             android:id="@+id/ivProfilePic" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" /> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:id="@+id/container" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:orientation="horizontal"> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageView | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" /> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:orientation="vertical"> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatImageView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" /> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatImageView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" /> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
|     </FrameLayout> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:orientation="vertical"> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatTextView | ||||
|                 android:id="@+id/tvUsername" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_gravity="start" | ||||
|                 android:layout_weight="1.0" | ||||
|                 android:ellipsize="marquee" | ||||
|                 android:paddingStart="8dp" | ||||
|                 android:paddingLeft="8dp" | ||||
|                 android:paddingTop="4dp" | ||||
|                 android:paddingEnd="4dp" | ||||
|                 android:paddingRight="4dp" | ||||
|                 android:singleLine="true" | ||||
|                 android:textAppearance="@style/TextAppearance.AppCompat.Medium" | ||||
|                 android:textColor="?android:textColorPrimary" | ||||
|                 android:textStyle="bold" /> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:orientation="horizontal" | ||||
|             android:paddingLeft="8dp" | ||||
|             android:paddingTop="4dp" | ||||
|             android:paddingRight="8dp" | ||||
|             android:paddingBottom="16dp"> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageView | ||||
|                 android:id="@+id/notTextType" | ||||
|                 android:layout_width="4dp" | ||||
|                 android:layout_height="4dp" | ||||
|                 android:layout_gravity="center_vertical" | ||||
|                 android:layout_marginEnd="4dp" | ||||
|                 android:layout_marginRight="4dp" | ||||
|                 android:visibility="gone" | ||||
|                 app:srcCompat="@android:drawable/ic_notification_overlay" | ||||
|                 app:tint="@color/feed_text_primary_color" /> | ||||
| 
 | ||||
|             <awais.instagrabber.customviews.RamboTextView | ||||
|                 android:id="@+id/tvComment" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_gravity="start" | ||||
|                 android:autoLink="web|email" | ||||
|                 android:ellipsize="end" | ||||
|                 android:linksClickable="true" | ||||
|                 android:textAppearance="@style/TextAppearance.AppCompat" /> | ||||
|         </LinearLayout> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:weightSum="3"> | ||||
|             <androidx.appcompat.widget.AppCompatTextView | ||||
|                 android:id="@+id/tvLikes" | ||||
|                 android:layout_width="0dp" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_weight="1" | ||||
|                 android:ellipsize="marquee" | ||||
|                 android:paddingStart="4dp" | ||||
|                 android:paddingLeft="4dp" | ||||
|                 android:paddingTop="4dp" | ||||
|                 android:paddingEnd="8dp" | ||||
|                 android:paddingRight="8dp" | ||||
|                 android:singleLine="true" | ||||
|                 android:textAppearance="@style/TextAppearance.AppCompat.Small" | ||||
|                 android:textSize="14sp" /> | ||||
|             <androidx.appcompat.widget.AppCompatTextView | ||||
|                 android:id="@+id/tvDate" | ||||
|                 android:layout_width="0dp" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_weight="2" | ||||
|                 android:layout_gravity="start" | ||||
|                 android:ellipsize="marquee" | ||||
|                 android:paddingStart="4dp" | ||||
|                 android:paddingLeft="4dp" | ||||
|                 android:paddingTop="4dp" | ||||
|                 android:paddingEnd="8dp" | ||||
|                 android:paddingRight="8dp" | ||||
|                 android:singleLine="true" | ||||
|                 android:textStyle="italic" | ||||
|                 android:gravity="right"/> | ||||
|         </LinearLayout> | ||||
| 
 | ||||
|     </LinearLayout> | ||||
| </LinearLayout> | ||||
							
								
								
									
										93
									
								
								app/src/main/res/layout/pref_custom_folder.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,93 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:animateLayoutChanges="true" | ||||
|     android:background="?android:attr/selectableItemBackground" | ||||
|     android:gravity="center_vertical" | ||||
|     android:minHeight="?android:attr/listPreferredItemHeight" | ||||
|     android:orientation="vertical" | ||||
|     android:paddingEnd="?android:attr/scrollbarSize" | ||||
|     android:paddingRight="?android:attr/scrollbarSize"> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:baselineAligned="false" | ||||
|         android:gravity="center_vertical"> | ||||
| 
 | ||||
|         <RelativeLayout | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginStart="15dip" | ||||
|             android:layout_marginLeft="15dip" | ||||
|             android:layout_marginTop="6dip" | ||||
|             android:layout_marginEnd="6dip" | ||||
|             android:layout_marginRight="6dip" | ||||
|             android:layout_marginBottom="6dip" | ||||
|             android:layout_weight="1"> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@android:id/title" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:ellipsize="marquee" | ||||
|                 android:fadingEdge="horizontal" | ||||
|                 android:singleLine="true" | ||||
|                 android:textAppearance="?android:attr/textAppearanceListItem" | ||||
|                 android:textColor="?android:attr/textColorPrimary" | ||||
|                 tools:text="Test" /> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@android:id/summary" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_below="@android:id/title" | ||||
|                 android:layout_alignStart="@android:id/title" | ||||
|                 android:layout_alignLeft="@android:id/title" | ||||
|                 android:maxLines="4" | ||||
|                 android:textAppearance="?android:attr/textAppearanceListItemSmall" | ||||
|                 android:textColor="?android:attr/textColorSecondary" | ||||
|                 tools:text="summary" /> | ||||
| 
 | ||||
|         </RelativeLayout> | ||||
| 
 | ||||
|         <com.google.android.material.switchmaterial.SwitchMaterial | ||||
|             android:id="@+id/cbSaveTo" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="match_parent" | ||||
|             android:layout_gravity="center_vertical" | ||||
|             android:contentDescription="@string/save_to_folder" | ||||
|             android:paddingEnd="10dp" | ||||
|             android:paddingRight="10dp" /> | ||||
| 
 | ||||
|     </LinearLayout> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:id="@+id/button_container" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="15dip" | ||||
|         android:layout_marginLeft="15dip" | ||||
|         android:gravity="center_vertical" | ||||
|         android:orientation="horizontal" | ||||
|         android:visibility="gone"> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatButton | ||||
|             android:id="@+id/btnSaveTo" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="@string/select_folder" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/custom_path" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:ellipsize="marquee" | ||||
|             android:singleLine="true" | ||||
|             android:textAppearance="?android:attr/textAppearanceListItemSmall" | ||||
|             android:textColor="?android:attr/textColorSecondary" | ||||
|             tools:text="test path" /> | ||||
|     </LinearLayout> | ||||
| </LinearLayout> | ||||
							
								
								
									
										14
									
								
								app/src/main/res/layout/pref_more_header.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,14 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:orientation="vertical"> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatImageView | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="200dp" | ||||
|         android:scaleType="fitCenter" | ||||
|         app:srcCompat="@mipmap/ic_launcher" /> | ||||
| 
 | ||||
| </LinearLayout> | ||||
| @ -24,7 +24,7 @@ | ||||
|     <!--    android:title="@string/title_favorites"/>--> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/moreFragment" | ||||
|         android:id="@+id/more_nav_graph" | ||||
|         android:icon="@drawable/ic_more_horiz_24" | ||||
|         android:title="@string/more" /> | ||||
| </menu> | ||||
| @ -28,6 +28,9 @@ | ||||
|         <action | ||||
|             android:id="@+id/action_dMThreadFragment_to_dMSettingsFragment" | ||||
|             app:destination="@id/directMessagesSettingsFragment" /> | ||||
|         <action | ||||
|             android:id="@+id/action_directMessagesThreadFragment_to_profileFragment" | ||||
|             app:destination="@id/profileFragment" /> | ||||
|     </fragment> | ||||
|     <fragment | ||||
|         android:id="@+id/directMessagesSettingsFragment" | ||||
| @ -41,4 +44,14 @@ | ||||
|             android:name="title" | ||||
|             app:argType="string" /> | ||||
|     </fragment> | ||||
|     <fragment | ||||
|         android:id="@+id/profileFragment" | ||||
|         android:name="awais.instagrabber.fragments.main.ProfileFragment" | ||||
|         android:label="ProfileFragment" | ||||
|         tools:layout="@layout/fragment_profile"> | ||||
|         <argument | ||||
|             android:name="username" | ||||
|             app:argType="string" | ||||
|             app:nullable="false" /> | ||||
|     </fragment> | ||||
| </navigation> | ||||
							
								
								
									
										19
									
								
								app/src/main/res/navigation/more_nav_graph.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,19 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <navigation xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:id="@+id/more_nav_graph" | ||||
|     app:startDestination="@id/morePreferencesFragment"> | ||||
| 
 | ||||
|     <fragment | ||||
|         android:id="@+id/morePreferencesFragment" | ||||
|         android:name="awais.instagrabber.fragments.settings.MorePreferencesFragment" | ||||
|         android:label="More"> | ||||
|         <action | ||||
|             android:id="@+id/action_morePreferencesFragment_to_settingsPreferencesFragment" | ||||
|             app:destination="@id/settingsPreferencesFragment" /> | ||||
|     </fragment> | ||||
|     <fragment | ||||
|         android:id="@+id/settingsPreferencesFragment" | ||||
|         android:name="awais.instagrabber.fragments.settings.SettingsPreferencesFragment" | ||||
|         android:label="@string/action_settings" /> | ||||
| </navigation> | ||||
| @ -13,12 +13,31 @@ | ||||
|         <item>Turkish [Thanks to @faydin90 (Telegram)]</item> | ||||
|         <item>Brazilian Portuguese [Thanks to @wagnim (GitHub)]</item> | ||||
|     </string-array> | ||||
|     <string-array name="languages_values"> | ||||
|         <item>0</item> | ||||
|         <item>1</item> | ||||
|         <item>2</item> | ||||
|         <item>3</item> | ||||
|         <item>4</item> | ||||
|         <item>5</item> | ||||
|         <item>6</item> | ||||
|         <item>7</item> | ||||
|         <item>8</item> | ||||
|         <item>9</item> | ||||
|         <item>10</item> | ||||
|     </string-array> | ||||
|     <string-array name="theme_presets"> | ||||
|         <item>Auto / Follow System</item> | ||||
|         <item>Auto / Follow Battery</item> | ||||
|         <item>Dark</item> | ||||
|         <item>Light</item> | ||||
|     </string-array> | ||||
|     <string-array name="theme_presets_values"> | ||||
|         <item>0</item> | ||||
|         <item>1</item> | ||||
|         <item>2</item> | ||||
|         <item>3</item> | ||||
|     </string-array> | ||||
|     <string-array name="separator_presets"> | ||||
|         <item>None</item> | ||||
|         <item>\@</item> | ||||
|  | ||||
| @ -12,8 +12,8 @@ | ||||
|     <dimen name="story_item_height">80dp</dimen> | ||||
|     <dimen name="story_item_width">45dp</dimen> | ||||
| 
 | ||||
|     <dimen name="simple_item_picture_size">@dimen/story_item_height</dimen> | ||||
|     <dimen name="simple_item_picture_size_half">@dimen/story_item_width</dimen> | ||||
|     <dimen name="simple_item_picture_size">80dp</dimen> | ||||
|     <dimen name="simple_item_picture_size_half">40dp</dimen> | ||||
| 
 | ||||
|     <dimen name="message_item_size">@dimen/simple_item_picture_size</dimen> | ||||
|     <dimen name="message_item_profile_size">@dimen/feed_profile_size</dimen> | ||||
|  | ||||
| @ -36,7 +36,8 @@ | ||||
|     <string name="bottom_toolbar">Show toolbar at bottom</string> | ||||
|     <string name="download_user_folder">Download posts to username folder in Downloads</string> | ||||
|     <string name="autoload_posts">Auto-load all posts from user</string> | ||||
|     <string name="mark_as_seen_setting">Mark stories as seen after viewing\n(Story author will know you viewed it)</string> | ||||
|     <string name="mark_as_seen_setting">Mark stories as seen after viewing</string> | ||||
|     <string name="mark_as_seen_setting_summary">Story author will know you viewed it</string> | ||||
|     <string name="activity_setting">Enable activity notifications</string> | ||||
|     <string name="error_loading_profile">Error loading profile!\nTry logging in and search again.</string> | ||||
|     <string name="error_creating_folders">Error creating Download folder(s).</string> | ||||
| @ -129,12 +130,12 @@ | ||||
|     <string name="refresh">Refresh</string> | ||||
|     <string name="get_cookies">Get cookies</string> | ||||
|     <string name="desktop_2fa">Desktop Mode</string> | ||||
|     <string name="time_settings_title_custom">Custom Format</string> | ||||
|     <string name="time_settings_title_custom">Use custom format</string> | ||||
|     <string name="time_settings_title_separator">Separator</string> | ||||
|     <string name="time_settings_title_time_format">Time Format</string> | ||||
|     <string name="time_settings_title_date_format">Date Format</string> | ||||
|     <string name="time_settings_title_preview">Preview</string> | ||||
|     <string name="time_settings_swap_time">Swap Time and\nDate positions</string> | ||||
|     <string name="time_settings_swap_time">Swap Time and Date positions</string> | ||||
|     <string name="quick_access_info_dialog">Favorites panel is for adding your favorite hashtags and/or usernames.\n\nAnd the Quick Access panel is for quickly switching between accounts.\n\nNote 1: Make sure to Login into each account [Settings > Login] to add account to the list!\n\nNote 2: Log out of the current account and then log into the other account.</string> | ||||
|     <string name="quick_access_cannot_delete_curr">Cannot delete currently in use account</string> | ||||
|     <string name="quick_access_confirm_delete">Are you sure you want to delete %s?</string> | ||||
| @ -239,4 +240,7 @@ | ||||
|     <string name="more">More</string> | ||||
|     <string name="title_dm">DM</string> | ||||
|     <string name="number_selected">%d selected</string> | ||||
|     <string name="relogin">Relogin</string> | ||||
|     <string name="relogin_summary">Refresh your cookies if facing any issues</string> | ||||
|     <string name="logout_success">Successfully logged out!</string> | ||||
| </resources> | ||||
|  | ||||