From 0d9db83dc37e7c8f784cbff87b0b19bb602821fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Ho=C5=99=C3=A1nek?= Date: Wed, 20 Jan 2021 00:09:04 +0100 Subject: [PATCH 01/42] Redesigned the BottomNavigationView for better clarity + to match the Material Guidelines --- .../instagrabber/activities/MainActivity.java | 2 +- app/src/main/res/drawable/ic_discover.xml | 9 ------ app/src/main/res/drawable/ic_explore_24.xml | 10 ++++++ app/src/main/res/drawable/ic_feed.xml | 9 ------ app/src/main/res/drawable/ic_home_24.xml | 10 ++++++ app/src/main/res/drawable/ic_message_24.xml | 10 ++++++ app/src/main/res/drawable/ic_person_24.xml | 10 ++++++ app/src/main/res/layout/activity_main.xml | 2 +- .../logged_out_bottom_navigation_menu.xml | 2 +- .../res/menu/main_bottom_navigation_menu.xml | 31 ++++++++++--------- 10 files changed, 60 insertions(+), 35 deletions(-) delete mode 100755 app/src/main/res/drawable/ic_discover.xml create mode 100644 app/src/main/res/drawable/ic_explore_24.xml delete mode 100755 app/src/main/res/drawable/ic_feed.xml create mode 100644 app/src/main/res/drawable/ic_home_24.xml create mode 100644 app/src/main/res/drawable/ic_message_24.xml create mode 100644 app/src/main/res/drawable/ic_person_24.xml diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index d488b69b..513c6e9e 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -394,7 +394,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage if (!TextUtils.isEmpty(defaultTabResNameString)) { navId = getResources().getIdentifier(defaultTabResNameString, "navigation", getPackageName()); } - final int defaultNavId = navId <= 0 ? R.navigation.profile_nav_graph + final int defaultNavId = navId <= 0 ? R.navigation.feed_nav_graph : navId; final int index = mainNavList.indexOf(defaultNavId); if (index >= 0) firstFragmentGraphIndex = index; diff --git a/app/src/main/res/drawable/ic_discover.xml b/app/src/main/res/drawable/ic_discover.xml deleted file mode 100755 index 7a1ab400..00000000 --- a/app/src/main/res/drawable/ic_discover.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_explore_24.xml b/app/src/main/res/drawable/ic_explore_24.xml new file mode 100644 index 00000000..0ac168a2 --- /dev/null +++ b/app/src/main/res/drawable/ic_explore_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_feed.xml b/app/src/main/res/drawable/ic_feed.xml deleted file mode 100755 index c163a23d..00000000 --- a/app/src/main/res/drawable/ic_feed.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_home_24.xml b/app/src/main/res/drawable/ic_home_24.xml new file mode 100644 index 00000000..3a4c7dac --- /dev/null +++ b/app/src/main/res/drawable/ic_home_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_message_24.xml b/app/src/main/res/drawable/ic_message_24.xml new file mode 100644 index 00000000..a7adce5a --- /dev/null +++ b/app/src/main/res/drawable/ic_message_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_person_24.xml b/app/src/main/res/drawable/ic_person_24.xml new file mode 100644 index 00000000..6bdced2d --- /dev/null +++ b/app/src/main/res/drawable/ic_person_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 866770aa..cd599480 100755 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -47,7 +47,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" - app:labelVisibilityMode="labeled" + app:labelVisibilityMode="selected" app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" app:menu="@menu/main_bottom_navigation_menu" /> \ No newline at end of file diff --git a/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml b/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml index e93193a0..4eb3da02 100644 --- a/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml +++ b/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml @@ -2,7 +2,7 @@ - - + + + + + - - - - + + + + Date: Wed, 20 Jan 2021 01:14:35 +0100 Subject: [PATCH 02/42] BottomNavigationView: show labels when selected only when logged in (more than or equal to 4 items) and always shown when logged out (less than 4 items) --- app/src/main/res/layout/activity_main.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index cd599480..d21d42a6 100755 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -47,7 +47,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" - app:labelVisibilityMode="selected" + app:labelVisibilityMode="auto" app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" app:menu="@menu/main_bottom_navigation_menu" /> \ No newline at end of file From c57e3057329df21affc7a6877d06cfdf7649742c Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Mon, 22 Mar 2021 20:59:08 +0900 Subject: [PATCH 03/42] Create RetrofitFactory to reuse retrofit objects. --- .../instagrabber/InstaGrabberApplication.java | 10 +- .../instagrabber/utils/MediaUploader.java | 2 +- .../instagrabber/webservices/BaseService.java | 42 -------- .../webservices/CollectionService.java | 18 ++-- .../webservices/DirectMessagesService.java | 8 +- .../webservices/DiscoverService.java | 8 +- .../instagrabber/webservices/FeedService.java | 8 +- .../webservices/FriendshipService.java | 16 ++- .../instagrabber/webservices/GifService.java | 8 +- .../webservices/GraphQLService.java | 8 +- .../webservices/LocationService.java | 8 +- .../webservices/MediaService.java | 8 +- .../instagrabber/webservices/NewsService.java | 30 ++---- .../webservices/ProfileService.java | 14 ++- .../webservices/RetrofitFactory.java | 97 +++++++++++++++++++ .../webservices/StoriesService.java | 11 +-- .../instagrabber/webservices/TagsService.java | 8 +- .../instagrabber/webservices/UserService.java | 8 +- .../AddCookiesInterceptor.java | 2 +- .../LoggingInterceptor.java | 2 +- 20 files changed, 170 insertions(+), 146 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java rename app/src/main/java/awais/instagrabber/webservices/{ => interceptors}/AddCookiesInterceptor.java (96%) rename app/src/main/java/awais/instagrabber/webservices/{ => interceptors}/LoggingInterceptor.java (96%) diff --git a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java index b90c8343..de555f94 100644 --- a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java +++ b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java @@ -17,17 +17,19 @@ import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.LocaleUtils; import awais.instagrabber.utils.SettingsHelper; import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.webservices.RetrofitFactory; import awaisomereport.CrashReporter; -//import awaisomereport.LogCollector; import static awais.instagrabber.utils.CookieUtils.NET_COOKIE_MANAGER; import static awais.instagrabber.utils.Utils.applicationHandler; import static awais.instagrabber.utils.Utils.cacheDir; import static awais.instagrabber.utils.Utils.clipboardManager; import static awais.instagrabber.utils.Utils.datetimeParser; -//import static awais.instagrabber.utils.Utils.logCollector; import static awais.instagrabber.utils.Utils.settingsHelper; +//import awaisomereport.LogCollector; +//import static awais.instagrabber.utils.Utils.logCollector; + public final class InstaGrabberApplication extends Application { private static final String TAG = "InstaGrabberApplication"; @@ -56,7 +58,7 @@ public final class InstaGrabberApplication extends Application { } if (!BuildConfig.DEBUG) CrashReporter.get(this).start(); -// logCollector = new LogCollector(this); + // logCollector = new LogCollector(this); CookieHandler.setDefault(NET_COOKIE_MANAGER); @@ -85,5 +87,7 @@ public final class InstaGrabberApplication extends Application { if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) { settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString()); } + + RetrofitFactory.setup(this); } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/MediaUploader.java b/app/src/main/java/awais/instagrabber/utils/MediaUploader.java index f9c47a91..beb5c1af 100644 --- a/app/src/main/java/awais/instagrabber/utils/MediaUploader.java +++ b/app/src/main/java/awais/instagrabber/utils/MediaUploader.java @@ -17,7 +17,7 @@ import java.util.Map; import awais.instagrabber.models.UploadPhotoOptions; import awais.instagrabber.models.UploadVideoOptions; -import awais.instagrabber.webservices.AddCookiesInterceptor; +import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor; import okhttp3.Call; import okhttp3.Headers; import okhttp3.MediaType; diff --git a/app/src/main/java/awais/instagrabber/webservices/BaseService.java b/app/src/main/java/awais/instagrabber/webservices/BaseService.java index e30aa992..a6cdf060 100644 --- a/app/src/main/java/awais/instagrabber/webservices/BaseService.java +++ b/app/src/main/java/awais/instagrabber/webservices/BaseService.java @@ -1,50 +1,8 @@ package awais.instagrabber.webservices; -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import java.io.File; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.repositories.responses.Caption; -import awais.instagrabber.utils.Utils; -import okhttp3.Cache; -import okhttp3.OkHttpClient; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import retrofit2.converter.scalars.ScalarsConverterFactory; - public abstract class BaseService { private static final String TAG = "BaseService"; - private Retrofit.Builder builder; - private final int cacheSize = 10 * 1024 * 1024; // 10 MB - private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize); - - Retrofit.Builder getRetrofitBuilder() { - if (builder == null) { - final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() - .addInterceptor(new AddCookiesInterceptor()) - .followRedirects(false) - .followSslRedirects(false) - .cache(cache); - if (BuildConfig.DEBUG) { - // clientBuilder.addInterceptor(new LoggingInterceptor()); - } - final Gson gson = new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer()) - .setLenient() - .create(); - builder = new Retrofit.Builder() - .addConverterFactory(ScalarsConverterFactory.create()) - .addConverterFactory(GsonConverterFactory.create(gson)) - .client(clientBuilder.build()); - } - return builder; - } - // protected String userBreadcrumb(final int size) { // final long term = (random(2, 4) * 1000) + size + (random(15, 21) * 1000); // final float div = (float) size / random(2, 4); diff --git a/app/src/main/java/awais/instagrabber/webservices/CollectionService.java b/app/src/main/java/awais/instagrabber/webservices/CollectionService.java index faafb6d0..e0c50dc2 100644 --- a/app/src/main/java/awais/instagrabber/webservices/CollectionService.java +++ b/app/src/main/java/awais/instagrabber/webservices/CollectionService.java @@ -1,5 +1,7 @@ package awais.instagrabber.webservices; +import android.text.TextUtils; + import androidx.annotation.NonNull; import java.util.HashMap; @@ -14,7 +16,6 @@ import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class CollectionService extends BaseService { private static final String TAG = "ProfileService"; @@ -31,10 +32,9 @@ public class CollectionService extends BaseService { this.deviceUuid = deviceUuid; this.csrfToken = csrfToken; this.userId = userId; - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(CollectionRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(CollectionRepository.class); } public String getCsrfToken() { @@ -66,10 +66,10 @@ public class CollectionService extends BaseService { form.put("module_name", "feed_saved_add_to_collection"); final List ids; ids = posts.stream() - .map(Media::getPk) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - form.put("added_media_ids", "[" + String.join(",", ids) + "]"); + .map(Media::getPk) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + form.put("added_media_ids", "[" + TextUtils.join(",", ids) + "]"); changeCollection(collectionId, "edit", form, callback); } diff --git a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java index 5e4afea5..0688c761 100644 --- a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java @@ -41,7 +41,6 @@ import awais.instagrabber.repositories.responses.giphy.GiphyGif; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import retrofit2.Call; -import retrofit2.Retrofit; public class DirectMessagesService extends BaseService { private static final String TAG = "DiscoverService"; @@ -59,10 +58,9 @@ public class DirectMessagesService extends BaseService { this.csrfToken = csrfToken; this.userId = userId; this.deviceUuid = deviceUuid; - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(DirectMessagesRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(DirectMessagesRepository.class); } public String getCsrfToken() { diff --git a/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java b/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java index 294a6a7d..880ae526 100644 --- a/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java +++ b/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java @@ -12,7 +12,6 @@ import awais.instagrabber.utils.TextUtils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class DiscoverService extends BaseService { @@ -23,10 +22,9 @@ public class DiscoverService extends BaseService { private static DiscoverService instance; private DiscoverService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(DiscoverRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(DiscoverRepository.class); } public static DiscoverService getInstance() { diff --git a/app/src/main/java/awais/instagrabber/webservices/FeedService.java b/app/src/main/java/awais/instagrabber/webservices/FeedService.java index 2bd91690..8b1626ed 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FeedService.java +++ b/app/src/main/java/awais/instagrabber/webservices/FeedService.java @@ -22,7 +22,6 @@ import awais.instagrabber.utils.TextUtils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class FeedService extends BaseService { private static final String TAG = "FeedService"; @@ -32,10 +31,9 @@ public class FeedService extends BaseService { private static FeedService instance; private FeedService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(FeedRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(FeedRepository.class); } public static FeedService getInstance() { diff --git a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java index 7c5da8cf..ced49305 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java +++ b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java @@ -25,7 +25,6 @@ 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 = "FriendshipService"; @@ -42,10 +41,9 @@ public class FriendshipService extends BaseService { this.deviceUuid = deviceUuid; this.csrfToken = csrfToken; this.userId = userId; - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(FriendshipRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(FriendshipRepository.class); } public String getCsrfToken() { @@ -168,8 +166,8 @@ public class FriendshipService extends BaseService { form.put("_uuid", deviceUuid); form.put(story ? "target_reel_author_id" : "target_posts_author_id", String.valueOf(targetUserId)); final Call request = repository.changeMute(unmute ? - "unmute_posts_or_story_from_follow" : - "mute_posts_or_story_from_follow", + "unmute_posts_or_story_from_follow" : + "mute_posts_or_story_from_follow", form); request.enqueue(new Callback() { @Override @@ -198,8 +196,8 @@ public class FriendshipService extends BaseService { if (maxId != null) queryMap.put("max_id", maxId); final Call request = repository.getList( targetUserId, - follower ? "followers" : "following", - queryMap); + follower ? "followers" : "following", + queryMap); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { diff --git a/app/src/main/java/awais/instagrabber/webservices/GifService.java b/app/src/main/java/awais/instagrabber/webservices/GifService.java index 6485efd1..e783f689 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GifService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GifService.java @@ -3,7 +3,6 @@ package awais.instagrabber.webservices; import awais.instagrabber.repositories.GifRepository; import awais.instagrabber.repositories.responses.giphy.GiphyGifResponse; import retrofit2.Call; -import retrofit2.Retrofit; public class GifService extends BaseService { @@ -12,10 +11,9 @@ public class GifService extends BaseService { private static GifService instance; private GifService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(GifRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(GifRepository.class); } public static GifService getInstance() { diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index 4cd1c1b6..e56f5581 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -28,7 +28,6 @@ import awais.instagrabber.utils.TextUtils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class GraphQLService extends BaseService { private static final String TAG = "GraphQLService"; @@ -39,10 +38,9 @@ public class GraphQLService extends BaseService { private static GraphQLService instance; private GraphQLService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://www.instagram.com") - .build(); - repository = retrofit.create(GraphQLRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofitWeb() + .create(GraphQLRepository.class); } public static GraphQLService getInstance() { diff --git a/app/src/main/java/awais/instagrabber/webservices/LocationService.java b/app/src/main/java/awais/instagrabber/webservices/LocationService.java index 381ba440..2f8036a3 100644 --- a/app/src/main/java/awais/instagrabber/webservices/LocationService.java +++ b/app/src/main/java/awais/instagrabber/webservices/LocationService.java @@ -11,7 +11,6 @@ import awais.instagrabber.utils.TextUtils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class LocationService extends BaseService { private static final String TAG = "LocationService"; @@ -21,10 +20,9 @@ public class LocationService extends BaseService { private static LocationService instance; private LocationService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(LocationRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(LocationRepository.class); } public static LocationService getInstance() { diff --git a/app/src/main/java/awais/instagrabber/webservices/MediaService.java b/app/src/main/java/awais/instagrabber/webservices/MediaService.java index e1990e87..d820b954 100644 --- a/app/src/main/java/awais/instagrabber/webservices/MediaService.java +++ b/app/src/main/java/awais/instagrabber/webservices/MediaService.java @@ -31,7 +31,6 @@ import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class MediaService extends BaseService { private static final String TAG = "MediaService"; @@ -51,10 +50,9 @@ public class MediaService extends BaseService { this.deviceUuid = deviceUuid; this.csrfToken = csrfToken; this.userId = userId; - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(MediaRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(MediaRepository.class); } public String getCsrfToken() { diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index fe54c13d..667fb647 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -1,39 +1,27 @@ package awais.instagrabber.webservices; -import android.util.Log; - import androidx.annotation.NonNull; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; -import awais.instagrabber.BuildConfig; -import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.NewsRepository; import awais.instagrabber.repositories.responses.AymlResponse; import awais.instagrabber.repositories.responses.AymlUser; -import awais.instagrabber.repositories.responses.NotificationCounts; -import awais.instagrabber.repositories.responses.UserSearchResponse; import awais.instagrabber.repositories.responses.NewsInboxResponse; import awais.instagrabber.repositories.responses.Notification; import awais.instagrabber.repositories.responses.NotificationArgs; -import awais.instagrabber.repositories.responses.NotificationImage; +import awais.instagrabber.repositories.responses.NotificationCounts; import awais.instagrabber.repositories.responses.User; +import awais.instagrabber.repositories.responses.UserSearchResponse; import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class NewsService extends BaseService { private static final String TAG = "NewsService"; @@ -43,10 +31,9 @@ public class NewsService extends BaseService { private static NewsService instance; private NewsService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(NewsRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(NewsRepository.class); } public static NewsService getInstance() { @@ -131,7 +118,8 @@ public class NewsService extends BaseService { aymlUsers.addAll(oldSuggestions); } - final List newsItems = aymlUsers.stream() + final List newsItems = aymlUsers + .stream() .map(i -> { final User u = i.getUser(); return new Notification( @@ -173,7 +161,9 @@ public class NewsService extends BaseService { return; } - final List newsItems = body.getUsers().stream() + final List newsItems = body + .getUsers() + .stream() .map(u -> { return new Notification( new NotificationArgs( diff --git a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java index 65f787a6..cc8199fd 100644 --- a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java +++ b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java @@ -23,7 +23,6 @@ import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class ProfileService extends BaseService { private static final String TAG = "ProfileService"; @@ -33,10 +32,9 @@ public class ProfileService extends BaseService { private static ProfileService instance; private ProfileService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(ProfileRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(ProfileRepository.class); } public static ProfileService getInstance() { @@ -104,9 +102,9 @@ public class ProfileService extends BaseService { posts = Collections.emptyList(); } else { posts = items.stream() - .map(WrappedMedia::getMedia) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + .map(WrappedMedia::getMedia) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } callback.onSuccess(new PostsFetchResponse( posts, diff --git a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java new file mode 100644 index 00000000..ce8cbfa7 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java @@ -0,0 +1,97 @@ +package awais.instagrabber.webservices; + +import android.app.Application; + +import androidx.annotation.NonNull; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.io.File; + +import awais.instagrabber.BuildConfig; +import awais.instagrabber.repositories.responses.Caption; +import awais.instagrabber.utils.Utils; +import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor; +import okhttp3.Cache; +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; +import retrofit2.converter.scalars.ScalarsConverterFactory; + +public final class RetrofitFactory { + private static final Object LOCK = new Object(); + + private static RetrofitFactory instance; + + private final Application application; + private final int cacheSize = 10 * 1024 * 1024; // 10 MB + private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize); + + private Retrofit.Builder builder; + private Retrofit retrofit; + private Retrofit retrofitWeb; + + public static void setup(@NonNull final Application application) { + if (instance == null) { + synchronized (LOCK) { + if (instance == null) { + instance = new RetrofitFactory(application); + } + } + } + } + + public static RetrofitFactory getInstance() { + if (instance == null) { + throw new RuntimeException("Setup not done!"); + } + return instance; + } + + private RetrofitFactory(@NonNull final Application application) { + this.application = application; + } + + private Retrofit.Builder getRetrofitBuilder() { + if (builder == null) { + final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() + .addInterceptor(new AddCookiesInterceptor()) + .followRedirects(false) + .followSslRedirects(false) + .cache(cache); + if (BuildConfig.DEBUG) { + // clientBuilder.addInterceptor(new LoggingInterceptor()); + } + final Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer()) + .setLenient() + .create(); + builder = new Retrofit.Builder() + .addConverterFactory(ScalarsConverterFactory.create()) + .addConverterFactory(GsonConverterFactory.create(gson)) + .client(clientBuilder.build()); + } + return builder; + } + + public Retrofit getRetrofit() { + if (retrofit == null) { + retrofit = getRetrofitBuilder() + .baseUrl("https://i.instagram.com") + .build(); + } + return retrofit; + } + + public Retrofit getRetrofitWeb() { + if (retrofitWeb == null) { + retrofitWeb = getRetrofitBuilder() + .baseUrl("https://www.instagram.com") + .build(); + } + return retrofitWeb; + } +} diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index fd05af17..cc19b086 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -32,7 +32,6 @@ import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class StoriesService extends BaseService { private static final String TAG = "StoriesService"; @@ -50,10 +49,9 @@ public class StoriesService extends BaseService { this.csrfToken = csrfToken; this.userId = userId; this.deviceUuid = deviceUuid; - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(StoriesRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(StoriesRepository.class); } public String getCsrfToken() { @@ -190,8 +188,7 @@ public class StoriesService extends BaseService { firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, false, null); } feedStoryModels.add(new FeedStoryModel(id, user, fullyRead, timestamp, firstStoryModel, mediaCount, false, isBestie)); - } - catch (Exception e) {} // to cover promotional reels with non-long user pk's + } catch (Exception e) {} // to cover promotional reels with non-long user pk's } final JSONArray broadcasts = new JSONObject(body).getJSONArray("broadcasts"); for (int i = 0; i < broadcasts.length(); ++i) { diff --git a/app/src/main/java/awais/instagrabber/webservices/TagsService.java b/app/src/main/java/awais/instagrabber/webservices/TagsService.java index 615d72af..276f0dc7 100644 --- a/app/src/main/java/awais/instagrabber/webservices/TagsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/TagsService.java @@ -21,7 +21,6 @@ import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class TagsService extends BaseService { @@ -32,10 +31,9 @@ public class TagsService extends BaseService { private final TagsRepository repository; private TagsService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com/") - .build(); - repository = retrofit.create(TagsRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(TagsRepository.class); } public static TagsService getInstance() { diff --git a/app/src/main/java/awais/instagrabber/webservices/UserService.java b/app/src/main/java/awais/instagrabber/webservices/UserService.java index 52bb064d..1266662f 100644 --- a/app/src/main/java/awais/instagrabber/webservices/UserService.java +++ b/app/src/main/java/awais/instagrabber/webservices/UserService.java @@ -12,7 +12,6 @@ import awais.instagrabber.repositories.responses.WrappedUser; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import retrofit2.Retrofit; public class UserService extends BaseService { private static final String TAG = UserService.class.getSimpleName(); @@ -22,10 +21,9 @@ public class UserService extends BaseService { private static UserService instance; private UserService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://i.instagram.com") - .build(); - repository = retrofit.create(UserRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofit() + .create(UserRepository.class); } public static UserService getInstance() { diff --git a/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/AddCookiesInterceptor.java similarity index 96% rename from app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java rename to app/src/main/java/awais/instagrabber/webservices/interceptors/AddCookiesInterceptor.java index 3b5f709f..610b5f89 100644 --- a/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java +++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/AddCookiesInterceptor.java @@ -1,4 +1,4 @@ -package awais.instagrabber.webservices; +package awais.instagrabber.webservices.interceptors; import androidx.annotation.NonNull; diff --git a/app/src/main/java/awais/instagrabber/webservices/LoggingInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/LoggingInterceptor.java similarity index 96% rename from app/src/main/java/awais/instagrabber/webservices/LoggingInterceptor.java rename to app/src/main/java/awais/instagrabber/webservices/interceptors/LoggingInterceptor.java index c9358a72..e7bedd3b 100644 --- a/app/src/main/java/awais/instagrabber/webservices/LoggingInterceptor.java +++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/LoggingInterceptor.java @@ -1,4 +1,4 @@ -package awais.instagrabber.webservices; +package awais.instagrabber.webservices.interceptors; import android.util.Log; From 91e13a23ad288243a17ca59776063cbd5212d996 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Mon, 22 Mar 2021 22:02:48 +0900 Subject: [PATCH 04/42] Add ig error interceptor --- .../instagrabber/InstaGrabberApplication.java | 3 - .../instagrabber/activities/MainActivity.java | 2 + .../awais/instagrabber/utils/Constants.java | 1 + .../webservices/RetrofitFactory.java | 17 +-- .../interceptors/IgErrorsInterceptor.java | 108 ++++++++++++++++++ app/src/main/res/values/strings.xml | 6 + 6 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java diff --git a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java index de555f94..36807a6c 100644 --- a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java +++ b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java @@ -17,7 +17,6 @@ import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.LocaleUtils; import awais.instagrabber.utils.SettingsHelper; import awais.instagrabber.utils.TextUtils; -import awais.instagrabber.webservices.RetrofitFactory; import awaisomereport.CrashReporter; import static awais.instagrabber.utils.CookieUtils.NET_COOKIE_MANAGER; @@ -87,7 +86,5 @@ public final class InstaGrabberApplication extends Application { if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) { settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString()); } - - RetrofitFactory.setup(this); } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index df2369cc..66670534 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -83,6 +83,7 @@ import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.emoji.EmojiParser; import awais.instagrabber.viewmodels.AppStateViewModel; +import awais.instagrabber.webservices.RetrofitFactory; import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController; import static awais.instagrabber.utils.Utils.settingsHelper; @@ -138,6 +139,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + RetrofitFactory.setup(this); binding = ActivityMainBinding.inflate(getLayoutInflater()); final String cookie = settingsHelper.getString(Constants.COOKIE); CookieUtils.setupCookies(cookie); diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index 0c92f0fd..4c064e81 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -111,6 +111,7 @@ public final class Constants { public static final int SHOW_ACTIVITY_REQUEST_CODE = 1738; public static final int SHOW_DM_THREAD = 2000; public static final int DM_SYNC_SERVICE_REQUEST_CODE = 3000; + public static final int GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE = 7777; public static final String ACTION_SHOW_ACTIVITY = "show_activity"; public static final String ACTION_SHOW_DM_THREAD = "show_dm_thread"; diff --git a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java index ce8cbfa7..71c78a4e 100644 --- a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java +++ b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java @@ -1,7 +1,5 @@ package awais.instagrabber.webservices; -import android.app.Application; - import androidx.annotation.NonNull; import com.google.gson.FieldNamingPolicy; @@ -11,9 +9,11 @@ import com.google.gson.GsonBuilder; import java.io.File; import awais.instagrabber.BuildConfig; +import awais.instagrabber.activities.MainActivity; import awais.instagrabber.repositories.responses.Caption; import awais.instagrabber.utils.Utils; import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor; +import awais.instagrabber.webservices.interceptors.IgErrorsInterceptor; import okhttp3.Cache; import okhttp3.OkHttpClient; import retrofit2.Retrofit; @@ -25,7 +25,7 @@ public final class RetrofitFactory { private static RetrofitFactory instance; - private final Application application; + private final MainActivity mainActivity; private final int cacheSize = 10 * 1024 * 1024; // 10 MB private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize); @@ -33,11 +33,11 @@ public final class RetrofitFactory { private Retrofit retrofit; private Retrofit retrofitWeb; - public static void setup(@NonNull final Application application) { + public static void setup(@NonNull final MainActivity mainActivity) { if (instance == null) { synchronized (LOCK) { if (instance == null) { - instance = new RetrofitFactory(application); + instance = new RetrofitFactory(mainActivity); } } } @@ -50,20 +50,21 @@ public final class RetrofitFactory { return instance; } - private RetrofitFactory(@NonNull final Application application) { - this.application = application; + private RetrofitFactory(@NonNull final MainActivity mainActivity) { + this.mainActivity = mainActivity; } private Retrofit.Builder getRetrofitBuilder() { if (builder == null) { final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() - .addInterceptor(new AddCookiesInterceptor()) .followRedirects(false) .followSslRedirects(false) .cache(cache); if (BuildConfig.DEBUG) { // clientBuilder.addInterceptor(new LoggingInterceptor()); } + clientBuilder.addInterceptor(new AddCookiesInterceptor()) + .addInterceptor(new IgErrorsInterceptor(mainActivity)); final Gson gson = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer()) diff --git a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java new file mode 100644 index 00000000..413f0e03 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java @@ -0,0 +1,108 @@ +package awais.instagrabber.webservices.interceptors; + +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; + +import org.json.JSONObject; + +import java.io.IOException; + +import awais.instagrabber.R; +import awais.instagrabber.activities.MainActivity; +import awais.instagrabber.dialogs.ConfirmDialogFragment; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.TextUtils; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class IgErrorsInterceptor implements Interceptor { + private static final String TAG = IgErrorsInterceptor.class.getSimpleName(); + + private final MainActivity mainActivity; + + public IgErrorsInterceptor(@NonNull final MainActivity mainActivity) { + this.mainActivity = mainActivity; + } + + @NonNull + @Override + public Response intercept(@NonNull final Chain chain) throws IOException { + final Request request = chain.request(); + final Response response = chain.proceed(request); + if (response.isSuccessful()) { + return response; + } + checkError(response); + return response; + } + + private void checkError(@NonNull final Response response) { + final int errorCode = response.code(); + switch (errorCode) { + case 429: // "429 Too Many Requests" + // ('Throttled by Instagram because of too many API requests.'); + showErrorDialog(R.string.throttle_error); + return; + case 431: // "431 Request Header Fields Too Large" + // show dialog? + Log.e(TAG, "Network error: " + getMessage(errorCode, "The request start-line and/or headers are too large to process.")); + return; + } + final ResponseBody body = response.body(); + if (body == null) return; + try { + final String bodyString = body.string(); + final JSONObject jsonObject = new JSONObject(bodyString); + String message = jsonObject.optString("message", null); + if (!TextUtils.isEmpty(message)) { + message = message.toLowerCase(); + switch (message) { + case "user_has_logged_out": + showErrorDialog(R.string.account_logged_out); + return; + case "login_required": + showErrorDialog(R.string.login_required); + return; + case "not authorized to view user": // Do we handle this in profile view fragment? + case "challenge_required": // Since we make users login using browser, we should not be getting this error in api requests + default: + Log.e(TAG, "checkError: " + bodyString); + return; + } + } + final String errorType = jsonObject.optString("error_type", null); + if (TextUtils.isEmpty(errorType)) return; + if (errorType.equals("sentry_block")) { + showErrorDialog(R.string.sentry_block); + return; + } + if (errorType.equals("inactive user")) { + showErrorDialog(R.string.inactive_user); + } + } catch (Exception e) { + Log.e(TAG, "checkError: ", e); + } + } + + @NonNull + private String getMessage(final int errorCode, final String message) { + return String.format("code: %s, internalMessage: %s", errorCode, message); + } + + private void showErrorDialog(@StringRes final int messageResId) { + if (messageResId == 0) return; + final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance( + Constants.GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE, + R.string.error, + messageResId, + R.string.ok, + 0, + 0 + ); + dialogFragment.show(mainActivity.getSupportFragmentManager(), "network_error_dialog"); + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f65ff8c9..af62d980 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -473,4 +473,10 @@ Removed keyword: %s from filter list Marked as seen Delete unsuccessful + Throttled by Instagram because of too many API requests. Wait for some time before retrying. + Error + This account has been logged out. + Login required! + Sentry block. + User is inactive! From 0d53e244e21aca6b4ee1e4adb5936244d3d15ff1 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Mon, 22 Mar 2021 23:46:47 +0900 Subject: [PATCH 05/42] Destroy references to solve leak --- .../instagrabber/activities/MainActivity.java | 1 + .../webservices/RetrofitFactory.java | 18 ++++++++++++++++-- .../interceptors/IgErrorsInterceptor.java | 7 ++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 66670534..8f16cd5d 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -248,6 +248,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage Log.e(TAG, "onDestroy: ", e); } unbindActivityCheckerService(); + RetrofitFactory.getInstance().destroy(); } @Override diff --git a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java index 71c78a4e..5062e5c7 100644 --- a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java +++ b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java @@ -25,10 +25,11 @@ public final class RetrofitFactory { private static RetrofitFactory instance; - private final MainActivity mainActivity; private final int cacheSize = 10 * 1024 * 1024; // 10 MB private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize); + private IgErrorsInterceptor igErrorsInterceptor; + private MainActivity mainActivity; private Retrofit.Builder builder; private Retrofit retrofit; private Retrofit retrofitWeb; @@ -56,6 +57,7 @@ public final class RetrofitFactory { private Retrofit.Builder getRetrofitBuilder() { if (builder == null) { + igErrorsInterceptor = new IgErrorsInterceptor(mainActivity); final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() .followRedirects(false) .followSslRedirects(false) @@ -64,7 +66,7 @@ public final class RetrofitFactory { // clientBuilder.addInterceptor(new LoggingInterceptor()); } clientBuilder.addInterceptor(new AddCookiesInterceptor()) - .addInterceptor(new IgErrorsInterceptor(mainActivity)); + .addInterceptor(igErrorsInterceptor); final Gson gson = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer()) @@ -95,4 +97,16 @@ public final class RetrofitFactory { } return retrofitWeb; } + + public void destroy() { + if (igErrorsInterceptor != null) { + igErrorsInterceptor.destroy(); + } + igErrorsInterceptor = null; + mainActivity = null; + retrofit = null; + retrofitWeb = null; + builder = null; + instance = null; + } } diff --git a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java index 413f0e03..7d424a2d 100644 --- a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java +++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java @@ -22,7 +22,7 @@ import okhttp3.ResponseBody; public class IgErrorsInterceptor implements Interceptor { private static final String TAG = IgErrorsInterceptor.class.getSimpleName(); - private final MainActivity mainActivity; + private MainActivity mainActivity; public IgErrorsInterceptor(@NonNull final MainActivity mainActivity) { this.mainActivity = mainActivity; @@ -94,6 +94,7 @@ public class IgErrorsInterceptor implements Interceptor { } private void showErrorDialog(@StringRes final int messageResId) { + if (mainActivity == null) return; if (messageResId == 0) return; final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance( Constants.GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE, @@ -105,4 +106,8 @@ public class IgErrorsInterceptor implements Interceptor { ); dialogFragment.show(mainActivity.getSupportFragmentManager(), "network_error_dialog"); } + + public void destroy() { + mainActivity = null; + } } \ No newline at end of file From 9fe896bc655f4a59ca4ce637759f568f4c1a12f3 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Wed, 24 Mar 2021 22:24:36 +0900 Subject: [PATCH 06/42] Customise screen/tab order --- .../instagrabber/activities/MainActivity.java | 155 +++++----- .../instagrabber/adapters/TabsAdapter.java | 156 ++++++++++ .../adapters/viewholder/TabViewHolder.java | 88 ++++++ .../TabOrderPreferenceDialogFragment.java | 267 ++++++++++++++++++ .../settings/GeneralPreferencesFragment.java | 44 ++- .../fragments/settings/PreferenceKeys.java | 1 + .../java/awais/instagrabber/models/Tab.java | 98 +++++++ .../instagrabber/utils/SettingsHelper.java | 5 +- .../java/awais/instagrabber/utils/Utils.java | 159 +++++++++-- .../res/drawable/ic_round_add_circle_24.xml | 10 + .../res/drawable/ic_round_drag_handle_24.xml | 10 + .../drawable/ic_round_remove_circle_24.xml | 10 + app/src/main/res/layout/activity_main.xml | 3 +- .../main/res/layout/item_tab_order_pref.xml | 45 +++ .../res/navigation/favorites_nav_graph.xml | 43 +++ app/src/main/res/values/arrays.xml | 32 ++- app/src/main/res/values/strings.xml | 2 + 17 files changed, 1017 insertions(+), 111 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/adapters/TabsAdapter.java create mode 100644 app/src/main/java/awais/instagrabber/adapters/viewholder/TabViewHolder.java create mode 100644 app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java create mode 100644 app/src/main/java/awais/instagrabber/models/Tab.java create mode 100644 app/src/main/res/drawable/ic_round_add_circle_24.xml create mode 100644 app/src/main/res/drawable/ic_round_drag_handle_24.xml create mode 100644 app/src/main/res/drawable/ic_round_remove_circle_24.xml create mode 100644 app/src/main/res/layout/item_tab_order_pref.xml create mode 100644 app/src/main/res/navigation/favorites_nav_graph.xml diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index c4a38834..d6540585 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -8,7 +8,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.res.TypedArray; import android.database.MatrixCursor; import android.net.Uri; import android.os.AsyncTask; @@ -25,6 +24,7 @@ import android.view.WindowManager; import android.widget.AutoCompleteTextView; import android.widget.Toast; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; @@ -50,13 +50,12 @@ import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.behavior.HideBottomViewOnScrollBehavior; import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterators; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Deque; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.stream.Collectors; import awais.instagrabber.R; import awais.instagrabber.adapters.SuggestionsAdapter; @@ -71,6 +70,7 @@ import awais.instagrabber.fragments.settings.PreferenceKeys; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.IntentModel; import awais.instagrabber.models.SuggestionModel; +import awais.instagrabber.models.Tab; import awais.instagrabber.models.enums.SuggestionType; import awais.instagrabber.services.ActivityCheckerService; import awais.instagrabber.services.DMSyncAlarmReceiver; @@ -90,13 +90,13 @@ import static awais.instagrabber.utils.Utils.settingsHelper; public class MainActivity extends BaseLanguageActivity implements FragmentManager.OnBackStackChangedListener { private static final String TAG = "MainActivity"; - private static final List SHOW_BOTTOM_VIEW_DESTINATIONS = Arrays.asList( + private static final List SHOW_BOTTOM_VIEW_DESTINATIONS = ImmutableList.of( R.id.directMessagesInboxFragment, R.id.feedFragment, R.id.profileFragment, R.id.discoverFragment, - R.id.morePreferencesFragment); - private static final Map NAV_TO_MENU_ID_MAP = new HashMap<>(); + R.id.morePreferencesFragment, + R.id.favoritesFragment); private static final String FIRST_FRAGMENT_GRAPH_INDEX_KEY = "firstFragmentGraphIndex"; private ActivityMainBinding binding; @@ -127,14 +127,6 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage } }; - static { - NAV_TO_MENU_ID_MAP.put(R.navigation.direct_messages_nav_graph, R.id.direct_messages_nav_graph); - NAV_TO_MENU_ID_MAP.put(R.navigation.feed_nav_graph, R.id.feed_nav_graph); - NAV_TO_MENU_ID_MAP.put(R.navigation.profile_nav_graph, R.id.profile_nav_graph); - NAV_TO_MENU_ID_MAP.put(R.navigation.discover_nav_graph, R.id.discover_nav_graph); - NAV_TO_MENU_ID_MAP.put(R.navigation.more_nav_graph, R.id.more_nav_graph); - } - @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -255,9 +247,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage final NavController navController = currentNavControllerLiveData.getValue(); if (navController != null) { @SuppressLint("RestrictedApi") final Deque backStack = navController.getBackStack(); - if (backStack != null) { - currentNavControllerBackStack = backStack.size(); - } + currentNavControllerBackStack = backStack.size(); } } if (isTaskRoot() && isBackStackEmpty && currentNavControllerBackStack == 2) { @@ -431,36 +421,14 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage return true; } - private void setupBottomNavigationBar(final boolean setDefaultFromSettings) { - int main_nav_ids = R.array.main_nav_ids; - if (!isLoggedIn) { - main_nav_ids = R.array.logged_out_main_nav_ids; - final int selectedItemId = binding.bottomNavView.getSelectedItemId(); - binding.bottomNavView.getMenu().clear(); - binding.bottomNavView.inflateMenu(R.menu.logged_out_bottom_navigation_menu); - if (selectedItemId == R.id.profile_nav_graph - || selectedItemId == R.id.more_nav_graph) { - binding.bottomNavView.setSelectedItemId(selectedItemId); - } else { - setBottomNavSelectedItem(R.navigation.profile_nav_graph); - } - } - final List mainNavList = getMainNavList(main_nav_ids); - if (setDefaultFromSettings) { - final String defaultTabResNameString = settingsHelper.getString(Constants.DEFAULT_TAB); - try { - int navId = 0; - if (!TextUtils.isEmpty(defaultTabResNameString)) { - navId = getResources().getIdentifier(defaultTabResNameString, "navigation", getPackageName()); - } - final int defaultNavId = navId <= 0 ? R.navigation.feed_nav_graph - : navId; - final int index = mainNavList.indexOf(defaultNavId); - if (index >= 0) firstFragmentGraphIndex = index; - setBottomNavSelectedItem(defaultNavId); - } catch (NumberFormatException e) { - Log.e(TAG, "Error parsing id", e); - } + private void setupBottomNavigationBar(final boolean setDefaultTabFromSettings) { + final List tabs = !isLoggedIn ? setupAnonBottomNav() : setupMainBottomNav(); + + final List mainNavList = tabs.stream() + .map(Tab::getNavigationResId) + .collect(Collectors.toList()); + if (setDefaultTabFromSettings) { + setSelectedTab(tabs); } final LiveData navControllerLiveData = setupWithNavController( binding.bottomNavView, @@ -483,27 +451,84 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage }); } - private void setBottomNavSelectedItem(final int navId) { - final Integer menuId = NAV_TO_MENU_ID_MAP.get(navId); - if (menuId != null) { - binding.bottomNavView.setSelectedItemId(menuId); + private void setSelectedTab(final List tabs) { + final String defaultTabResNameString = settingsHelper.getString(Constants.DEFAULT_TAB); + try { + int navId = 0; + if (!TextUtils.isEmpty(defaultTabResNameString)) { + navId = getResources().getIdentifier(defaultTabResNameString, "navigation", getPackageName()); + } + final int navGraph = isLoggedIn ? R.navigation.feed_nav_graph : R.navigation.profile_nav_graph; + final int defaultNavId = navId <= 0 ? navGraph : navId; + int index = Iterators.indexOf(tabs.iterator(), tab -> { + if (tab == null) return false; + return tab.getNavigationResId() == defaultNavId; + }); + if (index >= 0) firstFragmentGraphIndex = index; + if (index < 0 || index >= tabs.size()) index = 0; + setBottomNavSelectedTab(tabs.get(index)); + } catch (Exception e) { + Log.e(TAG, "Error parsing id", e); } } - @NonNull - private List getMainNavList(final int main_nav_ids) { - final TypedArray navIds = getResources().obtainTypedArray(main_nav_ids); - final List mainNavList = new ArrayList<>(navIds.length()); - final int length = navIds.length(); - for (int i = 0; i < length; i++) { - final int resourceId = navIds.getResourceId(i, -1); - if (resourceId < 0) continue; - mainNavList.add(resourceId); + private List setupAnonBottomNav() { + final int selectedItemId = binding.bottomNavView.getSelectedItemId(); + final Tab profileTab = new Tab(R.drawable.ic_person_24, + getString(R.string.profile), + false, + "profile_nav_graph", + R.navigation.profile_nav_graph, + R.id.profile_nav_graph); + final Tab moreTab = new Tab(R.drawable.ic_more_horiz_24, + getString(R.string.more), + false, + "more_nav_graph", + R.navigation.more_nav_graph, + R.id.more_nav_graph); + final Menu menu = binding.bottomNavView.getMenu(); + menu.clear(); + // binding.bottomNavView.inflateMenu(R.menu.logged_out_bottom_navigation_menu); + menu.add(0, profileTab.getNavigationRootId(), 0, profileTab.getTitle()).setIcon(profileTab.getIconResId()); + menu.add(0, moreTab.getNavigationRootId(), 0, moreTab.getTitle()).setIcon(moreTab.getIconResId()); + if (selectedItemId != R.id.profile_nav_graph && selectedItemId != R.id.more_nav_graph) { + setBottomNavSelectedTab(profileTab); } - navIds.recycle(); - return mainNavList; + return ImmutableList.of(profileTab, moreTab); } + private List setupMainBottomNav() { + final Menu menu = binding.bottomNavView.getMenu(); + menu.clear(); + final List navTabList = Utils.getNavTabList(this).first; + for (final Tab tab : navTabList) { + menu.add(0, tab.getNavigationRootId(), 0, tab.getTitle()).setIcon(tab.getIconResId()); + } + return navTabList; + } + + private void setBottomNavSelectedTab(@NonNull final Tab tab) { + binding.bottomNavView.setSelectedItemId(tab.getNavigationRootId()); + } + + private void setBottomNavSelectedTab(@SuppressWarnings("SameParameterValue") @IdRes final int navGraphRootId) { + binding.bottomNavView.setSelectedItemId(navGraphRootId); + } + + // @NonNull + // private List getMainNavList(final int main_nav_ids) { + // final TypedArray navIds = getResources().obtainTypedArray(main_nav_ids); + // final List mainNavList = new ArrayList<>(navIds.length()); + // final int length = navIds.length(); + // for (int i = 0; i < length; i++) { + // final int resourceId = navIds.getResourceId(i, -1); + // if (resourceId < 0) continue; + // mainNavList.add(resourceId); + // } + // navIds.recycle(); + // return mainNavList; + // } + private void setupNavigation(final Toolbar toolbar, final NavController navController) { if (navController == null) return; NavigationUI.setupWithNavController(toolbar, navController); @@ -631,7 +656,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage }); final int selectedItemId = binding.bottomNavView.getSelectedItemId(); if (selectedItemId != R.navigation.direct_messages_nav_graph) { - setBottomNavSelectedItem(R.navigation.direct_messages_nav_graph); + setBottomNavSelectedTab(R.id.direct_messages_nav_graph); } } diff --git a/app/src/main/java/awais/instagrabber/adapters/TabsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/TabsAdapter.java new file mode 100644 index 00000000..474e4190 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/adapters/TabsAdapter.java @@ -0,0 +1,156 @@ +package awais.instagrabber.adapters; + +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ListAdapter; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.common.collect.ImmutableList; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import awais.instagrabber.R; +import awais.instagrabber.adapters.viewholder.TabViewHolder; +import awais.instagrabber.databinding.ItemFavSectionHeaderBinding; +import awais.instagrabber.databinding.ItemTabOrderPrefBinding; +import awais.instagrabber.models.Tab; +import awais.instagrabber.utils.Utils; + +public class TabsAdapter extends ListAdapter { + private static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame(@NonNull final TabOrHeader oldItem, @NonNull final TabOrHeader newItem) { + if (oldItem.isHeader() && newItem.isHeader()) { + return oldItem.header == newItem.header; + } + if (!oldItem.isHeader() && !newItem.isHeader()) { + final Tab oldTab = oldItem.tab; + final Tab newTab = newItem.tab; + return oldTab.getIconResId() == newTab.getIconResId() + && Objects.equals(oldTab.getTitle(), newTab.getTitle()); + } + return false; + } + + @Override + public boolean areContentsTheSame(@NonNull final TabOrHeader oldItem, @NonNull final TabOrHeader newItem) { + if (oldItem.isHeader() && newItem.isHeader()) { + return oldItem.header == newItem.header; + } + if (!oldItem.isHeader() && !newItem.isHeader()) { + final Tab oldTab = oldItem.tab; + final Tab newTab = newItem.tab; + return oldTab.getIconResId() == newTab.getIconResId() + && Objects.equals(oldTab.getTitle(), newTab.getTitle()); + } + return false; + } + }; + + private final TabAdapterCallback tabAdapterCallback; + + private List current = new ArrayList<>(); + private List others = new ArrayList<>(); + + public TabsAdapter(@NonNull final TabAdapterCallback tabAdapterCallback) { + super(DIFF_CALLBACK); + this.tabAdapterCallback = tabAdapterCallback; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { + final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + if (viewType == 1) { + final ItemTabOrderPrefBinding binding = ItemTabOrderPrefBinding.inflate(layoutInflater, parent, false); + return new TabViewHolder(binding, tabAdapterCallback); + } + final ItemFavSectionHeaderBinding headerBinding = ItemFavSectionHeaderBinding.inflate(layoutInflater, parent, false); + return new DirectUsersAdapter.HeaderViewHolder(headerBinding); + } + + @Override + public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { + if (holder instanceof DirectUsersAdapter.HeaderViewHolder) { + ((DirectUsersAdapter.HeaderViewHolder) holder).bind(R.string.other_tabs); + return; + } + if (holder instanceof TabViewHolder) { + final Tab tab = getItem(position).tab; + ((TabViewHolder) holder).bind(tab, others.contains(tab), current.size() == 5); + } + } + + @Override + public int getItemViewType(final int position) { + return getItem(position).isHeader() ? 0 : 1; + } + + public void submitList(final List current, final List others, final Runnable commitCallback) { + final ImmutableList.Builder builder = ImmutableList.builder(); + if (current != null) { + builder.addAll(current.stream() + .map(TabOrHeader::new) + .collect(Collectors.toList())); + } + builder.add(new TabOrHeader(R.string.other_tabs)); + if (others != null) { + builder.addAll(others.stream() + .map(TabOrHeader::new) + .collect(Collectors.toList())); + } + // Mutable non-null copies + this.current = current != null ? new ArrayList<>(current) : new ArrayList<>(); + this.others = others != null ? new ArrayList<>(others) : new ArrayList<>(); + submitList(builder.build(), commitCallback); + } + + public void submitList(final List current, final List others) { + submitList(current, others, null); + } + + public void moveItem(final int from, final int to) { + final List currentCopy = new ArrayList<>(current); + Utils.moveItem(from, to, currentCopy); + submitList(currentCopy, others); + tabAdapterCallback.onOrderChange(currentCopy); + } + + public int getCurrentCount() { + return current.size(); + } + + public static class TabOrHeader { + Tab tab; + int header; + + public TabOrHeader(final Tab tab) { + this.tab = tab; + } + + public TabOrHeader(@StringRes final int header) { + this.header = header; + } + + boolean isHeader() { + return header != 0; + } + } + + public interface TabAdapterCallback { + void onStartDrag(TabViewHolder viewHolder); + + void onOrderChange(List newOrderTabs); + + void onAdd(Tab tab); + + void onRemove(Tab tab); + } +} diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/TabViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/TabViewHolder.java new file mode 100644 index 00000000..d4be8726 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/TabViewHolder.java @@ -0,0 +1,88 @@ +package awais.instagrabber.adapters.viewholder; + +import android.annotation.SuppressLint; +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; +import android.view.MotionEvent; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.widget.ImageViewCompat; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.color.MaterialColors; + +import awais.instagrabber.R; +import awais.instagrabber.adapters.TabsAdapter; +import awais.instagrabber.databinding.ItemTabOrderPrefBinding; +import awais.instagrabber.models.Tab; + +public class TabViewHolder extends RecyclerView.ViewHolder { + private final ItemTabOrderPrefBinding binding; + private final TabsAdapter.TabAdapterCallback tabAdapterCallback; + private final int highlightColor; + private final Drawable originalBgColor; + + private boolean draggable = true; + + @SuppressLint("ClickableViewAccessibility") + public TabViewHolder(@NonNull final ItemTabOrderPrefBinding binding, + @NonNull final TabsAdapter.TabAdapterCallback tabAdapterCallback) { + super(binding.getRoot()); + this.binding = binding; + this.tabAdapterCallback = tabAdapterCallback; + highlightColor = MaterialColors.getColor(itemView.getContext(), R.attr.colorControlHighlight, 0); + originalBgColor = itemView.getBackground(); + binding.handle.setOnTouchListener((v, event) -> { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + tabAdapterCallback.onStartDrag(this); + } + return true; + }); + } + + public void bind(@NonNull final Tab tab, + final boolean isInOthers, + final boolean isCurrentFull) { + draggable = !isInOthers; + binding.icon.setImageResource(tab.getIconResId()); + binding.title.setText(tab.getTitle()); + binding.handle.setVisibility(isInOthers ? View.GONE : View.VISIBLE); + binding.addRemove.setImageResource(isInOthers ? R.drawable.ic_round_add_circle_24 + : R.drawable.ic_round_remove_circle_24); + final ColorStateList tintList = ColorStateList.valueOf(ContextCompat.getColor( + itemView.getContext(), + isInOthers ? R.color.green_500 + : R.color.red_500)); + ImageViewCompat.setImageTintList(binding.addRemove, tintList); + binding.addRemove.setOnClickListener(v -> { + if (isInOthers) { + tabAdapterCallback.onAdd(tab); + return; + } + tabAdapterCallback.onRemove(tab); + }); + final boolean enabled = tab.isRemovable() + && !(isInOthers && isCurrentFull); // All slots are full in current + binding.addRemove.setEnabled(enabled); + binding.addRemove.setAlpha(enabled ? 1 : 0.5F); + } + + public boolean isDraggable() { + return draggable; + } + + public void setDragging(final boolean isDragging) { + if (isDragging) { + if (highlightColor != 0) { + itemView.setBackgroundColor(highlightColor); + } else { + itemView.setAlpha(0.5F); + } + return; + } + itemView.setAlpha(1); + itemView.setBackground(originalBgColor); + } +} diff --git a/app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java b/app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java new file mode 100644 index 00000000..83b4193f --- /dev/null +++ b/app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java @@ -0,0 +1,267 @@ +package awais.instagrabber.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Canvas; +import android.os.Bundle; +import android.util.Pair; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.ItemTouchHelper.SimpleCallback; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.stream.Collectors; + +import awais.instagrabber.R; +import awais.instagrabber.adapters.DirectUsersAdapter; +import awais.instagrabber.adapters.TabsAdapter; +import awais.instagrabber.adapters.viewholder.TabViewHolder; +import awais.instagrabber.fragments.settings.PreferenceKeys; +import awais.instagrabber.models.Tab; +import awais.instagrabber.utils.Utils; + +import static androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_DRAG; +import static androidx.recyclerview.widget.ItemTouchHelper.DOWN; +import static androidx.recyclerview.widget.ItemTouchHelper.UP; + +public class TabOrderPreferenceDialogFragment extends DialogFragment { + private Callback callback; + private Context context; + private List tabsInPref; + private ItemTouchHelper itemTouchHelper; + private AlertDialog dialog; + private List newOrderTabs; + private List newOtherTabs; + + private final TabsAdapter.TabAdapterCallback tabAdapterCallback = new TabsAdapter.TabAdapterCallback() { + @Override + public void onStartDrag(final TabViewHolder viewHolder) { + if (itemTouchHelper == null || viewHolder == null) return; + itemTouchHelper.startDrag(viewHolder); + } + + @Override + public void onOrderChange(final List newOrderTabs) { + if (newOrderTabs == null || tabsInPref == null || dialog == null) return; + TabOrderPreferenceDialogFragment.this.newOrderTabs = newOrderTabs; + setSaveButtonState(newOrderTabs); + } + + @Override + public void onAdd(final Tab tab) { + // Add this tab to newOrderTabs + newOrderTabs = ImmutableList.builder() + .addAll(newOrderTabs) + .add(tab) + .build(); + // Remove this tab from newOtherTabs + if (newOtherTabs != null) { + newOtherTabs = newOtherTabs.stream() + .filter(t -> !t.equals(tab)) + .collect(Collectors.toList()); + } + setSaveButtonState(newOrderTabs); + // submit these tab lists to adapter + if (adapter == null) return; + adapter.submitList(newOrderTabs, newOtherTabs, () -> list.postDelayed(() -> adapter.notifyDataSetChanged(), 300)); + } + + @Override + public void onRemove(final Tab tab) { + // Remove this tab from newOrderTabs + newOrderTabs = newOrderTabs.stream() + .filter(t -> !t.equals(tab)) + .collect(Collectors.toList()); + // Add this tab to newOtherTabs + if (newOtherTabs != null) { + newOtherTabs = ImmutableList.builder() + .addAll(newOtherTabs) + .add(tab) + .build(); + } + setSaveButtonState(newOrderTabs); + // submit these tab lists to adapter + if (adapter == null) return; + adapter.submitList(newOrderTabs, newOtherTabs, () -> list.postDelayed(() -> adapter.notifyDataSetChanged(), 500)); + } + + private void setSaveButtonState(final List newOrderTabs) { + dialog.getButton(AlertDialog.BUTTON_POSITIVE) + .setEnabled(!newOrderTabs.equals(tabsInPref)); + } + }; + private final SimpleCallback simpleCallback = new SimpleCallback(UP | DOWN, 0) { + private int movePosition = RecyclerView.NO_POSITION; + + @Override + public int getMovementFlags(@NonNull final RecyclerView recyclerView, @NonNull final RecyclerView.ViewHolder viewHolder) { + if (viewHolder instanceof DirectUsersAdapter.HeaderViewHolder) return 0; + if (viewHolder instanceof TabViewHolder && !((TabViewHolder) viewHolder).isDraggable()) return 0; + return super.getMovementFlags(recyclerView, viewHolder); + } + + @Override + public void onChildDraw(@NonNull final Canvas c, + @NonNull final RecyclerView recyclerView, + @NonNull final RecyclerView.ViewHolder viewHolder, + final float dX, + final float dY, + final int actionState, + final boolean isCurrentlyActive) { + if (actionState != ACTION_STATE_DRAG) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + return; + } + final TabsAdapter adapter = (TabsAdapter) recyclerView.getAdapter(); + if (adapter == null) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + return; + } + // Do not allow dragging into 'Other tabs' category + float edgeY = dY; + final int lastPosition = adapter.getCurrentCount() - 1; + final View view = viewHolder.itemView; + // final int topEdge = recyclerView.getTop(); + final int bottomEdge = view.getHeight() * adapter.getCurrentCount() - view.getBottom(); + // if (movePosition == 0 && dY < topEdge) { + // edgeY = topEdge; + // } else + if (movePosition >= lastPosition && dY >= bottomEdge) { + edgeY = bottomEdge; + } + super.onChildDraw(c, recyclerView, viewHolder, dX, edgeY, actionState, isCurrentlyActive); + } + + @Override + public boolean onMove(@NonNull final RecyclerView recyclerView, + @NonNull final RecyclerView.ViewHolder viewHolder, + @NonNull final RecyclerView.ViewHolder target) { + final TabsAdapter adapter = (TabsAdapter) recyclerView.getAdapter(); + if (adapter == null) return false; + movePosition = target.getBindingAdapterPosition(); + if (movePosition >= adapter.getCurrentCount()) { + return false; + } + final int from = viewHolder.getBindingAdapterPosition(); + final int to = target.getBindingAdapterPosition(); + adapter.moveItem(from, to); + // adapter.notifyItemMoved(from, to); + return true; + } + + @Override + public void onSwiped(@NonNull final RecyclerView.ViewHolder viewHolder, final int direction) {} + + @Override + public void onSelectedChanged(@Nullable final RecyclerView.ViewHolder viewHolder, final int actionState) { + super.onSelectedChanged(viewHolder, actionState); + if (!(viewHolder instanceof TabViewHolder)) { + movePosition = RecyclerView.NO_POSITION; + return; + } + if (actionState == ACTION_STATE_DRAG) { + ((TabViewHolder) viewHolder).setDragging(true); + movePosition = viewHolder.getBindingAdapterPosition(); + } + } + + @Override + public void clearView(@NonNull final RecyclerView recyclerView, + @NonNull final RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + ((TabViewHolder) viewHolder).setDragging(false); + movePosition = RecyclerView.NO_POSITION; + } + }; + private TabsAdapter adapter; + private RecyclerView list; + + public static TabOrderPreferenceDialogFragment newInstance() { + final Bundle args = new Bundle(); + final TabOrderPreferenceDialogFragment fragment = new TabOrderPreferenceDialogFragment(); + fragment.setArguments(args); + return fragment; + } + + public TabOrderPreferenceDialogFragment() {} + + @Override + public void onAttach(@NonNull final Context context) { + super.onAttach(context); + try { + callback = (Callback) getParentFragment(); + } catch (ClassCastException e) { + // throw new ClassCastException("Calling fragment must implement TabOrderPreferenceDialogFragment.Callback interface"); + } + this.context = context; + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { + return new MaterialAlertDialogBuilder(context) + .setView(createView()) + .setPositiveButton(R.string.save, (d, w) -> { + final boolean hasChanged = newOrderTabs != null && !newOrderTabs.equals(tabsInPref); + if (hasChanged) { + saveNewOrder(); + } + if (callback == null) return; + callback.onSave(hasChanged); + }) + .setNegativeButton(R.string.cancel, (dialog, which) -> { + if (callback == null) return; + callback.onCancel(); + }) + .create(); + } + + private void saveNewOrder() { + final String newOrderString = newOrderTabs.stream() + .map(Tab::getGraphName) + .collect(Collectors.joining(",")); + Utils.settingsHelper.putString(PreferenceKeys.PREF_TAB_ORDER, newOrderString); + } + + @Override + public void onStart() { + super.onStart(); + final Dialog dialog = getDialog(); + if (!(dialog instanceof AlertDialog)) return; + this.dialog = (AlertDialog) dialog; + this.dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + } + + @NonNull + private View createView() { + list = new RecyclerView(context); + list.setLayoutManager(new LinearLayoutManager(context)); + itemTouchHelper = new ItemTouchHelper(simpleCallback); + itemTouchHelper.attachToRecyclerView(list); + adapter = new TabsAdapter(tabAdapterCallback); + list.setAdapter(adapter); + final Pair, List> navTabListPair = Utils.getNavTabList(context); + tabsInPref = navTabListPair.first; + // initially set newOrderTabs and newOtherTabs same as current tabs + newOrderTabs = navTabListPair.first; + newOtherTabs = navTabListPair.second; + adapter.submitList(navTabListPair.first, navTabListPair.second); + return list; + } + + public interface Callback { + void onSave(final boolean orderHasChanged); + + void onCancel(); + } +} diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java index 4606fb48..99a5d735 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java @@ -2,6 +2,7 @@ package awais.instagrabber.fragments.settings; import android.content.Context; import android.content.res.TypedArray; +import android.util.Log; import androidx.annotation.NonNull; import androidx.preference.ListPreference; @@ -10,13 +11,14 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreferenceCompat; import awais.instagrabber.R; +import awais.instagrabber.dialogs.TabOrderPreferenceDialogFragment; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.TextUtils; import static awais.instagrabber.utils.Utils.settingsHelper; -public class GeneralPreferencesFragment extends BasePreferencesFragment { +public class GeneralPreferencesFragment extends BasePreferencesFragment implements TabOrderPreferenceDialogFragment.Callback { @Override void setupPreferenceScreen(final PreferenceScreen screen) { @@ -26,6 +28,7 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment { final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; if (isLoggedIn) { screen.addPreference(getDefaultTabPreference(context)); + screen.addPreference(getTabOrderPreference(context)); } screen.addPreference(getUpdateCheckPreference(context)); screen.addPreference(getFlagSecurePreference(context)); @@ -34,24 +37,37 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment { private Preference getDefaultTabPreference(@NonNull final Context context) { final ListPreference preference = new ListPreference(context); preference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance()); - final TypedArray mainNavIds = getResources().obtainTypedArray(R.array.main_nav_ids); - final int length = mainNavIds.length(); - final String[] values = new String[length]; + final TypedArray mainNavGraphs = getResources().obtainTypedArray(R.array.main_nav_graphs); + final int length = mainNavGraphs.length(); + final String[] navGraphFileNames = new String[length]; for (int i = 0; i < length; i++) { - final int resourceId = mainNavIds.getResourceId(i, -1); + final int resourceId = mainNavGraphs.getResourceId(i, -1); if (resourceId < 0) continue; - values[i] = getResources().getResourceEntryName(resourceId); + navGraphFileNames[i] = getResources().getResourceEntryName(resourceId); } - mainNavIds.recycle(); + mainNavGraphs.recycle(); preference.setKey(Constants.DEFAULT_TAB); preference.setTitle(R.string.pref_start_screen); preference.setDialogTitle(R.string.pref_start_screen); - preference.setEntries(R.array.main_nav_ids_values); - preference.setEntryValues(values); + preference.setEntries(R.array.main_nav_titles); + preference.setEntryValues(navGraphFileNames); preference.setIconSpaceReserved(false); return preference; } + @NonNull + private Preference getTabOrderPreference(@NonNull final Context context) { + final Preference preference = new Preference(context); + preference.setTitle(R.string.tab_order); + preference.setIconSpaceReserved(false); + preference.setOnPreferenceClickListener(preference1 -> { + final TabOrderPreferenceDialogFragment dialogFragment = TabOrderPreferenceDialogFragment.newInstance(); + dialogFragment.show(getChildFragmentManager(), "tab_order_dialog"); + return true; + }); + return preference; + } + private Preference getUpdateCheckPreference(@NonNull final Context context) { final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context); preference.setKey(Constants.CHECK_UPDATES); @@ -72,4 +88,14 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment { return true; }); } + + @Override + public void onSave(final boolean orderHasChanged) { + Log.d("", "onSave: " + orderHasChanged); + } + + @Override + public void onCancel() { + + } } diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java index 3f481685..6e6b9cf4 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java @@ -5,4 +5,5 @@ public final class PreferenceKeys { public static final String PREF_ENABLE_DM_AUTO_REFRESH = "enable_dm_auto_refresh"; public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT = "enable_dm_auto_refresh_freq_unit"; public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER = "enable_dm_auto_refresh_freq_number"; + public static final String PREF_TAB_ORDER = "tab_order"; } diff --git a/app/src/main/java/awais/instagrabber/models/Tab.java b/app/src/main/java/awais/instagrabber/models/Tab.java new file mode 100644 index 00000000..7f9bad89 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/models/Tab.java @@ -0,0 +1,98 @@ +package awais.instagrabber.models; + +import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; +import androidx.annotation.NavigationRes; +import androidx.annotation.NonNull; + +import java.util.Objects; + +public class Tab { + private final int iconResId; + private final String title; + private final boolean removable; + + /** + * This is name part of the navigation resource + * eg: @navigation/graphName + */ + private final String graphName; + + /** + * This is the actual resource id of the navigation resource (R.navigation.graphName = navigationResId) + */ + private final int navigationResId; + + /** + * This is the resource id of the root navigation tag of the navigation resource. + *

eg: inside R.navigation.direct_messages_nav_graph, the id of the root tag is R.id.direct_messages_nav_graph. + *

So this field would equal to the value of R.id.direct_messages_nav_graph + */ + private final int navigationRootId; + + public Tab(@DrawableRes final int iconResId, + @NonNull final String title, + final boolean removable, + @NonNull final String graphName, + @NavigationRes final int navigationResId, + @IdRes final int navigationRootId) { + this.iconResId = iconResId; + this.title = title; + this.removable = removable; + this.graphName = graphName; + this.navigationResId = navigationResId; + this.navigationRootId = navigationRootId; + } + + public int getIconResId() { + return iconResId; + } + + public String getTitle() { + return title; + } + + public boolean isRemovable() { + return removable; + } + + public String getGraphName() { + return graphName; + } + + public int getNavigationResId() { + return navigationResId; + } + + public int getNavigationRootId() { + return navigationRootId; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final Tab tab = (Tab) o; + return iconResId == tab.iconResId && + removable == tab.removable && + navigationResId == tab.navigationResId && + navigationRootId == tab.navigationRootId && + Objects.equals(title, tab.title) && + Objects.equals(graphName, tab.graphName); + } + + @Override + public int hashCode() { + return Objects.hash(iconResId, title, removable, graphName, navigationResId, navigationRootId); + } + + @NonNull + @Override + public String toString() { + return "Tab{" + + "title='" + title + '\'' + + ", removable=" + removable + + ", graphName='" + graphName + '\'' + + '}'; + } +} diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index e48a96cd..ce80b3d9 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -15,6 +15,7 @@ import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_D import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER; import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT; import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_NOTIFICATIONS; +import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_TAB_ORDER; import static awais.instagrabber.utils.Constants.APP_LANGUAGE; import static awais.instagrabber.utils.Constants.APP_THEME; import static awais.instagrabber.utils.Constants.APP_UA; @@ -36,12 +37,12 @@ import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER; import static awais.instagrabber.utils.Constants.FLAG_SECURE; import static awais.instagrabber.utils.Constants.FOLDER_PATH; import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO; +import static awais.instagrabber.utils.Constants.KEYWORD_FILTERS; import static awais.instagrabber.utils.Constants.MARK_AS_SEEN; import static awais.instagrabber.utils.Constants.MUTED_VIDEOS; import static awais.instagrabber.utils.Constants.PREF_DARK_THEME; import static awais.instagrabber.utils.Constants.PREF_EMOJI_VARIANTS; import static awais.instagrabber.utils.Constants.PREF_HASHTAG_POSTS_LAYOUT; -import static awais.instagrabber.utils.Constants.KEYWORD_FILTERS; import static awais.instagrabber.utils.Constants.PREF_LIGHT_THEME; import static awais.instagrabber.utils.Constants.PREF_LIKED_POSTS_LAYOUT; import static awais.instagrabber.utils.Constants.PREF_LOCATION_POSTS_LAYOUT; @@ -150,7 +151,7 @@ public final class SettingsHelper { CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT, PREF_LOCATION_POSTS_LAYOUT, PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT, - STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT}) + STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT, PREF_TAB_ORDER}) public @interface StringSettings {} @StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index bf716e5d..c67c1130 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -8,6 +8,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -40,6 +41,8 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; import com.google.android.exoplayer2.database.ExoDatabaseProvider; import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor; import com.google.android.exoplayer2.upstream.cache.SimpleCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Ordering; import com.google.common.io.Files; import org.json.JSONObject; @@ -47,22 +50,25 @@ import org.json.JSONObject; import java.io.File; import java.lang.reflect.Field; import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; - -//import javax.crypto.Mac; -//import javax.crypto.spec.SecretKeySpec; +import java.util.stream.Collectors; import awais.instagrabber.R; +import awais.instagrabber.fragments.settings.PreferenceKeys; import awais.instagrabber.models.PostsLayoutPreferences; +import awais.instagrabber.models.Tab; import awais.instagrabber.models.enums.FavoriteType; -//import awaisomereport.LogCollector; public final class Utils { private static final String TAG = "Utils"; private static final int VIDEO_CACHE_MAX_BYTES = 10 * 1024 * 1024; -// public static LogCollector logCollector; + // public static LogCollector logCollector; public static SettingsHelper settingsHelper; public static boolean sessionVolumeFull = false; public static final MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); @@ -93,34 +99,34 @@ public final class Utils { } public static Map sign(final Map form) { -// final String signed = sign(Constants.SIGNATURE_KEY, new JSONObject(form).toString()); -// if (signed == null) { -// return null; -// } + // final String signed = sign(Constants.SIGNATURE_KEY, new JSONObject(form).toString()); + // if (signed == null) { + // return null; + // } final Map map = new HashMap<>(); -// map.put("ig_sig_key_version", Constants.SIGNATURE_VERSION); -// map.put("signed_body", signed); + // map.put("ig_sig_key_version", Constants.SIGNATURE_VERSION); + // map.put("signed_body", signed); map.put("signed_body", "SIGNATURE." + new JSONObject(form).toString()); return map; } -// public static String sign(final String key, final String message) { -// try { -// final Mac hasher = Mac.getInstance("HmacSHA256"); -// hasher.init(new SecretKeySpec(key.getBytes(), "HmacSHA256")); -// byte[] hash = hasher.doFinal(message.getBytes()); -// final StringBuilder hexString = new StringBuilder(); -// for (byte b : hash) { -// final String hex = Integer.toHexString(0xff & b); -// if (hex.length() == 1) hexString.append('0'); -// hexString.append(hex); -// } -// return hexString.toString() + "." + message; -// } catch (Exception e) { -// Log.e(TAG, "Error signing", e); -// return null; -// } -// } + // public static String sign(final String key, final String message) { + // try { + // final Mac hasher = Mac.getInstance("HmacSHA256"); + // hasher.init(new SecretKeySpec(key.getBytes(), "HmacSHA256")); + // byte[] hash = hasher.doFinal(message.getBytes()); + // final StringBuilder hexString = new StringBuilder(); + // for (byte b : hash) { + // final String hex = Integer.toHexString(0xff & b); + // if (hex.length() == 1) hexString.append('0'); + // hexString.append(hex); + // } + // return hexString.toString() + "." + message; + // } catch (Exception e) { + // Log.e(TAG, "Error signing", e); + // return null; + // } + // } public static String getMimeType(@NonNull final Uri uri, final ContentResolver contentResolver) { String mimeType; @@ -371,4 +377,101 @@ public final class Utils { if (window == null) return; window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } + + public static void moveItem(int sourceIndex, int targetIndex, List list) { + if (sourceIndex <= targetIndex) { + Collections.rotate(list.subList(sourceIndex, targetIndex + 1), -1); + } else { + Collections.rotate(list.subList(targetIndex, sourceIndex + 1), 1); + } + } + + private static final List NON_REMOVABLE_NAV_ROOT_IDS = ImmutableList.of(R.id.profile_nav_graph, R.id.more_nav_graph); + + @NonNull + public static Pair, List> getNavTabList(@NonNull final Context context) { + final Resources resources = context.getResources(); + final String[] titleArray = resources.getStringArray(R.array.main_nav_titles); + + TypedArray typedArray = resources.obtainTypedArray(R.array.main_nav_graphs); + int length = typedArray.length(); + final String[] navGraphNames = new String[length]; + final int[] navigationResIds = new int[length]; + for (int i = 0; i < length; i++) { + final int resourceId = typedArray.getResourceId(i, 0); + if (resourceId == 0) continue; + navigationResIds[i] = resourceId; + navGraphNames[i] = resources.getResourceEntryName(resourceId); + } + typedArray.recycle(); + + typedArray = resources.obtainTypedArray(R.array.main_nav_graph_root_ids); + length = typedArray.length(); + final int[] navRootIds = new int[length]; + for (int i = 0; i < length; i++) { + final int resourceId = typedArray.getResourceId(i, 0); + if (resourceId == 0) continue; + navRootIds[i] = resourceId; + } + typedArray.recycle(); + + typedArray = resources.obtainTypedArray(R.array.main_nav_drawables); + length = typedArray.length(); + final int[] iconIds = new int[length]; + for (int i = 0; i < length; i++) { + final int resourceId = typedArray.getResourceId(i, 0); + if (resourceId == 0) continue; + iconIds[i] = resourceId; + } + typedArray.recycle(); + + final List currentOrderGraphNames = getCurrentOrderOfGraphNamesFromPref(navGraphNames); + + if (titleArray.length != iconIds.length || titleArray.length != navGraphNames.length) { + throw new RuntimeException(String.format("Array lengths don't match!: titleArray%s, navGraphNames: %s, iconIds: %s", + Arrays.toString(titleArray), Arrays.toString(navGraphNames), Arrays.toString(iconIds))); + } + final List tabs = new ArrayList<>(); + final List otherTabs = new ArrayList<>(); // Will contain tabs not in current list + for (int i = 0; i < length; i++) { + final String navGraphName = navGraphNames[i]; + final int navRootId = navRootIds[i]; + final Tab tab = new Tab(iconIds[i], + titleArray[i], + !NON_REMOVABLE_NAV_ROOT_IDS.contains(navRootId), + navGraphName, + navigationResIds[i], + navRootId); + if (!currentOrderGraphNames.contains(navGraphName)) { + otherTabs.add(tab); + continue; + } + tabs.add(tab); + } + Collections.sort(tabs, Ordering.explicit(currentOrderGraphNames).onResultOf(tab -> { + if (tab == null) return null; + return tab.getGraphName(); + })); + return new Pair<>(tabs, otherTabs); + } + + @NonNull + private static List getCurrentOrderOfGraphNamesFromPref(@NonNull final String[] navGraphNames) { + final String tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); + final List navGraphNameList = Arrays.asList(navGraphNames); + if (TextUtils.isEmpty(tabOrderString)) { + // Use top 5 entries for default list + return navGraphNameList.subList(0, 5); + } + // Make sure that the list from preference does not contain any invalid values + final List orderGraphNames = Arrays.stream(tabOrderString.split(",")) + .filter(s -> !TextUtils.isEmpty(s)) + .filter(navGraphNameList::contains) + .collect(Collectors.toList()); + if (orderGraphNames.isEmpty()) { + // Use top 5 entries for default list + return navGraphNameList.subList(0, 5); + } + return orderGraphNames; + } } diff --git a/app/src/main/res/drawable/ic_round_add_circle_24.xml b/app/src/main/res/drawable/ic_round_add_circle_24.xml new file mode 100644 index 00000000..1906afe5 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_add_circle_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_drag_handle_24.xml b/app/src/main/res/drawable/ic_round_drag_handle_24.xml new file mode 100644 index 00000000..3f4f79ca --- /dev/null +++ b/app/src/main/res/drawable/ic_round_drag_handle_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_remove_circle_24.xml b/app/src/main/res/drawable/ic_round_remove_circle_24.xml new file mode 100644 index 00000000..68d85995 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_remove_circle_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d21d42a6..97bcb0bb 100755 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -48,6 +48,5 @@ android:layout_height="wrap_content" android:layout_gravity="bottom" app:labelVisibilityMode="auto" - app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" - app:menu="@menu/main_bottom_navigation_menu" /> + app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_tab_order_pref.xml b/app/src/main/res/layout/item_tab_order_pref.xml new file mode 100644 index 00000000..8c2045c9 --- /dev/null +++ b/app/src/main/res/layout/item_tab_order_pref.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/favorites_nav_graph.xml b/app/src/main/res/navigation/favorites_nav_graph.xml new file mode 100644 index 00000000..1a288bf1 --- /dev/null +++ b/app/src/main/res/navigation/favorites_nav_graph.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 0ba42065..c24f1763 100755 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -88,24 +88,46 @@ HH:mm:ss H:mm:ss - + + @id/direct_messages_nav_graph + @id/feed_nav_graph + @id/profile_nav_graph + @id/discover_nav_graph + @id/more_nav_graph + + @id/favorites_nav_graph + + + @navigation/direct_messages_nav_graph @navigation/feed_nav_graph @navigation/profile_nav_graph @navigation/discover_nav_graph @navigation/more_nav_graph + @navigation/favorites_nav_graph - + + @string/title_dm @string/feed @string/profile @string/title_discover @string/more + @string/title_favorites - - @navigation/profile_nav_graph - @navigation/more_nav_graph + + + @drawable/ic_message_24 + @drawable/ic_home_24 + @drawable/ic_person_24 + @drawable/ic_explore_24 + @drawable/ic_more_horiz_24 + @drawable/ic_star_24 + + + + @string/light_white_theme @string/light_barinsta_theme diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f65ff8c9..ac04be66 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -473,4 +473,6 @@ Removed keyword: %s from filter list Marked as seen Delete unsuccessful + Screen order + Other tabs From ace2688c8d1f0035b3807a3b08eb97713dea9c68 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Wed, 24 Mar 2021 22:26:11 +0900 Subject: [PATCH 07/42] For db update check id != 0 instead of id > 0. Fixes an issue when the entry was saved with -1 in earlier stages of dev. --- .../awais/instagrabber/db/datasources/FavoriteDataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java b/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java index 36798b08..bc013926 100644 --- a/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java +++ b/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java @@ -47,7 +47,7 @@ public class FavoriteDataSource { } public final void insertOrUpdateFavorite(@NonNull final Favorite favorite) { - if (favorite.getId() > 0) { + if (favorite.getId() != 0) { favoriteDao.updateFavorites(favorite); return; } From 2fed236f04b88fb6c64629b8c2efb98afc0dca7d Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Thu, 25 Mar 2021 00:32:24 +0900 Subject: [PATCH 08/42] Disable DM if tab removed and do not add favs to more list if tab added --- .../instagrabber/activities/MainActivity.java | 31 ++++++----- .../TabOrderPreferenceDialogFragment.java | 10 +++- .../fragments/main/ProfileFragment.java | 52 +++++++++++-------- .../settings/GeneralPreferencesFragment.java | 19 +++++-- .../settings/MorePreferencesFragment.java | 26 +++++++--- app/src/main/res/values/strings.xml | 2 + 6 files changed, 92 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index fe5fa220..3e8139fa 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -116,6 +116,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage private boolean isBackStackEmpty = false; private boolean isLoggedIn; private HideBottomViewOnScrollBehavior behavior; + private List currentTabs; private final ServiceConnection serviceConnection = new ServiceConnection() { @Override @@ -357,12 +358,14 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage } final List result = new ArrayList<>(); if (isLoggedIn) { - if (body.getList() != null) result.addAll(searchHash ? body.getList() - .stream() - .filter(i -> i.getUser() == null) - .collect(Collectors.toList()) : body.getList()); - } - else { + if (body.getList() != null) { + result.addAll(searchHash ? body.getList() + .stream() + .filter(i -> i.getUser() == null) + .collect(Collectors.toList()) + : body.getList()); + } + } else { if (body.getUsers() != null && !searchHash) result.addAll(body.getUsers()); if (body.getHashtags() != null) result.addAll(body.getHashtags()); if (body.getPlaces() != null) result.addAll(body.getPlaces()); @@ -431,7 +434,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage } prevSuggestionAsync = searchService.search(isLoggedIn, searchUser || searchHash ? currentSearchQuery.substring(1) - : currentSearchQuery, + : currentSearchQuery, searchUser ? "user" : (searchHash ? "hashtag" : "blended")); suggestionAdapter.changeCursor(null); prevSuggestionAsync.enqueue(cb); @@ -462,13 +465,13 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage } private void setupBottomNavigationBar(final boolean setDefaultTabFromSettings) { - final List tabs = !isLoggedIn ? setupAnonBottomNav() : setupMainBottomNav(); + currentTabs = !isLoggedIn ? setupAnonBottomNav() : setupMainBottomNav(); - final List mainNavList = tabs.stream() - .map(Tab::getNavigationResId) - .collect(Collectors.toList()); + final List mainNavList = currentTabs.stream() + .map(Tab::getNavigationResId) + .collect(Collectors.toList()); if (setDefaultTabFromSettings) { - setSelectedTab(tabs); + setSelectedTab(currentTabs); } final LiveData navControllerLiveData = setupWithNavController( binding.bottomNavView, @@ -875,4 +878,8 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage public Toolbar getToolbar() { return binding.toolbar; } + + public List getCurrentTabs() { + return currentTabs; + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java b/app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java index 83b4193f..0ac2dd23 100644 --- a/app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java +++ b/app/src/main/java/awais/instagrabber/dialogs/TabOrderPreferenceDialogFragment.java @@ -92,7 +92,15 @@ public class TabOrderPreferenceDialogFragment extends DialogFragment { setSaveButtonState(newOrderTabs); // submit these tab lists to adapter if (adapter == null) return; - adapter.submitList(newOrderTabs, newOtherTabs, () -> list.postDelayed(() -> adapter.notifyDataSetChanged(), 500)); + adapter.submitList(newOrderTabs, newOtherTabs, () -> list.postDelayed(() -> { + adapter.notifyDataSetChanged(); + if (tab.getNavigationRootId() == R.id.direct_messages_nav_graph) { + final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance( + 111, 0, R.string.dm_remove_warning, R.string.ok, 0, 0 + ); + dialogFragment.show(getChildFragmentManager(), "dm_warning_dialog"); + } + }, 500)); } private void setSaveButtonState(final List newOrderTabs) { diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index a9b9f722..4c305f75 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -307,6 +307,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe private AccountRepository accountRepository; private FavoriteRepository favoriteRepository; private AppStateViewModel appStateViewModel; + private boolean disableDm = false; @Override public void onCreate(@Nullable final Bundle savedInstanceState) { @@ -322,8 +323,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null; userService = isLoggedIn ? UserService.getInstance() : null; graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); - accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); - favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); + final Context context = getContext(); + if (context == null) return; + accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context)); + favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context)); appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class); setHasOptionsMenu(true); } @@ -578,6 +581,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } private void init() { + disableDm = fragmentActivity.getCurrentTabs() + .stream() + .noneMatch(tab -> tab.getNavigationRootId() == R.id.direct_messages_nav_graph); if (getArguments() != null) { final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments()); username = fragmentArgs.getUsername(); @@ -612,8 +618,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe username = profileModel.getUsername(); setUsernameDelayed(); setProfileDetails(); - } - else if (isLoggedIn) { + } else if (isLoggedIn) { userService.getUsernameInfo(usernameTemp, new ServiceCallback() { @Override public void onSuccess(final User user) { @@ -647,8 +652,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } catch (final Throwable ignored) {} } }); - } - else { + } else { graphQLService.fetchUser(usernameTemp, new ServiceCallback() { @Override public void onSuccess(final User user) { @@ -939,7 +943,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } profileDetailsBinding.btnSaved.setVisibility(View.GONE); profileDetailsBinding.btnLiked.setVisibility(View.GONE); - profileDetailsBinding.btnDM.setVisibility(View.VISIBLE); + profileDetailsBinding.btnDM.setVisibility(disableDm ? View.GONE : View.VISIBLE); profileDetailsBinding.btnFollow.setVisibility(View.VISIBLE); final Context context = getContext(); if (context == null) return; @@ -1116,23 +1120,25 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe PostItemType.TAGGED); NavHostFragment.findNavController(this).navigate(action); }); - profileDetailsBinding.btnDM.setOnClickListener(v -> { - profileDetailsBinding.btnDM.setEnabled(false); - new CreateThreadAction(cookie, profileModel.getPk(), thread -> { - if (thread == null) { - Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + if (!disableDm) { + profileDetailsBinding.btnDM.setOnClickListener(v -> { + profileDetailsBinding.btnDM.setEnabled(false); + new CreateThreadAction(cookie, profileModel.getPk(), thread -> { + if (thread == null) { + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + profileDetailsBinding.btnDM.setEnabled(true); + return; + } + final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager(); + if (!inboxManager.containsThread(thread.getThreadId())) { + thread.setTemp(true); + inboxManager.addThread(thread, 0); + } + fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername()); profileDetailsBinding.btnDM.setEnabled(true); - return; - } - final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager(); - if (!inboxManager.containsThread(thread.getThreadId())) { - thread.setTemp(true); - inboxManager.addThread(thread, 0); - } - fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername()); - profileDetailsBinding.btnDM.setEnabled(true); - }).execute(); - }); + }).execute(); + }); + } profileDetailsBinding.mainProfileImage.setOnClickListener(v -> { if (!hasStories) { // show profile pic diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java index 62758946..69ed1f8e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java @@ -2,7 +2,6 @@ package awais.instagrabber.fragments.settings; import android.content.Context; import android.content.res.TypedArray; -import android.util.Log; import androidx.annotation.NonNull; import androidx.preference.ListPreference; @@ -13,6 +12,7 @@ import androidx.preference.SwitchPreferenceCompat; import java.util.List; import awais.instagrabber.R; +import awais.instagrabber.dialogs.ConfirmDialogFragment; import awais.instagrabber.dialogs.TabOrderPreferenceDialogFragment; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; @@ -34,9 +34,10 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment implemen } screen.addPreference(getUpdateCheckPreference(context)); screen.addPreference(getFlagSecurePreference(context)); - final List preferences = FlavorSettings.getInstance().getPreferences(context, - getChildFragmentManager(), - SettingCategory.GENERAL); + final List preferences = FlavorSettings.getInstance() + .getPreferences(context, + getChildFragmentManager(), + SettingCategory.GENERAL); if (preferences != null) { for (final Preference preference : preferences) { screen.addPreference(preference); @@ -101,7 +102,15 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment implemen @Override public void onSave(final boolean orderHasChanged) { - Log.d("", "onSave: " + orderHasChanged); + if (!orderHasChanged) return; + final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance( + 111, + 0, + R.string.tab_order_start_next_launch, + R.string.ok, + 0, + 0); + dialogFragment.show(getChildFragmentManager(), "tab_order_set_dialog"); } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 54bf518f..30137d7b 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -27,6 +27,7 @@ import java.util.List; import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.activities.Login; +import awais.instagrabber.activities.MainActivity; import awais.instagrabber.databinding.PrefAccountSwitcherBinding; import awais.instagrabber.db.datasources.AccountDataSource; import awais.instagrabber.db.entities.Account; @@ -157,13 +158,24 @@ public class MorePreferencesFragment extends BasePreferencesFragment { return true; })); } - screen.addPreference(getPreference(R.string.title_favorites, R.drawable.ic_star_24, preference -> { - if (isSafeToNavigate(navController)) { - final NavDirections navDirections = MorePreferencesFragmentDirections.actionMorePreferencesFragmentToFavoritesFragment(); - navController.navigate(navDirections); - } - return true; - })); + + // Check if favorites has been added as a tab. And if so, do not add in this list + boolean showFavorites = true; + final MainActivity activity = (MainActivity) getActivity(); + if (activity != null && activity.getCurrentTabs() != null) { + showFavorites = activity.getCurrentTabs() + .stream() + .noneMatch(tab -> tab.getNavigationRootId() == R.id.favorites_nav_graph); + } + if (showFavorites) { + screen.addPreference(getPreference(R.string.title_favorites, R.drawable.ic_star_24, preference -> { + if (isSafeToNavigate(navController)) { + final NavDirections navDirections = MorePreferencesFragmentDirections.actionMorePreferencesFragmentToFavoritesFragment(); + navController.navigate(navDirections); + } + return true; + })); + } screen.addPreference(getDivider(context)); screen.addPreference(getPreference(R.string.action_settings, R.drawable.ic_outline_settings_24, preference -> { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 25bddb2c..b997d98c 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -477,4 +477,6 @@ Select an email app to send crash logs Screen order Other tabs + The tab order will be reflected on next launch + If saved, all DM related features will be disabled on next launch From aa5c57e162013c6d7052d594bdc1f018b016e83f Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Thu, 25 Mar 2021 00:35:41 +0900 Subject: [PATCH 09/42] Remove unused menu files --- .../logged_out_bottom_navigation_menu.xml | 12 ------- .../res/menu/main_bottom_navigation_menu.xml | 33 ------------------- 2 files changed, 45 deletions(-) delete mode 100644 app/src/main/res/menu/logged_out_bottom_navigation_menu.xml delete mode 100644 app/src/main/res/menu/main_bottom_navigation_menu.xml diff --git a/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml b/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml deleted file mode 100644 index 4eb3da02..00000000 --- a/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml +++ /dev/null @@ -1,12 +0,0 @@ - -

- - - - \ No newline at end of file diff --git a/app/src/main/res/menu/main_bottom_navigation_menu.xml b/app/src/main/res/menu/main_bottom_navigation_menu.xml deleted file mode 100644 index 12e0ab12..00000000 --- a/app/src/main/res/menu/main_bottom_navigation_menu.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file From b80ae2fcfedcba621906bab9b2c32c16f6fe57e7 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Thu, 25 Mar 2021 01:23:33 +0900 Subject: [PATCH 10/42] Get 'show bottom destinations' from tabs. Add Activity to list of available tabs. --- .../instagrabber/activities/MainActivity.java | 28 ++++++++++--------- .../fragments/main/ProfileFragment.java | 4 +-- .../settings/MorePreferencesFragment.java | 28 +++++++++++-------- .../java/awais/instagrabber/models/Tab.java | 16 +++++++++-- .../java/awais/instagrabber/utils/Utils.java | 13 ++++++++- .../notification_viewer_nav_graph.xml | 3 +- app/src/main/res/values/arrays.xml | 15 ++++++++++ 7 files changed, 75 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 3e8139fa..4ac90477 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -53,6 +53,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; import java.util.ArrayList; +import java.util.Collections; import java.util.Deque; import java.util.List; import java.util.stream.Collectors; @@ -92,14 +93,6 @@ import static awais.instagrabber.utils.Utils.settingsHelper; public class MainActivity extends BaseLanguageActivity implements FragmentManager.OnBackStackChangedListener { private static final String TAG = "MainActivity"; - - private static final List SHOW_BOTTOM_VIEW_DESTINATIONS = ImmutableList.of( - R.id.directMessagesInboxFragment, - R.id.feedFragment, - R.id.profileFragment, - R.id.discoverFragment, - R.id.morePreferencesFragment, - R.id.favoritesFragment); private static final String FIRST_FRAGMENT_GRAPH_INDEX_KEY = "firstFragmentGraphIndex"; private ActivityMainBinding binding; @@ -117,6 +110,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage private boolean isLoggedIn; private HideBottomViewOnScrollBehavior behavior; private List currentTabs; + private List showBottomViewDestinations = Collections.emptyList(); private final ServiceConnection serviceConnection = new ServiceConnection() { @Override @@ -470,6 +464,9 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage final List mainNavList = currentTabs.stream() .map(Tab::getNavigationResId) .collect(Collectors.toList()); + showBottomViewDestinations = currentTabs.stream() + .map(Tab::getStartDestinationFragmentId) + .collect(Collectors.toList()); if (setDefaultTabFromSettings) { setSelectedTab(currentTabs); } @@ -522,16 +519,17 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage false, "profile_nav_graph", R.navigation.profile_nav_graph, - R.id.profile_nav_graph); + R.id.profile_nav_graph, + R.id.profileFragment); final Tab moreTab = new Tab(R.drawable.ic_more_horiz_24, getString(R.string.more), false, "more_nav_graph", R.navigation.more_nav_graph, - R.id.more_nav_graph); + R.id.more_nav_graph, + R.id.morePreferencesFragment); final Menu menu = binding.bottomNavView.getMenu(); menu.clear(); - // binding.bottomNavView.inflateMenu(R.menu.logged_out_bottom_navigation_menu); menu.add(0, profileTab.getNavigationRootId(), 0, profileTab.getTitle()).setIcon(profileTab.getIconResId()); menu.add(0, moreTab.getNavigationRootId(), 0, moreTab.getTitle()).setIcon(moreTab.getIconResId()); if (selectedItemId != R.id.profile_nav_graph && selectedItemId != R.id.more_nav_graph) { @@ -589,7 +587,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage final int destinationId = destination.getId(); @SuppressLint("RestrictedApi") final Deque backStack = navController.getBackStack(); setupMenu(backStack.size(), destinationId); - final boolean contains = SHOW_BOTTOM_VIEW_DESTINATIONS.contains(destinationId); + final boolean contains = showBottomViewDestinations.contains(destinationId); binding.bottomNavView.setVisibility(contains ? View.VISIBLE : View.GONE); if (contains && behavior != null) { behavior.slideUp(binding.bottomNavView); @@ -771,7 +769,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage final NavController navController = currentNavControllerLiveData.getValue(); if (navController == null) return; final Bundle bundle = new Bundle(); - bundle.putLong("locationId", Long.valueOf(locationId)); + bundle.putLong("locationId", Long.parseLong(locationId)); navController.navigate(R.id.action_global_locationFragment, bundle); } @@ -882,4 +880,8 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage public List getCurrentTabs() { return currentTabs; } + + public boolean isNavRootInCurrentTabs(@IdRes final int navRootId) { + return showBottomViewDestinations.stream().anyMatch(id -> id == navRootId); + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 4c305f75..2109f935 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -581,9 +581,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } private void init() { - disableDm = fragmentActivity.getCurrentTabs() - .stream() - .noneMatch(tab -> tab.getNavigationRootId() == R.id.direct_messages_nav_graph); + disableDm = !fragmentActivity.isNavRootInCurrentTabs(R.id.directMessagesInboxFragment); if (getArguments() != null) { final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments()); username = fragmentArgs.getUsername(); diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 30137d7b..947996a2 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -56,6 +56,7 @@ public class MorePreferencesFragment extends BasePreferencesFragment { void setupPreferenceScreen(final PreferenceScreen screen) { final String cookie = settingsHelper.getString(Constants.COOKIE); final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; + final MainActivity activity = (MainActivity) getActivity(); // screen.addPreference(new MoreHeaderPreference(getContext())); final Context context = getContext(); if (context == null) return; @@ -136,13 +137,19 @@ public class MorePreferencesFragment extends BasePreferencesFragment { screen.addPreference(getDivider(context)); final NavController navController = NavHostFragment.findNavController(this); if (isLoggedIn) { - screen.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> { - if (isSafeToNavigate(navController)) { - final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif"); - navController.navigate(navDirections); - } - return true; - })); + boolean showActivity = true; + if (activity != null) { + showActivity = !activity.isNavRootInCurrentTabs(R.id.notificationsViewer); + } + if (showActivity) { + screen.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> { + if (isSafeToNavigate(navController)) { + final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif"); + navController.navigate(navDirections); + } + return true; + })); + } screen.addPreference(getPreference(R.string.action_ayml, R.drawable.ic_suggested_users, preference -> { if (isSafeToNavigate(navController)) { final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml"); @@ -161,11 +168,8 @@ public class MorePreferencesFragment extends BasePreferencesFragment { // Check if favorites has been added as a tab. And if so, do not add in this list boolean showFavorites = true; - final MainActivity activity = (MainActivity) getActivity(); - if (activity != null && activity.getCurrentTabs() != null) { - showFavorites = activity.getCurrentTabs() - .stream() - .noneMatch(tab -> tab.getNavigationRootId() == R.id.favorites_nav_graph); + if (activity != null) { + showFavorites = !activity.isNavRootInCurrentTabs(R.id.favoritesFragment); } if (showFavorites) { screen.addPreference(getPreference(R.string.title_favorites, R.drawable.ic_star_24, preference -> { diff --git a/app/src/main/java/awais/instagrabber/models/Tab.java b/app/src/main/java/awais/instagrabber/models/Tab.java index 7f9bad89..e4e608be 100644 --- a/app/src/main/java/awais/instagrabber/models/Tab.java +++ b/app/src/main/java/awais/instagrabber/models/Tab.java @@ -30,18 +30,25 @@ public class Tab { */ private final int navigationRootId; + /** + * This is the start destination of the nav graph + */ + private final int startDestinationFragmentId; + public Tab(@DrawableRes final int iconResId, @NonNull final String title, final boolean removable, @NonNull final String graphName, @NavigationRes final int navigationResId, - @IdRes final int navigationRootId) { + @IdRes final int navigationRootId, + @IdRes final int startDestinationFragmentId) { this.iconResId = iconResId; this.title = title; this.removable = removable; this.graphName = graphName; this.navigationResId = navigationResId; this.navigationRootId = navigationRootId; + this.startDestinationFragmentId = startDestinationFragmentId; } public int getIconResId() { @@ -68,6 +75,10 @@ public class Tab { return navigationRootId; } + public int getStartDestinationFragmentId() { + return startDestinationFragmentId; + } + @Override public boolean equals(final Object o) { if (this == o) return true; @@ -77,13 +88,14 @@ public class Tab { removable == tab.removable && navigationResId == tab.navigationResId && navigationRootId == tab.navigationRootId && + startDestinationFragmentId == tab.startDestinationFragmentId && Objects.equals(title, tab.title) && Objects.equals(graphName, tab.graphName); } @Override public int hashCode() { - return Objects.hash(iconResId, title, removable, graphName, navigationResId, navigationRootId); + return Objects.hash(iconResId, title, removable, graphName, navigationResId, navigationRootId, startDestinationFragmentId); } @NonNull diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index c67c1130..7d0afd2b 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -425,6 +425,16 @@ public final class Utils { } typedArray.recycle(); + typedArray = resources.obtainTypedArray(R.array.main_nav_start_dest_frag_ids); + length = typedArray.length(); + final int[] startDestFragIds = new int[length]; + for (int i = 0; i < length; i++) { + final int resourceId = typedArray.getResourceId(i, 0); + if (resourceId == 0) continue; + startDestFragIds[i] = resourceId; + } + typedArray.recycle(); + final List currentOrderGraphNames = getCurrentOrderOfGraphNamesFromPref(navGraphNames); if (titleArray.length != iconIds.length || titleArray.length != navGraphNames.length) { @@ -441,7 +451,8 @@ public final class Utils { !NON_REMOVABLE_NAV_ROOT_IDS.contains(navRootId), navGraphName, navigationResIds[i], - navRootId); + navRootId, + startDestFragIds[i]); if (!currentOrderGraphNames.contains(navGraphName)) { otherTabs.add(tab); continue; diff --git a/app/src/main/res/navigation/notification_viewer_nav_graph.xml b/app/src/main/res/navigation/notification_viewer_nav_graph.xml index 245a2cee..89df18be 100644 --- a/app/src/main/res/navigation/notification_viewer_nav_graph.xml +++ b/app/src/main/res/navigation/notification_viewer_nav_graph.xml @@ -13,7 +13,8 @@ + app:nullable="false" + android:defaultValue="notif"/> @id/more_nav_graph
@id/favorites_nav_graph + @id/notification_viewer_nav_graph @@ -105,6 +106,7 @@ @navigation/discover_nav_graph @navigation/more_nav_graph @navigation/favorites_nav_graph + @navigation/notification_viewer_nav_graph @@ -114,6 +116,7 @@ @string/title_discover @string/more @string/title_favorites + @string/title_notifications @@ -123,6 +126,18 @@ @drawable/ic_explore_24 @drawable/ic_more_horiz_24 @drawable/ic_star_24 + @drawable/ic_not_liked + + + + + @id/directMessagesInboxFragment + @id/feedFragment + @id/profileFragment + @id/discoverFragment + @id/morePreferencesFragment + @id/favoritesFragment + @id/notificationsViewer From 1d3ec52857524abed10c3b61829c52e130da67f6 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Thu, 25 Mar 2021 19:29:56 +0900 Subject: [PATCH 11/42] Generate default tab preference list from current tabs --- .../instagrabber/activities/MainActivity.java | 12 ++++++---- .../settings/GeneralPreferencesFragment.java | 23 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 4ac90477..111ec538 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -300,7 +300,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage final Bundle bundle = new Bundle(); switch (type) { case TYPE_LOCATION: - bundle.putLong("locationId", Long.valueOf(query)); + bundle.putLong("locationId", Long.parseLong(query)); navController.navigate(R.id.action_global_locationFragment, bundle); break; case TYPE_HASHTAG: @@ -404,9 +404,10 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage @Override public void onFailure(@NonNull final Call call, - Throwable t) { - if (!call.isCanceled() && t != null) + @NonNull Throwable t) { + if (!call.isCanceled()) { Log.e(TAG, "Exception on search:", t); + } } }; @@ -498,14 +499,15 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage if (!TextUtils.isEmpty(defaultTabResNameString)) { navId = getResources().getIdentifier(defaultTabResNameString, "navigation", getPackageName()); } - final int navGraph = isLoggedIn ? R.navigation.feed_nav_graph : R.navigation.profile_nav_graph; + final int navGraph = isLoggedIn ? R.navigation.feed_nav_graph + : R.navigation.profile_nav_graph; final int defaultNavId = navId <= 0 ? navGraph : navId; int index = Iterators.indexOf(tabs.iterator(), tab -> { if (tab == null) return false; return tab.getNavigationResId() == defaultNavId; }); - if (index >= 0) firstFragmentGraphIndex = index; if (index < 0 || index >= tabs.size()) index = 0; + if (index >= 0) firstFragmentGraphIndex = index; setBottomNavSelectedTab(tabs.get(index)); } catch (Exception e) { Log.e(TAG, "Error parsing id", e); diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java index 69ed1f8e..2eba325e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java @@ -1,7 +1,7 @@ package awais.instagrabber.fragments.settings; import android.content.Context; -import android.content.res.TypedArray; +import android.util.Pair; import androidx.annotation.NonNull; import androidx.preference.ListPreference; @@ -14,9 +14,11 @@ import java.util.List; import awais.instagrabber.R; import awais.instagrabber.dialogs.ConfirmDialogFragment; import awais.instagrabber.dialogs.TabOrderPreferenceDialogFragment; +import awais.instagrabber.models.Tab; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.utils.Utils; import static awais.instagrabber.utils.Utils.settingsHelper; @@ -48,19 +50,18 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment implemen private Preference getDefaultTabPreference(@NonNull final Context context) { final ListPreference preference = new ListPreference(context); preference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance()); - final TypedArray mainNavGraphs = getResources().obtainTypedArray(R.array.main_nav_graphs); - final int length = mainNavGraphs.length(); - final String[] navGraphFileNames = new String[length]; - for (int i = 0; i < length; i++) { - final int resourceId = mainNavGraphs.getResourceId(i, -1); - if (resourceId < 0) continue; - navGraphFileNames[i] = getResources().getResourceEntryName(resourceId); - } - mainNavGraphs.recycle(); + final Pair, List> listPair = Utils.getNavTabList(context); + final List tabs = listPair.first; + final String[] titles = tabs.stream() + .map(Tab::getTitle) + .toArray(String[]::new); + final String[] navGraphFileNames = tabs.stream() + .map(Tab::getGraphName) + .toArray(String[]::new); preference.setKey(Constants.DEFAULT_TAB); preference.setTitle(R.string.pref_start_screen); preference.setDialogTitle(R.string.pref_start_screen); - preference.setEntries(R.array.main_nav_titles); + preference.setEntries(titles); preference.setEntryValues(navGraphFileNames); preference.setIconSpaceReserved(false); return preference; From 5653fcb41fe84048042de550ee227d0e9294853a Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 28 Mar 2021 17:42:09 +0900 Subject: [PATCH 12/42] Fix last selected tab on activity recreate --- .../instagrabber/activities/MainActivity.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 111ec538..50710107 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -94,6 +94,7 @@ import static awais.instagrabber.utils.Utils.settingsHelper; public class MainActivity extends BaseLanguageActivity implements FragmentManager.OnBackStackChangedListener { private static final String TAG = "MainActivity"; private static final String FIRST_FRAGMENT_GRAPH_INDEX_KEY = "firstFragmentGraphIndex"; + private static final String LAST_SELECT_NAV_MENU_ID = "lastSelectedNavMenuId"; private ActivityMainBinding binding; private LiveData currentNavControllerLiveData; @@ -105,6 +106,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage private boolean showSearch = true; private Handler suggestionsFetchHandler; private int firstFragmentGraphIndex; + private int lastSelectedNavMenuId; private boolean isActivityCheckerServiceBound = false; private boolean isBackStackEmpty = false; private boolean isLoggedIn; @@ -201,6 +203,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage @Override protected void onSaveInstanceState(@NonNull final Bundle outState) { outState.putString(FIRST_FRAGMENT_GRAPH_INDEX_KEY, String.valueOf(firstFragmentGraphIndex)); + outState.putString(LAST_SELECT_NAV_MENU_ID, String.valueOf(binding.bottomNavView.getSelectedItemId())); super.onSaveInstanceState(outState); } @@ -213,6 +216,12 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage firstFragmentGraphIndex = Integer.parseInt(key); } catch (NumberFormatException ignored) { } } + final String lastSelected = (String) savedInstanceState.get(LAST_SELECT_NAV_MENU_ID); + if (lastSelected != null) { + try { + lastSelectedNavMenuId = Integer.parseInt(lastSelected); + } catch (NumberFormatException ignored) { } + } setupBottomNavigationBar(false); } @@ -461,7 +470,6 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage private void setupBottomNavigationBar(final boolean setDefaultTabFromSettings) { currentTabs = !isLoggedIn ? setupAnonBottomNav() : setupMainBottomNav(); - final List mainNavList = currentTabs.stream() .map(Tab::getNavigationResId) .collect(Collectors.toList()); @@ -470,6 +478,8 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage .collect(Collectors.toList()); if (setDefaultTabFromSettings) { setSelectedTab(currentTabs); + } else { + binding.bottomNavView.setSelectedItemId(lastSelectedNavMenuId); } final LiveData navControllerLiveData = setupWithNavController( binding.bottomNavView, @@ -507,7 +517,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage return tab.getNavigationResId() == defaultNavId; }); if (index < 0 || index >= tabs.size()) index = 0; - if (index >= 0) firstFragmentGraphIndex = index; + firstFragmentGraphIndex = index; setBottomNavSelectedTab(tabs.get(index)); } catch (Exception e) { Log.e(TAG, "Error parsing id", e); From 1089a39375fe9791ea73fa8a734fc9c97ed89c71 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 28 Mar 2021 22:56:29 +0900 Subject: [PATCH 13/42] Separate out latest version check logic per flavor --- .../instagrabber/utils/UpdateChecker.java | 64 +++++++++++ .../instagrabber/utils/UpdateChecker.java | 61 +++++++++++ .../settings/MorePreferencesFragment.java | 4 +- .../awais/instagrabber/utils/Constants.java | 1 - .../awais/instagrabber/utils/FlavorTown.java | 100 +++--------------- .../instagrabber/utils/UpdateCheckCommon.java | 39 +++++++ .../instagrabber/utils/UpdateChecker.java | 58 ---------- app/src/main/res/values/strings.xml | 1 + 8 files changed, 184 insertions(+), 144 deletions(-) create mode 100644 app/src/fdroid/java/awais/instagrabber/utils/UpdateChecker.java create mode 100644 app/src/github/java/awais/instagrabber/utils/UpdateChecker.java create mode 100644 app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java delete mode 100755 app/src/main/java/awais/instagrabber/utils/UpdateChecker.java diff --git a/app/src/fdroid/java/awais/instagrabber/utils/UpdateChecker.java b/app/src/fdroid/java/awais/instagrabber/utils/UpdateChecker.java new file mode 100644 index 00000000..f25b8aa4 --- /dev/null +++ b/app/src/fdroid/java/awais/instagrabber/utils/UpdateChecker.java @@ -0,0 +1,64 @@ +package awais.instagrabber.utils; + +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import org.json.JSONObject; + +import java.net.HttpURLConnection; +import java.net.URL; + +public class UpdateChecker { + private static final Object LOCK = new Object(); + private static final String TAG = UpdateChecker.class.getSimpleName(); + + private static UpdateChecker instance; + + public static UpdateChecker getInstance() { + if (instance == null) { + synchronized (LOCK) { + if (instance == null) { + instance = new UpdateChecker(); + } + } + } + return instance; + } + + /** + * Needs to be called asynchronously + * + * @return the latest version from f-droid + */ + @Nullable + public String getLatestVersion() { + HttpURLConnection conn = null; + try { + conn = (HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection(); + conn.setUseCaches(false); + conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me"); + conn.connect(); + final int responseCode = conn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn)); + return "v" + data.getJSONArray("packages").getJSONObject(0).getString("versionName"); + // if (BuildConfig.VERSION_CODE < data.getInt("suggestedVersionCode")) { + // } + } + } catch (final Exception e) { + Log.e(TAG, "", e); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + return null; + } + + public void onDownload(@NonNull final AppCompatActivity context) { + Utils.openURL(context, "https://f-droid.org/packages/me.austinhuang.instagrabber/"); + } +} diff --git a/app/src/github/java/awais/instagrabber/utils/UpdateChecker.java b/app/src/github/java/awais/instagrabber/utils/UpdateChecker.java new file mode 100644 index 00000000..70bc2699 --- /dev/null +++ b/app/src/github/java/awais/instagrabber/utils/UpdateChecker.java @@ -0,0 +1,61 @@ +package awais.instagrabber.utils; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.net.HttpURLConnection; +import java.net.URL; + +public class UpdateChecker { + private static final Object LOCK = new Object(); + private static final String TAG = UpdateChecker.class.getSimpleName(); + + private static UpdateChecker instance; + + public static UpdateChecker getInstance() { + if (instance == null) { + synchronized (LOCK) { + if (instance == null) { + instance = new UpdateChecker(); + } + } + } + return instance; + } + + /** + * Needs to be called asynchronously + * + * @return the latest version from Github + */ + @Nullable + public String getLatestVersion() { + HttpURLConnection conn = null; + try { + conn = (HttpURLConnection) new URL("https://github.com/austinhuang0131/barinsta/releases/latest").openConnection(); + conn.setInstanceFollowRedirects(false); + conn.setUseCaches(false); + conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me"); + conn.connect(); + final int responseCode = conn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP) { + return "v" + conn.getHeaderField("Location").split("/v")[1]; + // return !version.equals(BuildConfig.VERSION_NAME); + } + } catch (final Exception e) { + Log.e(TAG, "", e); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + return null; + } + + public void onDownload(@NonNull final Context context) { + Utils.openURL(context, "https://github.com/austinhuang0131/instagrabber/releases/latest"); + } +} diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 54bf518f..1343bb60 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -193,7 +193,9 @@ public class MorePreferencesFragment extends BasePreferencesFragment { BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")", -1, preference -> { - FlavorTown.updateCheck((AppCompatActivity) requireActivity(), true); + final AppCompatActivity activity = (AppCompatActivity) getActivity(); + if (activity == null) return true; + FlavorTown.updateCheck(activity, true); return true; })); screen.addPreference(getDivider(context)); diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index 969f5d6a..f6da0362 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -79,7 +79,6 @@ public final class Constants { // public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc"; public static final String BREADCRUMB_KEY = "iN4$aGr0m"; public static final int LOGIN_RESULT_CODE = 5000; - public static final String FDROID_SHA1_FINGERPRINT = "C1661EB8FD09F618307E687786D5E5056F65084D"; public static final String SKIPPED_VERSION = "skipped_version"; public static final String DEFAULT_TAB = "default_tab"; public static final String PREF_DARK_THEME = "dark_theme"; diff --git a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java index ee859700..7083c694 100755 --- a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java +++ b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java @@ -1,104 +1,46 @@ package awais.instagrabber.utils; -import android.annotation.SuppressLint; -import android.content.ActivityNotFoundException; import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.Signature; -import android.content.res.Resources; -import android.net.Uri; -import android.os.AsyncTask; -import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.concurrent.ThreadLocalRandom; -import javax.security.cert.CertificateException; -import javax.security.cert.X509Certificate; - import awais.instagrabber.BuildConfig; import awais.instagrabber.R; -import awais.instagrabber.databinding.DialogUpdateBinding; import static awais.instagrabber.utils.Utils.settingsHelper; public final class FlavorTown { private static final String TAG = "FlavorTown"; - private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); - private static AlertDialog dialog; + private static final UpdateChecker UPDATE_CHECKER = UpdateChecker.getInstance(); + + private static boolean checking = false; public static void updateCheck(@NonNull final AppCompatActivity context) { updateCheck(context, false); } - @SuppressLint("PackageManagerGetSignatures") - public static void updateCheck(@NonNull final AppCompatActivity context, final boolean force) { - boolean isInstalledFromFdroid = false; - final PackageInfo packageInfo; - try { - packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); - for (Signature signature : packageInfo.signatures) { - final X509Certificate cert = X509Certificate.getInstance(signature.toByteArray()); - final String fingerprint = bytesToHex(MessageDigest.getInstance("SHA-1").digest(cert.getEncoded())); - isInstalledFromFdroid = fingerprint.equals(Constants.FDROID_SHA1_FINGERPRINT); - // Log.d(TAG, "fingerprint:" + fingerprint); - } - } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException | CertificateException e) { - Log.e(TAG, "Error", e); - } - if (isInstalledFromFdroid) return; - final DialogUpdateBinding binding = DialogUpdateBinding.inflate(context.getLayoutInflater(), null, false); - binding.skipUpdate.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (dialog == null) return; - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!isChecked); - }); - Resources res = context.getResources(); - new UpdateChecker(version -> { + public static void updateCheck(@NonNull final AppCompatActivity context, + final boolean force) { + if (checking) return; + checking = true; + AppExecutors.getInstance().networkIO().execute(() -> { + final String version = UPDATE_CHECKER.getLatestVersion(); + if (version == null) return; if (force && version.equals(BuildConfig.VERSION_NAME)) { Toast.makeText(context, "You're already on the latest version", Toast.LENGTH_SHORT).show(); return; } - final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION); - final boolean shouldShowDialog = force || (!version.equals(BuildConfig.VERSION_NAME) && !BuildConfig.DEBUG && !skippedVersion - .equals(version)); + final boolean shouldShowDialog = UpdateCheckCommon.shouldShowUpdateDialog(force, version); if (!shouldShowDialog) return; - dialog = new AlertDialog.Builder(context) - .setTitle(res.getString(R.string.update_available, version)) - .setView(binding.getRoot()) - .setNeutralButton(R.string.cancel, (dialog, which) -> { - if (binding.skipUpdate.isChecked()) { - settingsHelper.putString(Constants.SKIPPED_VERSION, version); - } - dialog.dismiss(); - }) - .setPositiveButton(R.string.action_github, (dialog1, which) -> { - try { - context.startActivity(new Intent(Intent.ACTION_VIEW).setData( - Uri.parse("https://github.com/austinhuang0131/instagrabber/releases/latest"))); - } catch (final ActivityNotFoundException e) { - // do nothing - } - }) - // if we don't show dialog for fdroid users, is the below required? - .setNegativeButton(R.string.action_fdroid, (dialog, which) -> { - try { - context.startActivity(new Intent(Intent.ACTION_VIEW).setData( - Uri.parse("https://f-droid.org/packages/me.austinhuang.instagrabber/"))); - } catch (final ActivityNotFoundException e) { - // do nothing - } - }) - .show(); - }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + UpdateCheckCommon.showUpdateDialog(context, version, (dialog, which) -> { + UPDATE_CHECKER.onDownload(context); + dialog.dismiss(); + }); + }); } public static void changelogCheck(@NonNull final Context context) { @@ -121,14 +63,4 @@ public final class FlavorTown { settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE); } } - - public static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars); - } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java b/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java new file mode 100644 index 00000000..8377c9e4 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java @@ -0,0 +1,39 @@ +package awais.instagrabber.utils; + +import android.content.Context; +import android.content.DialogInterface; + +import androidx.annotation.NonNull; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import awais.instagrabber.BuildConfig; +import awais.instagrabber.R; + +import static awais.instagrabber.utils.Utils.settingsHelper; + +public final class UpdateCheckCommon { + + public static boolean shouldShowUpdateDialog(final boolean force, + @NonNull final String version) { + final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION); + return force || (!version.equals(BuildConfig.VERSION_NAME) && !BuildConfig.DEBUG && !skippedVersion + .equals(version)); + } + + public static void showUpdateDialog(@NonNull final Context context, + @NonNull final String version, + @NonNull final DialogInterface.OnClickListener onDownloadClickListener) { + AppExecutors.getInstance().mainThread().execute(() -> { + new MaterialAlertDialogBuilder(context) + .setTitle(context.getString(R.string.update_available, version)) + .setNeutralButton(R.string.skip_update, (dialog, which) -> { + settingsHelper.putString(Constants.SKIPPED_VERSION, version); + dialog.dismiss(); + }) + .setPositiveButton(R.string.action_download, onDownloadClickListener) + .setNegativeButton(R.string.cancel, null) + .show(); + }); + } +} diff --git a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java b/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java deleted file mode 100755 index 3ea67ba1..00000000 --- a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java +++ /dev/null @@ -1,58 +0,0 @@ -package awais.instagrabber.utils; - -import android.os.AsyncTask; -import android.util.Log; - -import androidx.annotation.NonNull; - -import org.json.JSONObject; - -import java.net.HttpURLConnection; -import java.net.URL; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.interfaces.FetchListener; - -public final class UpdateChecker extends AsyncTask { - private final FetchListener fetchListener; - private String version; - - public UpdateChecker(final FetchListener fetchListener) { - this.fetchListener = fetchListener; - } - - @NonNull - @Override - protected Boolean doInBackground(final Void... voids) { - try { - version = ""; - - HttpURLConnection conn = - (HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection(); - conn.setUseCaches(false); - conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me"); - conn.connect(); - - final int responseCode = conn.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) { - final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn)); - if (BuildConfig.VERSION_CODE < data.getInt("suggestedVersionCode")) { - version = data.getJSONArray("packages").getJSONObject(0).getString("versionName"); - return true; - } - } - - conn.disconnect(); - } catch (final Exception e) { - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); - } - - return false; - } - - @Override - protected void onPostExecute(final Boolean result) { - if (result != null && result && fetchListener != null) - fetchListener.onResult("v"+version); - } -} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40838c81..e9cfe7e0 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -475,4 +475,5 @@ Delete unsuccessful Barinsta Crash Report Select an email app to send crash logs + Skip this update From 86b04e69eee1b3d5c6c265e6ddb327a7879603c5 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 28 Mar 2021 23:32:27 +0900 Subject: [PATCH 14/42] Skip update check for pre-release builds --- app/build.gradle | 3 +++ .../java/awais/instagrabber/activities/MainActivity.java | 7 +++++-- .../fragments/settings/MorePreferencesFragment.java | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9b39a1a2..f48a0439 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,11 +66,13 @@ android { dimension "repo" // versionNameSuffix "-github" // appended in assemble task buildConfigField("String", "dsn", SENTRY_DSN) + buildConfigField("boolean", "isPre", "false") } fdroid { dimension "repo" versionNameSuffix "-fdroid" + buildConfigField("boolean", "isPre", "false") } } @@ -84,6 +86,7 @@ android { def suffix = "${versionName}-${flavor}_${builtType}" // eg. 19.1.0-github_debug or release if (builtType.toString() == 'release' && project.hasProperty("pre")) { + buildConfigField("boolean", "isPre", "true") // append latest commit short hash for pre-release suffix = "${versionName}.${getGitHash()}-${flavor}" // eg. 19.1.0.b123456-github } diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 408a841a..5ea65279 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -58,6 +58,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.adapters.SuggestionsAdapter; import awais.instagrabber.asyncs.PostFetcher; @@ -163,8 +164,10 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage setupBottomNavigationBar(true); } setupSuggestions(); - final boolean checkUpdates = settingsHelper.getBoolean(Constants.CHECK_UPDATES); - if (checkUpdates) FlavorTown.updateCheck(this); + if (!BuildConfig.isPre) { + final boolean checkUpdates = settingsHelper.getBoolean(Constants.CHECK_UPDATES); + if (checkUpdates) FlavorTown.updateCheck(this); + } FlavorTown.changelogCheck(this); new ViewModelProvider(this).get(AppStateViewModel.class); // Just initiate the App state here final Intent intent = getIntent(); diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 1343bb60..684888c5 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -193,6 +193,7 @@ public class MorePreferencesFragment extends BasePreferencesFragment { BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")", -1, preference -> { + if (BuildConfig.isPre) return true; final AppCompatActivity activity = (AppCompatActivity) getActivity(); if (activity == null) return true; FlavorTown.updateCheck(activity, true); From 39b89423d981e01dbc831ac230990685a822d754 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Mon, 29 Mar 2021 22:42:08 +0900 Subject: [PATCH 15/42] Handle all possible version names in update checker --- .../awais/instagrabber/utils/FlavorTown.java | 38 ++++++++++++++++--- .../instagrabber/utils/UpdateCheckCommon.java | 3 +- app/src/main/res/values/strings.xml | 1 + 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java index 7083c694..8f06eb8b 100755 --- a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java +++ b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java @@ -1,12 +1,16 @@ package awais.instagrabber.utils; import android.content.Context; +import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import awais.instagrabber.BuildConfig; import awais.instagrabber.R; @@ -16,6 +20,7 @@ import static awais.instagrabber.utils.Utils.settingsHelper; public final class FlavorTown { private static final String TAG = "FlavorTown"; private static final UpdateChecker UPDATE_CHECKER = UpdateChecker.getInstance(); + private static final Pattern VERSION_NAME_PATTERN = Pattern.compile("v?(\\d+\\.\\d+\\.\\d+)(?:_?)(\\w*)(?:-?)(\\w*)"); private static boolean checking = false; @@ -28,21 +33,42 @@ public final class FlavorTown { if (checking) return; checking = true; AppExecutors.getInstance().networkIO().execute(() -> { - final String version = UPDATE_CHECKER.getLatestVersion(); - if (version == null) return; - if (force && version.equals(BuildConfig.VERSION_NAME)) { - Toast.makeText(context, "You're already on the latest version", Toast.LENGTH_SHORT).show(); + final String onlineVersionName = UPDATE_CHECKER.getLatestVersion(); + if (onlineVersionName == null) return; + final String onlineVersion = getVersion(onlineVersionName); + final String localVersion = getVersion(BuildConfig.VERSION_NAME); + if (Objects.equals(onlineVersion, localVersion)) { + if (force) { + AppExecutors.getInstance().mainThread().execute(() -> { + final Context applicationContext = context.getApplicationContext(); + // Check if app was closed or crashed before reaching here + if (applicationContext == null) return; + // Show toast if version number preference was tapped + Toast.makeText(applicationContext, R.string.on_latest_version, Toast.LENGTH_SHORT).show(); + }); + } return; } - final boolean shouldShowDialog = UpdateCheckCommon.shouldShowUpdateDialog(force, version); + final boolean shouldShowDialog = UpdateCheckCommon.shouldShowUpdateDialog(force, onlineVersionName); if (!shouldShowDialog) return; - UpdateCheckCommon.showUpdateDialog(context, version, (dialog, which) -> { + UpdateCheckCommon.showUpdateDialog(context, onlineVersionName, (dialog, which) -> { UPDATE_CHECKER.onDownload(context); dialog.dismiss(); }); }); } + private static String getVersion(@NonNull final String versionName) { + final Matcher matcher = VERSION_NAME_PATTERN.matcher(versionName); + if (!matcher.matches()) return versionName; + try { + return matcher.group(1); + } catch (Exception e) { + Log.e(TAG, "getVersion: ", e); + } + return versionName; + } + public static void changelogCheck(@NonNull final Context context) { if (settingsHelper.getInteger(Constants.PREV_INSTALL_VERSION) < BuildConfig.VERSION_CODE) { int appUaCode = settingsHelper.getInteger(Constants.APP_UA_CODE); diff --git a/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java b/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java index 8377c9e4..285fbb13 100644 --- a/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java +++ b/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java @@ -17,8 +17,7 @@ public final class UpdateCheckCommon { public static boolean shouldShowUpdateDialog(final boolean force, @NonNull final String version) { final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION); - return force || (!version.equals(BuildConfig.VERSION_NAME) && !BuildConfig.DEBUG && !skippedVersion - .equals(version)); + return force || (!BuildConfig.DEBUG && !skippedVersion.equals(version)); } public static void showUpdateDialog(@NonNull final Context context, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e9cfe7e0..20ab88c0 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -476,4 +476,5 @@ Barinsta Crash Report Select an email app to send crash logs Skip this update + You\'re already on the latest version From 07f41a8a8c524e4009ea1be8f7537f86573b6f80 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Tue, 30 Mar 2021 20:44:01 +0900 Subject: [PATCH 16/42] Add GraphQl error handling --- .../instagrabber/activities/MainActivity.java | 8 +++++-- .../instagrabber/webservices/NewsService.java | 8 ++----- .../webservices/SearchService.java | 19 +++++---------- .../interceptors/IgErrorsInterceptor.java | 23 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 2da9cb24..95c801ef 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -142,8 +142,8 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); RetrofitFactory.setup(this); + super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); final String cookie = settingsHelper.getString(Constants.COOKIE); CookieUtils.setupCookies(cookie); @@ -253,7 +253,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage Log.e(TAG, "onDestroy: ", e); } unbindActivityCheckerService(); - RetrofitFactory.getInstance().destroy(); + RetrofitFactory.getInstance().destroy(); } @Override @@ -853,4 +853,8 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage public Toolbar getToolbar() { return binding.toolbar; } + + public View getRootView() { + return binding.getRoot(); + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index a7664a8a..15b34def 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -13,15 +13,11 @@ import awais.instagrabber.repositories.NewsRepository; import awais.instagrabber.repositories.responses.AymlResponse; import awais.instagrabber.repositories.responses.AymlUser; import awais.instagrabber.repositories.responses.NewsInboxResponse; -import awais.instagrabber.repositories.responses.Notification; -import awais.instagrabber.repositories.responses.NotificationArgs; -import awais.instagrabber.repositories.responses.NotificationCounts; -import awais.instagrabber.repositories.responses.NewsInboxResponse; +import awais.instagrabber.repositories.responses.User; +import awais.instagrabber.repositories.responses.UserSearchResponse; import awais.instagrabber.repositories.responses.notification.Notification; import awais.instagrabber.repositories.responses.notification.NotificationArgs; import awais.instagrabber.repositories.responses.notification.NotificationCounts; -import awais.instagrabber.repositories.responses.User; -import awais.instagrabber.repositories.responses.UserSearchResponse; import awais.instagrabber.utils.Constants; import retrofit2.Call; import retrofit2.Callback; diff --git a/app/src/main/java/awais/instagrabber/webservices/SearchService.java b/app/src/main/java/awais/instagrabber/webservices/SearchService.java index 39b5bd65..4144f85d 100644 --- a/app/src/main/java/awais/instagrabber/webservices/SearchService.java +++ b/app/src/main/java/awais/instagrabber/webservices/SearchService.java @@ -1,16 +1,10 @@ package awais.instagrabber.webservices; -import androidx.annotation.NonNull; - import com.google.common.collect.ImmutableMap; import awais.instagrabber.repositories.SearchRepository; import awais.instagrabber.repositories.responses.search.SearchResponse; -import awais.instagrabber.utils.TextUtils; import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; public class SearchService extends BaseService { private static final String TAG = "LocationService"; @@ -20,10 +14,9 @@ public class SearchService extends BaseService { private static SearchService instance; private SearchService() { - final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://www.instagram.com") - .build(); - repository = retrofit.create(SearchRepository.class); + repository = RetrofitFactory.getInstance() + .getRetrofitWeb() + .create(SearchRepository.class); } public static SearchService getInstance() { @@ -43,8 +36,8 @@ public class SearchService extends BaseService { builder.put("context", context); builder.put("count", "50"); return repository.search(isLoggedIn - ? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/" - : "https://www.instagram.com/web/search/topsearch/", - builder.build()); + ? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/" + : "https://www.instagram.com/web/search/topsearch/", + builder.build()); } } diff --git a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java index 7d424a2d..e27eeae2 100644 --- a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java +++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java @@ -1,10 +1,13 @@ package awais.instagrabber.webservices.interceptors; import android.util.Log; +import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.StringRes; +import com.google.android.material.snackbar.Snackbar; + import org.json.JSONObject; import java.io.IOException; @@ -51,6 +54,16 @@ public class IgErrorsInterceptor implements Interceptor { // show dialog? Log.e(TAG, "Network error: " + getMessage(errorCode, "The request start-line and/or headers are too large to process.")); return; + case 404: + showErrorDialog(R.string.not_found); + return; + case 302: // redirect + final String location = response.header("location"); + if (location.equals("https://www.instagram.com/accounts/login/")) { + // rate limited + showErrorDialog(R.string.rate_limit); + } + return; } final ResponseBody body = response.body(); if (body == null) return; @@ -67,9 +80,13 @@ public class IgErrorsInterceptor implements Interceptor { case "login_required": showErrorDialog(R.string.login_required); return; + case "execution failure": + showSnackbar(message); + return; case "not authorized to view user": // Do we handle this in profile view fragment? case "challenge_required": // Since we make users login using browser, we should not be getting this error in api requests default: + showSnackbar(message); Log.e(TAG, "checkError: " + bodyString); return; } @@ -88,6 +105,12 @@ public class IgErrorsInterceptor implements Interceptor { } } + private void showSnackbar(final String message) { + final View view = mainActivity.getRootView(); + if (view == null) return; + Snackbar.make(view, message, Snackbar.LENGTH_LONG).show(); + } + @NonNull private String getMessage(final int errorCode, final String message) { return String.format("code: %s, internalMessage: %s", errorCode, message); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ce22f77f..86b2d1ac 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -481,4 +481,6 @@ User is inactive! Barinsta Crash Report Select an email app to send crash logs + Not found! + Your IP has been rate limited by Instagram. Wait for an hour and try again. From a2be48029f3787028243ac01cb3d2cf17fb9cf9b Mon Sep 17 00:00:00 2001 From: junhuicoding Date: Wed, 31 Mar 2021 22:53:56 +0800 Subject: [PATCH 17/42] initial implementation --- .../DownloadsPreferencesFragment.java | 9 +++++++ .../awais/instagrabber/utils/Constants.java | 1 + .../instagrabber/utils/DownloadUtils.java | 25 +++++++++++++++---- .../instagrabber/utils/SettingsHelper.java | 3 ++- app/src/main/res/values-ca/strings.xml | 1 + app/src/main/res/values-cs/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-eu/strings.xml | 1 + app/src/main/res/values-fa/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-hi/strings.xml | 1 + app/src/main/res/values-in/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-kn/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 1 + app/src/main/res/values-nl/strings.xml | 1 + app/src/main/res/values-or/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-sk/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-vi/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 29 files changed, 57 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java index c2637b78..63a22dd8 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java @@ -29,6 +29,7 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { if (context == null) return; screen.addPreference(getDownloadUserFolderPreference(context)); screen.addPreference(getSaveToCustomFolderPreference(context)); + screen.addPreference(getPrependUsernameToFilenamePreference(context)); } private Preference getDownloadUserFolderPreference(@NonNull final Context context) { @@ -49,6 +50,14 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { .show(getParentFragmentManager(), null)); } + private Preference getPrependUsernameToFilenamePreference(@NonNull final Context context) { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context); + preference.setKey(Constants.DOWNLOAD_PREPEND_USER_NAME); + preference.setTitle("Prepend Username to Filename"); + preference.setIconSpaceReserved(false); + return preference; + } + public static class SaveToCustomFolderPreference extends Preference { private AppCompatTextView customPathTextView; private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener; diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index 969f5d6a..0f7618c4 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -20,6 +20,7 @@ public final class Constants { // boolean prefs public static final String DOWNLOAD_USER_FOLDER = "download_user_folder"; public static final String TOGGLE_KEYWORD_FILTER = "toggle_keyword_filter"; + public static final String DOWNLOAD_PREPEND_USER_NAME = "download_user_name"; // deprecated: public static final String BOTTOM_TOOLBAR = "bottom_toolbar"; public static final String FOLDER_SAVE_TO = "saved_to"; public static final String AUTOPLAY_VIDEOS = "autoplay_videos"; diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index 85f45a21..aab36cea 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -116,7 +116,15 @@ public final class DownloadUtils { private static File getDownloadSaveFile(final File finalDir, final String postId, final String displayUrl) { - return getDownloadSaveFile(finalDir, postId, "", displayUrl); + return getDownloadSaveFile(finalDir, postId, "", displayUrl, ""); + } + + @NonNull + private static File getDownloadSaveFile(final File finalDir, + final String postId, + final String displayUrl, + final String username) { + return getDownloadSaveFile(finalDir, postId, "", displayUrl, username); } private static File getDownloadChildSaveFile(final File downloadDir, @@ -131,8 +139,10 @@ public final class DownloadUtils { private static File getDownloadSaveFile(final File finalDir, final String postId, final String sliderPostfix, - final String displayUrl) { - final String fileName = postId + sliderPostfix + getFileExtensionFromUrl(displayUrl); + final String displayUrl, + final String username) { + String usernamePrepend = (username.equals("")) ? "" : "@" + username + "_"; + final String fileName = usernamePrepend + postId + sliderPostfix + getFileExtensionFromUrl(displayUrl); return new File(finalDir, fileName); } @@ -263,7 +273,7 @@ public final class DownloadUtils { ? storyModel.getVideoUrl() : storyModel.getStoryUrl(); final File saveFile = new File(downloadDir, - storyModel.getStoryMediaId() + storyModel.getUsername() + storyModel.getStoryMediaId() + "_" + storyModel.getTimestamp() + DownloadUtils.getFileExtensionFromUrl(url)); download(context, url, saveFile.getAbsolutePath()); @@ -297,7 +307,12 @@ public final class DownloadUtils { case MEDIA_TYPE_IMAGE: case MEDIA_TYPE_VIDEO: { final String url = getUrlOfType(media); - final File file = getDownloadSaveFile(downloadDir, media.getCode(), url); + final File file; + if (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) && mediaUser != null) { + file = getDownloadSaveFile(downloadDir, media.getCode(), url, mediaUser.getUsername()); + } else { + file = getDownloadSaveFile(downloadDir, media.getCode(), url); + } map.put(url, file.getAbsolutePath()); break; } diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index 1ff49767..dd3437de 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -33,6 +33,7 @@ import static awais.instagrabber.utils.Constants.DATE_TIME_SELECTION; import static awais.instagrabber.utils.Constants.DEFAULT_TAB; import static awais.instagrabber.utils.Constants.DEVICE_UUID; import static awais.instagrabber.utils.Constants.DM_MARK_AS_SEEN; +import static awais.instagrabber.utils.Constants.DOWNLOAD_PREPEND_USER_NAME; import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER; import static awais.instagrabber.utils.Constants.FLAG_SECURE; import static awais.instagrabber.utils.Constants.FOLDER_PATH; @@ -158,7 +159,7 @@ public final class SettingsHelper { STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT}) public @interface StringSettings {} - @StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, + @StringDef({DOWNLOAD_USER_FOLDER, DOWNLOAD_PREPEND_USER_NAME, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY, CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH, FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY}) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 18b0557d..02092f94 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -23,6 +23,7 @@ Cerca actualitzacions a l\'inici Block screenshots & app preview Descarrega les publicacions a carpetes de nom d\'usuari + Prepend Username to Filename Marca les històries com a vistes després de visualitzar-es L\'autor de la història sabrà que l\'has vista Marca els missatges com a vists després de visualitzar-los diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 0bb9e0ac..c5bc0f11 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -23,6 +23,7 @@ Zkontrolovat aktualizace při spuštění Block screenshots & app preview Stáhnout příspěvky do složek s uživatelským jménem + Prepend Username to Filename Označit příběhy po zhlédnutí jako zobrazené Autor příběhu bude vědět, že jsi si ho zobrazili Označovat přímou zprávu po zobrazení jako zobrazenou diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1f541fcd..e023c6b9 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -23,6 +23,7 @@ Beim Start auf Aktualisierungen prüfen Block screenshots & app preview Beiträge in Benutzernamen-Ordner herunterladen + Prepend Username to Filename Stories nach dem Ansehen als gesehen markieren Die Person wird wissen, dass du dir die Story angesehen hast Direktnachrichten nach dem Ansehen als gesehen markieren diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index f9817a0a..b8c7df56 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -23,6 +23,7 @@ Έλεγχος για ενημερώσεις στο ξεκίνημα Block screenshots & app preview Λήψη δημοσίευσης στους φακέλους με ονόματα χρηστών + Prepend Username to Filename Επισήμανση ιστοριών ως προβληθέντων μετά την προβολή Ο συντάκτης της ιστορίας θα ξέρει ότι την προβάλατε Σήμανση ΠΜ ως αναγνωσμένου μετά την προβολή diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f392ec86..9ee7d1d0 100755 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -23,6 +23,7 @@ Buscar actualizaciones al inicio Bloquea capturas de pantalla & vista previa de aplicaciones Usar subcarpetas con el nombre de usuario + Prepend Username to Filename Marcar historias como vistas después de verlas El autor de la historia sabrá que lo has visto Marcar Mensaje Directo como visto después de verlo diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index dd0321e2..8f217f17 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -23,6 +23,7 @@ Bilatu eguneratzeak abioan Block screenshots & app preview Deskargatu bidalketak erabiltzaile-izena duten karpetetara + Prepend Username to Filename Markatu istorioak ikusita gisa ikusi ondoren Istorioaren egileak ikusi duzula jakingo du Markatu MZ ikusita gisa ikusi ondoren diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index c6da89cf..75371835 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -23,6 +23,7 @@ بررسی بروزرسانی هنگام آغاز برنامه Block screenshots & app preview بارگیری پست ها در پوشه های به نام کاربر + Prepend Username to Filename نشان کرد استوری ها به عنوان دیده شده بعد از دیدن نویسنده استوری می داند که شما آن را دیده اید نشان کردن پیام خصوصی بعنوان دیده شده بعد از دیدن diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 15f8a5cc..d2fd93dd 100755 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -23,6 +23,7 @@ Rechercher les mises à jours au démarrage Bloquer les captures d\'écran & l\'aperçu de l\'application Télécharger les messages dans les dossiers des noms d\'utilisateurs + Prepend Username to Filename Marquer les stories comme vues après consultation L\'auteur de la story saura que vous l\'avez vue Marquer les messages privés comme vus après consultation diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index bc923135..623bc2ce 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -23,6 +23,7 @@ खुलने पर अपडेट के लिए जाँच करें Block screenshots & app preview पोस्ट को ब्यबहारकारी के नाम पर किये फोल्डरस में रखें + Prepend Username to Filename स्टोरि को दिखने के बाद \"दिखा गया\" दिखादें सटोरि के लेखक जानेगा कि तुम देखे हो इसको तुम देखने के बाद सीधा संदेश को \"दिखागया\" लिखा जाएगा diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 462c1a2e..6801759b 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -23,6 +23,7 @@ Cek pembaruan saat memulai Block screenshots & app preview Unduh kiriman ke folder nama pengguna + Prepend Username to Filename Tandai cerita dibaca setelah melihat Pembuat cerita akan tahu Anda melihatnya Tandai DM dibaca setelah melihat diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d8202389..eefead25 100755 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -23,6 +23,7 @@ Verifica per aggiornamenti all\'avvio Blocca screenshot & anteprima app Scarica i post nelle cartelle del nome utente + Prepend Username to Filename Segna le storie come viste dopo la visualizzazione L\'autore della storia saprà che l\'hai visualizzata Segna il DM come visto dopo la visualizzazione diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 5a11dc06..178f3726 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -23,6 +23,7 @@ 起動時にアップデートを確認 Block screenshots & app preview ユーザ名のフォルダに投稿をダウンロード + Prepend Username to Filename ストーリーズを表示後に既読にする ストーリーの作成者は、あなたが閲覧したことを知ることができます。 DMを表示後に既読にする diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml index 80d8b915..85c0390c 100644 --- a/app/src/main/res/values-kn/strings.xml +++ b/app/src/main/res/values-kn/strings.xml @@ -23,6 +23,7 @@ Check for updates at startup Block screenshots & app preview Download posts to username folders + Prepend Username to Filename Mark stories as seen after viewing Story author will know you viewed it Mark DM as seen after viewing diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index abb89551..118e07f4 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -23,6 +23,7 @@ Провери за ажурирање Block screenshots & app preview Превземи објави во папката со кориснички имиња + Prepend Username to Filename Означи ги приказните како видени Авторот на приказната ќе знае дека сте ја погледнале приказната Означи порака како видена diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index fda4c863..b904bed6 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -23,6 +23,7 @@ Controleer op updates bij het opstarten Block screenshots & app preview Download berichten naar gebruikersnaam mappen + Prepend Username to Filename Markeer verhalen als gelezen na bekijken Verhaalmaker zal het weten als je het bekeken hebt Markeer privéberichten als gelezen na bekijken diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index ce4427ec..12b95d7b 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -23,6 +23,7 @@ ଖୋଲିବା ସମୟରେ ଅପଡେଟ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ Block screenshots & app preview ଡାଉନଲୋଡ ପୋଷ୍ଟକୁ ବ୍ୟବହାରକାରୀଙ୍କ ନାମରେ ହୋଇଥିବା ସ୍ଥାନ ରେ ରଖ + Prepend Username to Filename କାହାଣୀଗୁଡିକ ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ | କାହାଣୀ ପ୍ରେରକ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ ବାର୍ତା ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ | diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 93fb3ff8..2c449634 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -23,6 +23,7 @@ Sprawdź aktualizacje przy starcie Blokuj zrzuty ekranu & podgląd aplikacji Pobierz posty do folderów o nazwie użytkownika + Prepend Username to Filename Oznacz relacje jako widoczne po wyświetleniu Autor relacji będzie widział, że to wyświetliłeś Oznacz wiadomość jako przeczytaną diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 4c7bbbc4..f8c3f401 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -23,6 +23,7 @@ Verificar se há atualizações ao iniciar Block screenshots & app preview Baixar publicações para pastas com o nome de usuário + Prepend Username to Filename Marcar stories como vistos após a visualização O autor do story saberá que você viu Marcar DM como vista após a visualização diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b491a1c5..ca3155ef 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -23,6 +23,7 @@ Проверять наличие обновлений при запуске Block screenshots & app preview Скачать публикации в папки с именем пользователя + Prepend Username to Filename Отметить истории как увиденные после просмотра Автор истории узнает, что вы просмотрели её Отметить ЛС как увиденные после просмотра diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index f12178ec..7b1c175a 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -23,6 +23,7 @@ Kontrolovať aktualizácie pri štarte Block screenshots & app preview Ukľadať do priečinkov podľa mena + Prepend Username to Filename Označiť príbehy po videní ako videné Autor príbehu bude vedieť že ste ho videli Po prečítaní, označiť správu ako prečítanú diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 4ca6836d..fea3a299 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -23,6 +23,7 @@ Güncellemeleri başlangıçta kontrol et Block screenshots & app preview İndirmeleri kullanıcı adından oluşan bir alt klasörün içine yap + Prepend Username to Filename Hikayeleri gördükten sonra görüldü olarak işaretle Hikayeyi paylaşan gördüğünüzü bilecek DM\'leri gördükten sonra görüldü olarak işaretle diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index debb92fc..858193f6 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -23,6 +23,7 @@ Kiểm tra cập nhật khi khởi động Block screenshots & app preview Tải bài viết xuống theo thư mục tên người dùng trong Downloads + Prepend Username to Filename Đánh dấu story là đã xem sau khi xem Người đăng story sẽ biết bạn đã xem nó Đánh dấu DM là đã xem sau khi xem diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index a6fe9c77..0fb2193f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -23,6 +23,7 @@ 启动时检查更新 屏蔽截图及应用预览 下载帖子到用户名文件夹 + Prepend Username to Filename 查看快拍后将其标记为已读 快拍作者会知道您已看过 查看私信后将其标记为已读 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 26371e94..3ce706fa 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -23,6 +23,7 @@ 啟動時檢查更新 Block screenshots & app preview 將貼文下載到用戶名資料夾 + Prepend Username to Filename 檢視完限時動態後標記為已讀 限時動態的作者會知道您已查看了此限時動態 檢視完訊息後標記為已讀 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d3b7cf2b..11a44e5d 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,6 +26,7 @@ Check for updates at startup Block screenshots & app preview Download posts to username folders + Prepend Username to Filename Mark stories as seen after viewing Story author will know you viewed it Mark DM as seen after viewing From 50432468e579317e646e1332274a2393cd287724 Mon Sep 17 00:00:00 2001 From: junhuicoding Date: Wed, 31 Mar 2021 23:58:17 +0800 Subject: [PATCH 18/42] Updated username prepending for sliders and stories --- .../instagrabber/utils/DownloadUtils.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index aab36cea..fe92a0ce 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -130,9 +130,10 @@ public final class DownloadUtils { private static File getDownloadChildSaveFile(final File downloadDir, final String postId, final int childPosition, - final String url) { + final String url, + final String username) { final String sliderPostfix = "_slide_" + childPosition; - return getDownloadSaveFile(downloadDir, postId, sliderPostfix, url); + return getDownloadSaveFile(downloadDir, postId, sliderPostfix, url, username); } @NonNull @@ -211,11 +212,13 @@ public final class DownloadUtils { username = user.getUsername(); } final File downloadDir = getDownloadDir(null, "@" + username, true); + String usernamePrepend = (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) + && user != null) ? username : ""; switch (media.getMediaType()) { case MEDIA_TYPE_IMAGE: case MEDIA_TYPE_VIDEO: { final String url = ResponseBodyUtils.getImageUrl(media); - final File file = getDownloadSaveFile(downloadDir, media.getCode(), url); + final File file = getDownloadSaveFile(downloadDir, media.getCode(), url, usernamePrepend); checkList.add(file.exists()); break; } @@ -225,7 +228,7 @@ public final class DownloadUtils { final Media child = sliderItems.get(i); if (child == null) continue; final String url = ResponseBodyUtils.getImageUrl(child); - final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url); + final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, username); checkList.add(file.exists()); } break; @@ -272,10 +275,12 @@ public final class DownloadUtils { final String url = storyModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO ? storyModel.getVideoUrl() : storyModel.getStoryUrl(); + final String baseFileName = storyModel.getStoryMediaId() + "_" + + storyModel.getTimestamp() + DownloadUtils.getFileExtensionFromUrl(url); + String usernamePrepend = (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) + && storyModel.getUsername() != null) ? "@" + storyModel.getUsername() + "_" : ""; final File saveFile = new File(downloadDir, - storyModel.getUsername() + storyModel.getStoryMediaId() - + "_" + storyModel.getTimestamp() - + DownloadUtils.getFileExtensionFromUrl(url)); + usernamePrepend + baseFileName); download(context, url, saveFile.getAbsolutePath()); } @@ -307,7 +312,7 @@ public final class DownloadUtils { case MEDIA_TYPE_IMAGE: case MEDIA_TYPE_VIDEO: { final String url = getUrlOfType(media); - final File file; + File file; if (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) && mediaUser != null) { file = getDownloadSaveFile(downloadDir, media.getCode(), url, mediaUser.getUsername()); } else { @@ -334,7 +339,8 @@ public final class DownloadUtils { } final Media child = sliderItems.get(i); final String url = getUrlOfType(child); - final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url); + String usernamePrepend = (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) && mediaUser != null) ? mediaUser.getUsername() : ""; + final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, usernamePrepend); map.put(url, file.getAbsolutePath()); } break; From 7f5b91e343f01e1266133d3cf87bcc27b1512796 Mon Sep 17 00:00:00 2001 From: junhuicoding Date: Thu, 1 Apr 2021 00:24:15 +0800 Subject: [PATCH 19/42] nullchecker fix for profileModel --- .../instagrabber/fragments/main/ProfileFragment.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 4b3bfcfd..2f040392 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -604,10 +604,12 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe usernameTemp = usernameTemp.substring(1); } if (TextUtils.isEmpty(usernameTemp)) { - profileModel = appStateViewModel.getCurrentUser(); - username = profileModel.getUsername(); - setUsernameDelayed(); - setProfileDetails(); + profileModel = appStateViewModel.getCurrentUser(); + if (profileModel != null) { + username = profileModel.getUsername(); + setUsernameDelayed(); + setProfileDetails(); + } } else if (isLoggedIn) { userService.getUsernameInfo(usernameTemp, new ServiceCallback() { From f1df75860b5f66fbe2fa9430d4ecd11b940fb77b Mon Sep 17 00:00:00 2001 From: junhuicoding Date: Thu, 1 Apr 2021 00:48:58 +0800 Subject: [PATCH 20/42] Fix Codacy Issues --- .../main/java/awais/instagrabber/utils/DownloadUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index fe92a0ce..d06ef850 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -142,7 +142,7 @@ public final class DownloadUtils { final String sliderPostfix, final String displayUrl, final String username) { - String usernamePrepend = (username.equals("")) ? "" : "@" + username + "_"; + final String usernamePrepend = "".equals(username) ? "" : "@" + username + "_"; final String fileName = usernamePrepend + postId + sliderPostfix + getFileExtensionFromUrl(displayUrl); return new File(finalDir, fileName); } @@ -212,8 +212,8 @@ public final class DownloadUtils { username = user.getUsername(); } final File downloadDir = getDownloadDir(null, "@" + username, true); - String usernamePrepend = (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) - && user != null) ? username : ""; + final String usernamePrepend = Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) + && user != null ? username : ""; switch (media.getMediaType()) { case MEDIA_TYPE_IMAGE: case MEDIA_TYPE_VIDEO: { @@ -339,7 +339,7 @@ public final class DownloadUtils { } final Media child = sliderItems.get(i); final String url = getUrlOfType(child); - String usernamePrepend = (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) && mediaUser != null) ? mediaUser.getUsername() : ""; + final String usernamePrepend = Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) && mediaUser != null ? mediaUser.getUsername() : ""; final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, usernamePrepend); map.put(url, file.getAbsolutePath()); } From 2d2ad6130b6ca12ec3e9e8fa91b64ad7103bf529 Mon Sep 17 00:00:00 2001 From: junhuicoding Date: Thu, 1 Apr 2021 00:55:20 +0800 Subject: [PATCH 21/42] Fix Codacy Issues --- app/src/main/java/awais/instagrabber/utils/DownloadUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index d06ef850..cb3c5273 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -277,8 +277,8 @@ public final class DownloadUtils { : storyModel.getStoryUrl(); final String baseFileName = storyModel.getStoryMediaId() + "_" + storyModel.getTimestamp() + DownloadUtils.getFileExtensionFromUrl(url); - String usernamePrepend = (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) - && storyModel.getUsername() != null) ? "@" + storyModel.getUsername() + "_" : ""; + final String usernamePrepend = Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) + && storyModel.getUsername() != null ? "@" + storyModel.getUsername() + "_" : ""; final File saveFile = new File(downloadDir, usernamePrepend + baseFileName); download(context, url, saveFile.getAbsolutePath()); From 23611df3feffbe128e904f4143010c5128893c05 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 2 Apr 2021 12:01:29 -0400 Subject: [PATCH 22/42] make isNavRootInCurrentTabs consistent, show/hide explore --- .../instagrabber/activities/MainActivity.java | 6 +++--- .../fragments/main/ProfileFragment.java | 2 +- .../settings/MorePreferencesFragment.java | 17 +++++++++++++++-- .../java/awais/instagrabber/utils/Utils.java | 8 +++++++- app/src/main/res/navigation/more_nav_graph.xml | 1 + 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index fa6b65f2..b03a3696 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -906,9 +906,9 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage return currentTabs; } - public boolean isNavRootInCurrentTabs(@IdRes final int navRootId) { - return showBottomViewDestinations.stream().anyMatch(id -> id == navRootId); - } +// public boolean isNavRootInCurrentTabs(@IdRes final int navRootId) { +// return showBottomViewDestinations.stream().anyMatch(id -> id == navRootId); +// } private void setNavBarDMUnreadCountBadge(final int unseenCount) { final BadgeDrawable badge = binding.bottomNavView.getOrCreateBadge(R.id.direct_messages_nav_graph); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 2cb002ff..cc2ce13a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -580,7 +580,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } private void init() { - disableDm = !fragmentActivity.isNavRootInCurrentTabs(R.id.directMessagesInboxFragment); + disableDm = !Utils.isNavRootInCurrentTabs("direct_messages_nav_graph"); if (getArguments() != null) { final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments()); username = fragmentArgs.getUsername(); diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 947996a2..ecfcff77 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -39,6 +39,7 @@ import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.FlavorTown; import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.utils.Utils; import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.UserService; @@ -59,6 +60,7 @@ public class MorePreferencesFragment extends BasePreferencesFragment { final MainActivity activity = (MainActivity) getActivity(); // screen.addPreference(new MoreHeaderPreference(getContext())); final Context context = getContext(); + final Resources resources = context.getResources(); if (context == null) return; accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context)); final PreferenceCategory accountCategory = new PreferenceCategory(context); @@ -138,8 +140,10 @@ public class MorePreferencesFragment extends BasePreferencesFragment { final NavController navController = NavHostFragment.findNavController(this); if (isLoggedIn) { boolean showActivity = true; + boolean showExplore = false; if (activity != null) { - showActivity = !activity.isNavRootInCurrentTabs(R.id.notificationsViewer); + showActivity = !Utils.isNavRootInCurrentTabs("notification_viewer_nav_graph"); + showExplore = !Utils.isNavRootInCurrentTabs("discover_nav_graph"); } if (showActivity) { screen.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> { @@ -150,6 +154,15 @@ public class MorePreferencesFragment extends BasePreferencesFragment { return true; })); } + if (showExplore) { + screen.addPreference(getPreference(R.string.title_discover, R.drawable.ic_explore_24, preference -> { + if (isSafeToNavigate(navController)) { + navController.navigate(R.id.discover_nav_graph); + } + return true; + })); + } + screen.addPreference(getPreference(R.string.action_ayml, R.drawable.ic_suggested_users, preference -> { if (isSafeToNavigate(navController)) { final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml"); @@ -169,7 +182,7 @@ public class MorePreferencesFragment extends BasePreferencesFragment { // Check if favorites has been added as a tab. And if so, do not add in this list boolean showFavorites = true; if (activity != null) { - showFavorites = !activity.isNavRootInCurrentTabs(R.id.favoritesFragment); + showFavorites = !Utils.isNavRootInCurrentTabs("favorites_nav_graph"); } if (showFavorites) { screen.addPreference(getPreference(R.string.title_favorites, R.drawable.ic_star_24, preference -> { diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index 7d0afd2b..6f966c33 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -31,6 +31,7 @@ import android.webkit.MimeTypeMap; import android.widget.Toast; import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; @@ -80,6 +81,7 @@ public final class Utils { private static int actionBarHeight; public static Handler applicationHandler; public static String cacheDir; + public static String tabOrderString; private static int defaultStatusBarColor; public static int convertDpToPx(final float dp) { @@ -468,7 +470,7 @@ public final class Utils { @NonNull private static List getCurrentOrderOfGraphNamesFromPref(@NonNull final String[] navGraphNames) { - final String tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); + tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); final List navGraphNameList = Arrays.asList(navGraphNames); if (TextUtils.isEmpty(tabOrderString)) { // Use top 5 entries for default list @@ -485,4 +487,8 @@ public final class Utils { } return orderGraphNames; } + + public static boolean isNavRootInCurrentTabs(final String navRootString) { + return tabOrderString.contains(navRootString); + } } diff --git a/app/src/main/res/navigation/more_nav_graph.xml b/app/src/main/res/navigation/more_nav_graph.xml index 84ae9423..0274390e 100644 --- a/app/src/main/res/navigation/more_nav_graph.xml +++ b/app/src/main/res/navigation/more_nav_graph.xml @@ -11,6 +11,7 @@ + Date: Fri, 2 Apr 2021 13:22:46 -0400 Subject: [PATCH 23/42] close #880 --- .../instagrabber/utils/ExportImportUtils.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java index ca5ca21c..a0a2e190 100755 --- a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java @@ -156,12 +156,21 @@ public final class ExportImportUtils { query, favoriteType, favsObject.optString("s"), - favoriteType == FavoriteType.HASHTAG ? null - : favsObject.optString("pic_url"), + favoriteType == FavoriteType.USER ? favsObject.optString("pic_url") : null, new Date(favsObject.getLong("d"))); // Log.d(TAG, "importJson: favoriteModel: " + favoriteModel); - FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context)) - .insertOrUpdateFavorite(favorite, null); + final FavoriteRepository favRepo = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context)); + favRepo.getFavorite(query, favoriteType, new RepositoryCallback() { + @Override + public void onSuccess(final Favorite result) { + // local has priority since it's more frequently updated + } + + @Override + public void onDataNotAvailable() { + favRepo.insertOrUpdateFavorite(favorite, null); + } + }); } } From f0167f2d933fb6e7d09cc2dd8b1b83c220faa6bb Mon Sep 17 00:00:00 2001 From: junhuicoding Date: Sat, 3 Apr 2021 01:24:13 +0800 Subject: [PATCH 24/42] Resolve PR comments --- .../fragments/settings/DownloadsPreferencesFragment.java | 2 +- app/src/main/java/awais/instagrabber/utils/DownloadUtils.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java index 63a22dd8..4e75a97f 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java @@ -53,7 +53,7 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { private Preference getPrependUsernameToFilenamePreference(@NonNull final Context context) { final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context); preference.setKey(Constants.DOWNLOAD_PREPEND_USER_NAME); - preference.setTitle("Prepend Username to Filename"); + preference.setTitle(R.string.download_prepend_username); preference.setIconSpaceReserved(false); return preference; } diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index cb3c5273..52b6a41d 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -142,7 +142,7 @@ public final class DownloadUtils { final String sliderPostfix, final String displayUrl, final String username) { - final String usernamePrepend = "".equals(username) ? "" : "@" + username + "_"; + final String usernamePrepend = TextUtils.isEmpty(username) ? "" : "@" + username + "_"; final String fileName = usernamePrepend + postId + sliderPostfix + getFileExtensionFromUrl(displayUrl); return new File(finalDir, fileName); } @@ -228,7 +228,7 @@ public final class DownloadUtils { final Media child = sliderItems.get(i); if (child == null) continue; final String url = ResponseBodyUtils.getImageUrl(child); - final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, username); + final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, usernamePrepend); checkList.add(file.exists()); } break; From ee95c3f77d060f1c4366da377372047efbed4a43 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 2 Apr 2021 14:03:54 -0400 Subject: [PATCH 25/42] fix image resolution mechanism --- .../awais/instagrabber/utils/ResponseBodyUtils.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index 2722d11e..0d7acc16 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -1090,11 +1090,19 @@ public final class ResponseBodyUtils { if (imageVersions2 == null) return null; final List candidates = imageVersions2.getCandidates(); if (candidates == null || candidates.isEmpty()) return null; + final boolean isSquare = Integer.compare(media.getOriginalWidth(), media.getOriginalHeight()) == 0; final List sortedCandidates = candidates.stream() .sorted((c1, c2) -> Integer.compare(c2.getWidth(), c1.getWidth())) - .filter(c -> c.getWidth() < type.getValue()) .collect(Collectors.toList()); - final MediaCandidate candidate = sortedCandidates.get(0); + if (sortedCandidates.size() == 1) return sortedCandidates.get(0).getUrl(); + final List filteredCandidates = sortedCandidates.stream() + .filter(c -> + c.getWidth() <= media.getOriginalWidth() + && c.getWidth() <= type.getValue() + && (isSquare || Integer.compare(c.getWidth(), c.getHeight()) != 0) + ) + .collect(Collectors.toList()); + final MediaCandidate candidate = filteredCandidates.get(0); if (candidate == null) return null; return candidate.getUrl(); } From f9816ec335adcc18dcc74e714659c0f54831bcda Mon Sep 17 00:00:00 2001 From: junhuicoding Date: Sat, 3 Apr 2021 04:05:00 +0800 Subject: [PATCH 26/42] Fix checkDownloaded to check for both with and without username --- .../java/awais/instagrabber/utils/DownloadUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index 52b6a41d..b125b320 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -212,14 +212,13 @@ public final class DownloadUtils { username = user.getUsername(); } final File downloadDir = getDownloadDir(null, "@" + username, true); - final String usernamePrepend = Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) - && user != null ? username : ""; switch (media.getMediaType()) { case MEDIA_TYPE_IMAGE: case MEDIA_TYPE_VIDEO: { final String url = ResponseBodyUtils.getImageUrl(media); - final File file = getDownloadSaveFile(downloadDir, media.getCode(), url, usernamePrepend); - checkList.add(file.exists()); + final File file = getDownloadSaveFile(downloadDir, media.getCode(), url, ""); + final File usernamePrependedFile = getDownloadSaveFile(downloadDir, media.getCode(), url, username); + checkList.add(file.exists() || usernamePrependedFile.exists()); break; } case MEDIA_TYPE_SLIDER: @@ -228,8 +227,9 @@ public final class DownloadUtils { final Media child = sliderItems.get(i); if (child == null) continue; final String url = ResponseBodyUtils.getImageUrl(child); - final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, usernamePrepend); - checkList.add(file.exists()); + final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, ""); + final File usernamePrependedFile = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url, username); + checkList.add(file.exists() || usernamePrependedFile.exists()); } break; default: From d0e01b3b9b79b5d2449c0cc4b34d16c176459372 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 2 Apr 2021 16:59:28 -0400 Subject: [PATCH 27/42] fix notification navigation in pursuant to #850 --- .../NotificationsViewerFragment.java | 3 +-- .../settings/MorePreferencesFragment.java | 2 -- .../notification_viewer_nav_graph.xml | 11 ++++++++++ .../main/res/navigation/profile_nav_graph.xml | 20 ++++++++++++++++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java index d9b56ce7..77157ab6 100644 --- a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java @@ -31,7 +31,6 @@ import awais.instagrabber.R; import awais.instagrabber.adapters.NotificationsAdapter; import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener; import awais.instagrabber.databinding.FragmentNotificationsViewerBinding; -import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections; import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.requests.StoryViewerOptions; import awais.instagrabber.repositories.responses.FriendshipChangeResponse; @@ -278,7 +277,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe } private void openProfile(final String username) { - final NavDirections action = MorePreferencesFragmentDirections + final NavDirections action = NotificationsViewerFragmentDirections .actionGlobalProfileFragment("@" + username); NavHostFragment.findNavController(this).navigate(action); } diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 6e9e13fd..a7d39fc8 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -223,8 +223,6 @@ public class MorePreferencesFragment extends BasePreferencesFragment { -1, preference -> { if (BuildConfig.isPre) return true; - final AppCompatActivity activity = (AppCompatActivity) getActivity(); - if (activity == null) return true; FlavorTown.updateCheck(activity, true); return true; })); diff --git a/app/src/main/res/navigation/notification_viewer_nav_graph.xml b/app/src/main/res/navigation/notification_viewer_nav_graph.xml index 89df18be..8f80b18e 100644 --- a/app/src/main/res/navigation/notification_viewer_nav_graph.xml +++ b/app/src/main/res/navigation/notification_viewer_nav_graph.xml @@ -24,6 +24,17 @@ app:destination="@id/storyViewerFragment" /> + + + + + + diff --git a/app/src/main/res/navigation/profile_nav_graph.xml b/app/src/main/res/navigation/profile_nav_graph.xml index 8ef07dca..8bff84b8 100644 --- a/app/src/main/res/navigation/profile_nav_graph.xml +++ b/app/src/main/res/navigation/profile_nav_graph.xml @@ -71,11 +71,9 @@ app:argType="long" /> - - + app:destination="@id/notificationsViewer"> + + + + + Date: Fri, 2 Apr 2021 17:14:37 -0400 Subject: [PATCH 28/42] muted reels behaviour setting --- .../settings/StoriesPreferencesFragment.java | 8 +++++ .../awais/instagrabber/utils/Constants.java | 1 + .../instagrabber/utils/SettingsHelper.java | 3 +- .../webservices/StoriesService.java | 32 ++++++++++++------- app/src/main/res/values/strings.xml | 1 + 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java index 8337f7c3..99eee7c7 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java @@ -37,6 +37,14 @@ public class StoriesPreferencesFragment extends BasePreferencesFragment { return preference; } + private Preference getHideMutedReelsPreference(@NonNull final Context context) { + final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context); + preference.setKey(Constants.HIDE_MUTED_REELS); + preference.setTitle(R.string.hide_muted_reels_setting); + preference.setIconSpaceReserved(false); + return preference; + } + private Preference getMarkStoriesSeenPreference(@NonNull final Context context) { final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context); preference.setKey(Constants.MARK_AS_SEEN); diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index f6da0362..d305010b 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -28,6 +28,7 @@ public final class Constants { public static final String CUSTOM_DATE_TIME_FORMAT_ENABLED = "data_time_custom_enabled"; public static final String SWAP_DATE_TIME_FORMAT_ENABLED = "swap_date_time_enabled"; public static final String MARK_AS_SEEN = "mark_as_seen"; + public static final String HIDE_MUTED_REELS = "hide_muted_reels"; public static final String DM_MARK_AS_SEEN = "dm_mark_as_seen"; // deprecated: public static final String INSTADP = "instadp"; // deprecated: public static final String STORIESIG = "storiesig"; diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index 9ae6cfd4..7b89597d 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -38,6 +38,7 @@ import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER; import static awais.instagrabber.utils.Constants.FLAG_SECURE; import static awais.instagrabber.utils.Constants.FOLDER_PATH; import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO; +import static awais.instagrabber.utils.Constants.HIDE_MUTED_REELS; import static awais.instagrabber.utils.Constants.KEYWORD_FILTERS; import static awais.instagrabber.utils.Constants.MARK_AS_SEEN; import static awais.instagrabber.utils.Constants.MUTED_VIDEOS; @@ -162,7 +163,7 @@ public final class SettingsHelper { @StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY, CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH, - FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY}) + FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY, HIDE_MUTED_REELS}) public @interface BooleanSettings {} @StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER}) diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index 9b47839b..5901ad7b 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -137,7 +137,7 @@ public class StoriesService extends BaseService { final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray"); for (int i = 0; i < feedStoriesReel.length(); ++i) { final JSONObject node = feedStoriesReel.getJSONObject(i); - if (node.optBoolean("hide_from_feed_unit")) continue; + if (node.optBoolean("hide_from_feed_unit") && Utils.settingsHelper.getBoolean(Constants.HIDE_MUTED_REELS)) continue; final JSONObject userJson = node.getJSONObject(node.has("user") ? "user" : "owner"); try { final User user = new User(userJson.getLong("pk"), @@ -179,17 +179,22 @@ public class StoriesService extends BaseService { null, null ); - final String id = node.getString("id"); final long timestamp = node.getLong("latest_reel_media"); - final int mediaCount = node.getInt("media_count"); final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp; final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").optJSONObject(0) : null; - final boolean isBestie = node.optBoolean("has_besties_media", false); StoryModel firstStoryModel = null; if (itemJson != null) { firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null); } - feedStoryModels.add(new FeedStoryModel(id, user, fullyRead, timestamp, firstStoryModel, mediaCount, false, isBestie)); + feedStoryModels.add(new FeedStoryModel( + node.getString("id"), + user, + fullyRead, + timestamp, + firstStoryModel, + node.getInt("media_count"), + false, + node.optBoolean("has_besties_media"))); } catch (Exception e) {} // to cover promotional reels with non-long user pk's } @@ -242,13 +247,16 @@ public class StoriesService extends BaseService { null, null ); - final String id = node.getString("id"); - final long timestamp = node.getLong("published_time"); - // final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").getJSONObject(0) : null; - final StoryModel firstStoryModel = ResponseBodyUtils.parseBroadcastItem(node); - // if (itemJson != null) { - // } - feedStoryModels.add(new FeedStoryModel(id, user, false, timestamp, firstStoryModel, 1, true, false)); + feedStoryModels.add(new FeedStoryModel( + node.getString("id"), + user, + false, + node.getLong("published_time"), + ResponseBodyUtils.parseBroadcastItem(node), + 1, + true, + false + )); } callback.onSuccess(sort(feedStoryModels)); } catch (JSONException e) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ab8c25f3..ac325b4a 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -28,6 +28,7 @@ Download posts to username folders Mark stories as seen after viewing Story author will know you viewed it + Hide muted stories from feed Mark DM as seen after viewing Other members will know you viewed it Enable activity notifications From ddb911624cfcc5f475fa4d28e453dd7180382b3f Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 2 Apr 2021 17:26:44 -0400 Subject: [PATCH 29/42] dm attachment filename issue --- .../instagrabber/utils/DownloadUtils.java | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index 85f45a21..12b46b35 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -98,19 +98,19 @@ public final class DownloadUtils { // } // } - private static void dmDownloadImpl(@NonNull final Context context, - @Nullable final String username, - final String modelId, - final String url) { - final File dir = getDownloadDir(context, username); - if (dir.exists() || dir.mkdirs()) { - download(context, - url, - getDownloadSaveFile(dir, modelId, url).getAbsolutePath()); - return; - } - Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show(); - } +// private static void dmDownloadImpl(@NonNull final Context context, +// @Nullable final String username, +// final String modelId, +// final String url) { +// final File dir = getDownloadDir(context, username); +// if (dir.exists() || dir.mkdirs()) { +// download(context, +// url, +// getDownloadSaveFile(dir, modelId, url).getAbsolutePath()); +// return; +// } +// Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show(); +// } @NonNull private static File getDownloadSaveFile(final File finalDir, @@ -297,7 +297,14 @@ public final class DownloadUtils { case MEDIA_TYPE_IMAGE: case MEDIA_TYPE_VIDEO: { final String url = getUrlOfType(media); - final File file = getDownloadSaveFile(downloadDir, media.getCode(), url); + String fileName = media.getId(); + if (mediaUser != null) { + fileName = mediaUser.getUsername() + "_" + fileName; + } + if (!TextUtils.isEmpty(media.getCode())) { + fileName = media.getCode(); + } + final File file = getDownloadSaveFile(downloadDir, fileName, url); map.put(url, file.getAbsolutePath()); break; } From bde319ecd46ca4f56e03845a036c33b6c40d0e78 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 20:23:03 +0900 Subject: [PATCH 30/42] 1. Fix NavDirection compile issue. 2. Fix null pointer if tab order pref is null. 3. Set initial tab order in pref if empty. --- .../NotificationsViewerFragment.java | 7 ++-- .../java/awais/instagrabber/utils/Utils.java | 7 +++- .../notification_viewer_nav_graph.xml | 38 +++++++++---------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java index 77157ab6..60c4a7be 100644 --- a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java @@ -79,7 +79,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe binding.swipeRefreshLayout.setRefreshing(false); Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show(); } - catch(Throwable e) {} + catch(Throwable ignored) {} } }; @@ -92,7 +92,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe @Override public void onPreviewClick(final Notification model) { final NotificationImage notificationImage = model.getArgs().getMedia().get(0); - final long mediaId = Long.valueOf(notificationImage.getId().split("_")[0]); + final long mediaId = Long.parseLong(notificationImage.getId().split("_")[0]); if (model.getType() == NotificationType.RESPONDED_STORY) { final NavDirections action = NotificationsViewerFragmentDirections .actionNotificationsViewerFragmentToStoryViewerFragment( @@ -277,8 +277,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe } private void openProfile(final String username) { - final NavDirections action = NotificationsViewerFragmentDirections - .actionGlobalProfileFragment("@" + username); + final NavDirections action = NotificationsViewerFragmentDirections.actionGlobalProfileFragment("@" + username); NavHostFragment.findNavController(this).navigate(action); } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index 6f966c33..e6824d84 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -31,7 +31,6 @@ import android.webkit.MimeTypeMap; import android.widget.Toast; import androidx.annotation.DrawableRes; -import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; @@ -474,7 +473,10 @@ public final class Utils { final List navGraphNameList = Arrays.asList(navGraphNames); if (TextUtils.isEmpty(tabOrderString)) { // Use top 5 entries for default list - return navGraphNameList.subList(0, 5); + final List top5navGraphNames = navGraphNameList.subList(0, 5); + final String newOrderString = android.text.TextUtils.join(",", top5navGraphNames); + Utils.settingsHelper.putString(PreferenceKeys.PREF_TAB_ORDER, newOrderString); + return top5navGraphNames; } // Make sure that the list from preference does not contain any invalid values final List orderGraphNames = Arrays.stream(tabOrderString.split(",")) @@ -489,6 +491,7 @@ public final class Utils { } public static boolean isNavRootInCurrentTabs(final String navRootString) { + if (navRootString == null || tabOrderString == null) return false; return tabOrderString.contains(navRootString); } } diff --git a/app/src/main/res/navigation/notification_viewer_nav_graph.xml b/app/src/main/res/navigation/notification_viewer_nav_graph.xml index 8f80b18e..8f838474 100644 --- a/app/src/main/res/navigation/notification_viewer_nav_graph.xml +++ b/app/src/main/res/navigation/notification_viewer_nav_graph.xml @@ -5,25 +5,6 @@ android:id="@+id/notification_viewer_nav_graph" app:startDestination="@id/notificationsViewer"> - - - - - - + + + + + + \ No newline at end of file From b1dd0e6e3c37cbdfa7737fd6a90f1cdc57393f6d Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 20:41:35 +0900 Subject: [PATCH 31/42] Get tabOrderString always from settings, so that it's not stale if preferences were updated --- app/src/main/java/awais/instagrabber/utils/Utils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index e6824d84..ff79f67f 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -80,7 +80,6 @@ public final class Utils { private static int actionBarHeight; public static Handler applicationHandler; public static String cacheDir; - public static String tabOrderString; private static int defaultStatusBarColor; public static int convertDpToPx(final float dp) { @@ -469,7 +468,7 @@ public final class Utils { @NonNull private static List getCurrentOrderOfGraphNamesFromPref(@NonNull final String[] navGraphNames) { - tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); + final String tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); final List navGraphNameList = Arrays.asList(navGraphNames); if (TextUtils.isEmpty(tabOrderString)) { // Use top 5 entries for default list @@ -491,6 +490,7 @@ public final class Utils { } public static boolean isNavRootInCurrentTabs(final String navRootString) { + final String tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); if (navRootString == null || tabOrderString == null) return false; return tabOrderString.contains(navRootString); } From e2c15e76b8d051e36b647777b12eb6c279e05158 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 20:41:35 +0900 Subject: [PATCH 32/42] Revert "Get tabOrderString always from settings, so that it's not stale if preferences were updated" This reverts commit b1dd0e6e3c37cbdfa7737fd6a90f1cdc57393f6d. --- app/src/main/java/awais/instagrabber/utils/Utils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index ff79f67f..e6824d84 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -80,6 +80,7 @@ public final class Utils { private static int actionBarHeight; public static Handler applicationHandler; public static String cacheDir; + public static String tabOrderString; private static int defaultStatusBarColor; public static int convertDpToPx(final float dp) { @@ -468,7 +469,7 @@ public final class Utils { @NonNull private static List getCurrentOrderOfGraphNamesFromPref(@NonNull final String[] navGraphNames) { - final String tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); + tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); final List navGraphNameList = Arrays.asList(navGraphNames); if (TextUtils.isEmpty(tabOrderString)) { // Use top 5 entries for default list @@ -490,7 +491,6 @@ public final class Utils { } public static boolean isNavRootInCurrentTabs(final String navRootString) { - final String tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER); if (navRootString == null || tabOrderString == null) return false; return tabOrderString.contains(navRootString); } From c5786a684304a505779b61e6a80c44e930ea3136 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 20:48:21 +0900 Subject: [PATCH 33/42] Set tabOrderString value with default graph names when its empty --- app/src/main/java/awais/instagrabber/utils/Utils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index e6824d84..6f711a45 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -476,6 +476,7 @@ public final class Utils { final List top5navGraphNames = navGraphNameList.subList(0, 5); final String newOrderString = android.text.TextUtils.join(",", top5navGraphNames); Utils.settingsHelper.putString(PreferenceKeys.PREF_TAB_ORDER, newOrderString); + tabOrderString = newOrderString; return top5navGraphNames; } // Make sure that the list from preference does not contain any invalid values From 3038a06dca803d37b6071480c36b4b4c972f358f Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 22:07:58 +0900 Subject: [PATCH 34/42] Long name causing compile issues on windows? --- .../instagrabber/fragments/NotificationsViewerFragment.java | 5 ++--- .../main/res/navigation/notification_viewer_nav_graph.xml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java index 60c4a7be..15d5306d 100644 --- a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java @@ -78,8 +78,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe try { binding.swipeRefreshLayout.setRefreshing(false); Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(Throwable ignored) {} + } catch (Throwable ignored) {} } }; @@ -95,7 +94,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe final long mediaId = Long.parseLong(notificationImage.getId().split("_")[0]); if (model.getType() == NotificationType.RESPONDED_STORY) { final NavDirections action = NotificationsViewerFragmentDirections - .actionNotificationsViewerFragmentToStoryViewerFragment( + .actionNotificationsToStory( StoryViewerOptions.forStory( mediaId, model.getArgs().getUsername())); diff --git a/app/src/main/res/navigation/notification_viewer_nav_graph.xml b/app/src/main/res/navigation/notification_viewer_nav_graph.xml index 8f838474..50e2fbdf 100644 --- a/app/src/main/res/navigation/notification_viewer_nav_graph.xml +++ b/app/src/main/res/navigation/notification_viewer_nav_graph.xml @@ -97,7 +97,7 @@ android:defaultValue="0L" app:argType="long" /> \ No newline at end of file From 043b0d50eb7aeb091f9026222e27729b390b2623 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 23:08:37 +0900 Subject: [PATCH 35/42] Remove unused files --- app/src/main/resources/feed_response.json | 1 - app/src/main/resources/stories_response.json | 1 - 2 files changed, 2 deletions(-) delete mode 100644 app/src/main/resources/feed_response.json delete mode 100644 app/src/main/resources/stories_response.json diff --git a/app/src/main/resources/feed_response.json b/app/src/main/resources/feed_response.json deleted file mode 100644 index 9e26dfee..00000000 --- a/app/src/main/resources/feed_response.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/app/src/main/resources/stories_response.json b/app/src/main/resources/stories_response.json deleted file mode 100644 index 9e26dfee..00000000 --- a/app/src/main/resources/stories_response.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file From 70055271500c9ae72a070fa98a8fc8de09679c03 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 23:44:46 +0900 Subject: [PATCH 36/42] Check navigation. Fixes https://github.com/austinhuang0131/barinsta/issues/380 --- .../instagrabber/fragments/main/FeedFragment.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index f4b8d47e..bfc1dee3 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -83,9 +83,12 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre new FeedStoriesAdapter.OnFeedStoryClickListener() { @Override public void onFeedStoryClick(FeedStoryModel model, int position) { - final NavDirections action = FeedFragmentDirections - .actionFeedFragmentToStoryViewerFragment(StoryViewerOptions.forFeedStoryPosition(position)); - NavHostFragment.findNavController(FeedFragment.this).navigate(action); + final NavController navController = NavHostFragment.findNavController(FeedFragment.this); + if (isSafeToNavigate(navController)) { + final NavDirections action = FeedFragmentDirections + .actionFeedFragmentToStoryViewerFragment(StoryViewerOptions.forFeedStoryPosition(position)); + navController.navigate(action); + } } @Override @@ -437,4 +440,9 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre binding.feedRecyclerView.smoothScrollToPosition(0); // binding.storiesContainer.setExpanded(true); } + + private boolean isSafeToNavigate(final NavController navController) { + return navController.getCurrentDestination() != null + && navController.getCurrentDestination().getId() == R.id.feedFragment; + } } From 122f9b23818f6fd5de6841850dac47bf85494acf Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sat, 3 Apr 2021 23:49:54 +0900 Subject: [PATCH 37/42] Fix highlights overlapping counts --- app/src/main/res/layout/layout_profile_details.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index 035a04b0..ea4df164 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -326,6 +326,7 @@ From 0cc03b98c25c0675444eb028e27e62ae62b142e1 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 4 Apr 2021 00:43:01 +0900 Subject: [PATCH 38/42] Completely restart app on login logout --- app/src/main/AndroidManifest.xml | 3 + .../AccountSwitcherDialogFragment.java | 14 ++- .../settings/MorePreferencesFragment.java | 34 ++++-- .../instagrabber/utils/ProcessPhoenix.java | 111 ++++++++++++++++++ 4 files changed, 148 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ce5e77c9..a958a9a3 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -130,6 +130,9 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activities.MainActivity" /> + { + final Context context = getContext(); + if (context == null) return; + ProcessPhoenix.triggerRebirth(context); + }, 200); }; private final AccountSwitcherAdapter.OnAccountLongClickListener accountLongClickListener = (model, isCurrent) -> { diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index a7d39fc8..8348123b 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -11,8 +11,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.navigation.NavController; import androidx.navigation.NavDirections; @@ -35,9 +33,11 @@ import awais.instagrabber.db.repositories.AccountRepository; import awais.instagrabber.db.repositories.RepositoryCallback; import awais.instagrabber.dialogs.AccountSwitcherDialogFragment; import awais.instagrabber.repositories.responses.User; +import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.FlavorTown; +import awais.instagrabber.utils.ProcessPhoenix; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import awais.instagrabber.webservices.ServiceCallback; @@ -71,11 +71,15 @@ public class MorePreferencesFragment extends BasePreferencesFragment { accountCategory.setSummary(R.string.account_hint); accountCategory.addPreference(getAccountSwitcherPreference(cookie, context)); accountCategory.addPreference(getPreference(R.string.logout, R.string.logout_summary, R.drawable.ic_logout_24, preference -> { - if (getContext() == null) return false; + final Context context1 = getContext(); + if (context1 == null) return false; CookieUtils.setupCookies("LOGOUT"); - shouldRecreate(); - Toast.makeText(context, R.string.logout_success, Toast.LENGTH_SHORT).show(); + // shouldRecreate(); + Toast.makeText(context1, R.string.logout_success, Toast.LENGTH_SHORT).show(); settingsHelper.putString(Constants.COOKIE, ""); + AppExecutors.getInstance().mainThread().execute(() -> { + ProcessPhoenix.triggerRebirth(context1); + }, 200); return true; })); } @@ -103,9 +107,14 @@ public class MorePreferencesFragment extends BasePreferencesFragment { CookieUtils.removeAllAccounts(context, new RepositoryCallback() { @Override public void onSuccess(final Void result) { - shouldRecreate(); - Toast.makeText(context, R.string.logout_success, Toast.LENGTH_SHORT).show(); + // shouldRecreate(); + final Context context1 = getContext(); + if (context1 == null) return; + Toast.makeText(context1, R.string.logout_success, Toast.LENGTH_SHORT).show(); settingsHelper.putString(Constants.COOKIE, ""); + AppExecutors.getInstance().mainThread().execute(() -> { + ProcessPhoenix.triggerRebirth(context1); + }, 200); } @Override @@ -265,9 +274,14 @@ public class MorePreferencesFragment extends BasePreferencesFragment { new RepositoryCallback() { @Override public void onSuccess(final Account result) { - final FragmentActivity activity = getActivity(); - if (activity == null) return; - activity.recreate(); + // final FragmentActivity activity = getActivity(); + // if (activity == null) return; + // activity.recreate(); + AppExecutors.getInstance().mainThread().execute(() -> { + final Context context = getContext(); + if (context == null) return; + ProcessPhoenix.triggerRebirth(context); + }, 200); } @Override diff --git a/app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java b/app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java new file mode 100644 index 00000000..5dcc6e19 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 Jake Wharton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package awais.instagrabber.utils; + +import android.app.Activity; +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Process; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; + +/** + * Process Phoenix facilitates restarting your application process. This should only be used for + * things like fundamental state changes in your debug builds (e.g., changing from staging to + * production). + *

+ * Trigger process recreation by calling {@link #triggerRebirth} with a {@link Context} instance. + */ +public final class ProcessPhoenix extends Activity { + private static final String KEY_RESTART_INTENTS = "phoenix_restart_intents"; + + /** + * Call to restart the application process using the {@linkplain Intent#CATEGORY_DEFAULT default} + * activity as an intent. + *

+ * Behavior of the current process after invoking this method is undefined. + */ + public static void triggerRebirth(Context context) { + triggerRebirth(context, getRestartIntent(context)); + } + + /** + * Call to restart the application process using the specified intents. + *

+ * Behavior of the current process after invoking this method is undefined. + */ + public static void triggerRebirth(Context context, Intent... nextIntents) { + Intent intent = new Intent(context, ProcessPhoenix.class); + intent.addFlags(FLAG_ACTIVITY_NEW_TASK); // In case we are called with non-Activity context. + intent.putParcelableArrayListExtra(KEY_RESTART_INTENTS, new ArrayList<>(Arrays.asList(nextIntents))); + context.startActivity(intent); + if (context instanceof Activity) { + ((Activity) context).finish(); + } + Runtime.getRuntime().exit(0); // Kill kill kill! + } + + private static Intent getRestartIntent(Context context) { + String packageName = context.getPackageName(); + Intent defaultIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); + if (defaultIntent != null) { + defaultIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); + return defaultIntent; + } + + throw new IllegalStateException("Unable to determine default activity for " + + packageName + + ". Does an activity specify the DEFAULT category in its intent filter?"); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ArrayList intents = getIntent().getParcelableArrayListExtra(KEY_RESTART_INTENTS); + startActivities(intents.toArray(new Intent[intents.size()])); + finish(); + Runtime.getRuntime().exit(0); // Kill kill kill! + } + + /** + * Checks if the current process is a temporary Phoenix Process. + * This can be used to avoid initialisation of unused resources or to prevent running code that + * is not multi-process ready. + * + * @return true if the current process is a temporary Phoenix Process + */ + public static boolean isPhoenixProcess(Context context) { + int currentPid = Process.myPid(); + ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List runningProcesses = manager.getRunningAppProcesses(); + if (runningProcesses != null) { + for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { + if (processInfo.pid == currentPid && processInfo.processName.endsWith(":phoenix")) { + return true; + } + } + } + return false; + } +} From 04ee3883ea04768a2d2c66ffcd2025ae6a6df51b Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 3 Apr 2021 11:44:15 -0400 Subject: [PATCH 39/42] close #952 --- .../java/awais/instagrabber/webservices/NewsService.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index 63fede99..db20e984 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -56,9 +56,11 @@ public class NewsService extends BaseService { callback.onSuccess(null); return; } - final List result = new ArrayList<>(); - result.addAll(body.getNewStories()); - result.addAll(body.getOldStories()); + final List result = new ArrayList(); + final List newStories = body.getNewStories(); + if (newStories != null) result.addAll(newStories); + final List oldStories = body.getOldStories(); + if (oldStories != null) result.addAll(oldStories); callback.onSuccess(result); } From 4c800835c395a5fea8f436b13a971528fc0c2d3e Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 3 Apr 2021 12:29:56 -0400 Subject: [PATCH 40/42] new story menubar; effectively close #553 --- .../fragments/StoryViewerFragment.java | 74 +++++++++++++++---- app/src/main/res/menu/story_menu.xml | 13 +++- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 82438999..ddd84ce3 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -137,14 +137,14 @@ public class StoryViewerFragment extends Fragment { private String[] mentions; private QuizModel quiz; private SliderModel slider; - private MenuItem menuDownload; - private MenuItem menuDm; + private MenuItem menuDownload, menuDm, menuProfile; private SimpleExoPlayer player; // private boolean isHashtag; // private boolean isLoc; // private String highlight; - private String actionBarTitle; + private String actionBarTitle, actionBarSubtitle; private boolean fetching = false, sticking = false, shouldRefresh = true; + private boolean downloadVisible = false, dmVisible = false, profileVisible = true; private int currentFeedStoryIndex; private double sliderValue; private StoriesViewModel storiesViewModel; @@ -195,8 +195,10 @@ public class StoryViewerFragment extends Fragment { menuInflater.inflate(R.menu.story_menu, menu); menuDownload = menu.findItem(R.id.action_download); menuDm = menu.findItem(R.id.action_dms); - menuDownload.setVisible(false); - menuDm.setVisible(false); + menuProfile = menu.findItem(R.id.action_profile); + menuDownload.setVisible(downloadVisible); + menuDm.setVisible(dmVisible); + menuProfile.setVisible(profileVisible); } @Override @@ -215,7 +217,8 @@ public class StoryViewerFragment extends Fragment { else ActivityCompat.requestPermissions(requireActivity(), DownloadUtils.PERMS, 8020); return true; - } else if (itemId == R.id.action_dms) { + } + if (itemId == R.id.action_dms) { final EditText input = new EditText(context); input.setHint(R.string.reply_hint); new AlertDialog.Builder(context) @@ -259,6 +262,9 @@ public class StoryViewerFragment extends Fragment { .show(); return true; } + if (itemId == R.id.action_profile) { + openProfile("@" + currentStory.getUsername()); + } return false; } @@ -281,7 +287,9 @@ public class StoryViewerFragment extends Fragment { final ActionBar actionBar = fragmentActivity.getSupportActionBar(); if (actionBar != null) { actionBar.setTitle(actionBarTitle); + actionBar.setSubtitle(actionBarSubtitle); } + setHasOptionsMenu(true); } @Override @@ -697,6 +705,10 @@ public class StoryViewerFragment extends Fragment { lastSlidePos = 0; if (menuDownload != null) menuDownload.setVisible(false); if (menuDm != null) menuDm.setVisible(false); + if (menuProfile != null) menuProfile.setVisible(false); + downloadVisible = false; + dmVisible = false; + profileVisible = false; binding.imageViewer.setController(null); releasePlayer(); String currentStoryMediaId = null; @@ -846,7 +858,6 @@ public class StoryViewerFragment extends Fragment { final MediaItemType itemType = currentStory.getItemType(); - if (menuDownload != null) menuDownload.setVisible(false); url = itemType == MediaItemType.MEDIA_TYPE_IMAGE ? currentStory.getStoryUrl() : currentStory.getVideoUrl(); if (itemType != MediaItemType.MEDIA_TYPE_LIVE) { @@ -900,9 +911,10 @@ public class StoryViewerFragment extends Fragment { else setupImage(); final ActionBar actionBar = fragmentActivity.getSupportActionBar(); + actionBarSubtitle = Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L)); if (actionBar != null) { try { - actionBar.setSubtitle(Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L))); + actionBar.setSubtitle(actionBarSubtitle); } catch (Exception e) { Log.e(TAG, "refreshStory: ", e); } @@ -948,11 +960,17 @@ public class StoryViewerFragment extends Fragment { final ImageInfo imageInfo, final Animatable animatable) { if (menuDownload != null) { + downloadVisible = true; menuDownload.setVisible(true); } if (currentStory.canReply() && menuDm != null) { + dmVisible = true; menuDm.setVisible(true); } + if (!TextUtils.isEmpty(currentStory.getUsername())) { + profileVisible = true; + menuProfile.setVisible(true); + } binding.progressView.setVisibility(View.GONE); } }) @@ -982,9 +1000,18 @@ public class StoryViewerFragment extends Fragment { @Nullable final MediaSource.MediaPeriodId mediaPeriodId, @NonNull final LoadEventInfo loadEventInfo, @NonNull final MediaLoadData mediaLoadData) { - if (menuDownload != null) menuDownload.setVisible(true); - if (currentStory.canReply() && menuDm != null) + if (menuDownload != null) { + downloadVisible = true; + menuDownload.setVisible(true); + } + if (currentStory.canReply() && menuDm != null) { + dmVisible = true; menuDm.setVisible(true); + } + if (!TextUtils.isEmpty(currentStory.getUsername()) && menuProfile != null) { + profileVisible = true; + menuProfile.setVisible(true); + } binding.progressView.setVisibility(View.GONE); } @@ -993,9 +1020,18 @@ public class StoryViewerFragment extends Fragment { @Nullable final MediaSource.MediaPeriodId mediaPeriodId, @NonNull final LoadEventInfo loadEventInfo, @NonNull final MediaLoadData mediaLoadData) { - if (menuDownload != null) menuDownload.setVisible(true); - if (currentStory.canReply() && menuDm != null) + if (menuDownload != null) { + downloadVisible = true; + menuDownload.setVisible(true); + } + if (currentStory.canReply() && menuDm != null) { + dmVisible = true; menuDm.setVisible(true); + } + if (!TextUtils.isEmpty(currentStory.getUsername()) && menuProfile != null) { + profileVisible = true; + menuProfile.setVisible(true); + } binding.progressView.setVisibility(View.VISIBLE); } @@ -1014,8 +1050,18 @@ public class StoryViewerFragment extends Fragment { @NonNull final MediaLoadData mediaLoadData, @NonNull final IOException error, final boolean wasCanceled) { - if (menuDownload != null) menuDownload.setVisible(false); - if (menuDm != null) menuDm.setVisible(false); + if (menuDownload != null) { + downloadVisible = false; + menuDownload.setVisible(false); + } + if (menuDm != null) { + dmVisible = false; + menuDm.setVisible(false); + } + if (menuProfile != null) { + profileVisible = false; + menuProfile.setVisible(false); + } binding.progressView.setVisibility(View.GONE); } }); diff --git a/app/src/main/res/menu/story_menu.xml b/app/src/main/res/menu/story_menu.xml index a7293f91..8169fd62 100644 --- a/app/src/main/res/menu/story_menu.xml +++ b/app/src/main/res/menu/story_menu.xml @@ -5,13 +5,18 @@ + android:title="@string/reply_story" + android:titleCondensed="@string/reply_story" + app:showAsAction="never" /> + + app:showAsAction="never" />

\ No newline at end of file From fcdcef4ebb87bc5092d20e64b79878230e72b938 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 3 Apr 2021 12:50:46 -0400 Subject: [PATCH 41/42] removed "@" for consistency --- .../main/java/awais/instagrabber/utils/DownloadUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index ea0d73ac..18bf59c7 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -142,7 +142,7 @@ public final class DownloadUtils { final String sliderPostfix, final String displayUrl, final String username) { - final String usernamePrepend = TextUtils.isEmpty(username) ? "" : "@" + username + "_"; + final String usernamePrepend = TextUtils.isEmpty(username) ? "" : (username + "_"); final String fileName = usernamePrepend + postId + sliderPostfix + getFileExtensionFromUrl(displayUrl); return new File(finalDir, fileName); } @@ -278,7 +278,7 @@ public final class DownloadUtils { final String baseFileName = storyModel.getStoryMediaId() + "_" + storyModel.getTimestamp() + DownloadUtils.getFileExtensionFromUrl(url); final String usernamePrepend = Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) - && storyModel.getUsername() != null ? "@" + storyModel.getUsername() + "_" : ""; + && storyModel.getUsername() != null ? storyModel.getUsername() + "_" : ""; final File saveFile = new File(downloadDir, usernamePrepend + baseFileName); download(context, url, saveFile.getAbsolutePath()); @@ -306,7 +306,7 @@ public final class DownloadUtils { final Map map = new HashMap<>(); for (final Media media : feedModels) { final User mediaUser = media.getUser(); - final File downloadDir = getDownloadDir(context, mediaUser == null ? "" : "@" + mediaUser.getUsername()); + final File downloadDir = getDownloadDir(context, mediaUser == null ? "" : mediaUser.getUsername()); if (downloadDir == null) return; switch (media.getMediaType()) { case MEDIA_TYPE_IMAGE: From bcde6ac85ae0fd723e91e4a24749e1a6577e5edb Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 3 Apr 2021 19:30:00 -0400 Subject: [PATCH 42/42] login update --- .../awais/instagrabber/activities/Login.java | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/activities/Login.java b/app/src/main/java/awais/instagrabber/activities/Login.java index 37083794..879c92f3 100755 --- a/app/src/main/java/awais/instagrabber/activities/Login.java +++ b/app/src/main/java/awais/instagrabber/activities/Login.java @@ -24,7 +24,7 @@ import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.TextUtils; -public final class Login extends BaseLanguageActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { +public final class Login extends BaseLanguageActivity implements View.OnClickListener { private final WebViewClient webViewClient = new WebViewClient() { @Override public void onPageStarted(final WebView view, final String url, final Bitmap favicon) { @@ -53,7 +53,7 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis } private final WebChromeClient webChromeClient = new WebChromeClient(); - private String webViewUrl, defaultUserAgent; + private String webViewUrl; private boolean ready = false; private ActivityLoginBinding loginBinding; @@ -65,7 +65,6 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis initWebView(); - loginBinding.desktopMode.setOnCheckedChangeListener(this); loginBinding.cookies.setOnClickListener(this); loginBinding.refresh.setOnClickListener(this); } @@ -86,23 +85,6 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis } } - @Override - public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { - final WebSettings webSettings = loginBinding.webView.getSettings(); - - final String newUserAgent = isChecked - ? "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" - : defaultUserAgent; - - webSettings.setUserAgentString(newUserAgent); - webSettings.setUseWideViewPort(isChecked); - webSettings.setLoadWithOverviewMode(isChecked); - webSettings.setSupportZoom(isChecked); - webSettings.setBuiltInZoomControls(isChecked); - - loginBinding.webView.loadUrl("https://instagram.com/"); - } - @SuppressLint("SetJavaScriptEnabled") private void initWebView() { if (loginBinding != null) { @@ -110,7 +92,7 @@ public final class Login extends BaseLanguageActivity implements View.OnClickLis loginBinding.webView.setWebViewClient(webViewClient); final WebSettings webSettings = loginBinding.webView.getSettings(); if (webSettings != null) { - if (defaultUserAgent == null) defaultUserAgent = webSettings.getUserAgentString(); + webSettings.setUserAgentString("Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36"); webSettings.setJavaScriptEnabled(true); webSettings.setDomStorageEnabled(true); webSettings.setSupportZoom(true);