From 02a02b96cf46f2dbfa9dcc95ed5b5e11e46027fd Mon Sep 17 00:00:00 2001 From: Rahul Kumar Patel Date: Tue, 10 Dec 2019 02:20:08 +0530 Subject: [PATCH] UI : Redesign app [1/2] Addressed following bugs: https://gitlab.com/AuroraOSS/AuroraStore/issues/253 https://gitlab.com/AuroraOSS/AuroraStore/issues/237 https://gitlab.com/AuroraOSS/AuroraStore/issues/259 https://gitlab.com/AuroraOSS/AuroraStore/issues/257 https://gitlab.com/AuroraOSS/AuroraStore/issues/255 https://gitlab.com/AuroraOSS/AuroraStore/issues/251 https://gitlab.com/AuroraOSS/AuroraStore/issues/249 https://gitlab.com/AuroraOSS/AuroraStore/issues/234 https://gitlab.com/AuroraOSS/AuroraStore/issues/247 https://gitlab.com/AuroraOSS/AuroraStore/issues/232 --- README.md | 2 +- app/build.gradle | 32 +- app/proguard-rules.pro | 4 +- app/src/main/AndroidManifest.xml | 89 ++-- .../aurora/store/AnonymousLoginService.java | 85 ---- .../com/aurora/store/AppDiffCallback.java | 37 ++ .../com/aurora/store/AuroraApplication.java | 48 +- .../java/com/aurora/store/AuroraGlide.java | 2 +- .../com/aurora/store/BulkUpdateService.java | 110 +++++ .../main/java/com/aurora/store/Constants.java | 33 +- .../store/FavouriteItemTouchHelper.java | 93 ---- .../main/java/com/aurora/store/Filter.java | 63 --- .../aurora/store/HistoryItemTouchHelper.java | 91 ---- .../main/java/com/aurora/store/ListType.java | 27 -- .../com/aurora/store/PermissionGroup.java | 6 +- .../aurora/store/PermissionsComparator.java | 74 --- .../com/aurora/store/ReviewsDiffCallback.java | 37 ++ .../com/aurora/store/SelfUpdateService.java | 15 +- .../aurora/store/SuggestionDiffCallback.java | 37 ++ .../aurora/store/TokenDispenserMirrors.java | 4 +- .../com/aurora/store/ValidateApiService.java | 130 ++++++ .../aurora/store/activity/AuroraActivity.java | 321 ------------- .../store/activity/DetailsActivity.java | 189 -------- .../aurora/store/activity/IntroActivity.java | 113 ----- .../store/adapter/BlacklistAdapter.java | 128 ------ .../store/adapter/CategoriesListAdapter.java | 157 ------- .../store/adapter/DownloadsAdapter.java | 18 +- .../store/adapter/EndlessAppsAdapter.java | 61 --- .../aurora/store/adapter/ExodusAdapter.java | 22 +- .../store/adapter/FavouriteAppsAdapter.java | 137 ------ .../store/adapter/FeaturedAppsAdapter.java | 24 +- .../store/adapter/InstalledAppsAdapter.java | 198 -------- .../adapter/NativeHttpClientAdapter.java | 21 +- .../store/adapter/OkHttpClientAdapter.java | 2 +- .../aurora/store/adapter/ReviewsAdapter.java | 144 ------ .../store/adapter/SearchHistoryAdapter.java | 135 ------ .../adapter/SearchSuggestionAdapter.java | 106 +++++ .../store/adapter/SelectableAdapter.java | 62 --- .../store/adapter/SelectableViewHolder.java | 73 --- .../adapter/SmallScreenshotsAdapter.java | 3 +- .../store/adapter/SubCategoryAdapter.java | 80 ---- .../com/aurora/store/adapter/TabAdapter.java | 40 -- .../store/adapter/TopCategoriesAdapter.java | 148 ------ .../store/adapter/UpdatableAppsAdapter.java | 215 --------- .../store/adapter/ViewPagerAdapter.java | 33 -- .../store/api/PlayStoreApiAuthenticator.java | 45 +- .../store/download/DownloadManager.java | 2 +- .../aurora/store/download/RequestBuilder.java | 6 +- .../aurora/store/{ => enums}/CardType.java | 2 +- .../aurora/store/{ => enums}/ErrorType.java | 9 +- .../{ => enums}/NotificationProvider.java | 2 +- .../java/com/aurora/store/events/Event.java | 36 +- .../java/com/aurora/store/events/Events.java | 12 - .../java/com/aurora/store/events/RxBus.java | 31 +- .../aurora/store/fragment/AppsFragment.java | 84 ---- .../aurora/store/fragment/BaseFragment.java | 260 ----------- .../store/fragment/CategoriesFragment.java | 161 ------- .../store/fragment/CategoryAppsFragment.java | 121 ----- .../store/fragment/DetailsFragment.java | 220 --------- .../store/fragment/DevAppsFragment.java | 188 -------- .../aurora/store/fragment/HomeFragment.java | 318 ------------- .../store/fragment/InstalledFragment.java | 188 -------- .../store/fragment/SearchAppsFragment.java | 345 -------------- .../aurora/store/fragment/SearchFragment.java | 259 ----------- .../store/fragment/SubCategoryFragment.java | 236 ---------- .../store/fragment/UpdatesFragment.java | 297 ------------ .../aurora/store/fragment/details/Beta.java | 211 --------- .../store/fragment/details/ExodusPrivacy.java | 116 ----- .../store/fragment/intro/LoginFragment.java | 124 ------ .../aurora/store/installer/AppInstaller.java | 5 +- .../store/installer/AppInstallerAbstract.java | 23 +- .../installer/AppInstallerPrivileged.java | 6 +- .../store/installer/AppInstallerRooted.java | 8 +- .../store/installer/AppUninstallerRooted.java | 4 +- .../com/aurora/store/installer/Installer.java | 29 +- .../aurora/store/installer/Uninstaller.java | 8 +- .../store/iterator/CustomAppListIterator.java | 24 +- .../aurora/store/iterator/ReviewIterator.java | 7 - .../iterator/ReviewRetrieverIterator.java | 21 +- .../store/iterator/ReviewStorageIterator.java | 15 +- .../aurora/store/manager/BitmapManager.java | 91 ---- .../store/manager/BlacklistManager.java | 31 +- .../aurora/store/manager/CategoryManager.java | 97 ++-- .../store/manager/FavouriteListManager.java | 4 +- .../aurora/store/manager/FilterManager.java | 52 +++ .../aurora/store/manager/LocaleManager.java | 4 +- .../aurora/store/manager/SpoofManager.java | 6 +- .../com/aurora/store/model/AppBuilder.java | 2 +- .../com/aurora/store/model/CategoryModel.java | 16 + .../aurora/store/model/ConnectionModel.java | 14 + .../model/{Filter.java => FilterModel.java} | 14 +- .../com/aurora/store/model/LoginInfo.java | 4 +- .../notification/GeneralNotification.java | 14 +- .../store/notification/NotificationBase.java | 9 +- .../store/notification/QuickNotification.java | 22 +- .../provider/AuroraSuggestionProvider.java | 121 ----- .../provider/NativeGsfVersionProvider.java | 2 - .../aurora/store/receiver/BootReceiver.java | 2 +- .../store/receiver/UpdatesReceiver.java | 11 +- .../store/section/BlackListedAppSection.java | 160 +++++++ .../store/section/CategoriesSection.java | 148 ++++++ .../store/section/EndlessResultSection.java | 45 ++ .../store/section/FavouriteAppSection.java | 176 ++++++++ .../store/section/InstallAppSection.java | 200 +++++++++ .../aurora/store/section/ReviewsSection.java | 155 +++++++ .../store/section/SearchResultSection.java | 45 ++ .../section/SearchSuggestionSection.java | 108 +++++ .../store/section/UpdateAppSection.java | 215 +++++++++ .../com/aurora/store/sheet/AppMenuSheet.java | 38 +- .../aurora/store/sheet/DownloadMenuSheet.java | 2 +- .../aurora/store/sheet/ExodusBottomSheet.java | 2 +- .../aurora/store/sheet/FilterBottomSheet.java | 85 ++-- .../store/sheet/ReviewsBottomSheet.java | 133 ------ .../store/sheet/UserReviewBottomSheet.java | 7 +- .../com/aurora/store/task/AllAppsTask.java | 32 +- .../{DetailsApp.java => AppDetailTask.java} | 14 +- .../java/com/aurora/store/task/AuthTask.java | 6 +- .../java/com/aurora/store/task/BaseTask.java | 18 +- ...{BulkDetails.java => BulkDetailsTask.java} | 14 +- .../aurora/store/task/CategoryAppsTask.java | 11 +- ...ategoryList.java => CategoryListTask.java} | 49 +- .../com/aurora/store/task/DeliveryData.java | 5 +- .../aurora/store/task/DeviceInfoBuilder.java | 4 +- .../aurora/store/task/FeaturedAppsTask.java | 5 +- .../java/com/aurora/store/task/GZipTask.java | 2 +- .../com/aurora/store/task/GeoSpoofTask.java | 6 +- .../aurora/store/task/InstalledAppsTask.java | 36 +- .../com/aurora/store/task/LiveUpdate.java | 20 +- .../com/aurora/store/task/NetworkTask.java | 2 +- .../store/task/ObservableDeliveryData.java | 8 +- .../com/aurora/store/task/ReviewsHelper.java | 17 +- .../com/aurora/store/task/SearchTask.java | 41 +- .../SuggestionTask.java} | 24 +- .../aurora/store/task/UpdatableAppsTask.java | 39 +- .../com/aurora/store/task/UserProfiler.java | 51 --- .../accounts}/AccountsActivity.java | 13 +- .../accounts}/fragment/AccountsFragment.java | 24 +- .../ui/category/CategoryAppsActivity.java | 110 +++++ .../store/ui/category/CategoryAppsModel.java | 97 ++++ .../fragment/SubCategoryFragment.java | 193 ++++++++ .../store/ui/details/DetailsActivity.java | 279 ++++++++++++ .../store/ui/details/DetailsAppModel.java | 46 ++ .../store/ui/details/ReviewsActivity.java | 159 +++++++ .../details/views/AbstractDetails.java} | 101 +++-- .../details/views}/ActionButton.java | 45 +- .../details/views}/AppLinks.java | 20 +- .../aurora/store/ui/details/views/Beta.java | 237 ++++++++++ .../store/ui/details/views/ExodusPrivacy.java | 127 ++++++ .../details/views}/GeneralDetails.java | 120 ++--- .../details => ui/details/views}/Reviews.java | 162 ++----- .../details/views}/Screenshot.java | 17 +- .../details => ui/details/views}/Video.java | 16 +- .../store/ui/devapps/DevAppsActivity.java | 138 ++++++ .../aurora/store/ui/devapps/DevAppsModel.java | 32 ++ .../ui/installed/InstalledAppActivity.java | 155 +++++++ .../ui/installed/InstalledAppsModel.java | 96 ++++ .../aurora/store/ui/intro/IntroActivity.java | 242 ++++++++++ .../intro/fragment/LoginFragment.java} | 28 +- .../intro/fragment}/PermissionFragment.java | 60 +-- .../intro/fragment}/WelcomeFragment.java | 15 +- .../aurora/store/ui/main/AuroraActivity.java | 421 ++++++++++++++++++ .../fragment/category/CategoriesFragment.java | 111 +++++ .../fragment/category/CategoriesModel.java | 63 +++ .../ui/main/fragment/home/HomeAppsModel.java | 137 ++++++ .../ui/main/fragment/home/HomeFragment.java | 171 +++++++ .../fragment/updates/UpdatableAppsModel.java | 77 ++++ .../fragment/updates/UpdatesFragment.java | 243 ++++++++++ .../preference}/SettingsActivity.java | 19 +- .../preference/fragment}/AboutFragment.java | 4 +- .../fragment}/BlacklistFragment.java | 165 +++---- .../fragment}/DownloaderFragment.java | 12 +- .../fragment}/FavouriteFragment.java | 209 ++++----- .../preference/fragment}/FilterFragment.java | 2 +- .../fragment}/InstallationFragment.java | 82 ++-- .../fragment}/LanguageFragment.java | 19 +- .../preference/fragment}/NetworkFragment.java | 6 +- .../fragment}/NotificationFragment.java | 8 +- .../preference/fragment}/SpoofFragment.java | 28 +- .../preference/fragment}/UIFragment.java | 10 +- .../fragment}/UpdatesPrefFragment.java | 7 +- .../store/ui/search/SearchAppsModel.java | 76 ++++ .../ui/search/SearchSuggestionModel.java | 53 +++ .../ui/search/activity/SearchActivity.java | 188 ++++++++ .../search/activity/SearchResultActivity.java | 215 +++++++++ .../ui/single/activity/BaseActivity.java | 47 ++ .../single}/activity/DeviceInfoActivity.java | 31 +- .../single}/activity/DownloadsActivity.java | 36 +- .../activity/FullscreenImageActivity.java | 19 +- .../ui/single/activity/GenericActivity.java | 93 ++++ .../single}/activity/GoogleLoginActivity.java | 44 +- .../activity/ManualDownloadActivity.java | 23 +- .../ui/single/activity/SplashActivity.java | 115 +++++ .../view/CustomGridLayoutManager.java | 2 +- .../{ => ui}/view/CustomLayoutManager.java | 2 +- .../store/{ => ui}/view/CustomSnapHelper.java | 2 +- .../{ => ui}/view/CustomSwipeToRefresh.java | 17 +- .../store/{ => ui}/view/CustomViewPager.java | 6 +- .../store/{ => ui}/view/DetailsLinkView.java | 9 +- .../aurora/store/{ => ui}/view/LinkView.java | 2 +- .../store/{ => ui}/view/PropertyView.java | 2 +- .../store/{ => ui}/view/RatingView.java | 2 +- .../store/{utility => util}/Accountant.java | 3 +- .../{utility => util}/ApiBuilderUtil.java | 63 +-- .../store/{utility => util}/ApkCopier.java | 2 +- .../store/{utility => util}/CertUtil.java | 4 +- .../store/{utility => util}/ColorUtil.java | 2 +- .../store/{utility => util}/ContextUtil.java | 2 +- .../java/com/aurora/store/util/ImageUtil.java | 74 +++ .../aurora/store/{utility => util}/Log.java | 2 +- .../store/{utility => util}/NetworkUtil.java | 2 +- .../{utility => util}/NotificationUtil.java | 5 +- .../store/{utility => util}/PackageUtil.java | 41 +- .../store/{utility => util}/PathUtil.java | 4 +- .../store/{utility => util}/PrefUtil.java | 4 +- .../aurora/store/{utility => util}/Root.java | 2 +- .../store/{utility => util}/TextUtil.java | 2 +- .../store/{utility => util}/ThemeUtil.java | 34 +- .../aurora/store/{utility => util}/Util.java | 77 ++-- .../store/{utility => util}/ViewUtil.java | 86 +--- .../aurora/store/utility/ResponseUtil.java | 100 ----- .../java/com/aurora/store/view/ErrorView.java | 111 ----- .../aurora/store/viewmodel/BaseViewModel.java | 49 ++ .../store/viewmodel/BlackListedAppsModel.java | 66 +++ .../store/viewmodel/ConnectionLiveData.java | 50 +++ .../store/viewmodel/FavouriteAppsModel.java | 53 +++ .../aurora/store/viewmodel/ReviewsModel.java | 70 +++ app/src/main/res/drawable/app_settings.xml | 28 -- app/src/main/res/drawable/bottomsheet_bg.xml | 32 -- app/src/main/res/drawable/circle_bg.xml | 2 +- app/src/main/res/drawable/downloads_anim.xml | 206 --------- .../main/res/drawable/generic_padded_bg.xml | 3 +- .../main/res/drawable/gradient_bg_bottom.xml | 29 -- app/src/main/res/drawable/ic_about.xml | 4 +- app/src/main/res/drawable/ic_account.xml | 31 +- app/src/main/res/drawable/ic_android_wear.xml | 29 -- app/src/main/res/drawable/ic_apps.xml | 6 +- app/src/main/res/drawable/ic_arrow.xml | 6 +- app/src/main/res/drawable/ic_arrow_back.xml | 9 + app/src/main/res/drawable/ic_art_design.xml | 29 -- .../main/res/drawable/ic_auto_vehicles.xml | 29 -- app/src/main/res/drawable/ic_avatar_boy.xml | 76 ---- app/src/main/res/drawable/ic_beauty.xml | 29 -- .../main/res/drawable/ic_books_reference.xml | 29 -- app/src/main/res/drawable/ic_business.xml | 29 -- app/src/main/res/drawable/ic_cancel.xml | 6 +- app/src/main/res/drawable/ic_categories.xml | 9 + app/src/main/res/drawable/ic_check.xml | 9 + app/src/main/res/drawable/ic_checked.xml | 6 +- app/src/main/res/drawable/ic_comics.xml | 29 -- .../main/res/drawable/ic_communication.xml | 29 -- app/src/main/res/drawable/ic_copy.xml | 34 -- app/src/main/res/drawable/ic_dating.xml | 29 -- .../main/res/drawable/ic_device_avatar.xml | 65 --- app/src/main/res/drawable/ic_dot.xml | 6 +- app/src/main/res/drawable/ic_download.xml | 29 -- .../main/res/drawable/ic_download_cancel.xml | 34 -- .../main/res/drawable/ic_download_clear.xml | 34 -- .../main/res/drawable/ic_download_manager.xml | 29 -- .../main/res/drawable/ic_download_pause.xml | 34 -- .../main/res/drawable/ic_download_resume.xml | 34 -- app/src/main/res/drawable/ic_downloads.xml | 34 -- app/src/main/res/drawable/ic_edit.xml | 34 -- app/src/main/res/drawable/ic_education.xml | 29 -- .../main/res/drawable/ic_entertainment.xml | 29 -- app/src/main/res/drawable/ic_events.xml | 29 -- app/src/main/res/drawable/ic_family.xml | 29 -- app/src/main/res/drawable/ic_fav.xml | 4 +- app/src/main/res/drawable/ic_filter.xml | 30 +- app/src/main/res/drawable/ic_filter_apps.xml | 34 -- app/src/main/res/drawable/ic_filter_check.xml | 10 + app/src/main/res/drawable/ic_finance.xml | 29 -- app/src/main/res/drawable/ic_food_drink.xml | 29 -- app/src/main/res/drawable/ic_free.xml | 9 + app/src/main/res/drawable/ic_games.xml | 29 -- app/src/main/res/drawable/ic_google_play.xml | 29 -- .../drawable/{ic_open.xml => ic_grossing.xml} | 2 +- .../main/res/drawable/ic_health_fitness.xml | 29 -- app/src/main/res/drawable/ic_home.xml | 6 +- app/src/main/res/drawable/ic_house_home.xml | 29 -- app/src/main/res/drawable/ic_installation.xml | 31 +- .../main/res/drawable/ic_installation_alt.xml | 29 -- app/src/main/res/drawable/ic_language.xml | 31 +- .../main/res/drawable/ic_libraries_demo.xml | 29 -- app/src/main/res/drawable/ic_lifestyle.xml | 29 -- .../main/res/drawable/ic_maps_navigation.xml | 29 -- app/src/main/res/drawable/ic_medical.xml | 29 -- app/src/main/res/drawable/ic_menu_about.xml | 9 + app/src/main/res/drawable/ic_menu_account.xml | 9 + .../main/res/drawable/ic_menu_blacklist.xml | 9 + .../main/res/drawable/ic_menu_download.xml | 9 + app/src/main/res/drawable/ic_menu_fav.xml | 9 + app/src/main/res/drawable/ic_menu_line.xml | 9 + .../main/res/drawable/ic_menu_settings.xml | 9 + app/src/main/res/drawable/ic_menu_spoof.xml | 9 + app/src/main/res/drawable/ic_music__audio.xml | 29 -- app/src/main/res/drawable/ic_network.xml | 30 +- .../main/res/drawable/ic_news_magazines.xml | 29 -- app/src/main/res/drawable/ic_no_network.xml | 62 +-- app/src/main/res/drawable/ic_notification.xml | 27 +- .../main/res/drawable/ic_notifications.xml | 31 +- app/src/main/res/drawable/ic_parenting.xml | 29 -- app/src/main/res/drawable/ic_perm.xml | 34 -- .../main/res/drawable/ic_personalization.xml | 29 -- app/src/main/res/drawable/ic_photography.xml | 29 -- app/src/main/res/drawable/ic_play.xml | 1 - app/src/main/res/drawable/ic_productivity.xml | 29 -- .../main/res/drawable/ic_rating_negative.xml | 50 --- .../main/res/drawable/ic_rating_positive.xml | 50 --- app/src/main/res/drawable/ic_search.xml | 9 - app/src/main/res/drawable/ic_settings.xml | 29 -- app/src/main/res/drawable/ic_shopping.xml | 29 -- app/src/main/res/drawable/ic_size.xml | 29 -- app/src/main/res/drawable/ic_social.xml | 29 -- app/src/main/res/drawable/ic_spoof_alt.xml | 40 -- app/src/main/res/drawable/ic_sports.xml | 29 -- app/src/main/res/drawable/ic_star.xml | 29 -- app/src/main/res/drawable/ic_tab_explore.xml | 34 -- app/src/main/res/drawable/ic_tab_games.xml | 40 -- app/src/main/res/drawable/ic_tools.xml | 29 -- app/src/main/res/drawable/ic_travel_local.xml | 33 -- app/src/main/res/drawable/ic_trending.xml | 9 + app/src/main/res/drawable/ic_ui.xml | 41 +- app/src/main/res/drawable/ic_update.xml | 31 +- app/src/main/res/drawable/ic_updates.xml | 27 +- .../main/res/drawable/ic_video_editors.xml | 29 -- app/src/main/res/drawable/ic_weather.xml | 29 -- app/src/main/res/drawable/installed_bg.xml | 30 -- .../main/res/drawable/outline_bg_rounded.xml | 6 + app/src/main/res/drawable/tab_indicator.xml | 29 -- app/src/main/res/drawable/vd_downloading.xml | 84 ---- app/src/main/res/font/open_sans_semibold.xml | 7 - app/src/main/res/layout/activity_accounts.xml | 2 +- ...nt_installed.xml => activity_all_apps.xml} | 77 ++-- .../res/layout/activity_category_apps.xml | 42 ++ app/src/main/res/layout/activity_details.xml | 133 +++++- ...ragment_apps.xml => activity_dev_apps.xml} | 35 +- .../main/res/layout/activity_device_info.xml | 1 + .../main/res/layout/activity_downloads.xml | 2 +- .../activity_generic.xml} | 22 +- app/src/main/res/layout/activity_intro.xml | 58 ++- app/src/main/res/layout/activity_login.xml | 2 +- app/src/main/res/layout/activity_main.xml | 58 ++- app/src/main/res/layout/activity_manual.xml | 6 +- app/src/main/res/layout/activity_reviews.xml | 83 ++++ app/src/main/res/layout/activity_search.xml | 18 + .../res/layout/activity_search_result.xml | 32 ++ app/src/main/res/layout/activity_splash.xml | 50 +++ app/src/main/res/layout/fragment_about.xml | 136 +++--- app/src/main/res/layout/fragment_accounts.xml | 8 +- .../main/res/layout/fragment_blacklist.xml | 91 ++-- .../main/res/layout/fragment_categories.xml | 21 +- .../res/layout/fragment_category_applist.xml | 47 +- .../layout/fragment_category_container.xml | 68 --- app/src/main/res/layout/fragment_details.xml | 47 -- .../main/res/layout/fragment_dev_applist.xml | 57 +-- .../main/res/layout/fragment_favourites.xml | 153 +++---- app/src/main/res/layout/fragment_home.xml | 355 +++++++-------- .../main/res/layout/fragment_intro_login.xml | 44 +- .../res/layout/fragment_intro_permission.xml | 18 - .../res/layout/fragment_intro_welcome.xml | 21 +- app/src/main/res/layout/fragment_search.xml | 104 ----- .../res/layout/fragment_search_applist.xml | 115 ----- app/src/main/res/layout/fragment_spoof.xml | 5 +- app/src/main/res/layout/fragment_updates.xml | 118 +++-- .../main/res/layout/include_accounts_info.xml | 7 +- .../main/res/layout/include_accounts_init.xml | 12 +- .../res/layout/include_details_actions.xml | 5 +- .../layout/include_details_actions_button.xml | 44 +- .../main/res/layout/include_details_all.xml | 153 ------- .../main/res/layout/include_details_beta.xml | 35 +- .../res/layout/include_details_bottom.xml | 7 +- .../res/layout/include_details_changelog.xml | 7 +- .../res/layout/include_details_exodus.xml | 4 +- .../main/res/layout/include_details_main.xml | 96 ++-- .../res/layout/include_details_readmore.xml | 20 +- .../res/layout/include_details_reviews.xml | 46 +- app/src/main/res/layout/item_blacklist.xml | 36 +- app/src/main/res/layout/item_buildprop.xml | 21 +- .../main/res/layout/item_category_list.xml | 16 +- app/src/main/res/layout/item_category_top.xml | 31 -- app/src/main/res/layout/item_cluster.xml | 13 +- app/src/main/res/layout/item_downloads.xml | 20 +- app/src/main/res/layout/item_empty.xml | 26 ++ app/src/main/res/layout/item_error.xml | 26 ++ app/src/main/res/layout/item_favorite.xml | 139 ++---- app/src/main/res/layout/item_featured.xml | 6 +- app/src/main/res/layout/item_header.xml | 18 + .../main/res/layout/item_header_updates.xml | 36 ++ app/src/main/res/layout/item_history.xml | 108 ----- app/src/main/res/layout/item_installed.xml | 17 +- app/src/main/res/layout/item_link.xml | 8 +- app/src/main/res/layout/item_loading.xml | 23 + app/src/main/res/layout/item_nav_header.xml | 52 +++ app/src/main/res/layout/item_preference.xml | 53 +++ app/src/main/res/layout/item_rating.xml | 7 +- .../{item_review_list.xml => item_review.xml} | 44 +- app/src/main/res/layout/item_searchview.xml | 58 +++ app/src/main/res/layout/item_spinner.xml | 13 +- ...{sheet_reviews.xml => item_suggestion.xml} | 40 +- app/src/main/res/layout/item_updatable.xml | 26 +- app/src/main/res/layout/layout_permission.xml | 26 +- app/src/main/res/layout/search_bar.xml | 71 +++ app/src/main/res/layout/sheet_app_menu.xml | 2 +- .../main/res/layout/sheet_download_menu.xml | 2 +- app/src/main/res/layout/toolbar_main.xml | 4 +- .../main/res/menu/menu_download_single.xml | 8 +- app/src/main/res/menu/menu_drawer.xml | 67 +++ app/src/main/res/menu/menu_intro.xml | 2 +- ...{menu_main.xml => navigation_category.xml} | 23 +- .../{navigation.xml => navigation_main.xml} | 19 +- .../res/navigation/nav_graph_category.xml | 37 ++ .../main/res/navigation/nav_graph_intro.xml | 25 ++ .../main/res/navigation/nav_graph_main.xml | 25 ++ app/src/main/res/values-in-rID/strings.xml | 4 +- app/src/main/res/values-ru-rRU/strings.xml | 2 +- app/src/main/res/values-sk-rSK/strings.xml | 2 +- app/src/main/res/values-sv-rSE/strings.xml | 2 +- app/src/main/res/values-v23/styles.xml | 9 +- app/src/main/res/values-v27/styles.xml | 9 +- app/src/main/res/values/arrays.xml | 2 - app/src/main/res/values/colors.xml | 35 +- app/src/main/res/values/dimens.xml | 11 +- app/src/main/res/values/font_certs.xml | 17 - app/src/main/res/values/preloaded_fonts.xml | 6 - app/src/main/res/values/strings.xml | 30 +- app/src/main/res/values/styles.xml | 14 +- app/src/main/res/values/styles_text.xml | 49 +- app/src/main/res/values/styles_widget.xml | 108 +---- app/src/main/res/xml/preferences_main.xml | 57 +-- app/src/main/res/xml/preferences_ui.xml | 13 - build.gradle | 2 +- 431 files changed, 9554 insertions(+), 12854 deletions(-) delete mode 100644 app/src/main/java/com/aurora/store/AnonymousLoginService.java create mode 100644 app/src/main/java/com/aurora/store/AppDiffCallback.java create mode 100644 app/src/main/java/com/aurora/store/BulkUpdateService.java delete mode 100644 app/src/main/java/com/aurora/store/FavouriteItemTouchHelper.java delete mode 100644 app/src/main/java/com/aurora/store/Filter.java delete mode 100644 app/src/main/java/com/aurora/store/HistoryItemTouchHelper.java delete mode 100644 app/src/main/java/com/aurora/store/ListType.java delete mode 100644 app/src/main/java/com/aurora/store/PermissionsComparator.java create mode 100644 app/src/main/java/com/aurora/store/ReviewsDiffCallback.java create mode 100644 app/src/main/java/com/aurora/store/SuggestionDiffCallback.java create mode 100644 app/src/main/java/com/aurora/store/ValidateApiService.java delete mode 100644 app/src/main/java/com/aurora/store/activity/AuroraActivity.java delete mode 100644 app/src/main/java/com/aurora/store/activity/DetailsActivity.java delete mode 100644 app/src/main/java/com/aurora/store/activity/IntroActivity.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/BlacklistAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/CategoriesListAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/EndlessAppsAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/FavouriteAppsAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/InstalledAppsAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/ReviewsAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/SearchHistoryAdapter.java create mode 100644 app/src/main/java/com/aurora/store/adapter/SearchSuggestionAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/SelectableAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/SelectableViewHolder.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/SubCategoryAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/TabAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/TopCategoriesAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/UpdatableAppsAdapter.java delete mode 100644 app/src/main/java/com/aurora/store/adapter/ViewPagerAdapter.java rename app/src/main/java/com/aurora/store/{ => enums}/CardType.java (96%) rename app/src/main/java/com/aurora/store/{ => enums}/ErrorType.java (89%) rename app/src/main/java/com/aurora/store/{ => enums}/NotificationProvider.java (96%) delete mode 100644 app/src/main/java/com/aurora/store/events/Events.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/AppsFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/BaseFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/CategoriesFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/CategoryAppsFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/DetailsFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/DevAppsFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/HomeFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/InstalledFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/SearchAppsFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/SearchFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/SubCategoryFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/UpdatesFragment.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/details/Beta.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/details/ExodusPrivacy.java delete mode 100644 app/src/main/java/com/aurora/store/fragment/intro/LoginFragment.java delete mode 100644 app/src/main/java/com/aurora/store/manager/BitmapManager.java create mode 100644 app/src/main/java/com/aurora/store/manager/FilterManager.java create mode 100644 app/src/main/java/com/aurora/store/model/CategoryModel.java create mode 100644 app/src/main/java/com/aurora/store/model/ConnectionModel.java rename app/src/main/java/com/aurora/store/model/{Filter.java => FilterModel.java} (79%) delete mode 100644 app/src/main/java/com/aurora/store/provider/AuroraSuggestionProvider.java create mode 100644 app/src/main/java/com/aurora/store/section/BlackListedAppSection.java create mode 100644 app/src/main/java/com/aurora/store/section/CategoriesSection.java create mode 100644 app/src/main/java/com/aurora/store/section/EndlessResultSection.java create mode 100644 app/src/main/java/com/aurora/store/section/FavouriteAppSection.java create mode 100644 app/src/main/java/com/aurora/store/section/InstallAppSection.java create mode 100644 app/src/main/java/com/aurora/store/section/ReviewsSection.java create mode 100644 app/src/main/java/com/aurora/store/section/SearchResultSection.java create mode 100644 app/src/main/java/com/aurora/store/section/SearchSuggestionSection.java create mode 100644 app/src/main/java/com/aurora/store/section/UpdateAppSection.java delete mode 100644 app/src/main/java/com/aurora/store/sheet/ReviewsBottomSheet.java rename app/src/main/java/com/aurora/store/task/{DetailsApp.java => AppDetailTask.java} (82%) rename app/src/main/java/com/aurora/store/task/{BulkDetails.java => BulkDetailsTask.java} (82%) rename app/src/main/java/com/aurora/store/task/{CategoryList.java => CategoryListTask.java} (63%) rename app/src/main/java/com/aurora/store/{fragment/intro/IntroBaseFragment.java => task/SuggestionTask.java} (62%) delete mode 100644 app/src/main/java/com/aurora/store/task/UserProfiler.java rename app/src/main/java/com/aurora/store/{activity => ui/accounts}/AccountsActivity.java (86%) rename app/src/main/java/com/aurora/store/{ => ui/accounts}/fragment/AccountsFragment.java (94%) create mode 100644 app/src/main/java/com/aurora/store/ui/category/CategoryAppsActivity.java create mode 100644 app/src/main/java/com/aurora/store/ui/category/CategoryAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java create mode 100644 app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java create mode 100644 app/src/main/java/com/aurora/store/ui/details/DetailsAppModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/details/ReviewsActivity.java rename app/src/main/java/com/aurora/store/{fragment/details/AbstractHelper.java => ui/details/views/AbstractDetails.java} (57%) rename app/src/main/java/com/aurora/store/{fragment/details => ui/details/views}/ActionButton.java (94%) rename app/src/main/java/com/aurora/store/{fragment/details => ui/details/views}/AppLinks.java (86%) create mode 100644 app/src/main/java/com/aurora/store/ui/details/views/Beta.java create mode 100644 app/src/main/java/com/aurora/store/ui/details/views/ExodusPrivacy.java rename app/src/main/java/com/aurora/store/{fragment/details => ui/details/views}/GeneralDetails.java (73%) rename app/src/main/java/com/aurora/store/{fragment/details => ui/details/views}/Reviews.java (52%) rename app/src/main/java/com/aurora/store/{fragment/details => ui/details/views}/Screenshot.java (77%) rename app/src/main/java/com/aurora/store/{fragment/details => ui/details/views}/Video.java (90%) create mode 100644 app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java create mode 100644 app/src/main/java/com/aurora/store/ui/devapps/DevAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java create mode 100644 app/src/main/java/com/aurora/store/ui/installed/InstalledAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/intro/IntroActivity.java rename app/src/main/java/com/aurora/store/{ActionType.java => ui/intro/fragment/LoginFragment.java} (51%) rename app/src/main/java/com/aurora/store/{fragment/intro => ui/intro/fragment}/PermissionFragment.java (75%) rename app/src/main/java/com/aurora/store/{fragment/intro => ui/intro/fragment}/WelcomeFragment.java (79%) create mode 100644 app/src/main/java/com/aurora/store/ui/main/AuroraActivity.java create mode 100644 app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java create mode 100644 app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeFragment.java create mode 100644 app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java rename app/src/main/java/com/aurora/store/{activity => ui/preference}/SettingsActivity.java (90%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/AboutFragment.java (97%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/BlacklistFragment.java (51%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/DownloaderFragment.java (95%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/FavouriteFragment.java (54%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/FilterFragment.java (90%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/InstallationFragment.java (75%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/LanguageFragment.java (81%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/NetworkFragment.java (91%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/NotificationFragment.java (92%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/SpoofFragment.java (93%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/UIFragment.java (89%) rename app/src/main/java/com/aurora/store/{fragment/preference => ui/preference/fragment}/UpdatesPrefFragment.java (91%) create mode 100644 app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/search/SearchSuggestionModel.java create mode 100644 app/src/main/java/com/aurora/store/ui/search/activity/SearchActivity.java create mode 100644 app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java create mode 100644 app/src/main/java/com/aurora/store/ui/single/activity/BaseActivity.java rename app/src/main/java/com/aurora/store/{ => ui/single}/activity/DeviceInfoActivity.java (86%) rename app/src/main/java/com/aurora/store/{ => ui/single}/activity/DownloadsActivity.java (87%) rename app/src/main/java/com/aurora/store/{ => ui/single}/activity/FullscreenImageActivity.java (83%) create mode 100644 app/src/main/java/com/aurora/store/ui/single/activity/GenericActivity.java rename app/src/main/java/com/aurora/store/{ => ui/single}/activity/GoogleLoginActivity.java (74%) rename app/src/main/java/com/aurora/store/{ => ui/single}/activity/ManualDownloadActivity.java (93%) create mode 100644 app/src/main/java/com/aurora/store/ui/single/activity/SplashActivity.java rename app/src/main/java/com/aurora/store/{ => ui}/view/CustomGridLayoutManager.java (98%) rename app/src/main/java/com/aurora/store/{ => ui}/view/CustomLayoutManager.java (99%) rename app/src/main/java/com/aurora/store/{ => ui}/view/CustomSnapHelper.java (98%) rename app/src/main/java/com/aurora/store/{ => ui}/view/CustomSwipeToRefresh.java (77%) rename app/src/main/java/com/aurora/store/{ => ui}/view/CustomViewPager.java (98%) rename app/src/main/java/com/aurora/store/{ => ui}/view/DetailsLinkView.java (88%) rename app/src/main/java/com/aurora/store/{ => ui}/view/LinkView.java (98%) rename app/src/main/java/com/aurora/store/{ => ui}/view/PropertyView.java (98%) rename app/src/main/java/com/aurora/store/{ => ui}/view/RatingView.java (98%) rename app/src/main/java/com/aurora/store/{utility => util}/Accountant.java (98%) rename app/src/main/java/com/aurora/store/{utility => util}/ApiBuilderUtil.java (69%) rename app/src/main/java/com/aurora/store/{utility => util}/ApkCopier.java (99%) rename app/src/main/java/com/aurora/store/{utility => util}/CertUtil.java (95%) rename app/src/main/java/com/aurora/store/{utility => util}/ColorUtil.java (97%) rename app/src/main/java/com/aurora/store/{utility => util}/ContextUtil.java (98%) create mode 100644 app/src/main/java/com/aurora/store/util/ImageUtil.java rename app/src/main/java/com/aurora/store/{utility => util}/Log.java (97%) rename app/src/main/java/com/aurora/store/{utility => util}/NetworkUtil.java (98%) rename app/src/main/java/com/aurora/store/{utility => util}/NotificationUtil.java (88%) rename app/src/main/java/com/aurora/store/{utility => util}/PackageUtil.java (73%) rename app/src/main/java/com/aurora/store/{utility => util}/PathUtil.java (97%) rename app/src/main/java/com/aurora/store/{utility => util}/PrefUtil.java (98%) rename app/src/main/java/com/aurora/store/{utility => util}/Root.java (99%) rename app/src/main/java/com/aurora/store/{utility => util}/TextUtil.java (97%) rename app/src/main/java/com/aurora/store/{utility => util}/ThemeUtil.java (84%) rename app/src/main/java/com/aurora/store/{utility => util}/Util.java (91%) rename app/src/main/java/com/aurora/store/{utility => util}/ViewUtil.java (64%) delete mode 100644 app/src/main/java/com/aurora/store/utility/ResponseUtil.java delete mode 100644 app/src/main/java/com/aurora/store/view/ErrorView.java create mode 100644 app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java create mode 100644 app/src/main/java/com/aurora/store/viewmodel/BlackListedAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/viewmodel/ConnectionLiveData.java create mode 100644 app/src/main/java/com/aurora/store/viewmodel/FavouriteAppsModel.java create mode 100644 app/src/main/java/com/aurora/store/viewmodel/ReviewsModel.java delete mode 100644 app/src/main/res/drawable/app_settings.xml delete mode 100644 app/src/main/res/drawable/bottomsheet_bg.xml delete mode 100644 app/src/main/res/drawable/downloads_anim.xml delete mode 100644 app/src/main/res/drawable/gradient_bg_bottom.xml delete mode 100644 app/src/main/res/drawable/ic_android_wear.xml create mode 100644 app/src/main/res/drawable/ic_arrow_back.xml delete mode 100644 app/src/main/res/drawable/ic_art_design.xml delete mode 100644 app/src/main/res/drawable/ic_auto_vehicles.xml delete mode 100644 app/src/main/res/drawable/ic_avatar_boy.xml delete mode 100644 app/src/main/res/drawable/ic_beauty.xml delete mode 100644 app/src/main/res/drawable/ic_books_reference.xml delete mode 100644 app/src/main/res/drawable/ic_business.xml create mode 100644 app/src/main/res/drawable/ic_categories.xml create mode 100644 app/src/main/res/drawable/ic_check.xml delete mode 100644 app/src/main/res/drawable/ic_comics.xml delete mode 100644 app/src/main/res/drawable/ic_communication.xml delete mode 100644 app/src/main/res/drawable/ic_copy.xml delete mode 100644 app/src/main/res/drawable/ic_dating.xml delete mode 100644 app/src/main/res/drawable/ic_device_avatar.xml delete mode 100644 app/src/main/res/drawable/ic_download.xml delete mode 100644 app/src/main/res/drawable/ic_download_cancel.xml delete mode 100644 app/src/main/res/drawable/ic_download_clear.xml delete mode 100644 app/src/main/res/drawable/ic_download_manager.xml delete mode 100644 app/src/main/res/drawable/ic_download_pause.xml delete mode 100644 app/src/main/res/drawable/ic_download_resume.xml delete mode 100644 app/src/main/res/drawable/ic_downloads.xml delete mode 100644 app/src/main/res/drawable/ic_edit.xml delete mode 100644 app/src/main/res/drawable/ic_education.xml delete mode 100644 app/src/main/res/drawable/ic_entertainment.xml delete mode 100644 app/src/main/res/drawable/ic_events.xml delete mode 100644 app/src/main/res/drawable/ic_family.xml delete mode 100644 app/src/main/res/drawable/ic_filter_apps.xml create mode 100644 app/src/main/res/drawable/ic_filter_check.xml delete mode 100644 app/src/main/res/drawable/ic_finance.xml delete mode 100644 app/src/main/res/drawable/ic_food_drink.xml create mode 100644 app/src/main/res/drawable/ic_free.xml delete mode 100644 app/src/main/res/drawable/ic_games.xml delete mode 100644 app/src/main/res/drawable/ic_google_play.xml rename app/src/main/res/drawable/{ic_open.xml => ic_grossing.xml} (53%) delete mode 100644 app/src/main/res/drawable/ic_health_fitness.xml delete mode 100644 app/src/main/res/drawable/ic_house_home.xml delete mode 100644 app/src/main/res/drawable/ic_installation_alt.xml delete mode 100644 app/src/main/res/drawable/ic_libraries_demo.xml delete mode 100644 app/src/main/res/drawable/ic_lifestyle.xml delete mode 100644 app/src/main/res/drawable/ic_maps_navigation.xml delete mode 100644 app/src/main/res/drawable/ic_medical.xml create mode 100644 app/src/main/res/drawable/ic_menu_about.xml create mode 100644 app/src/main/res/drawable/ic_menu_account.xml create mode 100644 app/src/main/res/drawable/ic_menu_blacklist.xml create mode 100644 app/src/main/res/drawable/ic_menu_download.xml create mode 100644 app/src/main/res/drawable/ic_menu_fav.xml create mode 100644 app/src/main/res/drawable/ic_menu_line.xml create mode 100644 app/src/main/res/drawable/ic_menu_settings.xml create mode 100644 app/src/main/res/drawable/ic_menu_spoof.xml delete mode 100644 app/src/main/res/drawable/ic_music__audio.xml delete mode 100644 app/src/main/res/drawable/ic_news_magazines.xml delete mode 100644 app/src/main/res/drawable/ic_parenting.xml delete mode 100644 app/src/main/res/drawable/ic_perm.xml delete mode 100644 app/src/main/res/drawable/ic_personalization.xml delete mode 100644 app/src/main/res/drawable/ic_photography.xml delete mode 100644 app/src/main/res/drawable/ic_productivity.xml delete mode 100644 app/src/main/res/drawable/ic_rating_negative.xml delete mode 100644 app/src/main/res/drawable/ic_rating_positive.xml delete mode 100644 app/src/main/res/drawable/ic_search.xml delete mode 100644 app/src/main/res/drawable/ic_settings.xml delete mode 100644 app/src/main/res/drawable/ic_shopping.xml delete mode 100644 app/src/main/res/drawable/ic_size.xml delete mode 100644 app/src/main/res/drawable/ic_social.xml delete mode 100644 app/src/main/res/drawable/ic_spoof_alt.xml delete mode 100644 app/src/main/res/drawable/ic_sports.xml delete mode 100644 app/src/main/res/drawable/ic_star.xml delete mode 100644 app/src/main/res/drawable/ic_tab_explore.xml delete mode 100644 app/src/main/res/drawable/ic_tab_games.xml delete mode 100644 app/src/main/res/drawable/ic_tools.xml delete mode 100644 app/src/main/res/drawable/ic_travel_local.xml create mode 100644 app/src/main/res/drawable/ic_trending.xml delete mode 100644 app/src/main/res/drawable/ic_video_editors.xml delete mode 100644 app/src/main/res/drawable/ic_weather.xml delete mode 100644 app/src/main/res/drawable/installed_bg.xml create mode 100644 app/src/main/res/drawable/outline_bg_rounded.xml delete mode 100644 app/src/main/res/drawable/tab_indicator.xml delete mode 100644 app/src/main/res/drawable/vd_downloading.xml delete mode 100644 app/src/main/res/font/open_sans_semibold.xml rename app/src/main/res/layout/{fragment_installed.xml => activity_all_apps.xml} (53%) create mode 100644 app/src/main/res/layout/activity_category_apps.xml rename app/src/main/res/layout/{fragment_apps.xml => activity_dev_apps.xml} (57%) rename app/src/main/res/{drawable/category_bg.xml => layout/activity_generic.xml} (57%) create mode 100644 app/src/main/res/layout/activity_reviews.xml create mode 100644 app/src/main/res/layout/activity_search.xml create mode 100644 app/src/main/res/layout/activity_search_result.xml create mode 100644 app/src/main/res/layout/activity_splash.xml delete mode 100644 app/src/main/res/layout/fragment_category_container.xml delete mode 100644 app/src/main/res/layout/fragment_details.xml delete mode 100644 app/src/main/res/layout/fragment_search.xml delete mode 100644 app/src/main/res/layout/fragment_search_applist.xml delete mode 100644 app/src/main/res/layout/include_details_all.xml delete mode 100644 app/src/main/res/layout/item_category_top.xml create mode 100644 app/src/main/res/layout/item_empty.xml create mode 100644 app/src/main/res/layout/item_error.xml create mode 100644 app/src/main/res/layout/item_header.xml create mode 100644 app/src/main/res/layout/item_header_updates.xml delete mode 100644 app/src/main/res/layout/item_history.xml create mode 100644 app/src/main/res/layout/item_loading.xml create mode 100644 app/src/main/res/layout/item_nav_header.xml create mode 100644 app/src/main/res/layout/item_preference.xml rename app/src/main/res/layout/{item_review_list.xml => item_review.xml} (72%) create mode 100644 app/src/main/res/layout/item_searchview.xml rename app/src/main/res/layout/{sheet_reviews.xml => item_suggestion.xml} (52%) create mode 100644 app/src/main/res/layout/search_bar.xml create mode 100644 app/src/main/res/menu/menu_drawer.xml rename app/src/main/res/menu/{menu_main.xml => navigation_category.xml} (66%) mode change 100644 => 100755 rename app/src/main/res/menu/{navigation.xml => navigation_main.xml} (71%) create mode 100644 app/src/main/res/navigation/nav_graph_category.xml create mode 100644 app/src/main/res/navigation/nav_graph_intro.xml create mode 100644 app/src/main/res/navigation/nav_graph_main.xml delete mode 100644 app/src/main/res/values/font_certs.xml delete mode 100644 app/src/main/res/values/preloaded_fonts.xml diff --git a/README.md b/README.md index 255c65faa..3113e5f71 100644 --- a/README.md +++ b/README.md @@ -197,4 +197,4 @@ While *Aurora Store* was originally based on Sergei Yeriomin's [Yalp store](http * [Raccoon](https://github.com/onyxbits/raccoon4) * [SAI](https://github.com/Aefyr/SAI) -[Get it on F-Droid](https://f-droid.org/packages/com.dragons.aurora/) [Join POEditor](https://poeditor.com/join/project/54swaCpFXJ) \ No newline at end of file +[Get it on F-Droid](https://f-droid.org/packages/com.dragons.aurora/) [Join POEditor](https://poeditor.com/join/project/54swaCpFXJ) diff --git a/app/build.gradle b/app/build.gradle index 65f898fe7..ad8f2c270 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,7 +42,9 @@ android { } buildTypes { release { - minifyEnabled false + minifyEnabled true + zipAlignEnabled true + shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } @@ -52,19 +54,7 @@ android { sourceCompatibility 1.8 } lintOptions { - checkReleaseBuilds false - abortOnError false - } -} - -configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - def requested = details.requested - if (requested.group == "androidx") { - if (!requested.name.startsWith("multidex")) { - details.useVersion "${targetSdk}.+" - } - } + warning 'MissingTranslation', 'GetLocales', 'VectorDrawableCompat' } } @@ -72,12 +62,19 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'commons-io:commons-io:2.6' implementation 'org.apache.maven:maven-artifact:3.6.2' + implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' + //UI-Libs implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4' implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' - implementation 'com.google.android.material:material:1.1.0-alpha10' implementation 'androidx.palette:palette:1.0.0' + implementation 'androidx.navigation:navigation-fragment:2.1.0' + implementation 'androidx.navigation:navigation-ui:2.1.0' + implementation 'com.google.android.material:material:1.1.0-alpha10' + implementation 'io.github.luizgrp.sectionedrecyclerviewadapter:sectionedrecyclerviewadapter:3.0.0' + //Utils implementation 'androidx.annotation:annotation:1.1.0' implementation 'org.apache.commons:commons-text:1.8' @@ -85,18 +82,23 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' compileOnly 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10' + //PlayStoreApi implementation 'com.github.whyorean:playstore-api-v2:2.4' + //OkHTTP3 implementation 'com.squareup.okhttp3:okhttp:4.2.2' implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.2.2' + //RX-Java2 implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'io.reactivex.rxjava2:rxjava:2.2.14' implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.1' + //ButterKnife implementation 'com.jakewharton:butterknife:10.2.0' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0' + //Glide implementation 'com.github.bumptech.glide:glide:4.10.0' implementation "com.github.bumptech.glide:okhttp3-integration:4.10.0" diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 95f167ef0..a69866ef8 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -51,4 +51,6 @@ # is used to reflectively look up the generated ViewBinding. -keep class butterknife.* -keepclasseswithmembernames class * { @butterknife.* ; } --keepclasseswithmembernames class * { @butterknife.* ; } \ No newline at end of file +-keepclasseswithmembernames class * { @butterknife.* ; } + +-keep public class com.aurora.store.ui.preference.fragment.* \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 975db7342..99ceddeca 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -67,34 +67,12 @@ tools:targetApi="q"> - - - - - - - - - - - - - - - - - - @@ -121,36 +99,61 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + - \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/AnonymousLoginService.java b/app/src/main/java/com/aurora/store/AnonymousLoginService.java deleted file mode 100644 index 8163e4bf0..000000000 --- a/app/src/main/java/com/aurora/store/AnonymousLoginService.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.aurora.store; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -import androidx.annotation.Nullable; - -import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.events.Event; -import com.aurora.store.events.Events; -import com.aurora.store.events.RxBus; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.Log; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class AnonymousLoginService extends Service { - - public static AnonymousLoginService instance = null; - - private CompositeDisposable disposable = new CompositeDisposable(); - - public static boolean isServiceRunning() { - try { - return instance != null && instance.isRunning(); - } catch (NullPointerException e) { - return false; - } - } - - private boolean isRunning() { - return true; - } - - @Nullable - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return START_NOT_STICKY; - } - - @Override - public void onCreate() { - super.onCreate(); - login(); - } - - private void login() { - disposable.add(Observable.fromCallable(() -> PlayStoreApiAuthenticator - .login(this)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((api) -> { - if (api != null) { - Log.i("Anonymous Login Successful"); - Accountant.setAnonymous(this, true); - RxBus.publish(new Event(Events.LOGGED_IN)); - } else - Log.e("Anonymous Login Failed Permanently"); - destroyService(); - }, err -> { - Log.e(err.getMessage()); - destroyService(); - })); - } - - @Override - public void onDestroy() { - instance = null; - super.onDestroy(); - } - - private void destroyService() { - Log.e("Anonymous login service destroyed"); - stopSelf(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/AppDiffCallback.java b/app/src/main/java/com/aurora/store/AppDiffCallback.java new file mode 100644 index 000000000..857634542 --- /dev/null +++ b/app/src/main/java/com/aurora/store/AppDiffCallback.java @@ -0,0 +1,37 @@ +package com.aurora.store; + +import androidx.recyclerview.widget.DiffUtil; + +import com.aurora.store.model.App; + +import java.util.List; + +public class AppDiffCallback extends DiffUtil.Callback { + private List newList; + private List oldList; + + public AppDiffCallback(List newList, List oldList) { + this.newList = newList; + this.oldList = oldList; + } + + @Override + public int getOldListSize() { + return oldList != null ? oldList.size() : 0; + } + + @Override + public int getNewListSize() { + return newList != null ? newList.size() : 0; + } + + @Override + public boolean areItemsTheSame(int oldIndex, int newIndex) { + return true; + } + + @Override + public boolean areContentsTheSame(int oldIndex, int newIndex) { + return oldList.get(oldIndex).equals(newList.get(newIndex)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/AuroraApplication.java b/app/src/main/java/com/aurora/store/AuroraApplication.java index e1eac1cdd..c7bd8f09d 100644 --- a/app/src/main/java/com/aurora/store/AuroraApplication.java +++ b/app/src/main/java/com/aurora/store/AuroraApplication.java @@ -24,11 +24,15 @@ import android.annotation.SuppressLint; import android.app.Application; import android.content.IntentFilter; +import com.aurora.store.events.Event; +import com.aurora.store.events.RxBus; import com.aurora.store.installer.Installer; import com.aurora.store.installer.InstallerService; import com.aurora.store.installer.Uninstaller; import com.aurora.store.model.App; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Log; +import com.aurora.store.util.Util; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import java.util.ArrayList; import java.util.Iterator; @@ -38,20 +42,27 @@ import io.reactivex.plugins.RxJavaPlugins; public class AuroraApplication extends Application { - public static boolean updating = false; - public static List ongoingUpdateList = new ArrayList<>(); + public static GooglePlayAPI api = null; + + private static RxBus rxBus = null; + private static boolean bulkUpdateAlive = false; + private static List ongoingUpdateList = new ArrayList<>(); @SuppressLint("StaticFieldLeak") - public static Installer installer; + private static Installer installer; @SuppressLint("StaticFieldLeak") - public static Uninstaller uninstaller; + private static Uninstaller uninstaller; - public static boolean getOnGoingUpdate() { - return updating; + public static RxBus getRxBus() { + return rxBus; } - public static void setOnGoingUpdate(boolean updating) { - AuroraApplication.updating = updating; + public static boolean isBulkUpdateAlive() { + return bulkUpdateAlive; + } + + public static void setBulkUpdateAlive(boolean updating) { + AuroraApplication.bulkUpdateAlive = updating; } public static List getOngoingUpdateList() { @@ -69,7 +80,7 @@ public class AuroraApplication extends Application { iterator.remove(); } if (ongoingUpdateList.isEmpty()) - setOnGoingUpdate(false); + setBulkUpdateAlive(false); } public static Installer getInstaller() { @@ -80,24 +91,35 @@ public class AuroraApplication extends Application { return uninstaller; } + public static void rxNotify(Event event) { + rxBus.getBus().accept(event); + } + @Override public void onCreate() { super.onCreate(); + + rxBus = new RxBus(); installer = new Installer(this); uninstaller = new Uninstaller(this); + + //Clear all old installation sessions. Util.clearOldInstallationSessions(this); + + //Register global install broadcast receiver. registerReceiver(installer.getPackageInstaller().getBroadcastReceiver(), new IntentFilter(InstallerService.ACTION_INSTALLATION_STATUS_NOTIFICATION)); - RxJavaPlugins.setErrorHandler(err -> { - }); + + //Global RX-Error handler, just simply logs, I make sure all errors are handled at origin. + RxJavaPlugins.setErrorHandler(err -> Log.i(err.getMessage())); } @Override public void onTerminate() { - super.onTerminate(); try { unregisterReceiver(installer.getPackageInstaller().getBroadcastReceiver()); } catch (Exception ignored) { } + super.onTerminate(); } } diff --git a/app/src/main/java/com/aurora/store/AuroraGlide.java b/app/src/main/java/com/aurora/store/AuroraGlide.java index a78066cbb..879ba0584 100644 --- a/app/src/main/java/com/aurora/store/AuroraGlide.java +++ b/app/src/main/java/com/aurora/store/AuroraGlide.java @@ -25,7 +25,7 @@ import android.graphics.Bitmap; import androidx.annotation.NonNull; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import com.bumptech.glide.Glide; import com.bumptech.glide.GlideBuilder; import com.bumptech.glide.Registry; diff --git a/app/src/main/java/com/aurora/store/BulkUpdateService.java b/app/src/main/java/com/aurora/store/BulkUpdateService.java new file mode 100644 index 000000000..adc38d4d5 --- /dev/null +++ b/app/src/main/java/com/aurora/store/BulkUpdateService.java @@ -0,0 +1,110 @@ +package com.aurora.store; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +import com.aurora.store.events.Event; +import com.aurora.store.exception.CredentialsEmptyException; +import com.aurora.store.exception.MalformedRequestException; +import com.aurora.store.exception.NotPurchasedException; +import com.aurora.store.exception.TooManyRequestsException; +import com.aurora.store.model.App; +import com.aurora.store.notification.QuickNotification; +import com.aurora.store.task.LiveUpdate; +import com.aurora.store.task.ObservableDeliveryData; +import com.aurora.store.util.Log; +import com.dragons.aurora.playstoreapiv2.AuthException; + +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class BulkUpdateService extends Service { + public static BulkUpdateService instance = null; + + private List appList = new ArrayList<>(); + private CompositeDisposable disposable = new CompositeDisposable(); + + public static boolean isServiceRunning() { + try { + return instance != null && instance.isRunning(); + } catch (NullPointerException e) { + return false; + } + } + + private boolean isRunning() { + return true; + } + + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return START_NOT_STICKY; + } + + @Override + public void onCreate() { + super.onCreate(); + instance = this; + appList = AuroraApplication.getOngoingUpdateList(); + updateAllApps(); + } + + private void updateAllApps() { + AuroraApplication.setBulkUpdateAlive(true); + AuroraApplication.rxNotify(new Event(Event.SubType.BULK_UPDATE_NOTIFY)); + disposable.add(Observable.fromIterable(appList) + .flatMap(app -> new ObservableDeliveryData(getApplicationContext()).getDeliveryData(app)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext(deliveryDataBundle -> new LiveUpdate(getApplicationContext()) + .enqueueUpdate(deliveryDataBundle.getApp(), + deliveryDataBundle.getAndroidAppDeliveryData())) + .subscribe(deliveryDataBundle -> { + }, err -> { + if (err instanceof MalformedRequestException || err instanceof NotPurchasedException) { + QuickNotification.show(getApplication(), + getString(R.string.action_updates), + err.getMessage(), + null); + } + processException(err); + Log.e(err.getMessage()); + })); + } + + private void processException(Throwable e) { + if (e instanceof CredentialsEmptyException) { + AuroraApplication.rxNotify(new Event(Event.SubType.API_ERROR)); + } else if (e instanceof AuthException | e instanceof TooManyRequestsException) { + AuroraApplication.rxNotify(new Event(Event.SubType.API_FAILED)); + } else if (e instanceof UnknownHostException) { + AuroraApplication.rxNotify(new Event(Event.SubType.NETWORK_UNAVAILABLE)); + } else + Log.e(e.getMessage()); + stopSelf(); + } + + @Override + public void onDestroy() { + AuroraApplication.setBulkUpdateAlive(false); + AuroraApplication.rxNotify(new Event(Event.SubType.BULK_UPDATE_NOTIFY)); + instance = null; + super.onDestroy(); + } +} diff --git a/app/src/main/java/com/aurora/store/Constants.java b/app/src/main/java/com/aurora/store/Constants.java index 569906118..aac0b8bc1 100644 --- a/app/src/main/java/com/aurora/store/Constants.java +++ b/app/src/main/java/com/aurora/store/Constants.java @@ -31,6 +31,7 @@ public class Constants { public static final String INTENT_DEVICE_NAME = "INTENT_DEVICE_NAME"; public static final String INTENT_DEVICE_INDEX = "INTENT_DEVICE_INDEX"; public static final String INTENT_FRAGMENT_POSITION = "INTENT_FRAGMENT_POSITION"; + public static final String INTENT_PACKAGE_NAME = "INTENT_PACKAGE_NAME"; public static final String BUILD_DEVICE = "Build.DEVICE"; public static final String BUILD_MANUFACTURER = "Build.MANUFACTURER"; @@ -40,16 +41,18 @@ public class Constants { public static final String TAG = "Aurora Store"; public static final String FILES = "Files"; + public static final String CATEGORY_APPS = "APPLICATION"; + public static final String CATEGORY_GAME = "GAME"; + public static final String CATEGORY_FAMILY = "FAMILY"; + + public static final String TOP_APPS = "TOP_APPS"; + public static final String TOP_GAME = "TOP_GAME"; + public static final String TOP_FAMILY = "TOP_FAMILY"; + public static final String RECENT_HISTORY = "RECENT_HISTORY"; - public static final String FILTER_SYSTEM_APPS = "FILTER_SYSTEM_APPS"; - public static final String FILTER_APPS_WITH_ADS = "FILTER_APPS_WITH_ADS"; - public static final String FILTER_PAID_APPS = "FILTER_PAID_APPS"; - public static final String FILTER_GSF_DEPENDENT_APPS = "FILTER_GSF_DEPENDENT_APPS"; - public static final String FILTER_CATEGORY = "FILTER_CATEGORY"; - public static final String FILTER_RATING = "FILTER_RATING"; - public static final String FILTER_DOWNLOADS = "FILTER_DOWNLOADS"; - + public static final String NOTIFICATION_CHANNEL_ALERT = "NOTIFICATION_CHANNEL_ALERT"; + public static final String NOTIFICATION_CHANNEL_GENERAL = "NOTIFICATION_CHANNEL_GENERAL"; public static final String PRIVILEGED_EXTENSION_PACKAGE_NAME = "com.aurora.services"; public static final String PRIVILEGED_EXTENSION_SERVICE_INTENT = "com.aurora.services.IPrivilegedService"; @@ -57,9 +60,7 @@ public class Constants { public static final String PREFERENCE_THEME = "PREFERENCE_THEME"; public static final String PREFERENCE_DEFAULT_TAB = "PREFERENCE_DEFAULT_TAB"; public static final String PREFERENCE_UI_CARD_STYLE = "PREFERENCE_UI_CARD_STYLE"; - public static final String PREFERENCE_UI_TRANSPARENT = "PREFERENCE_UI_TRANSPARENT"; public static final String PREFERENCE_FEATURED_SNAP = "PREFERENCE_FEATURED_SNAP"; - public static final String PREFERENCE_TAB_MODE = "PREFERENCE_TAB_MODE"; public static final String PREFERENCE_SEARCH_IME = "PREFERENCE_SEARCH_IME"; public static final String PREFERENCE_SEARCH_PACKAGE = "PREFERENCE_SEARCH_PACKAGE"; public static final String PREFERENCE_DO_NOT_SHOW_INTRO = "PREFERENCE_DO_NOT_SHOW_INTRO"; @@ -70,6 +71,7 @@ public class Constants { public static final String PREFERENCE_DEVICE_TO_PRETEND_TO_BE_INDEX = "PREFERENCE_DEVICE_TO_PRETEND_TO_BE_INDEX"; public static final String PREFERENCE_REQUESTED_LOCATION_INDEX = "PREFERENCE_REQUESTED_LOCATION_INDEX"; public static final String PREFERENCE_BLACKLIST_APPS_LIST = "PREFERENCE_BLACKLIST_APPS_LIST"; + public static final String PREFERENCE_FILTER_APPS = "PREFERENCE_FILTER_APPS"; public static final String PREFERENCE_FILTER_GOOGLE = "PREFERENCE_FILTER_GOOGLE"; public static final String PREFERENCE_FILTER_F_DROID = "PREFERENCE_FILTER_F_DROID"; public static final String PREFERENCE_FILTER_SEARCH = "PREFERENCE_FILTER_SEARCH"; @@ -109,11 +111,16 @@ public class Constants { public static final String PREFERENCE_INSTALLATION_PROFILE = "PREFERENCE_INSTALLATION_PROFILE"; public static final String PREFERENCE_ACCOUNTS_PASSWORD_SWITCH = "PREFERENCE_ACCOUNTS_PASSWORD_SWITCH"; - public static final String PREFERENCE_TOP_APPS = "PREFERENCE_TOP_APPS"; - public static final String PREFERENCE_TOP_GAMES = "PREFERENCE_TOP_GAMES"; - public static final String PREFERENCE_TOP_FAMILY = "PREFERENCE_TOP_FAMILY"; public static final String PREFERENCE_INSTALLED_APPS = "PREFERENCE_INSTALLED_APPS"; public static final String PREFERENCE_CACHE_DATE = "PREFERENCE_CACHE_DATE"; public static final String PREFERENCE_SELF_UPDATE_DATE = "PREFERENCE_SELF_UPDATE_DATE"; public static final String PREFERENCE_SELF_UPDATE = "PREFERENCE_SELF_UPDATE"; + + + public static final String FRAGMENT_NAME = "FRAGMENT_NAME"; + public static final String FRAGMENT_ABOUT = "FRAGMENT_ABOUT"; + public static final String FRAGMENT_ACCOUNTS = "FRAGMENT_ACCOUNTS"; + public static final String FRAGMENT_BLACKLIST = "FRAGMENT_BLACKLIST"; + public static final String FRAGMENT_FAV_LIST = "FRAGMENT_FAV_LIST"; + public static final String FRAGMENT_SPOOF = "FRAGMENT_SPOOF"; } diff --git a/app/src/main/java/com/aurora/store/FavouriteItemTouchHelper.java b/app/src/main/java/com/aurora/store/FavouriteItemTouchHelper.java deleted file mode 100644 index 8fe60f4ee..000000000 --- a/app/src/main/java/com/aurora/store/FavouriteItemTouchHelper.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store; - -import android.graphics.Canvas; -import android.view.View; - -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.adapter.SelectableViewHolder; - -import org.jetbrains.annotations.NotNull; - -public class FavouriteItemTouchHelper extends ItemTouchHelper.SimpleCallback { - - private RecyclerItemTouchHelperListener listener; - - public FavouriteItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) { - super(dragDirs, swipeDirs); - this.listener = listener; - } - - @Override - public boolean onMove(@NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder viewHolder, @NotNull RecyclerView.ViewHolder target) { - return true; - } - - @Override - public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { - if (viewHolder != null) { - final View foregroundView = ((SelectableViewHolder) viewHolder).viewForeground; - getDefaultUIUtil().onSelected(foregroundView); - } - } - - @Override - public void onChildDrawOver(@NotNull Canvas c, @NotNull RecyclerView recyclerView, - RecyclerView.ViewHolder viewHolder, float dX, float dY, - int actionState, boolean isCurrentlyActive) { - final View foregroundView = ((SelectableViewHolder) viewHolder).viewForeground; - getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY, - actionState, isCurrentlyActive); - } - - @Override - public void clearView(@NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder viewHolder) { - final View foregroundView = ((SelectableViewHolder) viewHolder).viewForeground; - getDefaultUIUtil().clearView(foregroundView); - } - - @Override - public void onChildDraw(@NotNull Canvas c, @NotNull RecyclerView recyclerView, @NotNull - RecyclerView.ViewHolder viewHolder, float dX, float dY, - int actionState, boolean isCurrentlyActive) { - final View foregroundView = ((SelectableViewHolder) viewHolder).viewForeground; - - getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY, - actionState, isCurrentlyActive); - } - - @Override - public void onSwiped(@NotNull RecyclerView.ViewHolder viewHolder, int direction) { - listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition()); - } - - @Override - public int convertToAbsoluteDirection(int flags, int layoutDirection) { - return super.convertToAbsoluteDirection(flags, layoutDirection); - } - - public interface RecyclerItemTouchHelperListener { - void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position); - } -} diff --git a/app/src/main/java/com/aurora/store/Filter.java b/app/src/main/java/com/aurora/store/Filter.java deleted file mode 100644 index 4843cdbc4..000000000 --- a/app/src/main/java/com/aurora/store/Filter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Yalp Store - * Copyright (C) 2018 Sergey Yeriomin - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store; - -import android.content.Context; -import android.content.SharedPreferences; - -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; - -public class Filter { - - private Context context; - - public Filter(Context context) { - this.context = context; - } - - public com.aurora.store.model.Filter getFilterPreferences() { - com.aurora.store.model.Filter filter = new com.aurora.store.model.Filter(); - SharedPreferences prefs = Util.getPrefs(context); - filter.setSystemApps(prefs.getBoolean(Constants.FILTER_SYSTEM_APPS, false)); - filter.setAppsWithAds(prefs.getBoolean(Constants.FILTER_APPS_WITH_ADS, true)); - filter.setPaidApps(prefs.getBoolean(Constants.FILTER_PAID_APPS, true)); - filter.setGsfDependentApps(prefs.getBoolean(Constants.FILTER_GSF_DEPENDENT_APPS, true)); - filter.setCategory(prefs.getString(Constants.FILTER_CATEGORY, Constants.TOP)); - filter.setRating(prefs.getFloat(Constants.FILTER_RATING, 0.0f)); - filter.setDownloads(prefs.getInt(Constants.FILTER_DOWNLOADS, 0)); - return filter; - } - - public void resetFilterPreferences() { - SharedPreferences prefs = Util.getPrefs(context); - PrefUtil.putBoolean(context, Constants.FILTER_SYSTEM_APPS, false); - PrefUtil.putBoolean(context, Constants.FILTER_APPS_WITH_ADS, true); - PrefUtil.putBoolean(context, Constants.FILTER_PAID_APPS, true); - PrefUtil.putBoolean(context, Constants.FILTER_GSF_DEPENDENT_APPS, true); - PrefUtil.putString(context, Constants.FILTER_CATEGORY, Constants.TOP); - PrefUtil.putFloat(context, Constants.FILTER_RATING, 0.0f); - PrefUtil.putInteger(context, Constants.FILTER_DOWNLOADS, 0); - } -} diff --git a/app/src/main/java/com/aurora/store/HistoryItemTouchHelper.java b/app/src/main/java/com/aurora/store/HistoryItemTouchHelper.java deleted file mode 100644 index e93bc13b9..000000000 --- a/app/src/main/java/com/aurora/store/HistoryItemTouchHelper.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store; - -import android.graphics.Canvas; -import android.view.View; - -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.adapter.SearchHistoryAdapter; - -public class HistoryItemTouchHelper extends ItemTouchHelper.SimpleCallback { - - private RecyclerItemTouchHelperListener listener; - - public HistoryItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) { - super(dragDirs, swipeDirs); - this.listener = listener; - } - - @Override - public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { - return true; - } - - @Override - public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { - if (viewHolder != null) { - final View foregroundView = ((SearchHistoryAdapter.ViewHolder) viewHolder).viewForeground; - getDefaultUIUtil().onSelected(foregroundView); - } - } - - @Override - public void onChildDrawOver(Canvas c, RecyclerView recyclerView, - RecyclerView.ViewHolder viewHolder, float dX, float dY, - int actionState, boolean isCurrentlyActive) { - final View foregroundView = ((SearchHistoryAdapter.ViewHolder) viewHolder).viewForeground; - getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY, - actionState, isCurrentlyActive); - } - - @Override - public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { - final View foregroundView = ((SearchHistoryAdapter.ViewHolder) viewHolder).viewForeground; - getDefaultUIUtil().clearView(foregroundView); - } - - @Override - public void onChildDraw(Canvas c, RecyclerView recyclerView, - RecyclerView.ViewHolder viewHolder, float dX, float dY, - int actionState, boolean isCurrentlyActive) { - final View foregroundView = ((SearchHistoryAdapter.ViewHolder) viewHolder).viewForeground; - - getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY, - actionState, isCurrentlyActive); - } - - @Override - public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { - listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition()); - } - - @Override - public int convertToAbsoluteDirection(int flags, int layoutDirection) { - return super.convertToAbsoluteDirection(flags, layoutDirection); - } - - public interface RecyclerItemTouchHelperListener { - void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position); - } -} diff --git a/app/src/main/java/com/aurora/store/ListType.java b/app/src/main/java/com/aurora/store/ListType.java deleted file mode 100644 index b94104046..000000000 --- a/app/src/main/java/com/aurora/store/ListType.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store; - -public enum ListType { - INSTALLED, - UPDATES, - ENDLESS -} diff --git a/app/src/main/java/com/aurora/store/PermissionGroup.java b/app/src/main/java/com/aurora/store/PermissionGroup.java index b1284003a..da48647d1 100644 --- a/app/src/main/java/com/aurora/store/PermissionGroup.java +++ b/app/src/main/java/com/aurora/store/PermissionGroup.java @@ -37,8 +37,8 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.apache.commons.lang3.StringUtils; @@ -101,7 +101,7 @@ public class PermissionGroup extends LinearLayout { public void setPermissionGroupInfo(final PermissionGroupInfo permissionGroupInfo) { this.permissionGroupInfo = permissionGroupInfo; - ImageView imageView = (ImageView) findViewById(R.id.permission_group_icon); + ImageView imageView = findViewById(R.id.permission_group_icon); imageView.setImageDrawable(getPermissionGroupIcon(permissionGroupInfo)); imageView.setColorFilter(ViewUtil.getStyledAttribute(imageView.getContext(), android.R.attr.colorAccent)); } diff --git a/app/src/main/java/com/aurora/store/PermissionsComparator.java b/app/src/main/java/com/aurora/store/PermissionsComparator.java deleted file mode 100644 index 3f4c6b40e..000000000 --- a/app/src/main/java/com/aurora/store/PermissionsComparator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Yalp Store - * Copyright (C) 2018 Sergey Yeriomin - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.text.TextUtils; - -import com.aurora.store.model.App; -import com.aurora.store.utility.Log; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -public class PermissionsComparator { - - private Context context; - - public PermissionsComparator(Context context) { - this.context = context; - } - - public boolean isSame(App app) { - Log.i("Checking %s", app.getPackageName()); - Set oldPermissions = getOldPermissions(app.getPackageName()); - if (null == oldPermissions) { - return true; - } - Set newPermissions = new HashSet<>(app.getPermissions()); - newPermissions.removeAll(oldPermissions); - Log.i(newPermissions.isEmpty() - ? app.getPackageName() + " requests no new permissions" - : app.getPackageName() + " requests new permissions: " + TextUtils.join(", ", newPermissions)); - return newPermissions.isEmpty(); - } - - private Set getOldPermissions(String packageName) { - PackageManager pm = context.getPackageManager(); - try { - PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); - return new HashSet<>(Arrays.asList( - null == pi.requestedPermissions - ? new String[0] - : pi.requestedPermissions - )); - } catch (PackageManager.NameNotFoundException e) { - Log.e("Package " + packageName + " doesn't seem to be installed"); - } - return null; - } -} diff --git a/app/src/main/java/com/aurora/store/ReviewsDiffCallback.java b/app/src/main/java/com/aurora/store/ReviewsDiffCallback.java new file mode 100644 index 000000000..554790721 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ReviewsDiffCallback.java @@ -0,0 +1,37 @@ +package com.aurora.store; + +import androidx.recyclerview.widget.DiffUtil; + +import com.aurora.store.model.Review; + +import java.util.List; + +public class ReviewsDiffCallback extends DiffUtil.Callback { + private List newList; + private List oldList; + + public ReviewsDiffCallback(List newList, List oldList) { + this.newList = newList; + this.oldList = oldList; + } + + @Override + public int getOldListSize() { + return oldList != null ? oldList.size() : 0; + } + + @Override + public int getNewListSize() { + return newList != null ? newList.size() : 0; + } + + @Override + public boolean areItemsTheSame(int oldIndex, int newIndex) { + return true; + } + + @Override + public boolean areContentsTheSame(int oldIndex, int newIndex) { + return oldList.get(oldIndex).equals(newList.get(newIndex)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/SelfUpdateService.java b/app/src/main/java/com/aurora/store/SelfUpdateService.java index 268f20dcc..d65d2da79 100644 --- a/app/src/main/java/com/aurora/store/SelfUpdateService.java +++ b/app/src/main/java/com/aurora/store/SelfUpdateService.java @@ -18,10 +18,10 @@ import com.aurora.store.download.RequestBuilder; import com.aurora.store.model.App; import com.aurora.store.model.Update; import com.aurora.store.task.NetworkTask; -import com.aurora.store.utility.CertUtil; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; +import com.aurora.store.util.CertUtil; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; import com.google.gson.Gson; import com.tonyodev.fetch2.AbstractFetchGroupListener; import com.tonyodev.fetch2.Download; @@ -79,6 +79,7 @@ public class SelfUpdateService extends Service { @Override public void onCreate() { super.onCreate(); + instance = this; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { startForeground(1, getNotification()); } else { @@ -119,7 +120,7 @@ public class SelfUpdateService extends Service { } else downloadAndUpdate(update); } catch (Exception e) { - Log.e("Error checking self-update"); + Log.d("Error checking self-update"); destroyService(); } })); @@ -189,7 +190,7 @@ public class SelfUpdateService extends Service { public void onError(int groupId, @NotNull Download download, @NotNull Error error, @org.jetbrains.annotations.Nullable Throwable throwable, @NotNull FetchGroup fetchGroup) { if (groupId == hashCode) { - Log.e("Error self-updating %s", app.getDisplayName()); + Log.d("Error self-updating %s", app.getDisplayName()); destroyService(); } } @@ -205,7 +206,7 @@ public class SelfUpdateService extends Service { @Override public void onCancelled(int groupId, @NotNull Download download, @NotNull FetchGroup fetchGroup) { if (groupId == hashCode) { - Log.e("Self-update cancelled %s", app.getDisplayName()); + Log.d("Self-update cancelled %s", app.getDisplayName()); destroyService(); } } diff --git a/app/src/main/java/com/aurora/store/SuggestionDiffCallback.java b/app/src/main/java/com/aurora/store/SuggestionDiffCallback.java new file mode 100644 index 000000000..469f6885d --- /dev/null +++ b/app/src/main/java/com/aurora/store/SuggestionDiffCallback.java @@ -0,0 +1,37 @@ +package com.aurora.store; + +import androidx.recyclerview.widget.DiffUtil; + +import com.dragons.aurora.playstoreapiv2.SearchSuggestEntry; + +import java.util.List; + +public class SuggestionDiffCallback extends DiffUtil.Callback { + private List newList; + private List oldList; + + public SuggestionDiffCallback(List newList, List oldList) { + this.newList = newList; + this.oldList = oldList; + } + + @Override + public int getOldListSize() { + return oldList != null ? oldList.size() : 0; + } + + @Override + public int getNewListSize() { + return newList != null ? newList.size() : 0; + } + + @Override + public boolean areItemsTheSame(int oldIndex, int newIndex) { + return true; + } + + @Override + public boolean areContentsTheSame(int oldIndex, int newIndex) { + return oldList.get(oldIndex).equals(newList.get(newIndex)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/TokenDispenserMirrors.java b/app/src/main/java/com/aurora/store/TokenDispenserMirrors.java index 0c5520595..bcb123f97 100644 --- a/app/src/main/java/com/aurora/store/TokenDispenserMirrors.java +++ b/app/src/main/java/com/aurora/store/TokenDispenserMirrors.java @@ -25,8 +25,8 @@ package com.aurora.store; import android.content.Context; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; import java.util.ArrayList; import java.util.List; diff --git a/app/src/main/java/com/aurora/store/ValidateApiService.java b/app/src/main/java/com/aurora/store/ValidateApiService.java new file mode 100644 index 000000000..a107a2daf --- /dev/null +++ b/app/src/main/java/com/aurora/store/ValidateApiService.java @@ -0,0 +1,130 @@ +package com.aurora.store; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +import com.aurora.store.api.PlayStoreApiAuthenticator; +import com.aurora.store.events.Event; +import com.aurora.store.exception.CredentialsEmptyException; +import com.aurora.store.exception.TooManyRequestsException; +import com.aurora.store.util.ApiBuilderUtil; +import com.aurora.store.util.Log; +import com.dragons.aurora.playstoreapiv2.AuthException; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; +import com.dragons.aurora.playstoreapiv2.TocResponse; + +import java.net.UnknownHostException; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class ValidateApiService extends Service { + public static ValidateApiService instance = null; + + private CompositeDisposable disposable = new CompositeDisposable(); + + + public static boolean isServiceRunning() { + try { + return instance != null && instance.isRunning(); + } catch (NullPointerException e) { + return false; + } + } + + private boolean isRunning() { + return true; + } + + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return START_NOT_STICKY; + } + + @Override + public void onCreate() { + super.onCreate(); + instance = this; + buildAndTestApi(); + } + + private void buildAndTestApi() { + Log.d(getString(R.string.toast_api_build_api)); + disposable.clear(); + disposable.add(Observable.fromCallable(() -> new PlayStoreApiAuthenticator() + .getPlayApi(this)) + .flatMap(api -> { + AuroraApplication.api = api; + return getTocResponse(api); + }) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> { + Log.d(getString(R.string.toast_api_all_ok)); + AuroraApplication.rxNotify(new Event(Event.SubType.API_SUCCESS)); + }, err -> { + Log.d(getString(R.string.toast_api_build_failed)); + processException(err); + }) + ); + } + + private void processException(Throwable e) { + if (e instanceof CredentialsEmptyException) { + AuroraApplication.rxNotify(new Event(Event.SubType.API_ERROR)); + } else if (e instanceof AuthException | e instanceof TooManyRequestsException) { + AuroraApplication.rxNotify(new Event(Event.SubType.API_FAILED)); + getNewAuthToken(); + } else if (e instanceof UnknownHostException) { + AuroraApplication.rxNotify(new Event(Event.SubType.NETWORK_UNAVAILABLE)); + } else + Log.e(e.getMessage()); + stopSelf(); + } + + public void getNewAuthToken() { + disposable.clear(); + disposable.add(Observable.fromCallable(() -> ApiBuilderUtil + .generateApiWithNewAuthToken(this)) + .flatMap(api -> { + AuroraApplication.api = api; + return getTocResponse(api); + }) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> { + AuroraApplication.rxNotify(new Event(Event.SubType.API_SUCCESS)); + }, err -> { + Log.e(err.getMessage()); + AuroraApplication.rxNotify(new Event(Event.SubType.API_ERROR)); + }) + ); + } + + public Observable getTocResponse(GooglePlayAPI api) { + return Observable.create(emitter -> { + TocResponse tocResponse = api.toc(); + emitter.onNext(tocResponse); + emitter.onComplete(); + }); + } + + + @Override + public void onDestroy() { + instance = null; + super.onDestroy(); + } +} diff --git a/app/src/main/java/com/aurora/store/activity/AuroraActivity.java b/app/src/main/java/com/aurora/store/activity/AuroraActivity.java deleted file mode 100644 index 3ecb2656a..000000000 --- a/app/src/main/java/com/aurora/store/activity/AuroraActivity.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.activity; - -import android.Manifest; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; - -import androidx.annotation.ColorInt; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.ColorUtils; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; - -import com.aurora.store.BuildConfig; -import com.aurora.store.Constants; -import com.aurora.store.R; -import com.aurora.store.SelfUpdateService; -import com.aurora.store.adapter.ViewPagerAdapter; -import com.aurora.store.fragment.AppsFragment; -import com.aurora.store.fragment.HomeFragment; -import com.aurora.store.fragment.SearchFragment; -import com.aurora.store.model.Update; -import com.aurora.store.task.NetworkTask; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.CertUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.NetworkUtil; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.TextUtil; -import com.aurora.store.utility.ThemeUtil; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; -import com.aurora.store.view.CustomViewPager; -import com.google.android.material.bottomnavigation.BottomNavigationView; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.gson.Gson; - -import java.util.Calendar; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class AuroraActivity extends AppCompatActivity { - - - public static String externalQuery; - - @BindView(R.id.toolbar) - Toolbar toolbar; - @BindView(R.id.viewpager) - CustomViewPager viewPager; - @BindView(R.id.bottom_navigation) - BottomNavigationView bottomNavigationView; - - private ActionBar actionBar; - private ViewPagerAdapter pagerAdapter; - private ThemeUtil themeUtil = new ThemeUtil(); - private CompositeDisposable disposable = new CompositeDisposable(); - private int fragmentCur = 0; - private boolean isSearchIntent = false; - - public BottomNavigationView getBottomNavigation() { - return bottomNavigationView; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - themeUtil.onCreate(this); - setContentView(R.layout.activity_main); - ButterKnife.bind(this); - fragmentCur = Util.getDefaultTab(this); - onNewIntent(getIntent()); - - if (!PrefUtil.getBoolean(this, Constants.PREFERENCE_DO_NOT_SHOW_INTRO)) { - PrefUtil.putBoolean(this, Constants.PREFERENCE_DO_NOT_SHOW_INTRO, true); - startActivity(new Intent(this, IntroActivity.class)); - finish(); - } else { - if (Accountant.isLoggedIn(this)) - init(); - else - startActivity(new Intent(this, AccountsActivity.class)); - } - - if (NetworkUtil.isConnected(this)) { - if (Util.isCacheObsolete(this)) - Util.clearCache(this); - - if (Util.shouldCheckUpdate(this) && !SelfUpdateService.isServiceRunning()) - checkSelfUpdate(); - } - checkPermissions(); - } - - private void init() { - setupActionbar(); - setupViewPager(); - setupBottomNavigation(); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - Bundle bundle = intent.getExtras(); - if (bundle != null) - fragmentCur = bundle.getInt(Constants.INTENT_FRAGMENT_POSITION); - else if (intent.getScheme() != null && intent.getScheme().equals("market")) { - fragmentCur = 2; - isSearchIntent = true; - if (intent.getData() != null) - externalQuery = intent.getData().getQueryParameter("q"); - } else - fragmentCur = Util.getDefaultTab(this); - } - - @Override - public void onBackPressed() { - Fragment fragment = pagerAdapter.getItem(viewPager.getCurrentItem()); - if (!fragment.isAdded()) - return; - if (fragment instanceof SearchFragment || fragment instanceof HomeFragment) { - FragmentManager fragmentManager = fragment.getChildFragmentManager(); - if (!fragmentManager.getFragments().isEmpty()) - fragmentManager.popBackStack(); - else - super.onBackPressed(); - } else - super.onBackPressed(); - } - - @Override - public boolean onSupportNavigateUp() { - return super.onSupportNavigateUp(); - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(final MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - case R.id.action_download: - startActivity(new Intent(this, DownloadsActivity.class)); - return true; - case R.id.action_setting: - startActivity(new Intent(this, SettingsActivity.class)); - return true; - } - return super.onOptionsItemSelected(menuItem); - } - - @Override - protected void onResume() { - super.onResume(); - themeUtil.onResume(this); - Util.toggleSoftInput(this, false); - if (pagerAdapter == null) - init(); - } - - @Override - protected void onUserLeaveHint() { - super.onUserLeaveHint(); - Util.toggleSoftInput(this, false); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - disposable.clear(); - } - - private void setupActionbar() { - setSupportActionBar(toolbar); - actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setElevation(0f); - actionBar.setTitle(getString(R.string.app_name)); - } - } - - private void setupViewPager() { - pagerAdapter = new ViewPagerAdapter(getSupportFragmentManager()); - pagerAdapter.addFragment(0, new HomeFragment()); - pagerAdapter.addFragment(1, new AppsFragment()); - pagerAdapter.addFragment(2, new SearchFragment()); - viewPager.setAdapter(pagerAdapter); - viewPager.setScroll(false); - viewPager.setOffscreenPageLimit(2); - viewPager.setCurrentItem(fragmentCur, true); - } - - private void setupBottomNavigation() { - @ColorInt - int backGroundColor = ViewUtil.getStyledAttribute(this, android.R.attr.colorBackground); - bottomNavigationView.setBackgroundColor(ColorUtils.setAlphaComponent(backGroundColor, 245)); - bottomNavigationView.setOnNavigationItemSelectedListener(menuItem -> { - viewPager.setCurrentItem(menuItem.getOrder(), true); - switch (menuItem.getItemId()) { - case R.id.action_home: - Util.toggleSoftInput(this, false); - actionBar.setTitle(getString(R.string.title_home)); - break; - case R.id.action_apps: - Util.toggleSoftInput(this, false); - actionBar.setTitle(getString(R.string.title_installed)); - break; - case R.id.action_search: - if (Util.isIMEEnabled(this)) - Util.toggleSoftInput(this, true); - actionBar.setTitle(getString(R.string.title_search)); - break; - } - return true; - }); - - if (isSearchIntent) - bottomNavigationView.setSelectedItemId(R.id.action_search); - if (fragmentCur != 0 && !isSearchIntent) - bottomNavigationView.setSelectedItemId(bottomNavigationView.getMenu() - .getItem(fragmentCur).getItemId()); - } - - private void checkSelfUpdate() { - disposable.add(Observable.fromCallable(() -> new NetworkTask(this) - .get(Constants.UPDATE_URL)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> { - try { - Util.setSelfUpdateTime(this, Calendar.getInstance().getTimeInMillis()); - Gson gson = new Gson(); - Update update = gson.fromJson(response, Update.class); - if (update.getVersionCode() > BuildConfig.VERSION_CODE) { - if (CertUtil.isFDroidApp(this, BuildConfig.APPLICATION_ID) - && TextUtil.emptyIfNull(update.getFdroidBuild()).isEmpty()) { - Log.d("FDroid build of latest version is not published yet"); - return; - } - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - showAddRepoDialog(update); - } else { - Log.i("No new update available"); - } - } - } catch (Exception e) { - Log.e("Error checking updates"); - } - })); - } - - private void checkPermissions() { - if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - 1337); - } - } - - protected void showAddRepoDialog(Update update) { - final String changelog = TextUtil.emptyIfNull(update.getChangelog()); - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this) - .setTitle(getString(R.string.dialog_title_self_update)) - .setMessage(new StringBuilder() - .append(update.getVersionName()) - .append("\n\n") - .append(changelog.isEmpty() ? getString(R.string.details_no_changes) : changelog) - .append("\n\n") - .append(getString(R.string.dialog_desc_self_update)) - .toString()) - .setPositiveButton(getString(android.R.string.yes), (dialog, which) -> { - Intent intent = new Intent(this, SelfUpdateService.class); - startService(intent); - }) - .setNegativeButton(getString(android.R.string.no), (dialog, which) -> { - dialog.dismiss(); - }); - builder.create(); - builder.show(); - } -} diff --git a/app/src/main/java/com/aurora/store/activity/DetailsActivity.java b/app/src/main/java/com/aurora/store/activity/DetailsActivity.java deleted file mode 100644 index ab2993209..000000000 --- a/app/src/main/java/com/aurora/store/activity/DetailsActivity.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.activity; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuItem; - -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; - -import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; -import com.aurora.store.manager.BlacklistManager; -import com.aurora.store.manager.FavouriteListManager; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.ThemeUtil; - -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class DetailsActivity extends AppCompatActivity { - - public static final String INTENT_PACKAGE_NAME = "INTENT_PACKAGE_NAME"; - - @BindView(R.id.toolbar) - Toolbar toolbar; - - private String packageName; - private DetailsFragment detailsFragment; - private ThemeUtil themeUtil = new ThemeUtil(); - private FavouriteListManager favouriteListManager; - - static public Intent getDetailsIntent(Context context, String packageName) { - Intent intent = new Intent(context, DetailsActivity.class); - intent.putExtra(DetailsActivity.INTENT_PACKAGE_NAME, packageName); - return intent; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - themeUtil.onCreate(this); - setContentView(R.layout.activity_details); - ButterKnife.bind(this); - setupActionBar(); - favouriteListManager = new FavouriteListManager(this); - onNewIntent(getIntent()); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - packageName = getIntentPackageName(intent); - if (TextUtils.isEmpty(packageName)) { - Log.e("No package name provided"); - finish(); - return; - } - Log.i("Getting info about %s", packageName); - grabDetails(packageName); - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.menu_app_details, menu); - menu.findItem(R.id.action_favourite).setIcon(favouriteListManager.contains(packageName) - ? R.drawable.ic_favourite_red - : R.drawable.ic_favourite_remove); - return true; - } - - @Override - public boolean onOptionsItemSelected(final MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - case R.id.action_favourite: - if (favouriteListManager.contains(packageName)) { - favouriteListManager.remove(packageName); - menuItem.setIcon(R.drawable.ic_favourite_remove); - } else { - favouriteListManager.add(packageName); - menuItem.setIcon(R.drawable.ic_favourite_red); - } - return true; - case R.id.action_manual: - startActivity(new Intent(this, ManualDownloadActivity.class)); - return true; - case R.id.action_downloads: - startActivity(new Intent(this, DownloadsActivity.class)); - return true; - case R.id.action_blacklist: - new BlacklistManager(this).add(packageName); - return true; - } - return super.onOptionsItemSelected(menuItem); - } - - @Override - protected void onResume() { - super.onResume(); - themeUtil.onResume(this); - } - - @Override - public void onBackPressed() { - List fragments = getSupportFragmentManager().getFragments(); - if (fragments.get(0) instanceof DetailsFragment) { - FragmentManager fm = fragments.get(0).getChildFragmentManager(); - if (!fm.getFragments().isEmpty()) - fm.popBackStack(); - else - super.onBackPressed(); - } else - super.onBackPressed(); - } - - private void setupActionBar() { - setSupportActionBar(toolbar); - ActionBar mActionBar = getSupportActionBar(); - if (mActionBar != null) { - mActionBar.setDisplayHomeAsUpEnabled(true); - mActionBar.setDisplayShowTitleEnabled(false); - } - } - - private String getIntentPackageName(Intent intent) { - if (intent.hasExtra(INTENT_PACKAGE_NAME)) { - return intent.getStringExtra(INTENT_PACKAGE_NAME); - } else if (intent.getScheme() != null - && (intent.getScheme().equals("market") - || intent.getScheme().equals("http") - || intent.getScheme().equals("https"))) { - return intent.getData().getQueryParameter("id"); - } else if (intent.getExtras() != null) { - Bundle bundle = intent.getExtras(); - return bundle.getString(INTENT_PACKAGE_NAME); - } - return null; - } - - public void grabDetails(String packageName) { - detailsFragment = new DetailsFragment(); - Bundle arguments = new Bundle(); - arguments.putString("PackageName", packageName); - detailsFragment.setArguments(arguments); - getSupportFragmentManager() - .beginTransaction() - .replace(R.id.content, detailsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .commitAllowingStateLoss(); - } - - public void redrawButtons() { - if (detailsFragment != null) - detailsFragment.drawButtons(); - } - -} diff --git a/app/src/main/java/com/aurora/store/activity/IntroActivity.java b/app/src/main/java/com/aurora/store/activity/IntroActivity.java deleted file mode 100644 index 692966f5d..000000000 --- a/app/src/main/java/com/aurora/store/activity/IntroActivity.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.activity; - -import android.content.Intent; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; - -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; - -import com.aurora.store.R; -import com.aurora.store.adapter.ViewPagerAdapter; -import com.aurora.store.fragment.AccountsFragment; -import com.aurora.store.fragment.intro.LoginFragment; -import com.aurora.store.fragment.intro.PermissionFragment; -import com.aurora.store.fragment.intro.WelcomeFragment; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.ThemeUtil; -import com.aurora.store.view.CustomViewPager; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class IntroActivity extends AppCompatActivity { - - @BindView(R.id.viewpager) - CustomViewPager viewPager; - @BindView(R.id.toolbar) - Toolbar toolbar; - - private ActionBar actionBar; - private ThemeUtil themeUtil = new ThemeUtil(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - themeUtil.onCreate(this); - setContentView(R.layout.activity_intro); - ButterKnife.bind(this); - setupActionbar(); - setupViewPager(); - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.menu_intro, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(final MenuItem menuItem) { - switch (menuItem.getItemId()) { - case R.id.action_setting: - startActivity(new Intent(this, SettingsActivity.class)); - return true; - } - return super.onOptionsItemSelected(menuItem); - } - - private void setupActionbar() { - setSupportActionBar(toolbar); - actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setElevation(0f); - } - } - - @Override - protected void onResume() { - super.onResume(); - themeUtil.onResume(this); - if (Accountant.isLoggedIn(this)) { - startActivity(new Intent(this, AuroraActivity.class)); - finish(); - } - } - - private void setupViewPager() { - ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager()); - viewPagerAdapter.addFragment(0, new WelcomeFragment()); - viewPagerAdapter.addFragment(1, new PermissionFragment()); - viewPagerAdapter.addFragment(2, new LoginFragment()); - viewPager.setAdapter(viewPagerAdapter); - viewPager.setScroll(false); - } - - public void moveForward() { - viewPager.setCurrentItem(viewPager.getCurrentItem() + 1); - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/BlacklistAdapter.java b/app/src/main/java/com/aurora/store/adapter/BlacklistAdapter.java deleted file mode 100644 index 34e1eb2cf..000000000 --- a/app/src/main/java/com/aurora/store/adapter/BlacklistAdapter.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.GlideApp; -import com.aurora.store.R; -import com.aurora.store.model.App; - -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; - - -public class BlacklistAdapter extends SelectableAdapter { - - private List appList; - private ItemClickListener itemClickListener; - - public BlacklistAdapter(Context context, List appList, ItemClickListener itemClickListener) { - super(context); - this.itemClickListener = itemClickListener; - this.appList = appList; - } - - @NotNull - @Override - public ViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) { - View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_blacklist, parent, false); - return new ViewHolder(itemLayoutView, itemClickListener); - } - - @Override - public void onBindViewHolder(@NotNull ViewHolder viewHolder, int position) { - final App app = appList.get(position); - viewHolder.label.setText(app.getDisplayName()); - viewHolder.packageName.setText(app.getPackageName()); - viewHolder.checkBox.setChecked(isSelected(app.getPackageName())); - GlideApp - .with(context) - .load(app.getIconInfo().getUrl()) - .into(viewHolder.icon); - } - - @Override - public int getItemCount() { - return appList.size(); - } - - @Override - public void toggleSelection(int position) { - String packageName = appList.get(position).getPackageName(); - if (mSelections.contains(packageName)) { - mSelections.remove(packageName); - mBlacklistManager.remove(packageName); - } else { - mSelections.add(packageName); - } - notifyItemChanged(position); - } - - public int getSelectedCount() { - return mSelections.size(); - } - - public interface ItemClickListener { - void onItemClicked(int position); - } - - class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { - - @BindView(R.id.label) - TextView label; - @BindView(R.id.packageName) - TextView packageName; - @BindView(R.id.icon) - ImageView icon; - @BindView(R.id.check) - CheckBox checkBox; - - private ItemClickListener listener; - - ViewHolder(View itemLayoutView, ItemClickListener listener) { - super(itemLayoutView); - this.listener = listener; - ButterKnife.bind(this, itemView); - itemLayoutView.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - if (listener != null) { - listener.onItemClicked(getAdapterPosition()); - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/CategoriesListAdapter.java b/app/src/main/java/com/aurora/store/adapter/CategoriesListAdapter.java deleted file mode 100644 index 8ca6ca98f..000000000 --- a/app/src/main/java/com/aurora/store/adapter/CategoriesListAdapter.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.R; -import com.aurora.store.SharedPreferencesTranslator; -import com.aurora.store.fragment.CategoryAppsFragment; -import com.aurora.store.utility.Util; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class CategoriesListAdapter extends RecyclerView.Adapter { - - private Context context; - private Fragment fragment; - private Map categories = new HashMap<>(); - - private Integer[] categoriesImg = { - R.drawable.ic_android_wear, - R.drawable.ic_art_design, - R.drawable.ic_auto_vehicles, - R.drawable.ic_beauty, - R.drawable.ic_books_reference, - R.drawable.ic_business, - R.drawable.ic_comics, - R.drawable.ic_communication, - R.drawable.ic_dating, - R.drawable.ic_education, - R.drawable.ic_entertainment, - R.drawable.ic_events, - R.drawable.ic_family, - R.drawable.ic_finance, - R.drawable.ic_food_drink, - R.drawable.ic_games, - R.drawable.ic_health_fitness, - R.drawable.ic_house_home, - R.drawable.ic_libraries_demo, - R.drawable.ic_lifestyle, - R.drawable.ic_maps_navigation, - R.drawable.ic_medical, - R.drawable.ic_music__audio, - R.drawable.ic_news_magazines, - R.drawable.ic_parenting, - R.drawable.ic_personalization, - R.drawable.ic_photography, - R.drawable.ic_productivity, - R.drawable.ic_shopping, - R.drawable.ic_social, - R.drawable.ic_sports, - R.drawable.ic_tools, - R.drawable.ic_travel_local, - R.drawable.ic_video_editors, - R.drawable.ic_weather, - }; - - private SharedPreferencesTranslator translator; - - public CategoriesListAdapter(Fragment fragment) { - this.fragment = fragment; - this.context = fragment.getContext(); - translator = new SharedPreferencesTranslator(Util.getPrefs(context)); - } - - public void addData(Map categories) { - this.categories.clear(); - this.categories = categories; - notifyDataSetChanged(); - } - - public boolean isDataEmpty() { - return categories.isEmpty(); - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_category_list, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { - holder.topLabel.setText(translator.getString(new ArrayList<>(categories.keySet()).get(position))); - holder.topImage.setImageDrawable(context.getResources().getDrawable(categoriesImg[position])); - holder.itemView.setOnClickListener(v -> { - CategoryAppsFragment categoryAppsFragment = new CategoryAppsFragment(); - Bundle arguments = new Bundle(); - arguments.putString("CategoryId", new ArrayList<>(categories.keySet()).get(position)); - arguments.putString("CategoryName", translator.getString(new ArrayList<>(categories.keySet()).get(position))); - categoryAppsFragment.setArguments(arguments); - FragmentManager fragmentManager = fragment.getFragmentManager(); - if (fragmentManager != null) - fragmentManager - .beginTransaction() - .replace(R.id.coordinator, categoryAppsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); - }); - } - - @Override - public int getItemCount() { - return categories.size(); - } - - static class ViewHolder extends RecyclerView.ViewHolder { - - @BindView(R.id.all_cat_img) - ImageView topImage; - @BindView(R.id.all_cat_name) - TextView topLabel; - - ViewHolder(@NonNull View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - } - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/DownloadsAdapter.java b/app/src/main/java/com/aurora/store/adapter/DownloadsAdapter.java index bd2356162..7aa715e37 100644 --- a/app/src/main/java/com/aurora/store/adapter/DownloadsAdapter.java +++ b/app/src/main/java/com/aurora/store/adapter/DownloadsAdapter.java @@ -30,15 +30,20 @@ import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.RecyclerView; +import com.aurora.store.Constants; import com.aurora.store.GlideApp; import com.aurora.store.R; -import com.aurora.store.activity.DetailsActivity; -import com.aurora.store.activity.DownloadsActivity; import com.aurora.store.sheet.DownloadMenuSheet; -import com.aurora.store.utility.PackageUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.single.activity.DownloadsActivity; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.tonyodev.fetch2.Download; import com.tonyodev.fetch2.Status; @@ -105,6 +110,7 @@ public class DownloadsAdapter extends RecyclerView.Adapter { Intent intent = new Intent(context, DetailsActivity.class); - intent.putExtra("INTENT_PACKAGE_NAME", packageName); - context.startActivity(intent); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, packageName); + context.startActivity(intent, ViewUtil.getEmptyActivityBundle((AppCompatActivity) context)); }); viewHolder.itemView.setOnLongClickListener(v -> { diff --git a/app/src/main/java/com/aurora/store/adapter/EndlessAppsAdapter.java b/app/src/main/java/com/aurora/store/adapter/EndlessAppsAdapter.java deleted file mode 100644 index 4cfa4fc75..000000000 --- a/app/src/main/java/com/aurora/store/adapter/EndlessAppsAdapter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; - -import androidx.annotation.NonNull; - -import com.aurora.store.ListType; -import com.aurora.store.R; -import com.aurora.store.model.App; -import com.aurora.store.utility.PackageUtil; -import com.aurora.store.utility.Util; - -import org.apache.commons.lang3.StringUtils; - -import java.util.List; - -public class EndlessAppsAdapter extends InstalledAppsAdapter { - - public EndlessAppsAdapter(Context context) { - super(context, ListType.ENDLESS); - } - - @Override - public void onBindViewHolder(@NonNull InstalledAppsAdapter.ViewHolder holder, int position) { - super.onBindViewHolder(holder, position); - } - - @Override - public void getDetails(List Version, List Extra, App app) { - Version.add(Util.addSiPrefix(app.getSize())); - if (!app.isEarlyAccess()) - Version.add(context.getString(R.string.details_rating, (app.getRating().getAverage()))); - if (PackageUtil.isInstalled(context, app.getPackageName())) - Version.add(context.getString(R.string.action_installed)); - Extra.add(app.getPrice()); - Extra.add(context.getString(app.containsAds() ? R.string.list_app_has_ads : R.string.list_app_no_ads)); - Extra.add(context.getString(app.getDependencies().isEmpty() ? R.string.list_app_independent_from_gsf : R.string.list_app_depends_on_gsf)); - if (!StringUtils.isEmpty(app.getUpdated())) - Extra.add(app.getUpdated()); - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/ExodusAdapter.java b/app/src/main/java/com/aurora/store/adapter/ExodusAdapter.java index 3faa15477..e56c19758 100644 --- a/app/src/main/java/com/aurora/store/adapter/ExodusAdapter.java +++ b/app/src/main/java/com/aurora/store/adapter/ExodusAdapter.java @@ -41,36 +41,36 @@ import butterknife.ButterKnife; public class ExodusAdapter extends RecyclerView.Adapter { - private Context mContext; - private List mExodusTrackers; + private Context context; + private List exodusTrackers; - public ExodusAdapter(Context mContext, List mExodusTrackers) { - this.mContext = mContext; - this.mExodusTrackers = mExodusTrackers; + public ExodusAdapter(Context context, List exodusTrackers) { + this.context = context; + this.exodusTrackers = exodusTrackers; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_exodus, parent, false); + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_exodus, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - ExodusTracker mExodusTracker = mExodusTrackers.get(position); + ExodusTracker mExodusTracker = exodusTrackers.get(position); holder.TrackerName.setText(mExodusTracker.Name); holder.TrackerSignature.setText(mExodusTracker.Signature); holder.TrackerDate.setText(mExodusTracker.Date); - holder.itemView.setOnClickListener(v -> - mContext.startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse(mExodusTracker.URL))) + holder.itemView.setOnClickListener(v -> context.startActivity(new Intent(Intent.ACTION_VIEW, + Uri.parse(mExodusTracker.URL))) ); } @Override public int getItemCount() { - return mExodusTrackers.size(); + return exodusTrackers.size(); } static class ViewHolder extends RecyclerView.ViewHolder { diff --git a/app/src/main/java/com/aurora/store/adapter/FavouriteAppsAdapter.java b/app/src/main/java/com/aurora/store/adapter/FavouriteAppsAdapter.java deleted file mode 100644 index 24620980c..000000000 --- a/app/src/main/java/com/aurora/store/adapter/FavouriteAppsAdapter.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.R; -import com.aurora.store.manager.FavouriteListManager; -import com.aurora.store.model.App; -import com.aurora.store.utility.PackageUtil; -import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.load.resource.bitmap.CenterCrop; -import com.bumptech.glide.load.resource.bitmap.RoundedCorners; -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; -import com.bumptech.glide.request.RequestOptions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class FavouriteAppsAdapter extends RecyclerView.Adapter { - - private List appList = new ArrayList<>(); - private List selectedList = new ArrayList<>(); - private Context context; - private FavouriteListManager manager; - private SelectableViewHolder.ItemClickListener itemClickListener; - - public FavouriteAppsAdapter(Context context, SelectableViewHolder.ItemClickListener itemClickListener, List appsToAdd) { - this.itemClickListener = itemClickListener; - this.context = context; - manager = new FavouriteListManager(context); - appList.addAll(appsToAdd); - Collections.sort(appsToAdd, (App1, App2) -> - App1.getDisplayName().compareToIgnoreCase(App2.getDisplayName())); - } - - public void add(int position, App app) { - appList.add(position, app); - notifyItemInserted(position); - } - - public void add(App app) { - appList.add(app); - } - - public void remove(int position) { - manager.remove(appList.get(position).getPackageName()); - appList.remove(position); - notifyItemRemoved(position); - } - - public boolean isEmpty() { - return appList.isEmpty(); - } - - @NonNull - @Override - public SelectableViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - View view = inflater.inflate(R.layout.item_favorite, parent, false); - return new SelectableViewHolder(view, itemClickListener); - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { - SelectableViewHolder holder = (SelectableViewHolder) viewHolder; - App app = appList.get(position); - - holder.AppTitle.setText(app.getDisplayName()); - - if (PackageUtil.isInstalled(context, app)) { - holder.AppExtra.setText(context.getText(R.string.list_installed)); - holder.AppCheckbox.setEnabled(false); - } else { - holder.AppExtra.setText(context.getText(R.string.list_not_installd)); - } - - Glide - .with(context) - .load(app.getIconInfo().getUrl()) - .apply(new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)) - .transition(new DrawableTransitionOptions().crossFade()) - .transforms(new CenterCrop(), new RoundedCorners(25)) - .into(holder.AppIcon); - - holder.setChecked(isSelected(appList.get(position))); - } - - public void toggleSelection(int position) { - App app = appList.get(position); - if (selectedList.contains(app)) { - selectedList.remove(app); - } else { - selectedList.add(app); - } - notifyItemChanged(position); - } - - private boolean isSelected(App app) { - return selectedList.contains(app); - } - - @Override - public int getItemCount() { - return appList.size(); - } - - public List getSelectedList() { - return new ArrayList<>(selectedList); - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/FeaturedAppsAdapter.java b/app/src/main/java/com/aurora/store/adapter/FeaturedAppsAdapter.java index a1e43a9e7..3764e8759 100644 --- a/app/src/main/java/com/aurora/store/adapter/FeaturedAppsAdapter.java +++ b/app/src/main/java/com/aurora/store/adapter/FeaturedAppsAdapter.java @@ -32,15 +32,18 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.RecyclerView; -import com.aurora.store.CardType; +import com.aurora.store.Constants; import com.aurora.store.GlideApp; import com.aurora.store.R; -import com.aurora.store.activity.DetailsActivity; +import com.aurora.store.enums.CardType; import com.aurora.store.model.App; -import com.aurora.store.utility.PackageUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; @@ -88,18 +91,19 @@ public class FeaturedAppsAdapter extends RecyclerView.Adapter { - Intent intent = new Intent(context, DetailsActivity.class); - intent.putExtra("INTENT_PACKAGE_NAME", app.getPackageName()); - context.startActivity(intent); - }); - viewHolder.txtIndicator.setVisibility(PackageUtil.isInstalled(context, app) ? View.VISIBLE : View.GONE); if (viewHolder.txtSize != null) viewHolder.txtSize.setText(Util.humanReadableByteValue(app.getSize(), true)); + + viewHolder.itemView.setOnClickListener(v -> { + DetailsActivity.app = app; + Intent intent = new Intent(context, DetailsActivity.class); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, app.getPackageName()); + context.startActivity(intent, ViewUtil.getEmptyActivityBundle((AppCompatActivity) context)); + }); } private void drawBackground(App app, ViewHolder holder) { diff --git a/app/src/main/java/com/aurora/store/adapter/InstalledAppsAdapter.java b/app/src/main/java/com/aurora/store/adapter/InstalledAppsAdapter.java deleted file mode 100644 index 31caedc35..000000000 --- a/app/src/main/java/com/aurora/store/adapter/InstalledAppsAdapter.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.content.Intent; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.fragment.app.FragmentManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.GlideApp; -import com.aurora.store.ListType; -import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; -import com.aurora.store.activity.DetailsActivity; -import com.aurora.store.model.App; -import com.aurora.store.sheet.AppMenuSheet; -import com.bumptech.glide.load.resource.bitmap.CenterCrop; -import com.bumptech.glide.load.resource.bitmap.RoundedCorners; -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class InstalledAppsAdapter extends RecyclerView.Adapter { - - public List appList = new ArrayList<>(); - public Context context; - private ListType listType; - private AppMenuSheet menuSheet; - - public InstalledAppsAdapter(Context context, ListType listType) { - this.context = context; - this.listType = listType; - this.menuSheet = new AppMenuSheet(); - } - - public void add(int position, App app) { - appList.add(position, app); - notifyItemInserted(position); - } - - public void add(App app) { - appList.add(app); - } - - public void remove(int position) { - appList.remove(position); - notifyItemRemoved(position); - } - - public void remove(String packageName) { - for (App app : appList) { - if (app.getPackageName().equals(packageName)) { - appList.remove(app); - notifyDataSetChanged(); - break; - } - } - } - - public void remove(App app) { - appList.remove(app); - notifyDataSetChanged(); - } - - public void addData(List appList) { - this.appList.clear(); - this.appList = appList; - final Set appSet = new LinkedHashSet<>(appList); - appList.clear(); - appList.addAll(appSet); - if (listType == ListType.INSTALLED || listType == ListType.UPDATES) - Collections.sort(appList, (App1, App2) -> - App1.getDisplayName().compareToIgnoreCase(App2.getDisplayName())); - notifyDataSetChanged(); - } - - public boolean isDataEmpty() { - return appList.isEmpty(); - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - View view = inflater.inflate(R.layout.item_installed, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - App app = appList.get(position); - List Version = new ArrayList<>(); - List Extra = new ArrayList<>(); - - holder.AppTitle.setText(app.getDisplayName()); - getDetails(Version, Extra, app); - setText(holder.AppExtra, TextUtils.join(" • ", Extra)); - setText(holder.AppVersion, TextUtils.join(" • ", Version)); - - holder.itemView.setOnClickListener(v -> { - Intent intent = new Intent(context, DetailsActivity.class); - intent.putExtra("INTENT_PACKAGE_NAME", app.getPackageName()); - context.startActivity(intent); - }); - - holder.itemView.setOnLongClickListener(v -> { - menuSheet.setApp(app); - menuSheet.setAdapter(this); - menuSheet.show(getFragmentManager(), "BOTTOM_MENU_SHEET"); - return false; - }); - - GlideApp - .with(context) - .load(app.getIconInfo().getUrl()) - .transition(new DrawableTransitionOptions().crossFade()) - .transforms(new CenterCrop(), new RoundedCorners(30)) - .into(holder.AppIcon); - } - - private FragmentManager getFragmentManager() { - if (context instanceof DetailsActivity) - return ((DetailsActivity) context).getSupportFragmentManager(); - else - return ((AuroraActivity) context).getSupportFragmentManager(); - } - - public void getDetails(List Version, List Extra, App app) { - Version.add("v" + app.getVersionName() + "." + app.getVersionCode()); - if (app.isSystem()) - Extra.add(context.getString(R.string.list_app_system)); - else - Extra.add(context.getString(R.string.list_app_user)); - } - - protected void setText(TextView textView, String text) { - if (!TextUtils.isEmpty(text)) { - textView.setText(text); - textView.setVisibility(View.VISIBLE); - } else { - textView.setVisibility(View.GONE); - } - } - - @Override - public int getItemCount() { - return appList.size(); - } - - public static class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.app_icon) - ImageView AppIcon; - @BindView(R.id.app_title) - TextView AppTitle; - @BindView(R.id.app_version) - TextView AppVersion; - @BindView(R.id.app_extra) - TextView AppExtra; - - ViewHolder(@NonNull View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - } - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/NativeHttpClientAdapter.java b/app/src/main/java/com/aurora/store/adapter/NativeHttpClientAdapter.java index 9f672aee5..af5314f75 100644 --- a/app/src/main/java/com/aurora/store/adapter/NativeHttpClientAdapter.java +++ b/app/src/main/java/com/aurora/store/adapter/NativeHttpClientAdapter.java @@ -28,7 +28,7 @@ import com.aurora.store.exception.AppNotFoundException; import com.aurora.store.exception.MalformedRequestException; import com.aurora.store.exception.TooManyRequestsException; import com.aurora.store.exception.UnknownException; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import com.dragons.aurora.playstoreapiv2.AuthException; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.dragons.aurora.playstoreapiv2.GooglePlayException; @@ -46,7 +46,6 @@ import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.zip.GZIPInputStream; public class NativeHttpClientAdapter extends HttpClientAdapter { @@ -81,13 +80,10 @@ public class NativeHttpClientAdapter extends HttpClientAdapter { } } - static private byte[] readFully(InputStream inputStream, boolean gzipped) throws IOException { + static private byte[] readFully(InputStream inputStream) throws IOException { if (null == inputStream) { return new byte[0]; } - if (gzipped) { - inputStream = new GZIPInputStream(inputStream); - } InputStream bufferedInputStream = new BufferedInputStream(inputStream); byte[] buffer = new byte[8192]; int bytesRead; @@ -177,8 +173,6 @@ public class NativeHttpClientAdapter extends HttpClientAdapter { protected byte[] request(HttpURLConnection connection, byte[] body, Map headers) throws IOException { connection.setConnectTimeout(TIMEOUT); connection.setReadTimeout(TIMEOUT); - connection.setRequestProperty("Accept-Encoding", "gzip"); - connection.addRequestProperty("Cache-Control", "max-age=300"); for (String headerName : headers.keySet()) { connection.addRequestProperty(headerName, headers.get(headerName)); } @@ -189,18 +183,11 @@ public class NativeHttpClientAdapter extends HttpClientAdapter { int code = 0; - boolean isGzip; - try { - isGzip = null != connection.getContentEncoding() && connection.getContentEncoding().contains("gzip"); - } catch (NullPointerException e) { - throw new AuthException(e.getMessage(), 401); - } - try { code = connection.getResponseCode(); - content = readFully(connection.getInputStream(), isGzip); + content = readFully(connection.getInputStream()); } catch (IOException e) { - content = readFully(connection.getErrorStream(), isGzip); + content = readFully(connection.getErrorStream()); } finally { connection.disconnect(); } diff --git a/app/src/main/java/com/aurora/store/adapter/OkHttpClientAdapter.java b/app/src/main/java/com/aurora/store/adapter/OkHttpClientAdapter.java index 3845060be..e8fccd705 100644 --- a/app/src/main/java/com/aurora/store/adapter/OkHttpClientAdapter.java +++ b/app/src/main/java/com/aurora/store/adapter/OkHttpClientAdapter.java @@ -26,7 +26,7 @@ import com.aurora.store.exception.AppNotFoundException; import com.aurora.store.exception.MalformedRequestException; import com.aurora.store.exception.TooManyRequestsException; import com.aurora.store.exception.UnknownException; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import com.dragons.aurora.playstoreapiv2.AuthException; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.dragons.aurora.playstoreapiv2.GooglePlayException; diff --git a/app/src/main/java/com/aurora/store/adapter/ReviewsAdapter.java b/app/src/main/java/com/aurora/store/adapter/ReviewsAdapter.java deleted file mode 100644 index 10946bb52..000000000 --- a/app/src/main/java/com/aurora/store/adapter/ReviewsAdapter.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.text.format.DateFormat; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.RatingBar; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.GlideApp; -import com.aurora.store.R; -import com.aurora.store.model.Review; -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import java.util.Calendar; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class ReviewsAdapter extends RecyclerView.Adapter { - - private Context context; - private List reviewList; - - public ReviewsAdapter(Context context, List reviewList) { - this.context = context; - this.reviewList = reviewList; - } - - public void add(int position, Review review) { - reviewList.add(position, review); - notifyItemInserted(position); - } - - public void add(Review review) { - reviewList.add(review); - } - - public void remove(int position) { - reviewList.remove(position); - notifyItemRemoved(position); - } - - public void sort() { - Collections.sort(reviewList, (lhs, rhs) -> lhs.getRating() > rhs.getRating() ? -1 : 1); - } - - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_review_list, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - Review mReview = reviewList.get(position); - holder.Author.setText(mReview.getUserName()); - holder.Rating.setRating(mReview.getRating()); - holder.Date.setText(getDate(mReview)); - holder.Comment.setText(mReview.getComment()); - - - GlideApp - .with(context) - .load(mReview.getUserPhotoUrl()) - .placeholder(R.color.colorTransparent) - .circleCrop() - .transition(new DrawableTransitionOptions().crossFade()) - .into(holder.Avatar); - - holder.itemView.setOnClickListener(v -> { - MaterialAlertDialogBuilder mBuilder = new MaterialAlertDialogBuilder(context) - .setIcon(holder.Avatar.getDrawable()) - .setTitle(mReview.getUserName()) - .setMessage(mReview.getComment()) - .setCancelable(false) - .setPositiveButton(android.R.string.ok, (dialog, which) -> { - dialog.dismiss(); - }); - mBuilder.create(); - mBuilder.show(); - }); - } - - private String getDate(Review review) { - Calendar calendar = Calendar.getInstance(Locale.getDefault()); - calendar.setTimeInMillis(review.getTimeStamp()); - return DateFormat.format("dd/MM/yyyy", calendar).toString(); - } - - @Override - public int getItemCount() { - return reviewList.size(); - } - - static class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.avatar) - ImageView Avatar; - @BindView(R.id.author) - TextView Author; - @BindView(R.id.rating) - RatingBar Rating; - @BindView(R.id.date) - TextView Date; - @BindView(R.id.comment) - TextView Comment; - - ViewHolder(@NonNull View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - } - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/SearchHistoryAdapter.java b/app/src/main/java/com/aurora/store/adapter/SearchHistoryAdapter.java deleted file mode 100644 index 26e4ff625..000000000 --- a/app/src/main/java/com/aurora/store/adapter/SearchHistoryAdapter.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.Constants; -import com.aurora.store.R; -import com.aurora.store.utility.PrefUtil; - -import org.apache.commons.lang3.StringUtils; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Locale; - -public class SearchHistoryAdapter extends RecyclerView.Adapter { - - private Context context; - private ArrayList queryList; - private ClickListener clickListener; - - public SearchHistoryAdapter(Context context, ArrayList queryList, ClickListener clickListener) { - this.queryList = queryList; - this.clickListener = clickListener; - this.context = context; - } - - public void add(int position, String mHistory) { - queryList.add(mHistory); - notifyItemInserted(position); - } - - public void remove(int position) { - queryList.remove(position); - updatePrefList(); - notifyItemRemoved(position); - } - - public void clear() { - queryList.clear(); - clearPrefList(); - notifyDataSetChanged(); - } - - public void reload() { - queryList = PrefUtil.getListString(context, Constants.RECENT_HISTORY); - notifyDataSetChanged(); - } - - private void updatePrefList() { - PrefUtil.putListString(context, Constants.RECENT_HISTORY, queryList); - } - - private void clearPrefList() { - PrefUtil.putListString(context, Constants.RECENT_HISTORY, new ArrayList<>()); - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - View view = inflater.inflate(R.layout.item_history, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { - String[] datedQuery = queryList.get(position).split(":"); - holder.query.setText(datedQuery[0]); - holder.date.setText(getQueryDate(datedQuery[1])); - holder.viewForeground.setOnClickListener(v -> clickListener.onClicked(datedQuery[0])); - } - - @Override - public int getItemCount() { - return queryList.size(); - } - - private String getQueryDate(String queryDate) { - try { - final long timeInMilli = Long.parseLong(queryDate); - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd MMM", Locale.getDefault()); - return simpleDateFormat.format(new Date(timeInMilli)); - } catch (NumberFormatException e) { - return StringUtils.EMPTY; - } - } - - public interface ClickListener { - void onClicked(String query); - } - - public class ViewHolder extends RecyclerView.ViewHolder { - public RelativeLayout viewForeground; - RelativeLayout viewBackground; - TextView query; - TextView date; - - ViewHolder(View view) { - super(view); - query = view.findViewById(R.id.query); - date = view.findViewById(R.id.queryTime); - viewBackground = view.findViewById(R.id.view_background); - viewForeground = view.findViewById(R.id.view_foreground); - } - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/SearchSuggestionAdapter.java b/app/src/main/java/com/aurora/store/adapter/SearchSuggestionAdapter.java new file mode 100644 index 000000000..7b4b08f5d --- /dev/null +++ b/app/src/main/java/com/aurora/store/adapter/SearchSuggestionAdapter.java @@ -0,0 +1,106 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.dragons.aurora.playstoreapiv2.SearchSuggestEntry; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class SearchSuggestionAdapter extends RecyclerView.Adapter { + + public List appList; + public Context context; + private ClickListener clickListener; + + public SearchSuggestionAdapter(Context context, ClickListener clickListener) { + this.context = context; + this.clickListener = clickListener; + this.appList = new ArrayList<>(); + } + + public void addData(List appList) { + this.appList.clear(); + this.appList.addAll(appList); + notifyDataSetChanged(); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.item_suggestion, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + SearchSuggestEntry suggestEntry = appList.get(position); + String title = suggestEntry.getTitle(); + String packageName = suggestEntry.getPackageNameContainer().getPackageName(); + holder.line1.setText(title); + GlideApp + .with(context) + .load(suggestEntry.getImageContainer().getImageUrl()) + .placeholder(R.drawable.ic_round_search) + .transforms(new CenterCrop(), new RoundedCorners(30)) + .into(holder.img); + holder.itemView.setOnClickListener(v -> clickListener.onClickedSuggestion(packageName.isEmpty() ? title : packageName)); + } + + @Override + public int getItemCount() { + return appList.size(); + } + + public interface ClickListener { + void onClickedSuggestion(String query); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + ViewHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/com/aurora/store/adapter/SelectableAdapter.java b/app/src/main/java/com/aurora/store/adapter/SelectableAdapter.java deleted file mode 100644 index ad5277ac9..000000000 --- a/app/src/main/java/com/aurora/store/adapter/SelectableAdapter.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; - -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.manager.BlacklistManager; - -import java.util.ArrayList; - -abstract class SelectableAdapter extends RecyclerView.Adapter { - - protected ArrayList mSelections; - protected Context context; - protected BlacklistManager mBlacklistManager; - - SelectableAdapter(Context context) { - this.context = context; - mBlacklistManager = new BlacklistManager(context); - ArrayList blacklistedApps = mBlacklistManager.get(); - mSelections = new ArrayList<>(); - if (blacklistedApps != null && !blacklistedApps.isEmpty()) { - mSelections.addAll(blacklistedApps); - } - } - - boolean isSelected(String packageName) { - return mSelections.contains(packageName); - } - - void toggleSelection(int position) { - } - - public void addSelectionsToBlackList() { - mBlacklistManager.addAll(mSelections); - } - - public void removeSelectionsFromBlackList() { - mBlacklistManager.removeAll(mSelections); - mSelections = new ArrayList<>(); - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/SelectableViewHolder.java b/app/src/main/java/com/aurora/store/adapter/SelectableViewHolder.java deleted file mode 100644 index 66f452629..000000000 --- a/app/src/main/java/com/aurora/store/adapter/SelectableViewHolder.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.view.View; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.R; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class SelectableViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { - @BindView(R.id.view_foreground) - public RelativeLayout viewForeground; - @BindView(R.id.view_background) - RelativeLayout viewBackground; - @BindView(R.id.app_icon) - ImageView AppIcon; - @BindView(R.id.app_title) - TextView AppTitle; - @BindView(R.id.app_extra) - TextView AppExtra; - @BindView(R.id.app_checkbox) - CheckBox AppCheckbox; - - private ItemClickListener listener; - - SelectableViewHolder(View view, ItemClickListener listener) { - super(view); - ButterKnife.bind(this, view); - this.listener = listener; - view.setOnClickListener(this); - } - - public void setChecked(boolean value) { - AppCheckbox.setChecked(value); - } - - @Override - public void onClick(View v) { - if (listener != null) { - listener.onItemClicked(getAdapterPosition()); - } - } - - public interface ItemClickListener { - void onItemClicked(int position); - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/SmallScreenshotsAdapter.java b/app/src/main/java/com/aurora/store/adapter/SmallScreenshotsAdapter.java index 3523736ee..f1abf59fe 100644 --- a/app/src/main/java/com/aurora/store/adapter/SmallScreenshotsAdapter.java +++ b/app/src/main/java/com/aurora/store/adapter/SmallScreenshotsAdapter.java @@ -34,8 +34,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.aurora.store.GlideApp; import com.aurora.store.R; -import com.aurora.store.activity.FullscreenImageActivity; -import com.aurora.store.utility.ViewUtil; +import com.aurora.store.ui.single.activity.FullscreenImageActivity; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; diff --git a/app/src/main/java/com/aurora/store/adapter/SubCategoryAdapter.java b/app/src/main/java/com/aurora/store/adapter/SubCategoryAdapter.java deleted file mode 100644 index 5b39ba117..000000000 --- a/app/src/main/java/com/aurora/store/adapter/SubCategoryAdapter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.os.Bundle; - -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentStatePagerAdapter; - -import com.aurora.store.R; -import com.aurora.store.fragment.SubCategoryFragment; - -import org.jetbrains.annotations.NotNull; - -public class SubCategoryAdapter extends FragmentStatePagerAdapter { - - private Context context; - - public SubCategoryAdapter(Context context, FragmentManager fragmentManager) { - super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); - this.context = context; - } - - @NotNull - @Override - public Fragment getItem(int position) { - final Bundle bundle = new Bundle(); - final Fragment subCategoryFragment = new SubCategoryFragment(); - switch (position) { - case 0: - bundle.putString("SUBCATEGORY", "TOP_FREE"); - break; - case 1: - bundle.putString("SUBCATEGORY", "MOVERS_SHAKERS"); - break; - default: - bundle.putString("SUBCATEGORY", "TOP_GROSSING"); - break; - } - subCategoryFragment.setArguments(bundle); - return subCategoryFragment; - } - - @Override - public int getCount() { - return 3; - } - - @Override - public CharSequence getPageTitle(int position) { - switch (position) { - case 0: - return context.getString(R.string.category_topFree); - case 1: - return context.getString(R.string.category_trending); - default: - return context.getString(R.string.category_topGrossing); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/adapter/TabAdapter.java b/app/src/main/java/com/aurora/store/adapter/TabAdapter.java deleted file mode 100644 index cfa40650c..000000000 --- a/app/src/main/java/com/aurora/store/adapter/TabAdapter.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.aurora.store.adapter; - -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; - -import java.util.ArrayList; -import java.util.List; - -public class TabAdapter extends FragmentPagerAdapter { - - private final List fragmentList = new ArrayList<>(); - private final List fragmentTitleList = new ArrayList<>(); - - public TabAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public Fragment getItem(int position) { - return fragmentList.get(position); - } - - public void addFragment(Fragment fragment, String title) { - fragmentList.add(fragment); - fragmentTitleList.add(title); - } - - @Nullable - @Override - public CharSequence getPageTitle(int position) { - return fragmentTitleList.get(position); - } - - @Override - public int getCount() { - return fragmentList.size(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/adapter/TopCategoriesAdapter.java b/app/src/main/java/com/aurora/store/adapter/TopCategoriesAdapter.java deleted file mode 100644 index c037d8fd5..000000000 --- a/app/src/main/java/com/aurora/store/adapter/TopCategoriesAdapter.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.core.graphics.ColorUtils; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentTransaction; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.R; -import com.aurora.store.SharedPreferencesTranslator; -import com.aurora.store.fragment.CategoriesFragment; -import com.aurora.store.fragment.CategoryAppsFragment; -import com.aurora.store.fragment.HomeFragment; -import com.aurora.store.utility.ColorUtil; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class TopCategoriesAdapter extends RecyclerView.Adapter { - - private Context context; - private Fragment fragment; - private String[] topCategoryIDs; - private SharedPreferencesTranslator translator; - private boolean isTransparent; - - private Integer[] categoriesImg = { - R.drawable.ic_cat_communication, - R.drawable.ic_cat_family, - R.drawable.ic_cat_games, - R.drawable.ic_cat_music, - R.drawable.ic_cat_personalization, - R.drawable.ic_cat_photography, - R.drawable.ic_cat_shopping, - R.drawable.ic_cat_social_alt, - }; - - public TopCategoriesAdapter(HomeFragment fragment) { - this.fragment = fragment; - this.context = fragment.getContext(); - this.topCategoryIDs = context.getResources().getStringArray(R.array.topCategories); - this.isTransparent = Util.isTransparentStyle(context); - this.translator = new SharedPreferencesTranslator(Util.getPrefs(context)); - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_category_top, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { - @ColorInt int color = ViewUtil.getSolidColors(position); - holder.itemView.setBackgroundTintList(ColorStateList.valueOf( - ColorUtils.setAlphaComponent(color, isTransparent ? 60 : 255))); - holder.imgCat.setImageDrawable(context.getResources().getDrawable(categoriesImg[position])); - holder.imgCat.setColorFilter(isTransparent ? ColorUtil.manipulateColor(color, 0.85f) : Color.WHITE); - holder.txtCat.setText(translator.getString(topCategoryIDs[position])); - holder.txtCat.setTextColor(isTransparent ? ColorUtil.manipulateColor(color, 0.75f) : Color.WHITE); - - if (topCategoryIDs[position].equals(CategoriesFragment.FAMILY)) { - holder.itemView.setOnClickListener(v -> getSubCategoryFragment(CategoriesFragment.FAMILY)); - } else if (topCategoryIDs[position].equals(CategoriesFragment.GAME)) { - holder.itemView.setOnClickListener(v -> getSubCategoryFragment(CategoriesFragment.GAME)); - } else - holder.itemView.setOnClickListener(v -> getCategoryAppsFragment(position)); - } - - private void getSubCategoryFragment(String subCategory) { - CategoriesFragment categoryAppsFragment = new CategoriesFragment(); - Bundle arguments = new Bundle(); - arguments.putString("CATEGORY_TYPE", subCategory); - categoryAppsFragment.setArguments(arguments); - fragment.getChildFragmentManager().beginTransaction() - .replace(R.id.coordinator, categoryAppsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); - } - - private void getCategoryAppsFragment(int position) { - CategoryAppsFragment categoryAppsFragment = new CategoryAppsFragment(); - Bundle arguments = new Bundle(); - arguments.putString("CategoryId", topCategoryIDs[position]); - arguments.putString("CategoryName", translator.getString(topCategoryIDs[position])); - categoryAppsFragment.setArguments(arguments); - fragment.getChildFragmentManager() - .beginTransaction() - .replace(R.id.coordinator, categoryAppsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); - } - - @Override - public int getItemCount() { - return topCategoryIDs.length; - } - - static class ViewHolder extends RecyclerView.ViewHolder { - - @BindView(R.id.cat_icon) - ImageView imgCat; - @BindView(R.id.cat_txt) - TextView txtCat; - - ViewHolder(@NonNull View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - } - } -} diff --git a/app/src/main/java/com/aurora/store/adapter/UpdatableAppsAdapter.java b/app/src/main/java/com/aurora/store/adapter/UpdatableAppsAdapter.java deleted file mode 100644 index 299605917..000000000 --- a/app/src/main/java/com/aurora/store/adapter/UpdatableAppsAdapter.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.adapter; - -import android.content.Context; -import android.content.Intent; -import android.text.Html; -import android.text.TextUtils; -import android.text.format.Formatter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.GlideApp; -import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; -import com.aurora.store.activity.DetailsActivity; -import com.aurora.store.model.App; -import com.aurora.store.sheet.AppMenuSheet; -import com.aurora.store.utility.ViewUtil; -import com.bumptech.glide.load.resource.bitmap.CenterCrop; -import com.bumptech.glide.load.resource.bitmap.RoundedCorners; -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class UpdatableAppsAdapter extends RecyclerView.Adapter { - - private List appList = new ArrayList<>(); - private Context context; - private AppMenuSheet menuSheet; - - public UpdatableAppsAdapter(Context context) { - this.context = context; - this.menuSheet = new AppMenuSheet(); - } - - public List getAppList() { - return appList; - } - - public void add(int position, App app) { - appList.add(position, app); - notifyItemInserted(position); - } - - public void add(App app) { - appList.add(app); - } - - public void remove(int position) { - appList.remove(position); - notifyItemRemoved(position); - } - - public void remove(String packageName) { - Iterator iterator = appList.iterator(); - while (iterator.hasNext()) { - final App app = iterator.next(); - if (packageName.equals(app.getPackageName()) || packageName.startsWith(app.getPackageName())) - iterator.remove(); - } - notifyDataSetChanged(); - } - - public void remove(App app) { - appList.remove(app); - notifyDataSetChanged(); - } - - public void addData(List appList) { - this.appList.clear(); - this.appList = appList; - Collections.sort(appList, (App1, App2) -> - App1.getDisplayName().compareToIgnoreCase(App2.getDisplayName())); - notifyDataSetChanged(); - } - - public boolean isDataEmpty() { - return appList.isEmpty(); - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - View view = inflater.inflate(R.layout.item_updatable, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { - App app = appList.get(position); - List Version = new ArrayList<>(); - List Extra = new ArrayList<>(); - - viewHolder.txtTitle.setText(app.getDisplayName()); - getDetails(Version, Extra, app); - setText(viewHolder.txtVersion, TextUtils.join(" • ", Version)); - setText(viewHolder.txtExtra, TextUtils.join(" • ", Extra)); - setText(viewHolder.txtChanges, app.getChanges().isEmpty() - ? context.getString(R.string.details_no_changes) - : Html.fromHtml(app.getChanges()).toString()); - - viewHolder.itemView.setOnClickListener(v -> { - Intent intent = new Intent(context, DetailsActivity.class); - intent.putExtra("INTENT_PACKAGE_NAME", app.getPackageName()); - context.startActivity(intent); - }); - - viewHolder.itemView.setOnLongClickListener(v -> { - menuSheet.setApp(app); - menuSheet.setAdapter(this); - menuSheet.show(((AuroraActivity) context).getSupportFragmentManager(), - "BOTTOM_MENU_SHEET"); - return false; - }); - - GlideApp - .with(context) - .load(app.getIconInfo().getUrl()) - .transition(new DrawableTransitionOptions().crossFade()) - .transforms(new CenterCrop(), new RoundedCorners(25)) - .into(viewHolder.imgIcon); - - viewHolder.imgExpand.setOnClickListener(v -> { - if (viewHolder.layoutChanges.getHeight() == 0) { - ViewUtil.rotateView(v, false); - ViewUtil.expandView(viewHolder.layoutChanges, - viewHolder.txtChanges.getHeight() - + viewHolder.txtChangesTitle.getHeight() - + 120 /*Padding & Margins*/); - } else { - ViewUtil.rotateView(v, true); - ViewUtil.collapseView(viewHolder.layoutChanges, 0); - } - }); - } - - private void getDetails(List Version, List Extra, App app) { - Version.add(app.getUpdated()); - Extra.add(app.getSize() == 0 ? "N/A" : Formatter.formatShortFileSize(context, app.getSize())); - } - - protected void setText(TextView textView, String text) { - if (!TextUtils.isEmpty(text)) { - textView.setText(text); - textView.setVisibility(View.VISIBLE); - } else { - textView.setVisibility(View.GONE); - } - } - - @Override - public int getItemCount() { - return appList.size(); - } - - public class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.layout_info) - RelativeLayout layoutInfo; - @BindView(R.id.layout_changes) - RelativeLayout layoutChanges; - @BindView(R.id.app_icon) - ImageView imgIcon; - @BindView(R.id.app_title) - TextView txtTitle; - @BindView(R.id.app_version) - TextView txtVersion; - @BindView(R.id.app_extra) - TextView txtExtra; - @BindView(R.id.img_expand) - ImageView imgExpand; - @BindView(R.id.txt_title) - TextView txtChangesTitle; - @BindView(R.id.txt_changes) - TextView txtChanges; - - ViewHolder(@NonNull View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - } - } - -} diff --git a/app/src/main/java/com/aurora/store/adapter/ViewPagerAdapter.java b/app/src/main/java/com/aurora/store/adapter/ViewPagerAdapter.java deleted file mode 100644 index be88b5800..000000000 --- a/app/src/main/java/com/aurora/store/adapter/ViewPagerAdapter.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.aurora.store.adapter; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentStatePagerAdapter; - -import java.util.ArrayList; -import java.util.List; - -public class ViewPagerAdapter extends FragmentStatePagerAdapter { - - private List fragmentList = new ArrayList<>(); - - public ViewPagerAdapter(@NonNull FragmentManager fragmentManager) { - super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); - } - - public void addFragment(int position, Fragment fragment) { - fragmentList.add(position, fragment); - } - - @Override - public int getCount() { - return fragmentList.size(); - } - - @NonNull - @Override - public Fragment getItem(int position) { - return fragmentList.get(position); - } -} diff --git a/app/src/main/java/com/aurora/store/api/PlayStoreApiAuthenticator.java b/app/src/main/java/com/aurora/store/api/PlayStoreApiAuthenticator.java index bd8b7c352..e142f2440 100644 --- a/app/src/main/java/com/aurora/store/api/PlayStoreApiAuthenticator.java +++ b/app/src/main/java/com/aurora/store/api/PlayStoreApiAuthenticator.java @@ -27,62 +27,33 @@ import android.content.Context; import com.aurora.store.TokenDispenserMirrors; import com.aurora.store.model.LoginInfo; -import com.aurora.store.utility.ApiBuilderUtil; +import com.aurora.store.util.ApiBuilderUtil; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import java.io.IOException; public class PlayStoreApiAuthenticator { - private static volatile PlayStoreApiAuthenticator instance; - private static GooglePlayAPI api; - - public PlayStoreApiAuthenticator() { - if (instance != null) { - throw new RuntimeException("Use getApi() method to get the single instance of RxBus"); - } - } - - public static GooglePlayAPI getApi() { - return api; - } - - public static GooglePlayAPI getInstance(Context context) throws Exception { - if (instance == null) { - synchronized (PlayStoreApiAuthenticator.class) { - if (instance == null) { - instance = new PlayStoreApiAuthenticator(); - api = instance.getApi(context); - } - } - } - return api; - } - public static boolean login(Context context, String email, String password) throws IOException { LoginInfo loginInfo = new LoginInfo(); loginInfo.setEmail(email); loginInfo.setAasToken(password); - GooglePlayAPI api = ApiBuilderUtil.buildApi(context, loginInfo); + GooglePlayAPI api = ApiBuilderUtil.buildApi(context, loginInfo, false); return api != null; } public static GooglePlayAPI login(Context context) throws IOException { LoginInfo loginInfo = new LoginInfo(); loginInfo.setTokenDispenserUrl(TokenDispenserMirrors.get(context)); - GooglePlayAPI api = ApiBuilderUtil.buildAnonymousApi(context, loginInfo); - return api; + return ApiBuilderUtil.buildApi(context, loginInfo, true); } - public static void destroyInstance() { - api = null; - instance = null; + public static GooglePlayAPI getApi(Context context) throws Exception { + return ApiBuilderUtil.buildFromPreferences(context); } - private synchronized GooglePlayAPI getApi(Context context) throws Exception { - if (api == null) { - api = ApiBuilderUtil.buildFromPreferences(context); - } - return api; + public GooglePlayAPI getPlayApi(Context context) throws Exception { + return ApiBuilderUtil.buildFromPreferences(context); } + } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/download/DownloadManager.java b/app/src/main/java/com/aurora/store/download/DownloadManager.java index f05c0948a..1d263927d 100644 --- a/app/src/main/java/com/aurora/store/download/DownloadManager.java +++ b/app/src/main/java/com/aurora/store/download/DownloadManager.java @@ -23,7 +23,7 @@ package com.aurora.store.download; import android.content.Context; import com.aurora.store.Constants; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import com.tonyodev.fetch2.Fetch; import com.tonyodev.fetch2.FetchConfiguration; import com.tonyodev.fetch2okhttp.OkHttpDownloader; diff --git a/app/src/main/java/com/aurora/store/download/RequestBuilder.java b/app/src/main/java/com/aurora/store/download/RequestBuilder.java index 0d1b579b9..9685daab5 100644 --- a/app/src/main/java/com/aurora/store/download/RequestBuilder.java +++ b/app/src/main/java/com/aurora/store/download/RequestBuilder.java @@ -23,9 +23,9 @@ package com.aurora.store.download; import android.content.Context; import com.aurora.store.model.App; -import com.aurora.store.utility.PathUtil; -import com.aurora.store.utility.TextUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.PathUtil; +import com.aurora.store.util.TextUtil; +import com.aurora.store.util.Util; import com.dragons.aurora.playstoreapiv2.AndroidAppDeliveryData; import com.dragons.aurora.playstoreapiv2.AppFileMetadata; import com.dragons.aurora.playstoreapiv2.Split; diff --git a/app/src/main/java/com/aurora/store/CardType.java b/app/src/main/java/com/aurora/store/enums/CardType.java similarity index 96% rename from app/src/main/java/com/aurora/store/CardType.java rename to app/src/main/java/com/aurora/store/enums/CardType.java index 46a7e159c..7c812e33d 100644 --- a/app/src/main/java/com/aurora/store/CardType.java +++ b/app/src/main/java/com/aurora/store/enums/CardType.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store; +package com.aurora.store.enums; public enum CardType { LEGACY, diff --git a/app/src/main/java/com/aurora/store/ErrorType.java b/app/src/main/java/com/aurora/store/enums/ErrorType.java similarity index 89% rename from app/src/main/java/com/aurora/store/ErrorType.java rename to app/src/main/java/com/aurora/store/enums/ErrorType.java index a3b00f638..112667ae8 100644 --- a/app/src/main/java/com/aurora/store/ErrorType.java +++ b/app/src/main/java/com/aurora/store/enums/ErrorType.java @@ -18,17 +18,14 @@ * */ -package com.aurora.store; +package com.aurora.store.enums; public enum ErrorType { NO_NETWORK, - NO_APPS, - NO_UPDATES, - NO_SEARCH, NO_DOWNLOADS, + NO_API, UNKNOWN, SESSION_EXPIRED, APP_NOT_FOUND, - LOGOUT_ERR, - IMPORT + LOGOUT_ERR } diff --git a/app/src/main/java/com/aurora/store/NotificationProvider.java b/app/src/main/java/com/aurora/store/enums/NotificationProvider.java similarity index 96% rename from app/src/main/java/com/aurora/store/NotificationProvider.java rename to app/src/main/java/com/aurora/store/enums/NotificationProvider.java index f0b0db32d..93324bad1 100644 --- a/app/src/main/java/com/aurora/store/NotificationProvider.java +++ b/app/src/main/java/com/aurora/store/enums/NotificationProvider.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store; +package com.aurora.store.enums; public enum NotificationProvider { NATIVE, diff --git a/app/src/main/java/com/aurora/store/events/Event.java b/app/src/main/java/com/aurora/store/events/Event.java index 38d9b6622..2cc24ef08 100644 --- a/app/src/main/java/com/aurora/store/events/Event.java +++ b/app/src/main/java/com/aurora/store/events/Event.java @@ -1,18 +1,40 @@ package com.aurora.store.events; +import lombok.Data; + + +@Data public class Event { - private Events event; + private SubType subType; + private String packageName; + private int status; - public Event(Events event) { - this.event = event; + public Event(SubType subType, String packageName, int status) { + this.subType = subType; + this.packageName = packageName; + this.status = status; } - public Events getEvent() { - return event; + public Event(SubType subType, String packageName) { + this.subType = subType; + this.packageName = packageName; } - public void setEvent(Events event) { - this.event = event; + public Event(SubType subType) { + this.subType = subType; + } + + public enum SubType { + API_SUCCESS, + API_FAILED, + API_ERROR, + BLACKLIST, + WHITELIST, + INSTALLED, + UNINSTALLED, + NETWORK_UNAVAILABLE, + NETWORK_AVAILABLE, + BULK_UPDATE_NOTIFY } } diff --git a/app/src/main/java/com/aurora/store/events/Events.java b/app/src/main/java/com/aurora/store/events/Events.java deleted file mode 100644 index 272dacab5..000000000 --- a/app/src/main/java/com/aurora/store/events/Events.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.aurora.store.events; - -public enum Events { - LOGGED_IN, - LOGGED_OUT, - TOKEN_REFRESHED, - TOKEN_EXPIRED, - NET_CONNECTED, - NET_DISCONNECTED, - PERMANENT_FAIL, - BLACKLIST -} diff --git a/app/src/main/java/com/aurora/store/events/RxBus.java b/app/src/main/java/com/aurora/store/events/RxBus.java index adb3c89f1..9420c60e0 100644 --- a/app/src/main/java/com/aurora/store/events/RxBus.java +++ b/app/src/main/java/com/aurora/store/events/RxBus.java @@ -3,38 +3,11 @@ package com.aurora.store.events; import com.jakewharton.rxrelay2.PublishRelay; import com.jakewharton.rxrelay2.Relay; -import io.reactivex.Observable; - public class RxBus { - public static volatile RxBus instance; - private final Relay bus = PublishRelay.create().toSerialized(); + private final Relay bus = PublishRelay.create(); - public RxBus() { - if (instance != null) { - throw new RuntimeException("Use get() method to get the single instance of RxBus"); - } - } - - public static RxBus get() { - if (instance == null) { - synchronized (RxBus.class) { - if (instance == null) instance = new RxBus(); - } - } - return instance; - } - - public static void publish(Object event) { - RxBus auroraBus = RxBus.get(); - auroraBus.bus.accept(event); - } - - public Observable toObservable() { + public Relay getBus() { return bus; } - - public boolean hasObservers() { - return bus.hasObservers(); - } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/AppsFragment.java b/app/src/main/java/com/aurora/store/fragment/AppsFragment.java deleted file mode 100644 index 47b5e0e9d..000000000 --- a/app/src/main/java/com/aurora/store/fragment/AppsFragment.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; -import androidx.viewpager.widget.ViewPager; - -import com.aurora.store.R; -import com.aurora.store.adapter.TabAdapter; -import com.aurora.store.utility.Util; -import com.google.android.material.tabs.TabLayout; - -import org.jetbrains.annotations.NotNull; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class AppsFragment extends Fragment { - - @BindView(R.id.tabLayout) - TabLayout mTabLayout; - @BindView(R.id.tabPager) - ViewPager mViewPager; - private Context context; - - @Override - public void onAttach(@NotNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - View view = inflater.inflate(R.layout.fragment_apps, container, false); - ButterKnife.bind(this, view); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - init(); - } - - private void init() { - TabAdapter mTabAdapter = new TabAdapter(getChildFragmentManager()); - mTabAdapter.addFragment(new UpdatesFragment(), getString(R.string.action_updates)); - mTabAdapter.addFragment(new InstalledFragment(), getString(R.string.action_installed)); - - mViewPager.setAdapter(mTabAdapter); - mViewPager.setOffscreenPageLimit(3); - mTabLayout.setupWithViewPager(mViewPager); - mTabLayout.setTabMode(Util.isTabScrollable(context) - ? TabLayout.MODE_SCROLLABLE - : TabLayout.MODE_FIXED); - } -} diff --git a/app/src/main/java/com/aurora/store/fragment/BaseFragment.java b/app/src/main/java/com/aurora/store/fragment/BaseFragment.java deleted file mode 100644 index f7d4b3fe1..000000000 --- a/app/src/main/java/com/aurora/store/fragment/BaseFragment.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.content.Intent; -import android.text.TextUtils; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ViewSwitcher; - -import androidx.annotation.NonNull; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.fragment.app.Fragment; - -import com.aurora.store.AnonymousLoginService; -import com.aurora.store.ErrorType; -import com.aurora.store.R; -import com.aurora.store.activity.AccountsActivity; -import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.events.Event; -import com.aurora.store.events.Events; -import com.aurora.store.events.RxBus; -import com.aurora.store.exception.CredentialsEmptyException; -import com.aurora.store.exception.InvalidApiException; -import com.aurora.store.exception.MalformedRequestException; -import com.aurora.store.exception.TooManyRequestsException; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.view.ErrorView; -import com.dragons.aurora.playstoreapiv2.AuthException; -import com.dragons.aurora.playstoreapiv2.IteratorGooglePlayException; -import com.google.android.material.snackbar.Snackbar; - -import java.io.IOException; - -import butterknife.BindView; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -import static com.aurora.store.utility.Util.noNetwork; - -public abstract class BaseFragment extends Fragment { - - protected CompositeDisposable disposable = new CompositeDisposable(); - - @BindView(R.id.coordinator) - CoordinatorLayout coordinatorLayout; - @BindView(R.id.view_switcher) - ViewSwitcher viewSwitcher; - @BindView(R.id.content_view) - ViewGroup layoutContent; - @BindView(R.id.err_view) - ViewGroup layoutError; - - private CompositeDisposable disposableBus = new CompositeDisposable(); - private Context context; - - protected abstract View.OnClickListener errRetry(); - - protected abstract void fetchData(); - - /*UI handling methods*/ - - protected void notifyLoggedIn() { - ContextUtil.runOnUiThread(() -> { - fetchData(); - notifyStatus(coordinatorLayout, context.getResources().getString(R.string.action_logging_in_success)); - }); - } - - protected void notifyNetworkFailure() { - setErrorView(ErrorType.NO_NETWORK); - notifyStatus(coordinatorLayout, context.getString(R.string.error_no_network)); - switchViews(true); - } - - protected void notifyPermanentFailure() { - setErrorView(ErrorType.UNKNOWN); - switchViews(true); - } - - protected void notifyLoggedOut() { - setErrorView(ErrorType.LOGOUT_ERR); - switchViews(true); - notifyStatus(coordinatorLayout, context.getString(R.string.error_logged_out)); - } - - protected void notifyTokenExpired() { - setErrorView(ErrorType.SESSION_EXPIRED); - switchViews(true); - notifyStatus(coordinatorLayout, context.getString(R.string.action_token_expired)); - } - - @Override - public void onStart() { - super.onStart(); - disposableBus.add(RxBus.get().toObservable() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(event -> { - if (event instanceof Event) { - Events eventEnum = ((Event) event).getEvent(); - switch (eventEnum) { - case LOGGED_IN: - case TOKEN_REFRESHED: - notifyLoggedIn(); - break; - case LOGGED_OUT: - notifyLoggedOut(); - break; - case TOKEN_EXPIRED: - notifyTokenExpired(); - break; - case NET_DISCONNECTED: - notifyNetworkFailure(); - break; - case PERMANENT_FAIL: - notifyPermanentFailure(); - break; - } - } - })); - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onStop() { - super.onStop(); - disposableBus.clear(); - } - - private void notifyStatus(@NonNull CoordinatorLayout coordinatorLayout, String message) { - Snackbar snackbar = Snackbar.make(coordinatorLayout, message, Snackbar.LENGTH_LONG); - snackbar.show(); - } - - /*ErrorView UI handling methods*/ - - protected void setErrorView(ErrorType errorType) { - layoutError.removeAllViews(); - layoutError.addView(new ErrorView(context, errorType, getAction(errorType))); - } - - protected void switchViews(boolean showError) { - if (viewSwitcher.getCurrentView() == layoutContent && showError) - viewSwitcher.showNext(); - else if (viewSwitcher.getCurrentView() == layoutError && !showError) - viewSwitcher.showPrevious(); - } - - private View.OnClickListener errLogin() { - return v -> { - ((Button) v).setText(getString(R.string.action_logging_in)); - ((Button) v).setEnabled(false); - if (Accountant.isLoggedIn(context)) { - RxBus.publish(new Event(Events.LOGGED_IN)); - return; - } - context.startActivity(new Intent(context, AccountsActivity.class)); - }; - } - - protected View.OnClickListener errClose() { - return v -> { - - }; - } - - private View.OnClickListener getAction(ErrorType errorType) { - switch (errorType) { - case LOGOUT_ERR: - return errLogin(); - case APP_NOT_FOUND: - return errClose(); - default: - return errRetry(); - } - } - - /*Exception handling methods*/ - - protected void processException(Throwable e) { - if (e instanceof AuthException) { - processAuthException((AuthException) e); - } else if (e instanceof IteratorGooglePlayException) { - processException(e.getCause()); - } else if (e instanceof TooManyRequestsException) { - processAuthException(new AuthException("Too many request", 429)); - } else if (e instanceof MalformedRequestException) { - processAuthException(new AuthException("Malformed Request", 401)); - } else if (e instanceof IOException) { - processIOException((IOException) e); - } else { - Log.e("Unknown exception " + e.getClass().getName() + " " + e.getMessage()); - e.printStackTrace(); - } - } - - private void processIOException(IOException e) { - String message; - if (noNetwork(e)) { - message = context.getString(R.string.error_no_network); - Log.i(message); - RxBus.publish(new Event(Events.NET_DISCONNECTED)); - } else { - message = TextUtils.isEmpty(e.getMessage()) - ? context.getString(R.string.error_network_other) - : e.getMessage(); - Log.i(message); - } - } - - private void processAuthException(AuthException e) { - PlayStoreApiAuthenticator.destroyInstance(); - if (e instanceof CredentialsEmptyException || e instanceof InvalidApiException) { - Accountant.completeCheckout(context); - RxBus.publish(new Event(Events.LOGGED_OUT)); - } else if (e.getCode() >= 400 && Accountant.isAnonymous(context)) { - RxBus.publish(new Event(Events.TOKEN_EXPIRED)); - Accountant.completeCheckout(context); - logInWithDummy(); - } else { - ContextUtil.toast(context, R.string.error_session_expired); - Accountant.completeCheckout(context); - } - } - - private void logInWithDummy() { - Intent intent = new Intent(context, AnonymousLoginService.class); - if (!AnonymousLoginService.isServiceRunning()) - context.startService(intent); - } -} diff --git a/app/src/main/java/com/aurora/store/fragment/CategoriesFragment.java b/app/src/main/java/com/aurora/store/fragment/CategoriesFragment.java deleted file mode 100644 index 76cdaffca..000000000 --- a/app/src/main/java/com/aurora/store/fragment/CategoriesFragment.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.R; -import com.aurora.store.adapter.CategoriesListAdapter; -import com.aurora.store.manager.CategoryManager; -import com.aurora.store.task.CategoryList; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.ViewUtil; -import com.bumptech.glide.Glide; -import com.google.android.material.bottomnavigation.BottomNavigationView; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class CategoriesFragment extends Fragment { - - public static final String APPS = "APPLICATION"; - public static final String GAME = "GAME"; - public static final String FAMILY = "FAMILY"; - - - @BindView(R.id.category_recycler) - RecyclerView recyclerView; - - private Context context; - private CategoryManager categoryManager; - private CompositeDisposable disposable = new CompositeDisposable(); - private CategoriesListAdapter categoriesListAdapter; - private String categoryType = APPS; - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setRetainInstance(true); - categoryManager = new CategoryManager(context); - categoriesListAdapter = new CategoriesListAdapter(this); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - View view = inflater.inflate(R.layout.fragment_categories, container, false); - ButterKnife.bind(this, view); - Bundle arguments = getArguments(); - if (arguments != null) { - categoryType = arguments.getString("CATEGORY_TYPE"); - setupAllCategories(); - } else - Log.e("No category id provided"); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - } - - @Override - public void onResume() { - super.onResume(); - if (categoriesListAdapter == null || categoriesListAdapter.isDataEmpty()) - getCategories(); - } - - @Override - public void onDestroy() { - Glide.with(this).pauseAllRequests(); - super.onDestroy(); - } - - private void setupAllCategories() { - recyclerView.setLayoutManager(new GridLayoutManager(context, getSpanCount())); - recyclerView.setAdapter(categoriesListAdapter); - } - - private int getSpanCount() { - int width = Resources.getSystem().getConfiguration().screenWidthDp; - return width / 200; - } - - private void getCategories() { - if (categoryManager.categoryListEmpty()) { - getCategoriesFromAPI(); - return; - } - switch (categoryType) { - case APPS: - categoriesListAdapter.addData(categoryManager.getAllCategories()); - break; - case GAME: - categoriesListAdapter.addData(categoryManager.getAllGames()); - break; - case FAMILY: - categoriesListAdapter.addData(categoryManager.getAllFamily()); - break; - default: - categoriesListAdapter.addData(categoryManager.getAllCategories()); - } - } - - private void getCategoriesFromAPI() { - disposable.add(Observable.fromCallable(() -> new CategoryList(context) - .getResult()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((success) -> { - if (success) { - Log.i("CategoryList fetch completed"); - ContextUtil.runOnUiThread(() -> { - getCategories(); - Log.i("Categories populated"); - }); - } - }, err -> Log.e(err.getMessage()))); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/CategoryAppsFragment.java b/app/src/main/java/com/aurora/store/fragment/CategoryAppsFragment.java deleted file mode 100644 index b70d92172..000000000 --- a/app/src/main/java/com/aurora/store/fragment/CategoryAppsFragment.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.fragment.app.Fragment; -import androidx.viewpager.widget.ViewPager; - -import com.aurora.store.Filter; -import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; -import com.aurora.store.adapter.SubCategoryAdapter; -import com.aurora.store.sheet.FilterBottomSheet; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.Util; -import com.bumptech.glide.Glide; -import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; -import com.google.android.material.tabs.TabLayout; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class CategoryAppsFragment extends Fragment { - - public static String categoryId; - - @BindView(R.id.view_pager) - ViewPager viewPager; - @BindView(R.id.category_tabs) - TabLayout tabLayout; - @BindView(R.id.filter_fab) - ExtendedFloatingActionButton filterFab; - - private Context context; - private ActionBar actionBar; - - public ExtendedFloatingActionButton getFilterFab() { - return filterFab; - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - View view = inflater.inflate(R.layout.fragment_category_container, container, false); - ButterKnife.bind(this, view); - Bundle arguments = getArguments(); - if (arguments != null) { - categoryId = arguments.getString("CategoryId"); - if (getActivity() instanceof AuroraActivity) { - actionBar = ((AuroraActivity) getActivity()).getSupportActionBar(); - actionBar.setTitle(arguments.getString("CategoryName")); - } - } else - Log.e("No category id provided"); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - SubCategoryAdapter subCategoryAdapter = new SubCategoryAdapter(getContext(), getChildFragmentManager()); - viewPager.setAdapter(subCategoryAdapter); - viewPager.setOffscreenPageLimit(2); - tabLayout.setupWithViewPager(viewPager); - filterFab.setOnClickListener(v -> { - getFilterDialog(); - }); - } - - @Override - public void onDestroy() { - Glide.with(this).pauseAllRequests(); - if (actionBar != null) - actionBar.setTitle(getString(R.string.app_name)); - if (Util.filterSearchNonPersistent(context)) - new Filter(context).resetFilterPreferences(); - super.onDestroy(); - } - - private void getFilterDialog() { - FilterBottomSheet filterSheet = new FilterBottomSheet(); - filterSheet.setOnApplyListener(v -> { - filterSheet.dismiss(); - viewPager.removeAllViews(); - viewPager.setAdapter(new SubCategoryAdapter(getContext(), getChildFragmentManager())); - }); - filterSheet.show(getChildFragmentManager(), "FILTER"); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/DetailsFragment.java b/app/src/main/java/com/aurora/store/fragment/DetailsFragment.java deleted file mode 100644 index ac666070d..000000000 --- a/app/src/main/java/com/aurora/store/fragment/DetailsFragment.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.widget.NestedScrollView; - -import com.aurora.store.ErrorType; -import com.aurora.store.R; -import com.aurora.store.exception.AppNotFoundException; -import com.aurora.store.fragment.details.AbstractHelper; -import com.aurora.store.fragment.details.ActionButton; -import com.aurora.store.fragment.details.AppLinks; -import com.aurora.store.fragment.details.Beta; -import com.aurora.store.fragment.details.ExodusPrivacy; -import com.aurora.store.fragment.details.GeneralDetails; -import com.aurora.store.fragment.details.Reviews; -import com.aurora.store.fragment.details.Screenshot; -import com.aurora.store.fragment.details.Video; -import com.aurora.store.model.App; -import com.aurora.store.task.DetailsApp; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; - -import java.util.concurrent.TimeUnit; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class DetailsFragment extends BaseFragment { - - private static final String ACTION_PACKAGE_REPLACED_NON_SYSTEM = "ACTION_PACKAGE_REPLACED_NON_SYSTEM"; - private static final String ACTION_PACKAGE_INSTALLATION_FAILED = "ACTION_PACKAGE_INSTALLATION_FAILED"; - private static final String ACTION_UNINSTALL_PACKAGE_FAILED = "ACTION_UNINSTALL_PACKAGE_FAILED"; - - public static App app; - - @BindView(R.id.scroll_view) - NestedScrollView mScrollView; - - private Context context; - private ActionButton actionButton; - private String packageName; - - private BroadcastReceiver localInstallReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String packageName = intent.getStringExtra("PACKAGE_NAME"); - int statusCode = intent.getIntExtra("STATUS_CODE", -1); - if (packageName != null && packageName.equals(app.getPackageName())) - ContextUtil.runOnUiThread(() -> drawButtons()); - if (statusCode == 0) - ContextUtil.toastLong(context, getString(R.string.installer_status_failure)); - } - }; - - private BroadcastReceiver globalInstallReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getData() == null || !TextUtils.equals(packageName, intent.getData().getSchemeSpecificPart())) { - return; - } - ContextUtil.runOnUiThread(() -> drawButtons()); - } - }; - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_details, container, false); - ButterKnife.bind(this, view); - setErrorView(ErrorType.NO_APPS); - Bundle arguments = getArguments(); - if (arguments != null) { - packageName = arguments.getString("PackageName"); - fetchData(); - } - return view; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - context.registerReceiver(localInstallReceiver, new IntentFilter("ACTION_INSTALL")); - context.registerReceiver(globalInstallReceiver, getFilter()); - } - - @Override - public void onDestroy() { - super.onDestroy(); - try { - context.unregisterReceiver(localInstallReceiver); - context.unregisterReceiver(globalInstallReceiver); - disposable.clear(); - } catch (Exception ignored) { - } - } - - @Override - protected void fetchData() { - disposable.add(Observable.fromCallable(() -> new DetailsApp(getContext()) - .getInfo(packageName)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(app -> { - switchViews(false); - draw(app); - }, err -> { - Log.e(err.getMessage()); - processException(err); - })); - } - - private void draw(App mApp) { - app = mApp; - actionButton = new ActionButton(this, app); - disposable.add(Observable.just( - new GeneralDetails(this, app), - new Screenshot(this, app), - new Reviews(this, app), - new ExodusPrivacy(this, app), - new Video(this, app), - new Beta(this, app), - new AppLinks(this, app)) - .zipWith(Observable.interval(16, TimeUnit.MILLISECONDS), (abstractHelper, interval) -> abstractHelper) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext(AbstractHelper::draw) - .subscribe()); - drawButtons(); - } - - public void drawButtons() { - if (PackageUtil.isInstalled(context, app)) - app.setInstalled(true); - if (actionButton != null) - actionButton.draw(); - } - - @Override - protected View.OnClickListener errRetry() { - return v -> { - fetchData(); - ((Button) v).setText(getString(R.string.action_retry_ing)); - ((Button) v).setEnabled(false); - }; - } - - @Override - protected View.OnClickListener errClose() { - return v -> { - if (getActivity() != null) - getActivity().onBackPressed(); - }; - } - - @Override - public void processException(Throwable e) { - disposable.clear(); - if (e instanceof AppNotFoundException) { - setErrorView(ErrorType.APP_NOT_FOUND); - switchViews(true); - } else - super.processException(e); - } - - public IntentFilter getFilter() { - IntentFilter filter = new IntentFilter(); - filter.addDataScheme("package"); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_INSTALL); - filter.addAction(Intent.ACTION_UNINSTALL_PACKAGE); - filter.addAction(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REPLACED); - filter.addAction(ACTION_PACKAGE_REPLACED_NON_SYSTEM); - filter.addAction(ACTION_PACKAGE_INSTALLATION_FAILED); - filter.addAction(ACTION_UNINSTALL_PACKAGE_FAILED); - return filter; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/DevAppsFragment.java b/app/src/main/java/com/aurora/store/fragment/DevAppsFragment.java deleted file mode 100644 index 5124e416f..000000000 --- a/app/src/main/java/com/aurora/store/fragment/DevAppsFragment.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.widget.Button; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.EndlessScrollListener; -import com.aurora.store.ErrorType; -import com.aurora.store.R; -import com.aurora.store.adapter.EndlessAppsAdapter; -import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.iterator.CustomAppListIterator; -import com.aurora.store.model.App; -import com.aurora.store.task.SearchTask; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.NetworkUtil; -import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import com.dragons.aurora.playstoreapiv2.SearchIterator; -import com.google.android.material.chip.Chip; - -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class DevAppsFragment extends BaseFragment { - - @BindView(R.id.search_apps_list) - RecyclerView recyclerView; - @BindView(R.id.dev_name) - Chip chipDevName; - - private Context context; - private String query; - private EndlessAppsAdapter endlessAppsAdapter; - private CustomAppListIterator iterator; - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - endlessAppsAdapter = new EndlessAppsAdapter(context); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_dev_applist, container, false); - ButterKnife.bind(this, view); - Bundle arguments = getArguments(); - if (arguments != null) { - query = arguments.getString("SearchQuery"); - chipDevName.setText(arguments.getString("SearchTitle")); - if (NetworkUtil.isConnected(context)) - setupRecycler(); - else - notifyNetworkFailure(); - } else - Log.e("No category id provided"); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - setErrorView(ErrorType.UNKNOWN); - fetchDevAppsList(false); - } - - @Override - protected void fetchData() { - fetchDevAppsList(true); - } - - private void fetchDevAppsList(boolean shouldIterate) { - if (!shouldIterate) - getIterator(); - disposable.add(Observable.fromCallable(() -> new SearchTask(context) - .getSearchResults(iterator)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(appList -> { - if (shouldIterate) { - addApps(appList); - } else if (appList.isEmpty()) { - setErrorView(ErrorType.NO_SEARCH); - switchViews(true); - } else { - switchViews(false); - endlessAppsAdapter.addData(appList); - } - }, err -> { - Log.e(err.getMessage()); - processException(err); - })); - } - - private void getIterator() { - try { - GooglePlayAPI api = PlayStoreApiAuthenticator.getInstance(context); - iterator = new CustomAppListIterator(new SearchIterator(api, query)); - } catch (Exception e) { - processException(e); - } - } - - private void addApps(List appsToAdd) { - if (!appsToAdd.isEmpty()) { - for (App app : appsToAdd) - endlessAppsAdapter.add(app); - endlessAppsAdapter.notifyItemInserted(endlessAppsAdapter.getItemCount() - 1); - } - if (iterator.hasNext() && endlessAppsAdapter.getItemCount() < 10) { - new Timer().scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - fetchDevAppsList(true); - cancel(); - } - }, 2500, 1000); - } - } - - private void setupRecycler() { - LinearLayoutManager mLayoutManager = new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false); - recyclerView.setLayoutManager(mLayoutManager); - recyclerView.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(this.getActivity(), R.anim.anim_falldown)); - recyclerView.setAdapter(endlessAppsAdapter); - EndlessScrollListener mScrollListener = new EndlessScrollListener(mLayoutManager) { - @Override - public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { - fetchDevAppsList(true); - } - }; - recyclerView.addOnScrollListener(mScrollListener); - } - - @Override - protected View.OnClickListener errRetry() { - return v -> { - if (NetworkUtil.isConnected(context)) { - fetchDevAppsList(false); - } else { - setErrorView(ErrorType.NO_NETWORK); - } - ((Button) v).setText(getString(R.string.action_retry_ing)); - ((Button) v).setEnabled(false); - }; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/HomeFragment.java b/app/src/main/java/com/aurora/store/fragment/HomeFragment.java deleted file mode 100644 index b03804509..000000000 --- a/app/src/main/java/com/aurora/store/fragment/HomeFragment.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentTransaction; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.Constants; -import com.aurora.store.ErrorType; -import com.aurora.store.R; -import com.aurora.store.SharedPreferencesTranslator; -import com.aurora.store.adapter.FeaturedAppsAdapter; -import com.aurora.store.adapter.TopCategoriesAdapter; -import com.aurora.store.manager.CategoryManager; -import com.aurora.store.model.App; -import com.aurora.store.task.CategoryList; -import com.aurora.store.task.FeaturedAppsTask; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; -import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import com.google.android.material.button.MaterialButton; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -import java.lang.reflect.Type; -import java.util.Calendar; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class HomeFragment extends BaseFragment { - - @BindView(R.id.recycler_top_categories) - RecyclerView recyclerTopCategories; - @BindView(R.id.recycler_top_apps) - RecyclerView recyclerTopApps; - @BindView(R.id.recycler_top_games) - RecyclerView recyclerTopGames; - @BindView(R.id.recycler_top_family) - RecyclerView recyclerTopFamily; - - @BindView(R.id.btn_all_categories) - MaterialButton btnAllCategories; - @BindView(R.id.btn_top_apps) - MaterialButton btnTopApps; - @BindView(R.id.btn_top_games) - MaterialButton btnTopGames; - @BindView(R.id.btn_top_family) - MaterialButton btnTopFamily; - - private Context context; - private FeaturedAppsAdapter topAppsAdapter; - private FeaturedAppsAdapter topGamesAdapter; - private FeaturedAppsAdapter topFamilyAdapter; - private CategoryManager categoryManager; - private FeaturedAppsTask featuredAppsTask; - private SharedPreferencesTranslator translator; - private CompositeDisposable disposable = new CompositeDisposable(); - - @Override - public void onStart() { - super.onStart(); - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - featuredAppsTask = new FeaturedAppsTask(context); - categoryManager = new CategoryManager(context); - translator = new SharedPreferencesTranslator(Util.getPrefs(context)); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_home, container, false); - ButterKnife.bind(this, view); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setErrorView(ErrorType.UNKNOWN); - init(); - } - - @Override - public void onResume() { - super.onResume(); - if (topAppsAdapter.isDataEmpty()) - fetchTopAppsFromCache(); - if (topGamesAdapter.isDataEmpty()) - fetchTopGamesFromCache(); - if (topFamilyAdapter.isDataEmpty()) - fetchTopFamilyFromCache(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - disposable.clear(); - featuredAppsTask = null; - } - - private void init() { - setupButtons(); - setupRecyclers(); - if (categoryManager.categoryListEmpty()) - getCategoriesFromAPI(); - } - - private void setupButtons() { - btnAllCategories.setOnClickListener(v -> getAllCategories()); - btnTopApps.setOnClickListener(v -> getCategoryApps("APPLICATION")); - btnTopGames.setOnClickListener(v -> getCategoryApps("GAME")); - btnTopFamily.setOnClickListener(v -> getCategoryApps("FAMILY")); - } - - private void setupRecyclers() { - topAppsAdapter = new FeaturedAppsAdapter(context); - topGamesAdapter = new FeaturedAppsAdapter(context); - topFamilyAdapter = new FeaturedAppsAdapter(context); - - recyclerTopCategories.setAdapter(new TopCategoriesAdapter(this)); - recyclerTopCategories.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); - recyclerTopApps.setAdapter(topAppsAdapter); - recyclerTopApps.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); - recyclerTopGames.setAdapter(topGamesAdapter); - recyclerTopGames.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); - recyclerTopFamily.setAdapter(topFamilyAdapter); - recyclerTopFamily.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); - - Util.attachSnapPager(context, recyclerTopApps); - Util.attachSnapPager(context, recyclerTopGames); - Util.attachSnapPager(context, recyclerTopFamily); - } - - private void fetchTopApps() { - disposable.add(Observable.fromCallable(() -> featuredAppsTask - .getApps("APPLICATION", GooglePlayAPI.SUBCATEGORY.TOP_FREE)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((appList) -> { - switchViews(false); - topAppsAdapter.addData(appList); - saveToCache(appList, Constants.PREFERENCE_TOP_APPS); - Util.setCacheCreateTime(context, Calendar.getInstance().getTimeInMillis()); - }, err -> { - processException(err); - Log.d(err.getMessage()); - })); - } - - private void fetchTopGames() { - disposable.add(Observable.fromCallable(() -> featuredAppsTask - .getApps("GAME", GooglePlayAPI.SUBCATEGORY.TOP_GROSSING)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((appList) -> { - switchViews(false); - topGamesAdapter.addData(appList); - saveToCache(appList, Constants.PREFERENCE_TOP_GAMES); - }, err -> Log.d(err.getMessage()))); - } - - private void fetchTopFamily() { - disposable.add(Observable.fromCallable(() -> featuredAppsTask - .getApps("FAMILY", GooglePlayAPI.SUBCATEGORY.TOP_GROSSING)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((appList) -> { - switchViews(false); - topFamilyAdapter.addData(appList); - saveToCache(appList, Constants.PREFERENCE_TOP_FAMILY); - }, err -> Log.d(err.getMessage()))); - } - - private void saveToCache(List appList, String key) { - Gson gson = new Gson(); - String jsonString = gson.toJson(appList); - PrefUtil.putString(context, key, jsonString); - } - - private void fetchTopAppsFromCache() { - Gson gson = new Gson(); - Type type = new TypeToken>() { - }.getType(); - String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_TOP_APPS); - List appList = gson.fromJson(jsonString, type); - if (appList == null || appList.isEmpty()) - fetchTopApps(); - else - topAppsAdapter.addData(appList); - } - - private void fetchTopGamesFromCache() { - Gson gson = new Gson(); - Type type = new TypeToken>() { - }.getType(); - String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_TOP_GAMES); - List appList = gson.fromJson(jsonString, type); - if (appList == null || appList.isEmpty()) - fetchTopGames(); - else - topGamesAdapter.addData(appList); - } - - private void fetchTopFamilyFromCache() { - Gson gson = new Gson(); - Type type = new TypeToken>() { - }.getType(); - String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_TOP_FAMILY); - List appList = gson.fromJson(jsonString, type); - if (appList == null || appList.isEmpty()) - fetchTopFamily(); - else - topFamilyAdapter.addData(appList); - } - - private void getAllCategories() { - CategoriesFragment categoryAppsFragment = new CategoriesFragment(); - Bundle arguments = new Bundle(); - arguments.putString("CATEGORY_TYPE", "APPLICATION"); - categoryAppsFragment.setArguments(arguments); - getChildFragmentManager() - .beginTransaction() - .replace(R.id.coordinator, categoryAppsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); - } - - private void getCategoryApps(String categoryID) { - CategoryAppsFragment categoryAppsFragment = new CategoryAppsFragment(); - Bundle arguments = new Bundle(); - arguments.putString("CategoryId", categoryID); - arguments.putString("CategoryName", translator.getString(categoryID)); - categoryAppsFragment.setArguments(arguments); - getChildFragmentManager() - .beginTransaction() - .replace(R.id.coordinator, categoryAppsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); - } - - private void getCategoriesFromAPI() { - disposable.add(Observable.fromCallable(() -> new CategoryList(getContext()) - .getResult()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(success -> { - }, err -> Log.e(err.getMessage()))); - } - - @Override - protected View.OnClickListener errRetry() { - return v -> { - fetchTopApps(); - fetchTopGames(); - fetchTopFamily(); - ((Button) v).setText(getString(R.string.action_retry_ing)); - ((Button) v).setEnabled(false); - }; - } - - @Override - protected void fetchData() { - ContextUtil.runOnUiThread(() -> { - fetchTopApps(); - fetchTopGames(); - fetchTopFamily(); - }); - } -} diff --git a/app/src/main/java/com/aurora/store/fragment/InstalledFragment.java b/app/src/main/java/com/aurora/store/fragment/InstalledFragment.java deleted file mode 100644 index ff0c01587..000000000 --- a/app/src/main/java/com/aurora/store/fragment/InstalledFragment.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.widget.Button; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.Constants; -import com.aurora.store.ErrorType; -import com.aurora.store.ListType; -import com.aurora.store.R; -import com.aurora.store.adapter.InstalledAppsAdapter; -import com.aurora.store.model.App; -import com.aurora.store.task.InstalledAppsTask; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.view.CustomSwipeToRefresh; -import com.google.android.material.switchmaterial.SwitchMaterial; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Type; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class InstalledFragment extends BaseFragment { - - @BindView(R.id.swipe_layout) - CustomSwipeToRefresh customSwipeToRefresh; - @BindView(R.id.recycler) - RecyclerView recyclerView; - @BindView(R.id.switch_system) - SwitchMaterial switchSystem; - - private Context context; - private View view; - private InstalledAppsAdapter adapter; - private InstalledAppsTask installedAppTask; - - @Override - public void onAttach(@NotNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - view = inflater.inflate(R.layout.fragment_installed, container, false); - ButterKnife.bind(this, view); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setErrorView(ErrorType.UNKNOWN); - - switchSystem.setChecked(PrefUtil.getBoolean(context, Constants.PREFERENCE_INCLUDE_SYSTEM)); - switchSystem.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (isChecked) - PrefUtil.putBoolean(context, Constants.PREFERENCE_INCLUDE_SYSTEM, true); - else - PrefUtil.putBoolean(context, Constants.PREFERENCE_INCLUDE_SYSTEM, false); - fetchData(); - }); - customSwipeToRefresh.setOnRefreshListener(() -> fetchData()); - setupRecycler(); - } - - @Override - public void onPause() { - super.onPause(); - customSwipeToRefresh.setRefreshing(false); - } - - @Override - public void onResume() { - super.onResume(); - if (adapter.isDataEmpty()) - fetchAppsFromCache(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - installedAppTask = null; - adapter = null; - } - - @Override - protected void fetchData() { - installedAppTask = new InstalledAppsTask(context); - disposable.add(Observable.fromCallable(() -> installedAppTask - .getInstalledApps(switchSystem.isChecked())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe(subscription -> customSwipeToRefresh.setRefreshing(true)) - .doOnTerminate(() -> customSwipeToRefresh.setRefreshing(false)) - .subscribe((appList) -> { - if (view != null) { - if (appList.isEmpty()) { - setErrorView(ErrorType.NO_APPS); - switchViews(true); - } else { - switchViews(false); - if (adapter != null) - adapter.addData(appList); - saveToCache(appList); - } - } - }, err -> { - Log.d(err.getMessage()); - processException(err); - })); - } - - private void saveToCache(List appList) { - Gson gson = new Gson(); - String jsonString = gson.toJson(appList); - PrefUtil.putString(context, Constants.PREFERENCE_INSTALLED_APPS, jsonString); - } - - private void fetchAppsFromCache() { - Gson gson = new Gson(); - Type type = new TypeToken>() { - }.getType(); - String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_INSTALLED_APPS); - List appList = gson.fromJson(jsonString, type); - if (appList == null || appList.isEmpty()) - fetchData(); - else { - adapter.addData(appList); - switchViews(false); - } - } - - private void setupRecycler() { - adapter = new InstalledAppsAdapter(context, ListType.INSTALLED); - recyclerView.setAdapter(adapter); - recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); - recyclerView.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(context, R.anim.anim_falldown)); - } - - @Override - protected View.OnClickListener errRetry() { - return v -> { - fetchData(); - ((Button) v).setText(getString(R.string.action_retry_ing)); - ((Button) v).setEnabled(false); - }; - } -} diff --git a/app/src/main/java/com/aurora/store/fragment/SearchAppsFragment.java b/app/src/main/java/com/aurora/store/fragment/SearchAppsFragment.java deleted file mode 100644 index 8ad308d0d..000000000 --- a/app/src/main/java/com/aurora/store/fragment/SearchAppsFragment.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.app.SearchManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.res.ColorStateList; -import android.database.Cursor; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.widget.Button; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.SearchView; -import androidx.core.graphics.ColorUtils; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.EndlessScrollListener; -import com.aurora.store.ErrorType; -import com.aurora.store.Filter; -import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; -import com.aurora.store.adapter.EndlessAppsAdapter; -import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.iterator.CustomAppListIterator; -import com.aurora.store.model.App; -import com.aurora.store.sheet.FilterBottomSheet; -import com.aurora.store.task.SearchTask; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.NetworkUtil; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; -import com.bumptech.glide.Glide; -import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import com.dragons.aurora.playstoreapiv2.SearchIterator; -import com.google.android.material.chip.Chip; -import com.google.android.material.chip.ChipGroup; -import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; - -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class SearchAppsFragment extends BaseFragment { - - @BindView(R.id.search_apps) - SearchView searchView; - @BindView(R.id.search_apps_list) - RecyclerView recyclerView; - @BindView(R.id.filter_fab) - ExtendedFloatingActionButton filterFab; - @BindView(R.id.related_chip_group) - ChipGroup relatedChipGroup; - - private Context context; - private String query; - private List relatedTags = new ArrayList<>(); - private CustomAppListIterator iterator; - private EndlessAppsAdapter endlessAppsAdapter; - - private String getQuery() { - return query; - } - - private void setQuery(String query) { - this.query = query; - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - endlessAppsAdapter = new EndlessAppsAdapter(context); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_search_applist, container, false); - ButterKnife.bind(this, view); - Bundle arguments = getArguments(); - if (arguments != null) { - setQuery(arguments.getString("SearchQuery")); - searchView.setQuery(getQuery(), false); - } else - Log.e("No category id provided"); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setErrorView(ErrorType.UNKNOWN); - if (!NetworkUtil.isConnected(context)) { - setErrorView(ErrorType.NO_NETWORK); - switchViews(true); - } - setupRecycler(); - setupSearch(); - filterFab.show(); - filterFab.setOnClickListener(v -> getFilterDialog()); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - fetchSearchAppsList(false); - } - - - @Override - public void onDestroy() { - Glide.with(this).pauseAllRequests(); - disposable.dispose(); - if (Util.filterSearchNonPersistent(context)) - new Filter(context).resetFilterPreferences(); - super.onDestroy(); - } - - private void setupSearch() { - SearchManager searchManager = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); - ComponentName componentName = getActivity().getComponentName(); - - if (null != searchManager && componentName != null) { - searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName)); - } - - if (!StringUtils.isEmpty(AuroraActivity.externalQuery)) - setQuery(AuroraActivity.externalQuery); - - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextChange(String query) { - return true; - } - - @Override - public boolean onQueryTextSubmit(String newQuery) { - searchView.clearFocus(); - query = newQuery; - fetchSearchAppsList(false); - return true; - } - }); - - searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { - @Override - public boolean onSuggestionSelect(int position) { - return true; - } - - @Override - public boolean onSuggestionClick(int position) { - Cursor cursor = searchView.getSuggestionsAdapter().getCursor(); - cursor.moveToPosition(position); - if (position == 0) { - searchView.setQuery(cursor.getString(2), true); - searchView.setQuery(cursor.getString(1), false); - } else - searchView.setQuery(cursor.getString(1), true); - return true; - } - }); - } - - private void getFilterDialog() { - FilterBottomSheet filterSheet = new FilterBottomSheet(); - filterSheet.setCancelable(true); - filterSheet.setOnApplyListener(v -> { - filterSheet.dismiss(); - recyclerView.removeAllViewsInLayout(); - fetchSearchAppsList(false); - }); - filterSheet.show(getChildFragmentManager(), "FILTER"); - } - - private void getIterator() { - try { - GooglePlayAPI api = PlayStoreApiAuthenticator.getInstance(context); - iterator = new CustomAppListIterator(new SearchIterator(api, query)); - iterator.setFilterEnabled(true); - iterator.setFilter(new Filter(getContext()).getFilterPreferences()); - relatedTags = iterator.getRelatedTags(); - } catch (Exception e) { - Log.e("BAZINGA"); - processException(e); - } - } - - private void fetchSearchAppsList(boolean shouldIterate) { - if (!shouldIterate) - getIterator(); - disposable.add(Observable.fromCallable(() -> new SearchTask(context) - .getSearchResults(iterator)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(appList -> { - if (shouldIterate) { - addApps(appList); - } else if (appList.isEmpty() && endlessAppsAdapter.isDataEmpty()) { - setErrorView(ErrorType.NO_SEARCH); - switchViews(true); - filterFab.hide(); - } else { - switchViews(false); - filterFab.show(); - if (endlessAppsAdapter != null) - endlessAppsAdapter.addData(appList); - if (!relatedTags.isEmpty()) - setupTags(); - } - }, err -> { - filterFab.hide(); - processException(err); - })); - } - - private void addApps(List appsToAdd) { - if (!appsToAdd.isEmpty()) { - for (App app : appsToAdd) - endlessAppsAdapter.add(app); - endlessAppsAdapter.notifyItemInserted(endlessAppsAdapter.getItemCount() - 1); - } - - /* - * Search results are scarce if filter are too strict, in this case endless scroll events - * fail to fetch next batch of apps, so manually fetch at least 10 apps until available. - */ - disposable.add(Observable.interval(1000, 2000, TimeUnit.MILLISECONDS) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(aLong -> { - if (iterator.hasNext() && endlessAppsAdapter.getItemCount() < 10) { - iterator.next(); - } - }, e -> Log.e(e.getMessage()))); - } - - private void setupRecycler() { - LinearLayoutManager layoutManager = new LinearLayoutManager(context, RecyclerView.VERTICAL, false); - recyclerView.setLayoutManager(layoutManager); - recyclerView.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(this.getActivity(), R.anim.anim_falldown)); - recyclerView.setAdapter(endlessAppsAdapter); - EndlessScrollListener endlessScrollListener = new EndlessScrollListener(layoutManager) { - @Override - public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { - fetchSearchAppsList(true); - } - }; - recyclerView.addOnScrollListener(endlessScrollListener); - recyclerView.setOnFlingListener(new RecyclerView.OnFlingListener() { - @Override - public boolean onFling(int velocityX, int velocityY) { - if (velocityY < 0) { - filterFab.show(); - } else if (velocityY > 0) { - filterFab.hide(); - } - return false; - } - }); - } - - private void setupTags() { - relatedChipGroup.removeAllViews(); - int i = 0; - for (String tag : relatedTags) { - final int color = ViewUtil.getSolidColors(i++); - Chip chip = new Chip(context); - chip.setText(tag); - chip.setChipIconSize(ViewUtil.dpToPx(context, 24)); - chip.setChipStrokeWidth(ViewUtil.dpToPx(context, 1)); - chip.setChipStrokeColor(ColorStateList.valueOf(color)); - chip.setChipBackgroundColor(ColorStateList.valueOf(ColorUtils.setAlphaComponent(color, 100))); - chip.setRippleColor(ColorStateList.valueOf(ColorUtils.setAlphaComponent(color, 200))); - chip.setCheckedIcon(context.getDrawable(R.drawable.ic_checked)); - chip.setOnClickListener(v -> { - if (chip.isChecked()) { - query = query + " " + tag; - fetchData(); - searchView.setQuery(query, false); - } else { - query = query.replace(tag, ""); - fetchData(); - searchView.setQuery(query, false); - } - }); - relatedChipGroup.addView(chip); - } - } - - @Override - protected void fetchData() { - fetchSearchAppsList(false); - } - - @Override - protected View.OnClickListener errRetry() { - return v -> { - if (NetworkUtil.isConnected(context)) { - fetchData(); - } else { - setErrorView(ErrorType.NO_NETWORK); - } - ((Button) v).setText(getString(R.string.action_retry_ing)); - ((Button) v).setEnabled(false); - }; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/SearchFragment.java b/app/src/main/java/com/aurora/store/fragment/SearchFragment.java deleted file mode 100644 index 63fb1451e..000000000 --- a/app/src/main/java/com/aurora/store/fragment/SearchFragment.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.app.SearchManager; -import android.content.ComponentName; -import android.content.Context; -import android.database.Cursor; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.SearchView; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentTransaction; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.Constants; -import com.aurora.store.HistoryItemTouchHelper; -import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; -import com.aurora.store.activity.DetailsActivity; -import com.aurora.store.adapter.SearchHistoryAdapter; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; - -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.regex.Pattern; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class SearchFragment extends Fragment implements HistoryItemTouchHelper.RecyclerItemTouchHelperListener, SearchHistoryAdapter.ClickListener { - - @BindView(R.id.search_apps) - SearchView searchView; - @BindView(R.id.searchHistory) - RecyclerView recyclerView; - @BindView(R.id.emptyView) - TextView emptyView; - @BindView(R.id.clearAll) - Button clearAll; - - private Context context; - private ArrayList queryList; - private SearchHistoryAdapter searchHistoryAdapter; - - @Override - public void onAttach(@NotNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - View view = inflater.inflate(R.layout.fragment_search, container, false); - ButterKnife.bind(this, view); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - setupSearch(); - setupHistory(); - clearAll.setOnClickListener(v -> clearAll()); - } - - @Override - public void onResume() { - super.onResume(); - if (searchView != null && Util.isIMEEnabled(context)) - searchView.requestFocus(); - } - - private void setupSearch() { - SearchManager searchManager = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); - ComponentName componentName = getActivity().getComponentName(); - - if (null != searchManager && componentName != null) { - searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName)); - } - - if (!StringUtils.isEmpty(AuroraActivity.externalQuery)) - setQuery(AuroraActivity.externalQuery); - - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextChange(String query) { - return true; - } - - @Override - public boolean onQueryTextSubmit(String query) { - searchView.clearFocus(); - setQuery(query); - return true; - } - }); - - searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { - @Override - public boolean onSuggestionSelect(int position) { - return true; - } - - @Override - public boolean onSuggestionClick(int position) { - Cursor cursor = searchView.getSuggestionsAdapter().getCursor(); - cursor.moveToPosition(position); - if (position == 0) { - searchView.setQuery(cursor.getString(2), true); - searchView.setQuery(cursor.getString(1), false); - saveQuery(cursor.getString(1)); - } else - searchView.setQuery(cursor.getString(1), true); - return true; - } - }); - } - - private void setQuery(String query) { - if (Util.isSearchByPackageEnabled(context) && looksLikeAPackageId(query)) { - context.startActivity(DetailsActivity.getDetailsIntent(getContext(), query)); - } else { - getQueriedApps(query); - saveQuery(query); - } - } - - private void saveQuery(String query) { - String mDatedQuery = query + ":" + Calendar.getInstance().getTimeInMillis(); - setQueryToPref(mDatedQuery); - } - - private void setQueryToPref(String query) { - queryList = PrefUtil.getListString(context, Constants.RECENT_HISTORY); - queryList.add(0, query); - PrefUtil.putListString(context, Constants.RECENT_HISTORY, queryList); - if (searchHistoryAdapter != null) - searchHistoryAdapter.reload(); - else - setupSearchHistory(queryList); - } - - private void setupHistory() { - queryList = PrefUtil.getListString(context, Constants.RECENT_HISTORY); - if (!queryList.isEmpty()) { - setupSearchHistory(queryList); - toggleViews(false); - } else { - toggleViews(true); - } - } - - private void setupSearchHistory(ArrayList historyList) { - searchHistoryAdapter = new SearchHistoryAdapter(context, historyList, this); - recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); - recyclerView.setItemAnimator(new DefaultItemAnimator()); - recyclerView.setAdapter(searchHistoryAdapter); - new ItemTouchHelper( - new HistoryItemTouchHelper(0, ItemTouchHelper.LEFT, this)) - .attachToRecyclerView(recyclerView); - } - - private void clearAll() { - if (searchHistoryAdapter != null) - searchHistoryAdapter.clear(); - toggleViews(true); - } - - private void toggleViews(Boolean shouldHide) { - if (shouldHide) { - recyclerView.setVisibility(View.GONE); - emptyView.setVisibility(View.VISIBLE); - } else { - recyclerView.setVisibility(View.VISIBLE); - emptyView.setVisibility(View.GONE); - } - } - - @Override - public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position) { - if (viewHolder instanceof SearchHistoryAdapter.ViewHolder) { - searchHistoryAdapter.remove(position); - if (searchHistoryAdapter.getItemCount() < 1) - clearAll(); - } - } - - private void getQueriedApps(String query) { - if (searchView != null) - searchView.setQuery("", false); - SearchAppsFragment searchAppsFragment = new SearchAppsFragment(); - Bundle arguments = new Bundle(); - arguments.putString("SearchQuery", query); - arguments.putString("SearchTitle", getTitleString(query)); - searchAppsFragment.setArguments(arguments); - getChildFragmentManager() - .beginTransaction() - .replace(R.id.coordinator, searchAppsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); - } - - private String getTitleString(String query) { - return query.startsWith(Constants.PUB_PREFIX) - ? getString(R.string.apps_by, query.substring(Constants.PUB_PREFIX.length())) - : getString(R.string.title_search_result, query) - ; - } - - private boolean looksLikeAPackageId(String query) { - if (TextUtils.isEmpty(query)) { - return false; - } - String pattern = "([\\p{L}_$][\\p{L}\\p{N}_$]*\\.)+[\\p{L}_$][\\p{L}\\p{N}_$]*"; - Pattern r = Pattern.compile(pattern); - return r.matcher(query).matches(); - } - - @Override - public void onClicked(String query) { - getQueriedApps(query); - } -} diff --git a/app/src/main/java/com/aurora/store/fragment/SubCategoryFragment.java b/app/src/main/java/com/aurora/store/fragment/SubCategoryFragment.java deleted file mode 100644 index d9d9fc834..000000000 --- a/app/src/main/java/com/aurora/store/fragment/SubCategoryFragment.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.EndlessScrollListener; -import com.aurora.store.ErrorType; -import com.aurora.store.Filter; -import com.aurora.store.R; -import com.aurora.store.adapter.EndlessAppsAdapter; -import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.iterator.CustomAppListIterator; -import com.aurora.store.model.App; -import com.aurora.store.task.CategoryAppsTask; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.dragons.aurora.playstoreapiv2.CategoryAppsIterator; -import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import com.dragons.aurora.playstoreapiv2.IteratorGooglePlayException; -import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class SubCategoryFragment extends BaseFragment { - - @BindView(R.id.endless_apps_list) - RecyclerView recyclerView; - - private Context context; - private CustomAppListIterator iterator; - private GooglePlayAPI.SUBCATEGORY subcategory = GooglePlayAPI.SUBCATEGORY.TOP_FREE; - private ExtendedFloatingActionButton filterFab; - private EndlessAppsAdapter endlessAppsAdapter; - - private GooglePlayAPI.SUBCATEGORY getSubcategory() { - return subcategory; - } - - private void setSubcategory(Bundle bundle) { - String category = bundle.getString("SUBCATEGORY"); - if (category != null) - switch (category) { - case "TOP_FREE": - subcategory = GooglePlayAPI.SUBCATEGORY.TOP_FREE; - break; - case "TOP_GROSSING": - subcategory = GooglePlayAPI.SUBCATEGORY.TOP_GROSSING; - break; - default: - subcategory = GooglePlayAPI.SUBCATEGORY.MOVERS_SHAKERS; - } - } - - private CustomAppListIterator getIterator() { - return iterator; - } - - private void setIterator(CustomAppListIterator iterator) { - this.iterator = iterator; - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - endlessAppsAdapter = new EndlessAppsAdapter(getContext()); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_category_applist, container, false); - ButterKnife.bind(this, view); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - Bundle bundle = getArguments(); - if (bundle != null) - setSubcategory(bundle); - initIterator(); - setupRecycler(); - - if (getParentFragment() != null && getParentFragment() instanceof CategoryAppsFragment) { - filterFab = ((CategoryAppsFragment) getParentFragment()).getFilterFab(); - } - } - - @Override - public void onResume() { - super.onResume(); - if (endlessAppsAdapter.isDataEmpty()) - fetchCategoryApps(false); - } - - @Override - public void onDestroy() { - disposable.clear(); - super.onDestroy(); - } - - private void initIterator() { - iterator = setupIterator(CategoryAppsFragment.categoryId, getSubcategory()); - if (iterator != null) { - iterator.setFilter(new Filter(getContext()).getFilterPreferences()); - iterator.setFilterEnabled(true); - setIterator(iterator); - } - } - - private void setupRecycler() { - LinearLayoutManager layoutManager = new LinearLayoutManager(context, RecyclerView.VERTICAL, false); - recyclerView.setLayoutManager(layoutManager); - recyclerView.setAdapter(endlessAppsAdapter); - EndlessScrollListener mEndlessRecyclerViewScrollListener = new EndlessScrollListener(layoutManager) { - @Override - public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { - fetchCategoryApps(true); - } - }; - recyclerView.addOnScrollListener(mEndlessRecyclerViewScrollListener); - recyclerView.setOnFlingListener(new RecyclerView.OnFlingListener() { - @Override - public boolean onFling(int velocityX, int velocityY) { - if (velocityY < 0) { - filterFab.show(); - } else if (velocityY > 0) { - filterFab.hide(); - } - return false; - } - }); - } - - private CustomAppListIterator setupIterator(String categoryId, GooglePlayAPI.SUBCATEGORY subcategory) { - try { - final GooglePlayAPI api = PlayStoreApiAuthenticator.getInstance(context); - final CategoryAppsIterator iterator = new CategoryAppsIterator(api, categoryId, subcategory); - return new CustomAppListIterator(iterator); - } catch (Exception err) { - processException(err); - return null; - } - } - - private void fetchCategoryApps(boolean shouldIterate) { - disposable.add(Observable.fromCallable(() -> new CategoryAppsTask(getContext()) - .getApps(getIterator())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(appList -> { - if (appList.isEmpty() && endlessAppsAdapter.isDataEmpty()) { - setErrorView(ErrorType.NO_APPS); - switchViews(true); - } else { - switchViews(false); - if (shouldIterate) { - addApps(appList); - } else - endlessAppsAdapter.addData(appList); - } - }, err -> { - if (err instanceof IteratorGooglePlayException) - processException(err.getCause()); - else - processException(err); - })); - } - - private void addApps(List appsToAdd) { - if (!appsToAdd.isEmpty()) { - for (App app : appsToAdd) - endlessAppsAdapter.add(app); - endlessAppsAdapter.notifyItemInserted(endlessAppsAdapter.getItemCount() - 1); - } - disposable.add(Observable.interval(1000, 2000, TimeUnit.MILLISECONDS) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(aLong -> { - if (iterator.hasNext() && endlessAppsAdapter.getItemCount() < 10) { - iterator.next(); - } - }, e -> Log.e(e.getMessage()))); - } - - @Override - protected View.OnClickListener errRetry() { - return v -> ContextUtil.runOnUiThread(() -> fetchCategoryApps(false)); - } - - @Override - protected void fetchData() { - fetchCategoryApps(false); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/UpdatesFragment.java b/app/src/main/java/com/aurora/store/fragment/UpdatesFragment.java deleted file mode 100644 index 2580bde37..000000000 --- a/app/src/main/java/com/aurora/store/fragment/UpdatesFragment.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.widget.Button; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.AuroraApplication; -import com.aurora.store.ErrorType; -import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; -import com.aurora.store.adapter.UpdatableAppsAdapter; -import com.aurora.store.download.DownloadManager; -import com.aurora.store.exception.MalformedRequestException; -import com.aurora.store.exception.NotPurchasedException; -import com.aurora.store.model.App; -import com.aurora.store.task.LiveUpdate; -import com.aurora.store.task.ObservableDeliveryData; -import com.aurora.store.task.UpdatableAppsTask; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; -import com.aurora.store.view.CustomSwipeToRefresh; -import com.google.android.material.bottomnavigation.BottomNavigationView; -import com.google.android.material.snackbar.Snackbar; -import com.tonyodev.fetch2.Fetch; - -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - - -public class UpdatesFragment extends BaseFragment { - - @BindView(R.id.swipe_layout) - CustomSwipeToRefresh customSwipeToRefresh; - @BindView(R.id.recycler) - RecyclerView recyclerView; - @BindView(R.id.btn_action) - Button btnAction; - @BindView(R.id.txt_update_all) - TextView txtUpdateAll; - - private Context context; - private List updatableAppList = new ArrayList<>(); - private UpdatableAppsAdapter adapter; - private Fetch fetch; - private UpdatableAppsTask updatableAppTask; - private BottomNavigationView bottomNavigationView; - - private BroadcastReceiver installReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String packageName = intent.getStringExtra("PACKAGE_NAME"); - try { - removeInstalledApp(packageName); - } catch (Exception ignored) { - } - } - }; - - @Override - public void onAttach(@NotNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_updates, container, false); - ButterKnife.bind(this, view); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - fetch = DownloadManager.getFetchInstance(context); - adapter = new UpdatableAppsAdapter(context); - updatableAppTask = new UpdatableAppsTask(context); - setErrorView(ErrorType.UNKNOWN); - customSwipeToRefresh.setOnRefreshListener(() -> fetchData()); - setupRecycler(); - - if (getActivity() instanceof AuroraActivity) { - bottomNavigationView = ((AuroraActivity) getActivity()).getBottomNavigation(); - } - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - context.registerReceiver(installReceiver, new IntentFilter("ACTION_INSTALL")); - } - - @Override - public void onResume() { - super.onResume(); - if (adapter.isDataEmpty()) { - fetchData(); - drawButtons(); - } - } - - @Override - public void onPause() { - super.onPause(); - customSwipeToRefresh.setRefreshing(false); - } - - @Override - public void onDestroy() { - try { - context.unregisterReceiver(installReceiver); - } catch (Exception ignored) { - } - super.onDestroy(); - } - - @Override - protected void fetchData() { - disposable.add(Observable.fromCallable(updatableAppTask::getUpdatableApps) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe(subscription -> customSwipeToRefresh.setRefreshing(true)) - .doOnTerminate(() -> customSwipeToRefresh.setRefreshing(false)) - .subscribe((appList) -> { - updatableAppList = appList; - if (appList.isEmpty()) { - setErrorView(ErrorType.NO_UPDATES); - switchViews(true); - } else { - switchViews(false); - if (adapter != null) - adapter.addData(appList); - drawButtons(); - updateCounter(); - } - }, err -> { - Log.d(err.getMessage()); - processException(err); - })); - } - - private void removeInstalledApp(String packageName) { - adapter.remove(packageName); - AuroraApplication.removeFromOngoingUpdateList(packageName); - drawButtons(); - updateCounter(); - } - - private void setupRecycler() { - recyclerView.setAdapter(adapter); - recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); - recyclerView.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(context, R.anim.anim_falldown)); - } - - @Override - protected View.OnClickListener errRetry() { - return v -> { - fetchData(); - if (updatableAppList != null) { - ((Button) v).setText(updatableAppList.isEmpty() - ? getString(R.string.action_recheck_ing) - : getString(R.string.action_retry_ing)); - ((Button) v).setEnabled(false); - } - }; - } - - private void drawButtons() { - btnAction.setEnabled(true); - if (updatableAppList != null && updatableAppList.isEmpty()) { - ViewUtil.hideWithAnimation(btnAction); - txtUpdateAll.setText(context.getString(R.string.list_empty_updates)); - setErrorView(ErrorType.NO_UPDATES); - } else if (AuroraApplication.getOnGoingUpdate()) { - btnAction.setOnClickListener(cancelAllListener()); - } else { - btnAction.setOnClickListener(updateAllListener()); - } - } - - private void updateCounter() { - int count = adapter.getItemCount(); - txtUpdateAll.setText(new StringBuilder() - .append(adapter.getItemCount()) - .append(StringUtils.SPACE) - .append(count == 1 ? context.getString(R.string.list_update_all_txt_one) : - context.getString(R.string.list_update_all_txt))); - } - - private View.OnClickListener updateAllListener() { - ViewUtil.showWithAnimation(btnAction); - btnAction.setText(getString(R.string.list_update_all)); - return v -> { - updateAllApps(); - btnAction.setText(getString(R.string.list_updating)); - btnAction.setEnabled(false); - }; - } - - private View.OnClickListener cancelAllListener() { - ViewUtil.showWithAnimation(btnAction); - btnAction.setText(getString(R.string.action_cancel)); - return v -> { - cancelAllRequests(); - AuroraApplication.setOngoingUpdateList(new ArrayList<>()); - AuroraApplication.setOnGoingUpdate(false); - Util.clearOldInstallationSessions(context); - ContextUtil.runOnUiThread(() -> drawButtons()); - }; - } - - private void updateAllApps() { - AuroraApplication.setOngoingUpdateList(updatableAppList); - AuroraApplication.setOnGoingUpdate(true); - disposable.add(Observable.fromIterable(updatableAppList) - .flatMap(app -> new ObservableDeliveryData(context).getDeliveryData(app)) - .subscribeOn(Schedulers.io()) - .doOnSubscribe(disposable -> drawButtons()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext(deliveryDataBundle -> new LiveUpdate(context) - .enqueueUpdate(deliveryDataBundle.getApp(), - deliveryDataBundle.getAndroidAppDeliveryData())) - .doOnError(throwable -> { - if (throwable instanceof MalformedRequestException || throwable instanceof NotPurchasedException) { - ContextUtil.runOnUiThread(() -> btnAction.setOnClickListener(updateAllListener())); - notifyStatusBlacklist(coordinatorLayout, throwable.getMessage()); - } else - Log.e(throwable.getMessage()); - }) - .subscribe()); - } - - private void cancelAllRequests() { - List ongoingUpdateList = AuroraApplication.getOngoingUpdateList(); - for (App app : ongoingUpdateList) { - Log.i("Cancelled -> %s", app.getDisplayName()); - fetch.cancelGroup(app.getPackageName().hashCode()); - } - } - - private void notifyStatusBlacklist(CoordinatorLayout coordinatorLayout, String packageName) { - final StringBuilder message = new StringBuilder() - .append(packageName) - .append(StringUtils.SPACE) - .append(context.getString(R.string.error_app_download)); - Snackbar snackbar = Snackbar.make(coordinatorLayout, message, Snackbar.LENGTH_LONG); - if (bottomNavigationView != null) - snackbar.setAnchorView(bottomNavigationView); - snackbar.show(); - } -} diff --git a/app/src/main/java/com/aurora/store/fragment/details/Beta.java b/app/src/main/java/com/aurora/store/fragment/details/Beta.java deleted file mode 100644 index e6589ac73..000000000 --- a/app/src/main/java/com/aurora/store/fragment/details/Beta.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment.details; - -import android.content.Context; -import android.text.TextUtils; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; -import com.aurora.store.model.App; -import com.aurora.store.task.BaseTask; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; - -import java.io.IOException; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class Beta extends AbstractHelper { - - @BindView(R.id.beta_comment) - EditText editText; - @BindView(R.id.beta_layout) - RelativeLayout beta_card; - @BindView(R.id.beta_feedback) - LinearLayout beta_feedback; - @BindView(R.id.beta_message) - TextView txt_beta_message; - @BindView(R.id.beta_subscribe_button) - Button beta_subscribe_button; - @BindView(R.id.beta_submit_button) - Button beta_submit_button; - @BindView(R.id.beta_delete_button) - Button beta_delete_button; - - private CompositeDisposable disposable = new CompositeDisposable(); - - public Beta(DetailsFragment fragment, App app) { - super(fragment, app); - } - - @Override - public void draw() { - ButterKnife.bind(this, view); - if (Accountant.isAnonymous(context)) - return; - - if (app.isTestingProgramAvailable() && app.isTestingProgramOptedIn()) { - disposable.add(Observable.fromCallable(() -> new BetaFeedbackToggleTask(context) - .toggle(app)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe()); - } - - if (!app.isInstalled() || !app.isTestingProgramAvailable()) { - return; - } - - setText(view, R.id.beta_header, app.isTestingProgramOptedIn() - ? R.string.testing_program_section_opted_in_title - : R.string.testing_program_section_opted_out_title); - - setText(view, R.id.beta_message, app.isTestingProgramOptedIn() - ? R.string.testing_program_section_opted_in_message - : R.string.testing_program_section_opted_out_message); - - setText(view, R.id.beta_subscribe_button, app.isTestingProgramOptedIn() - ? R.string.testing_program_opt_out - : R.string.testing_program_opt_in); - - setText(fragment.getView(), R.id.beta_email, app.getTestingProgramEmail()); - - beta_card.setVisibility(View.VISIBLE); - beta_feedback.setVisibility(app.isTestingProgramOptedIn() ? View.VISIBLE : View.GONE); - beta_subscribe_button.setOnClickListener(new BetaOnClickListener(txt_beta_message, app)); - beta_submit_button.setOnClickListener(v -> disposable.add(Observable.fromCallable(() -> - new BetaFeedbackSubmitTask(context).deleteFeedback(app.getPackageName(), editText.getText().toString())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((success) -> { - beta_delete_button.setVisibility(View.VISIBLE); - beta_delete_button.setEnabled(true); - }))); - beta_delete_button.setOnClickListener(v -> disposable.add(Observable.fromCallable(() -> - new BetaFeedbackDeleteTask(context).deleteFeedback(app.getPackageName())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((success) -> { - editText.setText(""); - ContextUtil.toastShort(context, context.getString(R.string.action_done)); - beta_delete_button.setEnabled(false); - }))); - - if (null != app.getUserReview() && !TextUtils.isEmpty(app.getUserReview().getComment())) { - editText.setText(app.getUserReview().getComment()); - show(view, R.id.beta_delete_button); - } - } - - static private class BetaOnClickListener implements View.OnClickListener { - - private TextView messageView; - private App app; - private CompositeDisposable mDisposable = new CompositeDisposable(); - - private BetaOnClickListener(TextView messageView, App app) { - this.messageView = messageView; - this.app = app; - } - - @Override - public void onClick(View view) { - view.setEnabled(false); - messageView.setText(app.isTestingProgramOptedIn() - ? R.string.testing_program_section_opted_out_propagating_message - : R.string.testing_program_section_opted_in_propagating_message); - mDisposable.add(Observable.fromCallable(() -> new BetaFeedbackToggleTask(messageView.getContext()).toggle(app)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe()); - mDisposable.dispose(); - } - } - - static private class BetaFeedbackToggleTask extends BaseTask { - - BetaFeedbackToggleTask(Context context) { - super(context); - } - - private boolean toggle(App app) throws Exception { - try { - GooglePlayAPI api = getApi(); - api.testingProgram(app.getPackageName(), !app.isTestingProgramOptedIn()); - return true; - } catch (IOException e) { - Log.e(e.getMessage()); - return false; - } - } - } - - static private class BetaFeedbackSubmitTask extends BaseTask { - - BetaFeedbackSubmitTask(Context context) { - super(context); - } - - private boolean deleteFeedback(String packageName, String feedback) { - try { - GooglePlayAPI api = getApi(); - api.betaFeedback(packageName, feedback); - return true; - } catch (Exception e) { - Log.e(e.getMessage()); - return false; - } - } - } - - static private class BetaFeedbackDeleteTask extends BaseTask { - - BetaFeedbackDeleteTask(Context context) { - super(context); - } - - private boolean deleteFeedback(String packageName) { - try { - GooglePlayAPI api = getApi(); - api.deleteBetaFeedback(packageName); - return true; - } catch (Exception e) { - Log.e(e.getMessage()); - return false; - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/details/ExodusPrivacy.java b/app/src/main/java/com/aurora/store/fragment/details/ExodusPrivacy.java deleted file mode 100644 index 2c46318af..000000000 --- a/app/src/main/java/com/aurora/store/fragment/details/ExodusPrivacy.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment.details; - -import android.view.View; -import android.widget.Button; -import android.widget.RelativeLayout; - -import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; -import com.aurora.store.model.App; -import com.aurora.store.model.ExodusReport; -import com.aurora.store.model.Report; -import com.aurora.store.sheet.ExodusBottomSheet; -import com.aurora.store.task.NetworkTask; -import com.aurora.store.utility.Log; -import com.google.gson.Gson; - -import org.apache.commons.lang3.StringUtils; -import org.json.JSONObject; - -import java.util.Collections; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class ExodusPrivacy extends AbstractHelper { - - public static final String EXODUS_PATH = "https://reports.exodus-privacy.eu.org/api/search/"; - - @BindView(R.id.exodus_card) - RelativeLayout exodus_card; - @BindView(R.id.moreButton) - Button moreButton; - - private Report report; - private CompositeDisposable disposable = new CompositeDisposable(); - - public ExodusPrivacy(DetailsFragment fragment, App app) { - super(fragment, app); - } - - @Override - public void draw() { - ButterKnife.bind(this, view); - get(EXODUS_PATH + app.getPackageName()); - } - - private void get(String url) { - disposable.add(Observable.fromCallable(() -> new NetworkTask(context) - .get(url)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> { - JSONObject jsonObject = new JSONObject(response); - JSONObject exodusObject = jsonObject.getJSONObject(app.getPackageName()); - Gson gson = new Gson(); - ExodusReport exodusReport = gson.fromJson(exodusObject.toString(), ExodusReport.class); - List reportList = exodusReport.getReports(); - Collections.sort(reportList, (Report1, Report2) -> - Report2.getCreationDate().compareTo(Report1.getCreationDate())); - report = reportList.get(0); - drawExodus(report); - }, throwable -> { - Log.i("Error occurred at generating report"); - })); - } - - private void drawExodus(Report mReport) { - if (context != null) { - exodus_card.setVisibility(View.VISIBLE); - if (mReport.getTrackers().size() > 0) { - setText(view, R.id.exodus_description, - new StringBuilder() - .append(context.getString(R.string.exodus_hasTracker)) - .append(StringUtils.SPACE) - .append(mReport.getTrackers().size()).toString()); - } else { - setText(view, R.id.exodus_description, R.string.exodus_noTracker); - } - - if (mReport.getTrackers().isEmpty()) - moreButton.setVisibility(View.GONE); - else - moreButton.setOnClickListener(v -> showBottomDialog()); - } - } - - private void showBottomDialog() { - ExodusBottomSheet bottomSheet = new ExodusBottomSheet(report); - bottomSheet.show(fragment.getChildFragmentManager(), "EXODUS"); - } -} diff --git a/app/src/main/java/com/aurora/store/fragment/intro/LoginFragment.java b/app/src/main/java/com/aurora/store/fragment/intro/LoginFragment.java deleted file mode 100644 index 16f1a330f..000000000 --- a/app/src/main/java/com/aurora/store/fragment/intro/LoginFragment.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.fragment.intro; - -import android.app.ActivityOptions; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ProgressBar; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; -import com.aurora.store.activity.GoogleLoginActivity; -import com.aurora.store.activity.IntroActivity; -import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.NetworkUtil; -import com.google.android.material.button.MaterialButton; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class LoginFragment extends IntroBaseFragment { - - @BindView(R.id.btn_next) - Button btnNext; - @BindView(R.id.btn_anonymous) - MaterialButton btnAnonymous; - @BindView(R.id.progress_bar) - ProgressBar progressBar; - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_intro_login, container, false); - ButterKnife.bind(this, view); - return view; - } - - @OnClick(R.id.btn_next) - public void openLoginActivity() { - context.startActivity(new Intent(context, GoogleLoginActivity.class)); - if (getActivity() instanceof IntroActivity) - ((IntroActivity) getActivity()).finish(); - - } - - @OnClick(R.id.btn_anonymous) - public void loginAnonymous() { - if (!NetworkUtil.isConnected(context)) { - Toast.makeText(context, getString(R.string.error_no_network), Toast.LENGTH_SHORT).show(); - return; - } - - CompositeDisposable disposable = new CompositeDisposable(); - disposable.add(Observable.fromCallable(() -> PlayStoreApiAuthenticator - .login(context)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe(d -> { - btnAnonymous.setText(getText(R.string.action_logging_in)); - btnAnonymous.setEnabled(false); - progressBar.setVisibility(View.VISIBLE); - }) - .subscribe(api -> { - if (api != null) { - Toast.makeText(context, getText(R.string.toast_login_success), Toast.LENGTH_SHORT).show(); - Intent intent = new Intent(context, AuroraActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation((IntroActivity) context); - startActivity(intent, activityOptions.toBundle()); - ((IntroActivity) getActivity()).finish(); - } else { - Toast.makeText(context, getText(R.string.toast_login_failed), Toast.LENGTH_LONG).show(); - ContextUtil.runOnUiThread(this::resetAnonymousLogin); - } - }, err -> { - Toast.makeText(context, getText(R.string.toast_login_failed), Toast.LENGTH_LONG).show(); - ContextUtil.runOnUiThread(this::resetAnonymousLogin); - })); - } - - private void resetAnonymousLogin() { - btnAnonymous.setEnabled(true); - btnAnonymous.setText(getText(R.string.account_dummy)); - progressBar.setVisibility(View.INVISIBLE); - } -} diff --git a/app/src/main/java/com/aurora/store/installer/AppInstaller.java b/app/src/main/java/com/aurora/store/installer/AppInstaller.java index 5306547b0..a10cb97a3 100644 --- a/app/src/main/java/com/aurora/store/installer/AppInstaller.java +++ b/app/src/main/java/com/aurora/store/installer/AppInstaller.java @@ -28,7 +28,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageInstaller; -import com.aurora.store.utility.Log; +import com.aurora.store.util.Log; import org.apache.commons.io.IOUtils; @@ -50,7 +50,8 @@ public class AppInstaller extends AppInstallerAbstract { public static AppInstaller getInstance(Context context) { if (instance == null) { synchronized (AppInstaller.class) { - if (instance == null) instance = new AppInstaller(context); + if (instance == null) + instance = new AppInstaller(context); } } return instance; diff --git a/app/src/main/java/com/aurora/store/installer/AppInstallerAbstract.java b/app/src/main/java/com/aurora/store/installer/AppInstallerAbstract.java index 2f39b430c..f838123f4 100644 --- a/app/src/main/java/com/aurora/store/installer/AppInstallerAbstract.java +++ b/app/src/main/java/com/aurora/store/installer/AppInstallerAbstract.java @@ -35,12 +35,15 @@ import androidx.annotation.Nullable; import java.io.File; import java.util.List; +import lombok.Getter; + +@Getter public abstract class AppInstallerAbstract { private Context context; private BroadcastReceiver broadcastReceiver; private Handler handler = new Handler(Looper.getMainLooper()); - private InstallationStatusListener installationStatusListener; + private InstallationStatusListener listener; AppInstallerAbstract(Context context) { this.context = context.getApplicationContext(); @@ -54,26 +57,18 @@ public abstract class AppInstallerAbstract { }; } - void addInstallationStatusListener(InstallationStatusListener installationStatusListener) { - this.installationStatusListener = installationStatusListener; + void addInstallationStatusListener(InstallationStatusListener listener) { + this.listener = listener; } void dispatchSessionUpdate(int status, String packageName) { handler.post(() -> { - if (installationStatusListener != null) - installationStatusListener.onStatusChanged(status, packageName); + if (listener != null) + listener.onStatusChanged(status, packageName); }); } - public BroadcastReceiver getBroadcastReceiver() { - return broadcastReceiver; - } - - protected Context getContext() { - return context; - } - - protected abstract void installApkFiles(String packageName,List apkFiles); + protected abstract void installApkFiles(String packageName, List apkFiles); public interface InstallationStatusListener { void onStatusChanged(int status, @Nullable String packageName); diff --git a/app/src/main/java/com/aurora/store/installer/AppInstallerPrivileged.java b/app/src/main/java/com/aurora/store/installer/AppInstallerPrivileged.java index 022380956..2c6e84dbe 100644 --- a/app/src/main/java/com/aurora/store/installer/AppInstallerPrivileged.java +++ b/app/src/main/java/com/aurora/store/installer/AppInstallerPrivileged.java @@ -34,9 +34,9 @@ import com.aurora.services.IPrivilegedService; import com.aurora.store.BuildConfig; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import java.io.File; diff --git a/app/src/main/java/com/aurora/store/installer/AppInstallerRooted.java b/app/src/main/java/com/aurora/store/installer/AppInstallerRooted.java index 8452e2db5..697f65ff0 100644 --- a/app/src/main/java/com/aurora/store/installer/AppInstallerRooted.java +++ b/app/src/main/java/com/aurora/store/installer/AppInstallerRooted.java @@ -26,10 +26,10 @@ package com.aurora.store.installer; import android.content.Context; import android.content.pm.PackageInstaller; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.Root; -import com.aurora.store.utility.Util; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.Root; +import com.aurora.store.util.Util; import java.io.File; import java.util.List; diff --git a/app/src/main/java/com/aurora/store/installer/AppUninstallerRooted.java b/app/src/main/java/com/aurora/store/installer/AppUninstallerRooted.java index 8eec185aa..3fc389b04 100644 --- a/app/src/main/java/com/aurora/store/installer/AppUninstallerRooted.java +++ b/app/src/main/java/com/aurora/store/installer/AppUninstallerRooted.java @@ -24,8 +24,8 @@ package com.aurora.store.installer; import com.aurora.store.model.App; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.Root; +import com.aurora.store.util.Log; +import com.aurora.store.util.Root; public class AppUninstallerRooted { diff --git a/app/src/main/java/com/aurora/store/installer/Installer.java b/app/src/main/java/com/aurora/store/installer/Installer.java index f1f292d21..7a7eece4e 100644 --- a/app/src/main/java/com/aurora/store/installer/Installer.java +++ b/app/src/main/java/com/aurora/store/installer/Installer.java @@ -36,16 +36,18 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.FileProvider; +import com.aurora.store.AuroraApplication; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.DetailsActivity; +import com.aurora.store.events.Event; import com.aurora.store.model.App; import com.aurora.store.notification.QuickNotification; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PathUtil; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.TextUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.Log; +import com.aurora.store.util.PathUtil; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.TextUtil; +import com.aurora.store.util.Util; import java.io.File; import java.util.ArrayList; @@ -147,7 +149,7 @@ public class Installer implements AppInstallerAbstract.InstallationStatusListene displayName, statusMessage, getContentIntent(intentPackageName)); - sendLocalBroadcast(intentPackageName, 0); + sendStatusBroadcast(intentPackageName, 0); checkAndProcessQueuedApps(); break; case PackageInstaller.STATUS_SUCCESS: @@ -156,7 +158,7 @@ public class Installer implements AppInstallerAbstract.InstallationStatusListene displayName, statusMessage, getContentIntent(intentPackageName)); - sendLocalBroadcast(intentPackageName, 1); + sendStatusBroadcast(intentPackageName, 1); if (app != null) { if (Util.shouldDeleteApk(context)) clearInstallationFiles(app); @@ -200,24 +202,19 @@ public class Installer implements AppInstallerAbstract.InstallationStatusListene notificationManager.cancel(app.getPackageName().hashCode()); } - private void sendLocalBroadcast(String packageName, int status) { - Intent intent = new Intent("ACTION_INSTALL"); - intent.putExtra("PACKAGE_NAME", packageName); - intent.putExtra("STATUS_CODE", status); - context.sendBroadcast(intent); + private void sendStatusBroadcast(String packageName, int status) { + AuroraApplication.rxNotify(new Event(Event.SubType.INSTALLED, packageName, status)); } private PendingIntent getContentIntent(String packageName) { Intent intent = new Intent(context, DetailsActivity.class); - intent.putExtra("INTENT_PACKAGE_NAME", packageName); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, packageName); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } private AppInstallerAbstract getInstallationMethod(Context context) { String prefValue = PrefUtil.getString(context, Constants.PREFERENCE_INSTALLATION_METHOD); switch (prefValue) { - case "0": - return AppInstaller.getInstance(context); case "1": return AppInstallerRooted.getInstance(context); case "2": diff --git a/app/src/main/java/com/aurora/store/installer/Uninstaller.java b/app/src/main/java/com/aurora/store/installer/Uninstaller.java index 9c631c84f..979719c44 100644 --- a/app/src/main/java/com/aurora/store/installer/Uninstaller.java +++ b/app/src/main/java/com/aurora/store/installer/Uninstaller.java @@ -13,8 +13,8 @@ import com.aurora.services.IPrivilegedCallback; import com.aurora.services.IPrivilegedService; import com.aurora.store.Constants; import com.aurora.store.model.App; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PrefUtil; public class Uninstaller { @@ -51,12 +51,10 @@ public class Uninstaller { }; try { if (!service.hasPrivilegedPermissions()) { - Log.e("service.hasPrivilegedPermissions() is false"); + Log.d("service.hasPrivilegedPermissions() is false"); return; } - service.deletePackage(app.getPackageName(), 1, callback); - } catch (RemoteException e) { Log.e("Connecting to privileged service failed"); } diff --git a/app/src/main/java/com/aurora/store/iterator/CustomAppListIterator.java b/app/src/main/java/com/aurora/store/iterator/CustomAppListIterator.java index 16bc80bc8..7a4b66ac1 100644 --- a/app/src/main/java/com/aurora/store/iterator/CustomAppListIterator.java +++ b/app/src/main/java/com/aurora/store/iterator/CustomAppListIterator.java @@ -25,8 +25,8 @@ package com.aurora.store.iterator; import com.aurora.store.model.App; import com.aurora.store.model.AppBuilder; -import com.aurora.store.model.Filter; -import com.aurora.store.utility.Log; +import com.aurora.store.model.FilterModel; +import com.aurora.store.util.Log; import com.dragons.aurora.playstoreapiv2.AppListIterator; import com.dragons.aurora.playstoreapiv2.DocV2; @@ -38,9 +38,9 @@ import java.util.Set; public class CustomAppListIterator implements Iterator { - protected boolean filterEnabled = false; - protected Filter filter = new Filter(); - protected AppListIterator iterator; + private boolean filterEnabled = false; + private FilterModel filterModel = new FilterModel(); + private AppListIterator iterator; private List relatedTags = new ArrayList<>(); public CustomAppListIterator(AppListIterator iterator) { @@ -58,8 +58,8 @@ public class CustomAppListIterator implements Iterator { this.filterEnabled = filterEnabled; } - public void setFilter(Filter filter) { - this.filter = filter; + public void setFilterModel(FilterModel filterModel) { + this.filterModel = filterModel; } @Override @@ -87,11 +87,11 @@ public class CustomAppListIterator implements Iterator { } private boolean shouldSkip(App app) { - return (!filter.isPaidApps() && !app.isFree()) - || (!filter.isAppsWithAds() && app.containsAds()) - || (!filter.isGsfDependentApps() && !app.getDependencies().isEmpty()) - || (filter.getRating() > 0 && app.getRating().getAverage() < filter.getRating()) - || (filter.getDownloads() > 0 && app.getInstalls() < filter.getDownloads()); + return (!filterModel.isPaidApps() && !app.isFree()) + || (!filterModel.isAppsWithAds() && app.containsAds()) + || (!filterModel.isGsfDependentApps() && !app.getDependencies().isEmpty()) + || (filterModel.getRating() > 0 && app.getRating().getAverage() < filterModel.getRating()) + || (filterModel.getDownloads() > 0 && app.getInstalls() < filterModel.getDownloads()); } private void addApp(List apps, App app) { diff --git a/app/src/main/java/com/aurora/store/iterator/ReviewIterator.java b/app/src/main/java/com/aurora/store/iterator/ReviewIterator.java index 74b2cfb93..b6e45cdb6 100644 --- a/app/src/main/java/com/aurora/store/iterator/ReviewIterator.java +++ b/app/src/main/java/com/aurora/store/iterator/ReviewIterator.java @@ -23,8 +23,6 @@ package com.aurora.store.iterator; -import android.content.Context; - import com.aurora.store.model.Review; import java.util.Iterator; @@ -33,15 +31,10 @@ import java.util.List; abstract public class ReviewIterator implements Iterator> { protected String packageName; - protected Context context; protected int page = -1; public void setPackageName(String packageName) { this.packageName = packageName; } - - public void setContext(Context context) { - this.context = context; - } } diff --git a/app/src/main/java/com/aurora/store/iterator/ReviewRetrieverIterator.java b/app/src/main/java/com/aurora/store/iterator/ReviewRetrieverIterator.java index f06b54db8..213fa89aa 100644 --- a/app/src/main/java/com/aurora/store/iterator/ReviewRetrieverIterator.java +++ b/app/src/main/java/com/aurora/store/iterator/ReviewRetrieverIterator.java @@ -23,14 +23,13 @@ package com.aurora.store.iterator; -import com.aurora.store.api.PlayStoreApiAuthenticator; +import com.aurora.store.AuroraApplication; import com.aurora.store.exception.InvalidApiException; import com.aurora.store.model.Review; import com.aurora.store.model.ReviewBuilder; -import com.aurora.store.utility.Log; +import com.aurora.store.util.Log; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -39,6 +38,12 @@ public class ReviewRetrieverIterator extends ReviewIterator { static private final int PAGE_SIZE = 15; protected boolean hasNext = true; + private GooglePlayAPI.REVIEW_SORT reviewSort = GooglePlayAPI.REVIEW_SORT.HIGHRATING; + + public void setReviewSort(GooglePlayAPI.REVIEW_SORT reviewSort) { + this.reviewSort = reviewSort; + } + @Override public boolean hasNext() { return hasNext; @@ -49,7 +54,7 @@ public class ReviewRetrieverIterator extends ReviewIterator { page++; List list = new ArrayList<>(); try { - list.addAll(getReviews(packageName, PAGE_SIZE * page, PAGE_SIZE)); + list.addAll(getReviews(packageName, PAGE_SIZE * page, reviewSort)); if (list.size() < PAGE_SIZE) { hasNext = false; } @@ -59,16 +64,16 @@ public class ReviewRetrieverIterator extends ReviewIterator { return list; } - private List getReviews(String packageId, int offset, int numberOfResults) throws Exception { + private List getReviews(String packageId, int offset, GooglePlayAPI.REVIEW_SORT reviewSort) throws Exception { List reviews = new ArrayList<>(); - GooglePlayAPI api = PlayStoreApiAuthenticator.getInstance(context); + GooglePlayAPI api = AuroraApplication.api; if (api == null) throw new InvalidApiException(); for (com.dragons.aurora.playstoreapiv2.Review review : api.reviews( packageId, - GooglePlayAPI.REVIEW_SORT.HELPFUL, + reviewSort, offset, - numberOfResults + PAGE_SIZE ).getGetResponse().getReviewList()) { reviews.add(ReviewBuilder.build(review)); } diff --git a/app/src/main/java/com/aurora/store/iterator/ReviewStorageIterator.java b/app/src/main/java/com/aurora/store/iterator/ReviewStorageIterator.java index e6d668783..e8e6903c5 100644 --- a/app/src/main/java/com/aurora/store/iterator/ReviewStorageIterator.java +++ b/app/src/main/java/com/aurora/store/iterator/ReviewStorageIterator.java @@ -33,28 +33,31 @@ public class ReviewStorageIterator extends ReviewIterator { static private final int PAGE_SIZE = 15; - private List list = new ArrayList<>(); + private List reviewList = new ArrayList<>(); private ReviewRetrieverIterator iterator; private ReviewRetrieverIterator getRetrievingIterator() { if (null == iterator) { iterator = new ReviewRetrieverIterator(); - iterator.setContext(context); iterator.setPackageName(packageName); } return iterator; } + public void setRetrievingIterator(ReviewRetrieverIterator iterator) { + this.iterator = iterator; + } + @Override public boolean hasNext() { - return list.size() > (PAGE_SIZE * page) || getRetrievingIterator().hasNext(); + return reviewList.size() > (PAGE_SIZE * page) || getRetrievingIterator().hasNext(); } @Override public List next() { page++; - if (list.size() < (PAGE_SIZE * (page + 1)) && getRetrievingIterator().hasNext()) { - list.addAll(getRetrievingIterator().next()); + if (reviewList.size() < (PAGE_SIZE * (page + 1)) && getRetrievingIterator().hasNext()) { + reviewList.addAll(getRetrievingIterator().next()); } return current(); } @@ -71,6 +74,6 @@ public class ReviewStorageIterator extends ReviewIterator { private List current() { int from = PAGE_SIZE * page; int to = from + PAGE_SIZE; - return (from < 0 || to > list.size()) ? new ArrayList() : list.subList(from, to); + return (from < 0 || to > reviewList.size()) ? new ArrayList() : reviewList.subList(from, to); } } diff --git a/app/src/main/java/com/aurora/store/manager/BitmapManager.java b/app/src/main/java/com/aurora/store/manager/BitmapManager.java deleted file mode 100644 index bf1c8f8cd..000000000 --- a/app/src/main/java/com/aurora/store/manager/BitmapManager.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Yalp Store - * Copyright (C) 2018 Sergey Yeriomin - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.manager; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - -import com.aurora.store.utility.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -public class BitmapManager { - - private File baseDir; - - public BitmapManager(Context context) { - baseDir = context.getCacheDir(); - } - - static private void cacheBitmapOnDisk(Bitmap bitmap, File cached) { - FileOutputStream out = null; - try { - out = new FileOutputStream(cached); - bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); - out.flush(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - static private Bitmap downloadBitmap(String url, boolean fullSize) { - try { - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); - connection.connect(); - connection.setConnectTimeout(3000); - InputStream input = connection.getInputStream(); - - BitmapFactory.Options options = new BitmapFactory.Options(); - if (!fullSize) { - options.inSampleSize = 4; - } - options.inJustDecodeBounds = false; - - return BitmapFactory.decodeStream(input, null, options); - } catch (IOException e) { - Log.e("Could not get icon from " + url + " " + e.getMessage()); - } - return null; - } - - public File downloadAndGetFile(String url) { - File onDisk = getFile(url); - Bitmap bitmap = downloadBitmap(url, true); - if (null != bitmap) { - cacheBitmapOnDisk(bitmap, onDisk); - return onDisk; - } - return null; - } - - private File getFile(String urlString) { - return new File(baseDir, urlString.hashCode() + ".png"); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/manager/BlacklistManager.java b/app/src/main/java/com/aurora/store/manager/BlacklistManager.java index c84e8bb72..7fbfa2e20 100644 --- a/app/src/main/java/com/aurora/store/manager/BlacklistManager.java +++ b/app/src/main/java/com/aurora/store/manager/BlacklistManager.java @@ -23,7 +23,7 @@ package com.aurora.store.manager; import android.content.Context; import com.aurora.store.Constants; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.PrefUtil; import java.util.ArrayList; import java.util.HashSet; @@ -36,24 +36,22 @@ public class BlacklistManager { public BlacklistManager(Context context) { this.context = context; - blackList = PrefUtil.getListString(context, Constants.PREFERENCE_BLACKLIST_APPS_LIST); + this.blackList = PrefUtil.getListString(context, Constants.PREFERENCE_BLACKLIST_APPS_LIST); } - public boolean add(String s) { + public void add(String packageName) { ArrayList arrayList = new ArrayList<>(); - arrayList.add(s); - boolean result = addAll(arrayList); + arrayList.add(packageName); + addAll(arrayList); save(); - return result; } - public boolean addAll(ArrayList arrayList) { - boolean result = blackList.addAll(arrayList); + public void addAll(ArrayList arrayList) { + blackList.addAll(arrayList); Set mAppSet = new HashSet<>(blackList); blackList.clear(); blackList.addAll(mAppSet); save(); - return result; } public ArrayList get() { @@ -64,16 +62,19 @@ public class BlacklistManager { return blackList.contains(packageName); } - public boolean remove(String packageName) { - boolean result = blackList.remove(packageName); + public void remove(String packageName) { + blackList.remove(packageName); save(); - return result; } - public boolean removeAll(ArrayList packageList) { - boolean result = blackList.removeAll(packageList); + public void removeAll(ArrayList packageList) { + blackList.removeAll(packageList); + save(); + } + + public void removeAll() { + blackList = new ArrayList<>(); save(); - return result; } private void save() { diff --git a/app/src/main/java/com/aurora/store/manager/CategoryManager.java b/app/src/main/java/com/aurora/store/manager/CategoryManager.java index feea4ef56..705fdc4e4 100644 --- a/app/src/main/java/com/aurora/store/manager/CategoryManager.java +++ b/app/src/main/java/com/aurora/store/manager/CategoryManager.java @@ -27,26 +27,31 @@ import android.content.Context; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.SharedPreferencesTranslator; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.model.CategoryModel; +import com.aurora.store.util.PrefUtil; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; public class CategoryManager { - private static final String SUBCATEGORY_ID_GAMES = "GAME"; - private static final String SUBCATEGORY_ID_FAMILY = "FAMILY"; - private Context context; - private SharedPreferencesTranslator translator; + private Gson gson; public CategoryManager(Context context) { this.context = context; - translator = new SharedPreferencesTranslator(Util.getPrefs(context)); + this.gson = new Gson(); + } + + public static void clear(Context context) { + PrefUtil.remove(context, Constants.CATEGORY_APPS); + PrefUtil.remove(context, Constants.CATEGORY_GAME); + PrefUtil.remove(context, Constants.CATEGORY_FAMILY); } public String getCategoryName(String categoryId) { @@ -56,71 +61,31 @@ public class CategoryManager { if (categoryId.equals(Constants.TOP)) { return context.getString(R.string.title_all_apps); } - return translator.getString(categoryId); - } - - public void save(String parent, Map categories) { - PrefUtil.putStringSet(context, parent, categories.keySet()); - for (String categoryId : categories.keySet()) { - translator.putString(categoryId, categories.get(categoryId)); - } + return StringUtils.EMPTY; } public boolean fits(String appCategoryId, String chosenCategoryId) { return null == chosenCategoryId || chosenCategoryId.equals(Constants.TOP) - || appCategoryId.equals(chosenCategoryId) - || PrefUtil.getStringSet(context, chosenCategoryId).contains(appCategoryId); + || appCategoryId.equals(chosenCategoryId); } public boolean categoryListEmpty() { - Set topSet = PrefUtil.getStringSet(context, Constants.TOP); - if (topSet.isEmpty()) { - return true; - } - int size = topSet.size(); - String categoryId = topSet.toArray(new String[size])[size - 1]; - return translator.getString(categoryId).equals(categoryId); + return PrefUtil.getString(context, Constants.CATEGORY_APPS).isEmpty(); } - public Map getAllCategories() { - Map categories = new TreeMap<>(); - Set topSet = PrefUtil.getStringSet(context, Constants.TOP); - for (String topCategoryId : topSet) { - categories.put(topCategoryId, translator.getString(topCategoryId)); - } - return categories; + public List getCategories(String categoryId) { + return getCategoryById(categoryId); } - public Map getAllGames() { - Map games = new TreeMap<>(); - Set topSet = PrefUtil.getStringSet(context, Constants.TOP); - for (String topCategoryId : topSet) { - Set subSet = PrefUtil.getStringSet(context, topCategoryId); - for (String subCategoryId : subSet) { - if (subCategoryId.startsWith(SUBCATEGORY_ID_GAMES)) - games.put(subCategoryId, games.get(topCategoryId) + " - " + translator.getString(subCategoryId)); - } - - } - return games; - } - - public Map getAllFamily() { - Map family = new TreeMap<>(); - Set topSet = PrefUtil.getStringSet(context, Constants.TOP); - for (String topCategoryId : topSet) { - Set subSet = PrefUtil.getStringSet(context, topCategoryId); - for (String subCategoryId : subSet) { - if (subCategoryId.startsWith(SUBCATEGORY_ID_FAMILY)) - family.put(subCategoryId, family.get(topCategoryId) + " - " + translator.getString(subCategoryId)); - } - } - return family; - } - - public void clearAll() { - Set emptySet = new TreeSet<>(); - PrefUtil.putStringSet(context, Constants.TOP, emptySet); + public List getCategoryById(String categoryId) { + Type type = new TypeToken>() { + }.getType(); + String jsonString = PrefUtil.getString(context, categoryId); + List categoryList = gson.fromJson(jsonString, type); + if (categoryList == null || categoryList.isEmpty()) + return new ArrayList<>(); + else + return categoryList; } } diff --git a/app/src/main/java/com/aurora/store/manager/FavouriteListManager.java b/app/src/main/java/com/aurora/store/manager/FavouriteListManager.java index 45c3de22e..8a6d572da 100644 --- a/app/src/main/java/com/aurora/store/manager/FavouriteListManager.java +++ b/app/src/main/java/com/aurora/store/manager/FavouriteListManager.java @@ -23,7 +23,7 @@ package com.aurora.store.manager; import android.content.Context; import com.aurora.store.Constants; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.PrefUtil; import java.util.ArrayList; import java.util.HashSet; @@ -32,7 +32,7 @@ import java.util.Set; public class FavouriteListManager { private Context context; - private ArrayList favouriteList; + private ArrayList favouriteList = new ArrayList<>(); public FavouriteListManager(Context context) { this.context = context; diff --git a/app/src/main/java/com/aurora/store/manager/FilterManager.java b/app/src/main/java/com/aurora/store/manager/FilterManager.java new file mode 100644 index 000000000..aad09644b --- /dev/null +++ b/app/src/main/java/com/aurora/store/manager/FilterManager.java @@ -0,0 +1,52 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Yalp Store + * Copyright (C) 2018 Sergey Yeriomin + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.manager; + +import android.content.Context; + +import com.aurora.store.Constants; +import com.aurora.store.model.FilterModel; +import com.aurora.store.util.PrefUtil; +import com.google.gson.Gson; + +public class FilterManager { + + public static FilterModel getFilterPreferences(Context context) { + Gson gson = new Gson(); + FilterModel filterModel = gson.fromJson(PrefUtil + .getString(context, Constants.PREFERENCE_FILTER_APPS), FilterModel.class); + if (filterModel == null) { + FilterModel defaultModel = new FilterModel(); + PrefUtil.putString(context, Constants.PREFERENCE_FILTER_APPS, gson.toJson(defaultModel)); + return defaultModel; + } else + return filterModel; + } + + public static void saveFilterPreferences(Context context, FilterModel filterModel) { + Gson gson = new Gson(); + String filterJSON = gson.toJson(filterModel); + PrefUtil.putString(context, Constants.PREFERENCE_FILTER_APPS, filterJSON); + } +} diff --git a/app/src/main/java/com/aurora/store/manager/LocaleManager.java b/app/src/main/java/com/aurora/store/manager/LocaleManager.java index 75e5b3ba3..14f33cbaa 100644 --- a/app/src/main/java/com/aurora/store/manager/LocaleManager.java +++ b/app/src/main/java/com/aurora/store/manager/LocaleManager.java @@ -5,8 +5,8 @@ import android.content.res.Configuration; import android.content.res.Resources; import com.aurora.store.Constants; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; import java.util.Locale; diff --git a/app/src/main/java/com/aurora/store/manager/SpoofManager.java b/app/src/main/java/com/aurora/store/manager/SpoofManager.java index 142c86f02..3364e246d 100644 --- a/app/src/main/java/com/aurora/store/manager/SpoofManager.java +++ b/app/src/main/java/com/aurora/store/manager/SpoofManager.java @@ -27,9 +27,9 @@ import android.preference.PreferenceManager; import android.text.TextUtils; import com.aurora.store.BuildConfig; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PathUtil; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PathUtil; +import com.aurora.store.util.PrefUtil; import java.io.BufferedInputStream; import java.io.File; diff --git a/app/src/main/java/com/aurora/store/model/AppBuilder.java b/app/src/main/java/com/aurora/store/model/AppBuilder.java index 6a5abdeda..3d68a7f6c 100644 --- a/app/src/main/java/com/aurora/store/model/AppBuilder.java +++ b/app/src/main/java/com/aurora/store/model/AppBuilder.java @@ -25,7 +25,7 @@ package com.aurora.store.model; import android.text.TextUtils; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import com.dragons.aurora.playstoreapiv2.AggregateRating; import com.dragons.aurora.playstoreapiv2.AppDetails; import com.dragons.aurora.playstoreapiv2.Badge; diff --git a/app/src/main/java/com/aurora/store/model/CategoryModel.java b/app/src/main/java/com/aurora/store/model/CategoryModel.java new file mode 100644 index 000000000..a8f41840b --- /dev/null +++ b/app/src/main/java/com/aurora/store/model/CategoryModel.java @@ -0,0 +1,16 @@ +package com.aurora.store.model; + +import lombok.Data; + +@Data +public class CategoryModel { + String categoryId; + String categoryTitle; + String categoryImageUrl; + + public CategoryModel(String categoryId, String categoryTitle, String categoryImageUrl) { + this.categoryId = categoryId; + this.categoryTitle = categoryTitle; + this.categoryImageUrl = categoryImageUrl; + } +} diff --git a/app/src/main/java/com/aurora/store/model/ConnectionModel.java b/app/src/main/java/com/aurora/store/model/ConnectionModel.java new file mode 100644 index 000000000..8499b00bb --- /dev/null +++ b/app/src/main/java/com/aurora/store/model/ConnectionModel.java @@ -0,0 +1,14 @@ +package com.aurora.store.model; + +import lombok.Data; + +@Data +public class ConnectionModel { + private String typeName; + private boolean isConnected; + + public ConnectionModel(String typeName, boolean isConnected) { + this.typeName = typeName; + this.isConnected = isConnected; + } +} diff --git a/app/src/main/java/com/aurora/store/model/Filter.java b/app/src/main/java/com/aurora/store/model/FilterModel.java similarity index 79% rename from app/src/main/java/com/aurora/store/model/Filter.java rename to app/src/main/java/com/aurora/store/model/FilterModel.java index d3cead80c..df0382494 100644 --- a/app/src/main/java/com/aurora/store/model/Filter.java +++ b/app/src/main/java/com/aurora/store/model/FilterModel.java @@ -28,13 +28,13 @@ import com.aurora.store.Constants; import lombok.Data; @Data -public class Filter { +public class FilterModel { - private boolean systemApps; - private boolean appsWithAds; - private boolean paidApps; - private boolean gsfDependentApps; + private boolean systemApps = false; + private boolean appsWithAds = true; + private boolean paidApps = true; + private boolean gsfDependentApps = true; private String category = Constants.TOP; - private float rating; - private int downloads; + private float rating = 0.0f; + private int downloads = 0; } diff --git a/app/src/main/java/com/aurora/store/model/LoginInfo.java b/app/src/main/java/com/aurora/store/model/LoginInfo.java index 465dce1dc..3a87d5190 100644 --- a/app/src/main/java/com/aurora/store/model/LoginInfo.java +++ b/app/src/main/java/com/aurora/store/model/LoginInfo.java @@ -26,8 +26,8 @@ package com.aurora.store.model; import android.content.Context; import android.text.TextUtils; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.PrefUtil; import com.google.gson.Gson; import java.util.Locale; diff --git a/app/src/main/java/com/aurora/store/notification/GeneralNotification.java b/app/src/main/java/com/aurora/store/notification/GeneralNotification.java index ec71b9fba..73b4a58e5 100644 --- a/app/src/main/java/com/aurora/store/notification/GeneralNotification.java +++ b/app/src/main/java/com/aurora/store/notification/GeneralNotification.java @@ -20,16 +20,14 @@ package com.aurora.store.notification; -import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; import android.graphics.Bitmap; -import android.os.Build; import com.aurora.store.R; import com.aurora.store.model.App; -import com.aurora.store.utility.NotificationUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.NotificationUtil; +import com.aurora.store.util.Util; import com.bumptech.glide.Glide; import com.bumptech.glide.request.target.SimpleTarget; import com.bumptech.glide.request.transition.Transition; @@ -135,14 +133,6 @@ public class GeneralNotification extends NotificationBase { public void show() { if (NotificationUtil.isNotificationEnabled(context)) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - channel = new NotificationChannel(context.getPackageName(), - context.getString(R.string.app_name), - NotificationManager.IMPORTANCE_DEFAULT); - channel.setDescription("Aurora Store Notification Channel"); - manager.createNotificationChannel(channel); - builder.setChannelId(channel.getId()); - } Glide.with(context.getApplicationContext()) .asBitmap() .load(app.getIconInfo().getUrl()) diff --git a/app/src/main/java/com/aurora/store/notification/NotificationBase.java b/app/src/main/java/com/aurora/store/notification/NotificationBase.java index 7384e9f0e..a6c65b24f 100644 --- a/app/src/main/java/com/aurora/store/notification/NotificationBase.java +++ b/app/src/main/java/com/aurora/store/notification/NotificationBase.java @@ -20,7 +20,6 @@ package com.aurora.store.notification; -import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; @@ -28,14 +27,15 @@ import android.content.Intent; import androidx.core.app.NotificationCompat; +import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.DetailsActivity; import com.aurora.store.model.App; import com.aurora.store.receiver.DownloadCancelReceiver; import com.aurora.store.receiver.DownloadPauseReceiver; import com.aurora.store.receiver.DownloadResumeReceiver; import com.aurora.store.receiver.InstallReceiver; -import com.aurora.store.utility.NotificationUtil; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.NotificationUtil; public class NotificationBase { @@ -44,7 +44,6 @@ public class NotificationBase { public static final String REQUEST_ID = "REQUEST_ID"; protected NotificationCompat.Builder builder; - protected NotificationChannel channel; protected NotificationManager manager; protected Context context; @@ -60,7 +59,7 @@ public class NotificationBase { } protected NotificationCompat.Builder getBuilder() { - return new NotificationCompat.Builder(context, app.getPackageName()) + return new NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_GENERAL) .setAutoCancel(true) .setCategory(NotificationCompat.CATEGORY_PROGRESS) .setColorized(true) diff --git a/app/src/main/java/com/aurora/store/notification/QuickNotification.java b/app/src/main/java/com/aurora/store/notification/QuickNotification.java index ed32c191c..afcfe8894 100644 --- a/app/src/main/java/com/aurora/store/notification/QuickNotification.java +++ b/app/src/main/java/com/aurora/store/notification/QuickNotification.java @@ -20,24 +20,23 @@ package com.aurora.store.notification; -import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; -import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; +import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.utility.NotificationUtil; +import com.aurora.store.util.NotificationUtil; public class QuickNotification extends NotificationBase { private static final int QUICK_NOTIFICATION_CHANNEL_ID = 69; - public QuickNotification(Context context) { + private QuickNotification(Context context) { super(context); } @@ -53,30 +52,19 @@ public class QuickNotification extends NotificationBase { public void show(String contentTitle, String contentText, PendingIntent contentIntent) { if (NotificationUtil.isNotificationEnabled(context)) { manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - builder = new NotificationCompat.Builder(context, context.getPackageName()) + builder = new NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERT) .setAutoCancel(true) - .setCategory(NotificationCompat.CATEGORY_PROGRESS) .setColorized(true) .setColor(context.getResources().getColor(R.color.colorAccent)) .setContentTitle(contentTitle) .setContentText(contentText) .setOnlyAlertOnce(true) .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .setSmallIcon(R.drawable.ic_notification) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC); + .setSmallIcon(R.drawable.ic_notification); if (contentIntent != null) builder.setContentIntent(contentIntent); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - channel = new NotificationChannel( - context.getPackageName(), - context.getString(R.string.app_name), - NotificationManager.IMPORTANCE_LOW); - channel.setDescription("Aurora Store Quick Notification Channel"); - manager.createNotificationChannel(channel); - builder.setChannelId(channel.getId()); - } manager.notify(QUICK_NOTIFICATION_CHANNEL_ID, builder.build()); } } diff --git a/app/src/main/java/com/aurora/store/provider/AuroraSuggestionProvider.java b/app/src/main/java/com/aurora/store/provider/AuroraSuggestionProvider.java deleted file mode 100644 index 9e86da2f1..000000000 --- a/app/src/main/java/com/aurora/store/provider/AuroraSuggestionProvider.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Yalp Store - * Copyright (C) 2018 Sergey Yeriomin - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.provider; - -import android.app.SearchManager; -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.net.Uri; -import android.provider.BaseColumns; -import android.text.TextUtils; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.aurora.store.R; -import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.manager.BitmapManager; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; -import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import com.dragons.aurora.playstoreapiv2.GooglePlayException; -import com.dragons.aurora.playstoreapiv2.SearchSuggestEntry; - -import java.io.File; - -public class AuroraSuggestionProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return true; - } - - @Override - public String getType(@NonNull Uri uri) { - return SearchManager.SUGGEST_MIME_TYPE; - } - - @Nullable - @Override - public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { - return null; - } - - @Override - public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { - return 0; - } - - @Override - public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { - return 0; - } - - @Override - public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - - MatrixCursor cursor = new MatrixCursor(new String[]{ - BaseColumns._ID, - SearchManager.SUGGEST_COLUMN_TEXT_1, - SearchManager.SUGGEST_COLUMN_INTENT_DATA, - SearchManager.SUGGEST_COLUMN_ICON_1 - }); - try { - fill(cursor, uri); - } catch (Exception e) { - Log.e(e.getMessage()); - } - return cursor; - } - - private void fill(MatrixCursor cursor, Uri uri) throws Exception { - String query = uri.getLastPathSegment(); - if (TextUtils.isEmpty(query) || query.equals("search_suggest_query")) { - return; - } - int i = 0; - GooglePlayAPI api = PlayStoreApiAuthenticator.getInstance(getContext()); - for (SearchSuggestEntry entry : api.searchSuggest(query).getEntryList()) { - cursor.addRow(constructRow(entry, i++)); - } - } - - private Object[] constructRow(SearchSuggestEntry entry, int id) { - return entry.getType() == GooglePlayAPI.SEARCH_SUGGESTION_TYPE.APP.value ? - constructAppRow(entry, id) : constructSuggestionRow(entry, id); - } - - private Object[] constructAppRow(SearchSuggestEntry entry, int id) { - File file = new BitmapManager(getContext()).downloadAndGetFile(entry.getImageContainer().getImageUrl()); - return new Object[]{id, entry.getTitle(), entry.getPackageNameContainer().getPackageName(), - null != file ? Uri.fromFile(file) : R.drawable.ic_placeholder}; - } - - private Object[] constructSuggestionRow(SearchSuggestEntry entry, int id) { - return new Object[]{id, entry.getSuggestedQuery(), entry.getSuggestedQuery(), R.drawable.ic_round_search}; - } -} diff --git a/app/src/main/java/com/aurora/store/provider/NativeGsfVersionProvider.java b/app/src/main/java/com/aurora/store/provider/NativeGsfVersionProvider.java index 5e9120c78..ec5f04232 100644 --- a/app/src/main/java/com/aurora/store/provider/NativeGsfVersionProvider.java +++ b/app/src/main/java/com/aurora/store/provider/NativeGsfVersionProvider.java @@ -27,8 +27,6 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import com.aurora.store.utility.Log; - public class NativeGsfVersionProvider { static private final String GOOGLE_SERVICES_PACKAGE_ID = "com.google.android.gms"; diff --git a/app/src/main/java/com/aurora/store/receiver/BootReceiver.java b/app/src/main/java/com/aurora/store/receiver/BootReceiver.java index cf8516b7a..91b927009 100644 --- a/app/src/main/java/com/aurora/store/receiver/BootReceiver.java +++ b/app/src/main/java/com/aurora/store/receiver/BootReceiver.java @@ -28,7 +28,7 @@ import android.content.Context; import android.content.Intent; import com.aurora.store.Constants; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; public class BootReceiver extends BroadcastReceiver { diff --git a/app/src/main/java/com/aurora/store/receiver/UpdatesReceiver.java b/app/src/main/java/com/aurora/store/receiver/UpdatesReceiver.java index 4cf636a94..46d2d4b36 100644 --- a/app/src/main/java/com/aurora/store/receiver/UpdatesReceiver.java +++ b/app/src/main/java/com/aurora/store/receiver/UpdatesReceiver.java @@ -8,14 +8,15 @@ import android.content.Intent; import com.aurora.store.AuroraApplication; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; import com.aurora.store.model.App; import com.aurora.store.notification.QuickNotification; import com.aurora.store.task.LiveUpdate; import com.aurora.store.task.ObservableDeliveryData; import com.aurora.store.task.UpdatableAppsTask; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.main.AuroraActivity; +import com.aurora.store.util.Log; +import com.aurora.store.util.Util; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import org.apache.commons.lang3.StringUtils; @@ -36,7 +37,7 @@ public class UpdatesReceiver extends BroadcastReceiver { this.context = context; Log.i("Update check Started"); CompositeDisposable disposable = new CompositeDisposable(); - UpdatableAppsTask updatableAppTask = new UpdatableAppsTask(context); + UpdatableAppsTask updatableAppTask = new UpdatableAppsTask(new GooglePlayAPI(), context); disposable.add(Observable.fromCallable(updatableAppTask::getUpdatableApps) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -60,7 +61,7 @@ public class UpdatesReceiver extends BroadcastReceiver { private void updateAllApps(List updatableAppList) { AuroraApplication.setOngoingUpdateList(updatableAppList); - AuroraApplication.setOnGoingUpdate(true); + AuroraApplication.setBulkUpdateAlive(true); disposable.add(Observable.fromIterable(updatableAppList) .flatMap(app -> new ObservableDeliveryData(context).getDeliveryData(app)) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/aurora/store/section/BlackListedAppSection.java b/app/src/main/java/com/aurora/store/section/BlackListedAppSection.java new file mode 100644 index 000000000..c557ba511 --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/BlackListedAppSection.java @@ -0,0 +1,160 @@ +package com.aurora.store.section; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.google.android.material.checkbox.MaterialCheckBox; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.Section; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters; + +public class BlackListedAppSection extends Section { + + private Context context; + private List appList = new ArrayList<>(); + private List blackList; + private ClickListener clickListener; + + public BlackListedAppSection(Context context, List blackList, ClickListener clickListener) { + super(SectionParameters.builder() + .itemResourceId(R.layout.item_blacklist) + .loadingResourceId(R.layout.item_loading) + .emptyResourceId(R.layout.item_empty) + .build()); + this.context = context; + this.blackList = blackList; + this.clickListener = clickListener; + setState(State.LOADING); + } + + public void updateList(List appList) { + this.appList.clear(); + this.appList.addAll(appList); + if (appList.isEmpty()) + setState(State.EMPTY); + else + setState(State.LOADED); + } + + public void remove(String packageName) { + blackList.remove(packageName); + } + + public void add(String packageName) { + blackList.add(packageName); + } + + public List getList() { + return appList; + } + + public List getBlacklist() { + return blackList; + } + + public int getSize() { + return appList.size(); + } + + @Override + public int getContentItemsTotal() { + return appList.size(); + } + + @Override + public RecyclerView.ViewHolder getItemViewHolder(View view) { + return new ContentHolder(view); + } + + @Override + public RecyclerView.ViewHolder getEmptyViewHolder(View view) { + return new EmptyHolder(view); + } + + @Override + public RecyclerView.ViewHolder getLoadingViewHolder(View view) { + return new LoadingHolder(view); + } + + @Override + public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { + final ContentHolder contentHolder = (ContentHolder) holder; + final App app = appList.get(position); + + contentHolder.line1.setText(app.getDisplayName()); + contentHolder.line2.setText(app.getPackageName()); + contentHolder.checkBox.setChecked(blackList.contains(app.getPackageName())); + + GlideApp + .with(context) + .load(app.getIconInfo().getUrl()) + .transforms(new CenterCrop(), new RoundedCorners(30)) + .into(contentHolder.img); + + contentHolder.itemView.setOnClickListener(v -> { + clickListener.onClick(position, app.getPackageName()); + }); + } + + public interface ClickListener { + void onClick(int position, String packageName); + } + + static class ContentHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + @BindView(R.id.line2) + TextView line2; + @BindView(R.id.check) + MaterialCheckBox checkBox; + + ContentHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class EmptyHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + EmptyHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + img.setImageDrawable(itemView.getResources().getDrawable(R.drawable.ic_menu_blacklist)); + line1.setText(itemView.getContext().getString(R.string.list_blacklist_none)); + } + } + + static class LoadingHolder extends RecyclerView.ViewHolder { + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.line1) + TextView line1; + + LoadingHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/com/aurora/store/section/CategoriesSection.java b/app/src/main/java/com/aurora/store/section/CategoriesSection.java new file mode 100644 index 000000000..1d776f095 --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/CategoriesSection.java @@ -0,0 +1,148 @@ +package com.aurora.store.section; + +import android.content.Context; +import android.graphics.drawable.GradientDrawable; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.model.CategoryModel; +import com.aurora.store.util.ImageUtil; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.Section; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters; + +public class CategoriesSection extends Section { + + private Context context; + private List categories; + private String header; + private ClickListener clickListener; + + public CategoriesSection(Context context, List categories, String header, ClickListener clickListener) { + super(SectionParameters.builder() + .itemResourceId(R.layout.item_category_list) + .headerResourceId(R.layout.item_header) + .loadingResourceId(R.layout.item_loading) + .emptyResourceId(R.layout.item_empty) + .build()); + this.context = context; + this.clickListener = clickListener; + this.categories = categories; + this.header = header; + + if (categories.isEmpty()) + setState(State.LOADING); + else + setState(State.LOADED); + } + + @Override + public int getContentItemsTotal() { + return categories.size(); + } + + @Override + public RecyclerView.ViewHolder getItemViewHolder(View view) { + return new ContentHolder(view); + } + + @Override + public RecyclerView.ViewHolder getHeaderViewHolder(View view) { + return new HeaderHolder(view); + } + + @Override + public RecyclerView.ViewHolder getEmptyViewHolder(View view) { + return new EmptyHolder(view); + } + + @Override + public RecyclerView.ViewHolder getLoadingViewHolder(View view) { + return new LoadingHolder(view); + } + + @Override + public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { + final ContentHolder contentHolder = (ContentHolder) holder; + CategoryModel categoryModel = categories.get(position); + contentHolder.topLabel.setText(categoryModel.getCategoryTitle()); + contentHolder.itemView.setOnClickListener(v -> clickListener.onClick(categoryModel.getCategoryId(), categoryModel.getCategoryTitle())); + contentHolder.topImage.setBackground(ImageUtil.getDrawable(position, GradientDrawable.OVAL)); + + GlideApp + .with(context) + .load(categoryModel.getCategoryImageUrl()) + .circleCrop() + .into(contentHolder.topImage); + } + + @Override + public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) { + final HeaderHolder headerHolder = (HeaderHolder) holder; + headerHolder.line1.setText(header); + } + + public interface ClickListener { + void onClick(String categoryId, String categoryName); + } + + public static class ContentHolder extends RecyclerView.ViewHolder { + @BindView(R.id.all_cat_img) + ImageView topImage; + @BindView(R.id.all_cat_name) + TextView topLabel; + + ContentHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class HeaderHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.line1) + TextView line1; + + HeaderHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class EmptyHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + EmptyHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + img.setImageDrawable(itemView.getResources().getDrawable(R.drawable.ic_apps)); + line1.setText(itemView.getContext().getString(R.string.list_empty_updates)); + } + } + + static class LoadingHolder extends RecyclerView.ViewHolder { + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.line1) + TextView line1; + + LoadingHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/com/aurora/store/section/EndlessResultSection.java b/app/src/main/java/com/aurora/store/section/EndlessResultSection.java new file mode 100644 index 000000000..f09e9c382 --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/EndlessResultSection.java @@ -0,0 +1,45 @@ +package com.aurora.store.section; + +import android.content.Context; + +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.Util; + +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +public class EndlessResultSection extends InstallAppSection { + + public EndlessResultSection(Context context, ClickListener clickListener) { + super(context, clickListener); + } + + public void add(App app) { + appList.add(app); + } + + public int getCount() { + return appList.size(); + } + + public void purgeData() { + appList.clear(); + } + + @Override + public void getDetails(List Version, List Extra, App app) { + Version.add(Util.addSiPrefix(app.getSize())); + if (!app.isEarlyAccess()) + Version.add(context.getString(R.string.details_rating, (app.getRating().getAverage()))); + if (PackageUtil.isInstalled(context, app.getPackageName())) + Version.add(context.getString(R.string.action_installed)); + Extra.add(app.getPrice()); + Extra.add(context.getString(app.containsAds() ? R.string.list_app_has_ads : R.string.list_app_no_ads)); + Extra.add(context.getString(app.getDependencies().isEmpty() ? R.string.list_app_independent_from_gsf : R.string.list_app_depends_on_gsf)); + if (!StringUtils.isEmpty(app.getUpdated())) + Extra.add(app.getUpdated()); + } +} diff --git a/app/src/main/java/com/aurora/store/section/FavouriteAppSection.java b/app/src/main/java/com/aurora/store/section/FavouriteAppSection.java new file mode 100644 index 000000000..422126c84 --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/FavouriteAppSection.java @@ -0,0 +1,176 @@ +package com.aurora.store.section; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.util.PackageUtil; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.google.android.material.checkbox.MaterialCheckBox; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.Section; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters; + +public class FavouriteAppSection extends Section { + + private Context context; + private List appList = new ArrayList<>(); + private List selectedPackages = new ArrayList<>(); + private ClickListener clickListener; + + public FavouriteAppSection(Context context, ClickListener clickListener) { + super(SectionParameters.builder() + .itemResourceId(R.layout.item_favorite) + .loadingResourceId(R.layout.item_loading) + .emptyResourceId(R.layout.item_empty) + .build()); + this.context = context; + this.clickListener = clickListener; + setState(State.LOADING); + } + + public List getAppList() { + return appList; + } + + public void updateList(List appList) { + this.appList.clear(); + this.appList.addAll(appList); + if (appList.isEmpty()) + setState(State.EMPTY); + else + setState(State.LOADED); + } + + public void remove(String packageName) { + selectedPackages.remove(packageName); + } + + public void add(String packageName) { + selectedPackages.add(packageName); + } + + public List getSelections() { + return selectedPackages; + } + + public List getSelectedList() { + List selectedList = new ArrayList<>(); + for (App app : appList) { + if (selectedPackages.contains(app.getPackageName())) + selectedList.add(app); + } + return selectedList; + } + + public int getSize() { + return appList.size(); + } + + @Override + public int getContentItemsTotal() { + return appList.size(); + } + + @Override + public RecyclerView.ViewHolder getItemViewHolder(View view) { + return new ContentHolder(view); + } + + @Override + public RecyclerView.ViewHolder getEmptyViewHolder(View view) { + return new EmptyHolder(view); + } + + @Override + public RecyclerView.ViewHolder getLoadingViewHolder(View view) { + return new LoadingHolder(view); + } + + @Override + public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { + final ContentHolder contentHolder = (ContentHolder) holder; + final App app = appList.get(position); + + contentHolder.line1.setText(app.getDisplayName()); + contentHolder.checkBox.setChecked(selectedPackages.contains(app.getPackageName())); + + GlideApp + .with(context) + .load(app.getIconInfo().getUrl()) + .transforms(new CenterCrop(), new RoundedCorners(30)) + .into(contentHolder.img); + + contentHolder.itemView.setOnClickListener(v -> { + clickListener.onClick(position, app.getPackageName()); + }); + + if (PackageUtil.isInstalled(context, app)) { + contentHolder.line2.setText(context.getText(R.string.list_installed)); + contentHolder.checkBox.setEnabled(false); + contentHolder.checkBox.setOnCheckedChangeListener(null); + } else { + contentHolder.line2.setText(context.getText(R.string.list_not_installd)); + } + } + + public interface ClickListener { + void onClick(int position, String packageName); + } + + static class ContentHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + @BindView(R.id.line2) + TextView line2; + @BindView(R.id.check) + MaterialCheckBox checkBox; + + ContentHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class EmptyHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + EmptyHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + img.setImageDrawable(itemView.getResources().getDrawable(R.drawable.ic_menu_fav)); + line1.setText(itemView.getContext().getString(R.string.list_empty_fav)); + } + } + + static class LoadingHolder extends RecyclerView.ViewHolder { + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.line1) + TextView line1; + + LoadingHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/com/aurora/store/section/InstallAppSection.java b/app/src/main/java/com/aurora/store/section/InstallAppSection.java new file mode 100644 index 000000000..514e8022f --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/InstallAppSection.java @@ -0,0 +1,200 @@ +package com.aurora.store.section; + +import android.app.ActivityOptions; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Pair; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.ui.details.DetailsActivity; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.Section; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters; + +public class InstallAppSection extends Section { + + protected Context context; + protected List appList = new ArrayList<>(); + private ClickListener clickListener; + + public InstallAppSection(Context context, ClickListener clickListener) { + super(SectionParameters.builder() + .itemResourceId(R.layout.item_installed) + .loadingResourceId(R.layout.item_loading) + .emptyResourceId(R.layout.item_empty) + .build()); + this.context = context; + this.clickListener = clickListener; + setState(State.LOADING); + } + + public void updateList(List appList) { + this.appList.clear(); + this.appList.addAll(appList); + + //Sort Apps by Names + Collections.sort(this.appList, (App1, App2) -> + App1.getDisplayName().compareToIgnoreCase(App2.getDisplayName())); + + if (appList.isEmpty()) + setState(State.EMPTY); + else + setState(State.LOADED); + } + + public int removeApp(String packageName) { + int i = 0; + for (Iterator iterator = appList.iterator(); iterator.hasNext(); ) { + if (iterator.next().getPackageName().equals(packageName)) { + iterator.remove(); + return i; + } + i++; + } + return -1; + } + + public List getList() { + return appList; + } + + @Override + public int getContentItemsTotal() { + return appList.size(); + } + + @Override + public RecyclerView.ViewHolder getItemViewHolder(View view) { + return new ContentHolder(view); + } + + @Override + public RecyclerView.ViewHolder getEmptyViewHolder(View view) { + return new EmptyHolder(view); + } + + @Override + public RecyclerView.ViewHolder getLoadingViewHolder(View view) { + return new LoadingHolder(view); + } + + @Override + public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { + final ContentHolder contentHolder = (ContentHolder) holder; + final App app = appList.get(position); + List Version = new ArrayList<>(); + List Extra = new ArrayList<>(); + + contentHolder.AppTitle.setText(app.getDisplayName()); + getDetails(Version, Extra, app); + setText(contentHolder.AppExtra, TextUtils.join(" • ", Extra)); + setText(contentHolder.AppVersion, TextUtils.join(" • ", Version)); + + GlideApp + .with(context) + .load(app.getIconInfo().getUrl()) + .transition(new DrawableTransitionOptions().crossFade()) + .transforms(new CenterCrop(), new RoundedCorners(30)) + .into(contentHolder.AppIcon); + + contentHolder.itemView.setOnClickListener(v -> { + Intent intent = new Intent(context, DetailsActivity.class); + intent.putExtra("INTENT_PACKAGE_NAME", app.getPackageName()); + Bundle bundle = ActivityOptions.makeSceneTransitionAnimation((AppCompatActivity) context, + Pair.create(contentHolder.AppIcon, "icon"), + Pair.create(contentHolder.AppTitle, "displayName")).toBundle(); + context.startActivity(intent, bundle); + }); + contentHolder.itemView.setOnLongClickListener(v -> { + clickListener.onLongClick(app); + return true; + }); + } + + public void getDetails(List Version, List Extra, App app) { + Version.add("v" + app.getVersionName() + "." + app.getVersionCode()); + if (app.isSystem()) + Extra.add(context.getString(R.string.list_app_system)); + else + Extra.add(context.getString(R.string.list_app_user)); + } + + private void setText(TextView textView, String text) { + if (!TextUtils.isEmpty(text)) { + textView.setText(text); + textView.setVisibility(View.VISIBLE); + } else { + textView.setVisibility(View.GONE); + } + } + + public interface ClickListener { + void onClick(App app); + + void onLongClick(App app); + } + + static class ContentHolder extends RecyclerView.ViewHolder { + @BindView(R.id.app_icon) + ImageView AppIcon; + @BindView(R.id.app_title) + TextView AppTitle; + @BindView(R.id.app_version) + TextView AppVersion; + @BindView(R.id.app_extra) + TextView AppExtra; + + ContentHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class EmptyHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + EmptyHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + img.setImageDrawable(itemView.getResources().getDrawable(R.drawable.ic_apps)); + line1.setText(itemView.getContext().getString(R.string.list_empty_updates)); + } + } + + static class LoadingHolder extends RecyclerView.ViewHolder { + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.line1) + TextView line1; + + LoadingHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/com/aurora/store/section/ReviewsSection.java b/app/src/main/java/com/aurora/store/section/ReviewsSection.java new file mode 100644 index 000000000..3be9a531f --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/ReviewsSection.java @@ -0,0 +1,155 @@ +package com.aurora.store.section; + +import android.content.Context; +import android.text.format.DateFormat; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RatingBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.model.Review; +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.Section; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters; + +public class ReviewsSection extends Section { + + private Context context; + private List reviewList = new ArrayList<>(); + + public ReviewsSection(Context context) { + super(SectionParameters.builder() + .itemResourceId(R.layout.item_review) + .loadingResourceId(R.layout.item_loading) + .emptyResourceId(R.layout.item_empty) + .build()); + this.context = context; + + setState(State.LOADING); + } + + private static String getDate(long millisecond) { + Calendar calendar = Calendar.getInstance(Locale.getDefault()); + calendar.setTimeInMillis(millisecond); + return DateFormat.format("dd/MM/yy", calendar).toString(); + } + + public void updateList(List appList) { + this.reviewList.clear(); + this.reviewList.addAll(appList); + if (!appList.isEmpty()) + setState(State.LOADED); + } + + public List getList() { + return reviewList; + } + + public void add(Review review) { + reviewList.add(review); + } + + public void clearReviews() { + this.reviewList.clear(); + setState(State.LOADING); + } + + public int getCount() { + return reviewList.size(); + } + + @Override + public int getContentItemsTotal() { + return reviewList.size(); + } + + @Override + public RecyclerView.ViewHolder getItemViewHolder(View view) { + return new ContentHolder(view); + } + + @Override + public RecyclerView.ViewHolder getEmptyViewHolder(View view) { + return new EmptyHolder(view); + } + + @Override + public RecyclerView.ViewHolder getLoadingViewHolder(View view) { + return new LoadingHolder(view); + } + + @Override + public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { + final ContentHolder contentHolder = (ContentHolder) holder; + final Review review = reviewList.get(position); + contentHolder.line1.setText(review.getUserName()); + contentHolder.rating.setRating(review.getRating()); + contentHolder.line2.setText(getDate(review.getTimeStamp())); + contentHolder.line3.setText(review.getComment()); + + GlideApp + .with(context) + .load(review.getUserPhotoUrl()) + .placeholder(R.color.colorTransparent) + .circleCrop() + .transition(new DrawableTransitionOptions().crossFade()) + .into(contentHolder.img); + } + + public static class ContentHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + @BindView(R.id.rating) + RatingBar rating; + @BindView(R.id.line2) + TextView line2; + @BindView(R.id.line3) + TextView line3; + + ContentHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class EmptyHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + EmptyHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + line1.setText(itemView.getContext().getString(R.string.list_empty_reviews)); + } + } + + static class LoadingHolder extends RecyclerView.ViewHolder { + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.line1) + TextView line1; + + LoadingHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/com/aurora/store/section/SearchResultSection.java b/app/src/main/java/com/aurora/store/section/SearchResultSection.java new file mode 100644 index 000000000..c81e6ce24 --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/SearchResultSection.java @@ -0,0 +1,45 @@ +package com.aurora.store.section; + +import android.content.Context; + +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.Util; + +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +public class SearchResultSection extends InstallAppSection { + + public SearchResultSection(Context context, ClickListener clickListener) { + super(context, clickListener); + } + + public void add(App app) { + appList.add(app); + } + + public int getCount() { + return appList.size(); + } + + public void purgeData() { + appList.clear(); + } + + @Override + public void getDetails(List Version, List Extra, App app) { + Version.add(Util.addSiPrefix(app.getSize())); + if (!app.isEarlyAccess()) + Version.add(context.getString(R.string.details_rating, (app.getRating().getAverage()))); + if (PackageUtil.isInstalled(context, app.getPackageName())) + Version.add(context.getString(R.string.action_installed)); + Extra.add(app.getPrice()); + Extra.add(context.getString(app.containsAds() ? R.string.list_app_has_ads : R.string.list_app_no_ads)); + Extra.add(context.getString(app.getDependencies().isEmpty() ? R.string.list_app_independent_from_gsf : R.string.list_app_depends_on_gsf)); + if (!StringUtils.isEmpty(app.getUpdated())) + Extra.add(app.getUpdated()); + } +} diff --git a/app/src/main/java/com/aurora/store/section/SearchSuggestionSection.java b/app/src/main/java/com/aurora/store/section/SearchSuggestionSection.java new file mode 100644 index 000000000..fb06fdee3 --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/SearchSuggestionSection.java @@ -0,0 +1,108 @@ +package com.aurora.store.section; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.dragons.aurora.playstoreapiv2.SearchSuggestEntry; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.Section; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters; + +public class SearchSuggestionSection extends Section { + + private Context context; + private List suggestEntryList = new ArrayList<>(); + private ClickListener clickListener; + + public SearchSuggestionSection(Context context, ClickListener clickListener) { + super(SectionParameters.builder() + .itemResourceId(R.layout.item_suggestion) + .build()); + this.context = context; + this.clickListener = clickListener; + } + + public void addData(List suggestEntryList) { + this.suggestEntryList.clear(); + this.suggestEntryList.addAll(suggestEntryList); + } + + @Override + public int getContentItemsTotal() { + return suggestEntryList.size(); + } + + @Override + public RecyclerView.ViewHolder getItemViewHolder(View view) { + return new ContentHolder(view); + } + + @Override + public RecyclerView.ViewHolder getEmptyViewHolder(View view) { + return new EmptyHolder(view); + } + + @Override + public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { + final ContentHolder contentHolder = (ContentHolder) holder; + SearchSuggestEntry suggestEntry = suggestEntryList.get(position); + String title = suggestEntry.getTitle(); + String packageName = suggestEntry.getPackageNameContainer().getPackageName(); + contentHolder.line1.setText(title); + GlideApp + .with(context) + .load(suggestEntry.getImageContainer().getImageUrl()) + .placeholder(R.drawable.ic_round_search) + .transforms(new CenterCrop(), new RoundedCorners(30)) + .into(contentHolder.img); + holder.itemView.setOnClickListener(v -> clickListener.onClick(packageName.isEmpty() ? title : packageName)); + } + + public List getList() { + return suggestEntryList; + } + + public interface ClickListener { + void onClick(String query); + } + + public static class ContentHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + ContentHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class EmptyHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + EmptyHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + img.setImageDrawable(itemView.getResources().getDrawable(R.drawable.ic_apps)); + line1.setText(itemView.getContext().getString(R.string.list_empty_updates)); + } + } +} diff --git a/app/src/main/java/com/aurora/store/section/UpdateAppSection.java b/app/src/main/java/com/aurora/store/section/UpdateAppSection.java new file mode 100644 index 000000000..078f0ad66 --- /dev/null +++ b/app/src/main/java/com/aurora/store/section/UpdateAppSection.java @@ -0,0 +1,215 @@ +package com.aurora.store.section; + +import android.content.Context; +import android.text.Html; +import android.text.TextUtils; +import android.text.format.Formatter; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.util.ViewUtil; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.Section; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters; + +public class UpdateAppSection extends Section { + + private Context context; + private List appList = new ArrayList<>(); + private ClickListener clickListener; + + public UpdateAppSection(Context context, ClickListener clickListener) { + super(SectionParameters.builder() + .itemResourceId(R.layout.item_updatable) + .loadingResourceId(R.layout.item_loading) + .emptyResourceId(R.layout.item_empty) + .build()); + this.context = context; + this.clickListener = clickListener; + setState(State.LOADING); + } + + public void updateList(List appList) { + this.appList.clear(); + this.appList.addAll(appList); + + //Sort Apps by Names + Collections.sort(this.appList, (App1, App2) -> + App1.getDisplayName().compareToIgnoreCase(App2.getDisplayName())); + + if (appList.isEmpty()) + setState(State.EMPTY); + else + setState(State.LOADED); + } + + + public int removeApp(String packageName) { + int i = 0; + for (Iterator iterator = appList.iterator(); iterator.hasNext(); ) { + if (iterator.next().getPackageName().equals(packageName)) { + iterator.remove(); + return i; + } + i++; + } + return -1; + } + + + public List getList() { + return appList; + } + + @Override + public int getContentItemsTotal() { + return appList.size(); + } + + @Override + public RecyclerView.ViewHolder getItemViewHolder(View view) { + return new ContentHolder(view); + } + + @Override + public RecyclerView.ViewHolder getEmptyViewHolder(View view) { + return new EmptyHolder(view); + } + + @Override + public RecyclerView.ViewHolder getLoadingViewHolder(View view) { + return new LoadingHolder(view); + } + + @Override + public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { + final ContentHolder contentHolder = (ContentHolder) holder; + final App app = appList.get(position); + List Version = new ArrayList<>(); + List Extra = new ArrayList<>(); + + contentHolder.txtTitle.setText(app.getDisplayName()); + getDetails(Version, Extra, app); + setText(contentHolder.txtExtra, TextUtils.join(" • ", Extra)); + setText(contentHolder.txtVersion, TextUtils.join(" • ", Version)); + setText(contentHolder.txtChanges, app.getChanges().isEmpty() + ? context.getString(R.string.details_no_changes) + : Html.fromHtml(app.getChanges()).toString()); + GlideApp + .with(context) + .load(app.getIconInfo().getUrl()) + .transition(new DrawableTransitionOptions().crossFade()) + .transforms(new CenterCrop(), new RoundedCorners(30)) + .into(contentHolder.imgIcon); + + contentHolder.imgExpand.setOnClickListener(v -> { + if (contentHolder.layoutChanges.getHeight() == 0) { + ViewUtil.rotateView(v, false); + ViewUtil.expandView(contentHolder.layoutChanges, + contentHolder.txtChanges.getHeight() + + contentHolder.txtChangesTitle.getHeight() + + 120 /*Padding & Margins*/); + } else { + ViewUtil.rotateView(v, true); + ViewUtil.collapseView(contentHolder.layoutChanges, 0); + } + }); + + contentHolder.itemView.setOnClickListener(v -> clickListener.onClick(app)); + contentHolder.itemView.setOnLongClickListener(v -> { + clickListener.onLongClick(app); + return true; + }); + } + + private void getDetails(List Version, List Extra, App app) { + Version.add(app.getUpdated()); + Extra.add(app.getSize() == 0 ? "N/A" : Formatter.formatShortFileSize(context, app.getSize())); + } + + protected void setText(TextView textView, String text) { + if (!TextUtils.isEmpty(text)) { + textView.setText(text); + textView.setVisibility(View.VISIBLE); + } else { + textView.setVisibility(View.GONE); + } + } + + public interface ClickListener { + void onClick(App app); + + void onLongClick(App app); + } + + public static class ContentHolder extends RecyclerView.ViewHolder { + @BindView(R.id.layout_info) + RelativeLayout layoutInfo; + @BindView(R.id.layout_changes) + RelativeLayout layoutChanges; + @BindView(R.id.app_icon) + ImageView imgIcon; + @BindView(R.id.app_title) + TextView txtTitle; + @BindView(R.id.app_version) + TextView txtVersion; + @BindView(R.id.app_extra) + TextView txtExtra; + @BindView(R.id.img_expand) + ImageView imgExpand; + @BindView(R.id.txt_title) + TextView txtChangesTitle; + @BindView(R.id.txt_changes) + TextView txtChanges; + + ContentHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + static class EmptyHolder extends RecyclerView.ViewHolder { + @BindView(R.id.img) + ImageView img; + @BindView(R.id.line1) + TextView line1; + + EmptyHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + img.setImageDrawable(itemView.getResources().getDrawable(R.drawable.ic_apps)); + line1.setText(itemView.getContext().getString(R.string.list_empty_updates)); + } + } + + static class LoadingHolder extends RecyclerView.ViewHolder { + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.line1) + TextView line1; + + LoadingHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/com/aurora/store/sheet/AppMenuSheet.java b/app/src/main/java/com/aurora/store/sheet/AppMenuSheet.java index 241b081cd..64f9afb20 100644 --- a/app/src/main/java/com/aurora/store/sheet/AppMenuSheet.java +++ b/app/src/main/java/com/aurora/store/sheet/AppMenuSheet.java @@ -33,20 +33,21 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; +import androidx.appcompat.app.AppCompatActivity; import com.aurora.store.AuroraApplication; import com.aurora.store.R; -import com.aurora.store.activity.ManualDownloadActivity; -import com.aurora.store.adapter.InstalledAppsAdapter; -import com.aurora.store.adapter.UpdatableAppsAdapter; -import com.aurora.store.fragment.DetailsFragment; +import com.aurora.store.events.Event; +import com.aurora.store.events.RxBus; import com.aurora.store.manager.BlacklistManager; import com.aurora.store.manager.FavouriteListManager; import com.aurora.store.model.App; -import com.aurora.store.utility.ApkCopier; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.single.activity.ManualDownloadActivity; +import com.aurora.store.util.ApkCopier; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.ViewUtil; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.navigation.NavigationView; @@ -64,16 +65,12 @@ public class AppMenuSheet extends BottomSheetDialogFragment { private App app; private Context context; - private RecyclerView.Adapter adapter; private CompositeDisposable disposable = new CompositeDisposable(); + private RxBus rxBus; public AppMenuSheet() { } - public void setAdapter(RecyclerView.Adapter adapter) { - this.adapter = adapter; - } - public App getApp() { return app; } @@ -86,6 +83,7 @@ public class AppMenuSheet extends BottomSheetDialogFragment { public void onAttach(@NonNull Context context) { super.onAttach(context); this.context = context; + this.rxBus = AuroraApplication.getRxBus(); } @Override @@ -128,14 +126,16 @@ public class AppMenuSheet extends BottomSheetDialogFragment { blacklistManager.remove(app.getPackageName()); Toast.makeText(context, context.getString(R.string.toast_apk_whitelisted), Toast.LENGTH_SHORT).show(); + rxBus + .getBus() + .accept(new Event(Event.SubType.WHITELIST, app.getPackageName())); } else { blacklistManager.add(app.getPackageName()); Toast.makeText(context, context.getString(R.string.toast_apk_blacklisted), Toast.LENGTH_SHORT).show(); - if (adapter instanceof InstalledAppsAdapter) - ((InstalledAppsAdapter) adapter).remove(app); - if (adapter instanceof UpdatableAppsAdapter) - ((UpdatableAppsAdapter) adapter).remove(app); + rxBus + .getBus() + .accept(new Event(Event.SubType.BLACKLIST, app.getPackageName())); } break; case R.id.action_local: @@ -151,8 +151,8 @@ public class AppMenuSheet extends BottomSheetDialogFragment { })); break; case R.id.action_manual: - DetailsFragment.app = app; - context.startActivity(new Intent(context, ManualDownloadActivity.class)); + DetailsActivity.app = app; + context.startActivity(new Intent(context, ManualDownloadActivity.class), ViewUtil.getEmptyActivityBundle((AppCompatActivity) context)); break; case R.id.action_uninstall: AuroraApplication.getUninstaller().uninstall(app); diff --git a/app/src/main/java/com/aurora/store/sheet/DownloadMenuSheet.java b/app/src/main/java/com/aurora/store/sheet/DownloadMenuSheet.java index dd82bcdf3..c70b33caf 100644 --- a/app/src/main/java/com/aurora/store/sheet/DownloadMenuSheet.java +++ b/app/src/main/java/com/aurora/store/sheet/DownloadMenuSheet.java @@ -32,7 +32,7 @@ import androidx.annotation.Nullable; import com.aurora.store.R; import com.aurora.store.download.DownloadManager; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.navigation.NavigationView; import com.tonyodev.fetch2.Download; diff --git a/app/src/main/java/com/aurora/store/sheet/ExodusBottomSheet.java b/app/src/main/java/com/aurora/store/sheet/ExodusBottomSheet.java index f0e48541f..57fe756be 100644 --- a/app/src/main/java/com/aurora/store/sheet/ExodusBottomSheet.java +++ b/app/src/main/java/com/aurora/store/sheet/ExodusBottomSheet.java @@ -39,7 +39,7 @@ import com.aurora.store.R; import com.aurora.store.adapter.ExodusAdapter; import com.aurora.store.model.ExodusTracker; import com.aurora.store.model.Report; -import com.aurora.store.utility.Log; +import com.aurora.store.util.Log; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; diff --git a/app/src/main/java/com/aurora/store/sheet/FilterBottomSheet.java b/app/src/main/java/com/aurora/store/sheet/FilterBottomSheet.java index 19ef4ec7b..6b9c4d5e8 100644 --- a/app/src/main/java/com/aurora/store/sheet/FilterBottomSheet.java +++ b/app/src/main/java/com/aurora/store/sheet/FilterBottomSheet.java @@ -22,6 +22,7 @@ package com.aurora.store.sheet; import android.content.Context; import android.content.res.ColorStateList; +import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -32,10 +33,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; -import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.ViewUtil; +import com.aurora.store.manager.FilterManager; +import com.aurora.store.model.FilterModel; +import com.aurora.store.util.ImageUtil; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.chip.Chip; @@ -43,6 +44,7 @@ import com.google.android.material.chip.ChipGroup; import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnClick; public class FilterBottomSheet extends BottomSheetDialogFragment { @@ -60,7 +62,7 @@ public class FilterBottomSheet extends BottomSheetDialogFragment { Button filter_apply; private Context context; - private View.OnClickListener onClickListener; + private FilterModel filterModel; @Override public void onAttach(@NonNull Context context) { @@ -77,33 +79,37 @@ public class FilterBottomSheet extends BottomSheetDialogFragment { @NonNull @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.sheet_filter, container, false); + View view = inflater.inflate(R.layout.sheet_filter, container, false); + ButterKnife.bind(this, view); + return view; } @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - ButterKnife.bind(this, view); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + filterModel = FilterManager.getFilterPreferences(context); setupMultipleChips(); setupSingleChips(); - setupActions(); + } + + @OnClick(R.id.filter_apply) + public void applyFilter() { + FilterManager.saveFilterPreferences(context, filterModel); + dismiss(); } private void setupSingleChips() { - applyStyles(chip_gsf, getResources().getColor(R.color.colorRed)); - chip_gsf.setOnCheckedChangeListener((v, isChecked) -> - PrefUtil.putBoolean(context, Constants.FILTER_GSF_DEPENDENT_APPS, isChecked)); - chip_gsf.setChecked(PrefUtil.getBoolean(context, Constants.FILTER_GSF_DEPENDENT_APPS)); + chip_gsf.setChecked(filterModel.isGsfDependentApps()); + chip_paid.setChecked(filterModel.isPaidApps()); + chip_ads.setChecked(filterModel.isAppsWithAds()); - applyStyles(chip_paid, getResources().getColor(R.color.colorPurple)); - chip_paid.setOnCheckedChangeListener((v, isChecked) -> - PrefUtil.putBoolean(context, Constants.FILTER_PAID_APPS, isChecked)); - chip_paid.setChecked(PrefUtil.getBoolean(context, Constants.FILTER_PAID_APPS)); + chip_gsf.setOnCheckedChangeListener((v, isChecked) -> filterModel.setGsfDependentApps(isChecked)); + chip_paid.setOnCheckedChangeListener((v, isChecked) -> filterModel.setPaidApps(isChecked)); + chip_ads.setOnCheckedChangeListener((v, isChecked) -> filterModel.setAppsWithAds(isChecked)); - applyStyles(chip_ads, getResources().getColor(R.color.colorOrange)); - chip_ads.setOnCheckedChangeListener((v, isChecked) -> - PrefUtil.putBoolean(context, Constants.FILTER_APPS_WITH_ADS, isChecked)); - chip_ads.setChecked(PrefUtil.getBoolean(context, Constants.FILTER_APPS_WITH_ADS)); + applyStyles(chip_gsf, 0); + applyStyles(chip_ads, 1); + applyStyles(chip_paid, 2); } private void setupMultipleChips() { @@ -111,24 +117,21 @@ public class FilterBottomSheet extends BottomSheetDialogFragment { String[] downloadValues = getResources().getStringArray(R.array.filterDownloadsValues); String[] ratingLabels = getResources().getStringArray(R.array.filterRatingLabels); String[] ratingValues = getResources().getStringArray(R.array.filterRatingValues); - int[] colorShades = getResources().getIntArray(R.array.colorShades); int i = 0; for (String downloadLabel : downloadLabels) { final int pos = i; Chip chip = new Chip(context); + applyStyles(chip, i); chip.setText(downloadLabel); - applyStyles(chip, colorShades[i]); chip.setOnCheckedChangeListener((v, isChecked) -> { download_chips.clearCheck(); chip.setChecked(isChecked); if (isChecked) { - PrefUtil.putInteger(v.getContext(), Constants.FILTER_DOWNLOADS, - Integer.parseInt(downloadValues[pos])); + filterModel.setDownloads(Integer.parseInt(downloadValues[pos])); } }); - chip.setChecked(PrefUtil.getInteger(context, Constants.FILTER_DOWNLOADS) - == Integer.parseInt(downloadValues[i])); + chip.setChecked(filterModel.getDownloads() == Integer.parseInt(downloadValues[i])); download_chips.addView(chip); i++; } @@ -137,41 +140,27 @@ public class FilterBottomSheet extends BottomSheetDialogFragment { for (String ratingLabel : ratingLabels) { final int pos = i; Chip chip = new Chip(context); - applyStyles(chip, colorShades[i]); + applyStyles(chip, i); chip.setText(ratingLabel); chip.setOnCheckedChangeListener((v, isChecked) -> { rating_chips.clearCheck(); chip.setChecked(isChecked); if (isChecked) { - PrefUtil.putFloat(context, Constants.FILTER_RATING, - Float.parseFloat(ratingValues[pos])); + filterModel.setRating(Float.parseFloat(ratingValues[pos])); } }); - chip.setChecked(PrefUtil.getFloat(context, Constants.FILTER_RATING) == - Float.parseFloat(ratingValues[i])); + chip.setChecked(filterModel.getRating() == Float.parseFloat(ratingValues[i])); rating_chips.addView(chip); i++; } } - private void applyStyles(Chip chip, int color) { - chip.setChipIconSize(ViewUtil.dpToPx(context, 24)); - chip.setChipIcon(context.getDrawable(R.drawable.circle_bg)); - chip.setChipIconTint(ColorStateList.valueOf(color)); + private void applyStyles(Chip chip, int index) { + int color = ImageUtil.getSolidColor(index); + chip.setChipIcon(ImageUtil.getDrawable(index, GradientDrawable.OVAL)); + chip.setCheckedIcon(context.getDrawable(R.drawable.ic_filter_check)); chip.setChipIconVisible(true); chip.setChipBackgroundColor(ColorStateList.valueOf(ColorUtils.setAlphaComponent(color, 100))); chip.setChipStrokeColor(ColorStateList.valueOf(color)); - chip.setChipStrokeWidth(ViewUtil.dpToPx(context, 1)); - chip.setCheckedIcon(context.getDrawable(R.drawable.ic_checked)); - } - - private void setupActions() { - if (filter_apply != null) { - filter_apply.setOnClickListener(onClickListener); - } - } - - public void setOnApplyListener(View.OnClickListener onClickListener) { - this.onClickListener = onClickListener; } } diff --git a/app/src/main/java/com/aurora/store/sheet/ReviewsBottomSheet.java b/app/src/main/java/com/aurora/store/sheet/ReviewsBottomSheet.java deleted file mode 100644 index 71fef12a0..000000000 --- a/app/src/main/java/com/aurora/store/sheet/ReviewsBottomSheet.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.sheet; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.aurora.store.EndlessScrollListener; -import com.aurora.store.R; -import com.aurora.store.adapter.ReviewsAdapter; -import com.aurora.store.iterator.ReviewStorageIterator; -import com.aurora.store.model.App; -import com.aurora.store.model.Review; -import com.aurora.store.task.ReviewsHelper; -import com.aurora.store.utility.Log; -import com.google.android.material.bottomsheet.BottomSheetBehavior; -import com.google.android.material.bottomsheet.BottomSheetDialogFragment; - -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class ReviewsBottomSheet extends BottomSheetDialogFragment { - - @BindView(R.id.reviews_recycler) - RecyclerView recyclerView; - - private Context context; - private App app; - private ReviewsAdapter adapter; - private ReviewStorageIterator iterator; - private CompositeDisposable disposable = new CompositeDisposable(); - - public ReviewsBottomSheet(App app) { - this.app = app; - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onStart() { - super.onStart(); - getDialog().getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.sheet_reviews, container, false); - ButterKnife.bind(this, view); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - iterator = new ReviewStorageIterator(); - iterator.setPackageName(app.getPackageName()); - iterator.setContext(context); - getReviews(false); - } - - private void getReviews(boolean shouldIterate) { - ReviewsHelper reviewsHelper = new ReviewsHelper(getContext()); - reviewsHelper.setIterator(iterator); - disposable.add(Observable.fromCallable(reviewsHelper::getReviews) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnError(err -> Log.e(err.getMessage())) - .subscribe(reviewList -> { - if (shouldIterate) - addReviews(reviewList); - else - setupRecycler(reviewList); - })); - } - - private void setupRecycler(List reviewList) { - LinearLayoutManager mLayoutManager = new LinearLayoutManager(context, RecyclerView.VERTICAL, false); - adapter = new ReviewsAdapter(getContext(), reviewList); - recyclerView.setLayoutManager(mLayoutManager); - recyclerView.setAdapter(adapter); - EndlessScrollListener endlessScrollListener = new EndlessScrollListener(mLayoutManager) { - @Override - public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { - getReviews(true); - } - }; - recyclerView.addOnScrollListener(endlessScrollListener); - } - - private void addReviews(List reviewList) { - if (!reviewList.isEmpty() && adapter != null) { - for (Review mReview : reviewList) - adapter.add(mReview); - adapter.notifyItemInserted(adapter.getItemCount() - 1); - } - } -} diff --git a/app/src/main/java/com/aurora/store/sheet/UserReviewBottomSheet.java b/app/src/main/java/com/aurora/store/sheet/UserReviewBottomSheet.java index 4a9aed0a8..42a7edea7 100644 --- a/app/src/main/java/com/aurora/store/sheet/UserReviewBottomSheet.java +++ b/app/src/main/java/com/aurora/store/sheet/UserReviewBottomSheet.java @@ -30,13 +30,14 @@ import android.widget.Button; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.aurora.store.AuroraApplication; import com.aurora.store.R; import com.aurora.store.model.App; import com.aurora.store.model.Review; import com.aurora.store.model.ReviewBuilder; import com.aurora.store.task.BaseTask; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.dragons.aurora.playstoreapiv2.ReviewResponse; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; @@ -134,7 +135,7 @@ public class UserReviewBottomSheet extends BottomSheetDialogFragment { boolean submit(String packageName, Review review) { try { - GooglePlayAPI api = getApi(); + GooglePlayAPI api = AuroraApplication.api; ReviewResponse response = api.addOrEditReview( packageName, review.getComment(), diff --git a/app/src/main/java/com/aurora/store/task/AllAppsTask.java b/app/src/main/java/com/aurora/store/task/AllAppsTask.java index 100a181c4..08a6ee8a4 100644 --- a/app/src/main/java/com/aurora/store/task/AllAppsTask.java +++ b/app/src/main/java/com/aurora/store/task/AllAppsTask.java @@ -24,28 +24,44 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import com.aurora.store.utility.CertUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.CertUtil; +import com.aurora.store.util.Util; import java.util.ArrayList; import java.util.List; -public class AllAppsTask extends BaseTask { +public class AllAppsTask { + + private Context context; + private PackageManager packageManager; + private boolean fDroidFilterEnabled; + private boolean isExtendedUpdatesEnabled; public AllAppsTask(Context context) { - super(context); + this.context = context; + this.packageManager = context.getPackageManager(); + this.fDroidFilterEnabled = Util.filterFDroidAppsEnabled(context); + this.isExtendedUpdatesEnabled = Util.isExtendedUpdatesEnabled(context); } - List getInstalledApps() { + public PackageManager getPackageManager() { + return packageManager; + } + + public Context getContext() { + return context; + } + + List getLocalInstalledApps() { List packageList = new ArrayList<>(); PackageManager packageManager = context.getPackageManager(); - for (PackageInfo packageInfo : packageManager.getInstalledPackages(0)) { + for (PackageInfo packageInfo : packageManager.getInstalledPackages(PackageManager.GET_META_DATA)) { final String packageName = packageInfo.packageName; if (packageInfo.applicationInfo != null && !packageInfo.applicationInfo.enabled - && !Util.isExtendedUpdatesEnabled(context)) + && !isExtendedUpdatesEnabled) continue; - if (Util.filterFDroidAppsEnabled(context) && CertUtil.isFDroidApp(context, packageName)) + if (fDroidFilterEnabled && CertUtil.isFDroidApp(context, packageName)) continue; packageList.add(packageName); } diff --git a/app/src/main/java/com/aurora/store/task/DetailsApp.java b/app/src/main/java/com/aurora/store/task/AppDetailTask.java similarity index 82% rename from app/src/main/java/com/aurora/store/task/DetailsApp.java rename to app/src/main/java/com/aurora/store/task/AppDetailTask.java index 05ffa0d30..4e8883d7f 100644 --- a/app/src/main/java/com/aurora/store/task/DetailsApp.java +++ b/app/src/main/java/com/aurora/store/task/AppDetailTask.java @@ -24,21 +24,21 @@ import android.content.Context; import com.aurora.store.model.App; import com.aurora.store.model.AppBuilder; -import com.aurora.store.utility.PackageUtil; +import com.aurora.store.util.PackageUtil; import com.dragons.aurora.playstoreapiv2.DetailsResponse; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -public class DetailsApp extends BaseTask { +public class AppDetailTask { - public DetailsApp(Context context) { - super(context); - } + private Context context; + private GooglePlayAPI api; - public void setContext(Context context) { + public AppDetailTask(Context context, GooglePlayAPI api) { this.context = context; + this.api = api; } public App getInfo(String packageName) throws Exception { - api = getApi(); DetailsResponse response = api.details(packageName); App app = AppBuilder.build(response); if (PackageUtil.isInstalled(context, app)) diff --git a/app/src/main/java/com/aurora/store/task/AuthTask.java b/app/src/main/java/com/aurora/store/task/AuthTask.java index 3b5b8bb0c..ed39cfdf3 100644 --- a/app/src/main/java/com/aurora/store/task/AuthTask.java +++ b/app/src/main/java/com/aurora/store/task/AuthTask.java @@ -4,9 +4,9 @@ import android.content.Context; import com.aurora.store.adapter.NativeHttpClientAdapter; import com.aurora.store.model.LoginInfo; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.ApiBuilderUtil; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.ApiBuilderUtil; +import com.aurora.store.util.PrefUtil; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.dragons.aurora.playstoreapiv2.Image; import com.dragons.aurora.playstoreapiv2.UserProfile; diff --git a/app/src/main/java/com/aurora/store/task/BaseTask.java b/app/src/main/java/com/aurora/store/task/BaseTask.java index 13041a9d3..e0ad47181 100644 --- a/app/src/main/java/com/aurora/store/task/BaseTask.java +++ b/app/src/main/java/com/aurora/store/task/BaseTask.java @@ -43,7 +43,7 @@ public abstract class BaseTask extends ContextWrapper { } public GooglePlayAPI getApi() throws Exception { - return PlayStoreApiAuthenticator.getInstance(context); + return PlayStoreApiAuthenticator.getApi(context); } public Context getContext() { @@ -55,17 +55,17 @@ public abstract class BaseTask extends ContextWrapper { } public List filterGoogleApps(List apps) { - Set shitSet = new HashSet<>(); - shitSet.add("com.chrome.beta"); - shitSet.add("com.chrome.canary"); - shitSet.add("com.chrome.dev"); - shitSet.add("com.android.chrome"); - shitSet.add("com.niksoftware.snapseed"); - shitSet.add("com.google.toontastic"); + Set gAppsSet = new HashSet<>(); + gAppsSet.add("com.chrome.beta"); + gAppsSet.add("com.chrome.canary"); + gAppsSet.add("com.chrome.dev"); + gAppsSet.add("com.android.chrome"); + gAppsSet.add("com.niksoftware.snapseed"); + gAppsSet.add("com.google.toontastic"); List appList = new ArrayList<>(); for (App app : apps) { - if (!app.getPackageName().startsWith("com.google") && !shitSet.contains(app.getPackageName())) { + if (!app.getPackageName().startsWith("com.google") && !gAppsSet.contains(app.getPackageName())) { appList.add(app); } } diff --git a/app/src/main/java/com/aurora/store/task/BulkDetails.java b/app/src/main/java/com/aurora/store/task/BulkDetailsTask.java similarity index 82% rename from app/src/main/java/com/aurora/store/task/BulkDetails.java rename to app/src/main/java/com/aurora/store/task/BulkDetailsTask.java index 582681cb2..ed29cec1a 100644 --- a/app/src/main/java/com/aurora/store/task/BulkDetails.java +++ b/app/src/main/java/com/aurora/store/task/BulkDetailsTask.java @@ -20,25 +20,25 @@ package com.aurora.store.task; -import android.content.Context; - import com.aurora.store.model.App; import com.aurora.store.model.AppBuilder; import com.dragons.aurora.playstoreapiv2.BulkDetailsEntry; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import java.io.IOException; import java.util.ArrayList; import java.util.List; -public class BulkDetails extends BaseTask { +public class BulkDetailsTask { - public BulkDetails(Context context) { - super(context); + private GooglePlayAPI api; + + public BulkDetailsTask(GooglePlayAPI api) { + this.api = api; } public List getRemoteAppList(List packageNames) throws Exception { List apps = new ArrayList<>(); - for (BulkDetailsEntry details : getApi().bulkDetails(packageNames).getEntryList()) { + for (BulkDetailsEntry details : api.bulkDetails(packageNames).getEntryList()) { if (!details.hasDoc()) { continue; } diff --git a/app/src/main/java/com/aurora/store/task/CategoryAppsTask.java b/app/src/main/java/com/aurora/store/task/CategoryAppsTask.java index 620bfb144..cd8fd6b58 100644 --- a/app/src/main/java/com/aurora/store/task/CategoryAppsTask.java +++ b/app/src/main/java/com/aurora/store/task/CategoryAppsTask.java @@ -24,11 +24,12 @@ import android.content.Context; import androidx.annotation.NonNull; -import com.aurora.store.manager.CategoryManager; -import com.aurora.store.Filter; import com.aurora.store.iterator.CustomAppListIterator; +import com.aurora.store.manager.CategoryManager; +import com.aurora.store.manager.FilterManager; import com.aurora.store.model.App; -import com.aurora.store.utility.Util; +import com.aurora.store.model.FilterModel; +import com.aurora.store.util.Util; import java.util.ArrayList; import java.util.List; @@ -52,10 +53,10 @@ public class CategoryAppsTask extends BaseTask { public List getNextBatch(CustomAppListIterator iterator) { CategoryManager categoryManager = new CategoryManager(getContext()); - com.aurora.store.model.Filter filter = new Filter(getContext()).getFilterPreferences(); + FilterModel filterModel = FilterManager.getFilterPreferences(getContext()); List apps = new ArrayList<>(); for (App app : iterator.next()) { - if (categoryManager.fits(app.getCategoryId(), filter.getCategory())) { + if (categoryManager.fits(app.getCategoryId(), filterModel.getCategory())) { apps.add(app); } } diff --git a/app/src/main/java/com/aurora/store/task/CategoryList.java b/app/src/main/java/com/aurora/store/task/CategoryListTask.java similarity index 63% rename from app/src/main/java/com/aurora/store/task/CategoryList.java rename to app/src/main/java/com/aurora/store/task/CategoryListTask.java index 3c3086452..e65eae3b7 100644 --- a/app/src/main/java/com/aurora/store/task/CategoryList.java +++ b/app/src/main/java/com/aurora/store/task/CategoryListTask.java @@ -23,37 +23,45 @@ package com.aurora.store.task; import android.content.Context; import android.text.TextUtils; -import com.aurora.store.manager.CategoryManager; import com.aurora.store.Constants; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.model.CategoryModel; +import com.aurora.store.util.PrefUtil; import com.dragons.aurora.playstoreapiv2.DocV2; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.dragons.aurora.playstoreapiv2.ListResponse; +import com.google.gson.Gson; -import java.io.IOException; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; -import java.util.Map; -public class CategoryList extends BaseTask { +public class CategoryListTask { - public CategoryList(Context context) { - super(context); + private Context context; + private GooglePlayAPI api; + + public CategoryListTask(Context context, GooglePlayAPI api) { + this.context = context; + this.api = api; } public boolean getResult() throws Exception { - CategoryManager categoryManager = new CategoryManager(context); - api = getApi(); api.setLocale(getLocale(context)); - Map categoryMap = buildCategoryMap(api.categoriesList()); - categoryManager.save(Constants.TOP, categoryMap); - for (String categoryId : categoryMap.keySet()) { - categoryManager.save(categoryId, buildCategoryMap(api.categoriesList(categoryId))); - } + + ListResponse response = api.categoriesList(); + buildAllCategories(response, Constants.CATEGORY_APPS); + + response = api.categoriesList(Constants.CATEGORY_GAME); + buildAllCategories(response, Constants.CATEGORY_GAME); + + response = api.categoriesList(Constants.CATEGORY_FAMILY); + buildAllCategories(response, Constants.CATEGORY_FAMILY); + return true; } - private Map buildCategoryMap(ListResponse response) { - Map categories = new HashMap<>(); + private void buildAllCategories(ListResponse response, String categoryPrefId) { + List categoryModels = new ArrayList<>(); for (DocV2 categoryCluster : response.getDoc(0).getChildList()) { if (!categoryCluster.getBackendDocid().equals("category_list_cluster")) { continue; @@ -68,10 +76,13 @@ public class CategoryList extends BaseTask { if (TextUtils.isEmpty(categoryId)) { continue; } - categories.put(categoryId, category.getTitle()); + CategoryModel categoryModel = new CategoryModel(categoryId, category.getTitle(), category.getImage(0).getImageUrl()); + categoryModels.add(categoryModel); } } - return categories; + Gson gson = new Gson(); + String jsonString = gson.toJson(categoryModels); + PrefUtil.putString(context, categoryPrefId, jsonString); } private Locale getLocale(Context context) { diff --git a/app/src/main/java/com/aurora/store/task/DeliveryData.java b/app/src/main/java/com/aurora/store/task/DeliveryData.java index ce76041fe..605493196 100644 --- a/app/src/main/java/com/aurora/store/task/DeliveryData.java +++ b/app/src/main/java/com/aurora/store/task/DeliveryData.java @@ -25,9 +25,8 @@ import android.content.Context; import com.aurora.store.Constants; import com.aurora.store.exception.NotPurchasedException; import com.aurora.store.model.App; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PrefUtil; import com.dragons.aurora.playstoreapiv2.AndroidAppDeliveryData; import com.dragons.aurora.playstoreapiv2.BuyResponse; import com.dragons.aurora.playstoreapiv2.DeliveryResponse; diff --git a/app/src/main/java/com/aurora/store/task/DeviceInfoBuilder.java b/app/src/main/java/com/aurora/store/task/DeviceInfoBuilder.java index 5aee9edcc..c291b07d2 100644 --- a/app/src/main/java/com/aurora/store/task/DeviceInfoBuilder.java +++ b/app/src/main/java/com/aurora/store/task/DeviceInfoBuilder.java @@ -34,8 +34,8 @@ import android.util.DisplayMetrics; import com.aurora.store.provider.EglExtensionProvider; import com.aurora.store.provider.NativeDeviceInfoProvider; import com.aurora.store.provider.NativeGsfVersionProvider; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PathUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PathUtil; import java.io.File; import java.io.FileWriter; diff --git a/app/src/main/java/com/aurora/store/task/FeaturedAppsTask.java b/app/src/main/java/com/aurora/store/task/FeaturedAppsTask.java index 3b7412dc6..404c2ed9b 100644 --- a/app/src/main/java/com/aurora/store/task/FeaturedAppsTask.java +++ b/app/src/main/java/com/aurora/store/task/FeaturedAppsTask.java @@ -24,7 +24,7 @@ import android.content.Context; import com.aurora.store.iterator.CustomAppListIterator; import com.aurora.store.model.App; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import com.dragons.aurora.playstoreapiv2.CategoryAppsIterator; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; @@ -37,8 +37,7 @@ public class FeaturedAppsTask extends BaseTask { super(context); } - public List getApps(String categoryId, GooglePlayAPI.SUBCATEGORY subCategory) throws Exception { - final GooglePlayAPI api = getApi(); + public List getApps(GooglePlayAPI api, String categoryId, GooglePlayAPI.SUBCATEGORY subCategory) throws Exception { final CustomAppListIterator iterator = new CustomAppListIterator(new CategoryAppsIterator(api, categoryId, subCategory)); List apps = new ArrayList<>(); while (iterator.hasNext() && apps.isEmpty()) { diff --git a/app/src/main/java/com/aurora/store/task/GZipTask.java b/app/src/main/java/com/aurora/store/task/GZipTask.java index e2cda908c..6e795f8ad 100644 --- a/app/src/main/java/com/aurora/store/task/GZipTask.java +++ b/app/src/main/java/com/aurora/store/task/GZipTask.java @@ -3,7 +3,7 @@ package com.aurora.store.task; import android.content.Context; import android.content.ContextWrapper; -import com.aurora.store.utility.Log; +import com.aurora.store.util.Log; import org.apache.commons.io.IOUtils; diff --git a/app/src/main/java/com/aurora/store/task/GeoSpoofTask.java b/app/src/main/java/com/aurora/store/task/GeoSpoofTask.java index 6905a7283..a58320710 100644 --- a/app/src/main/java/com/aurora/store/task/GeoSpoofTask.java +++ b/app/src/main/java/com/aurora/store/task/GeoSpoofTask.java @@ -31,9 +31,9 @@ import android.os.SystemClock; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PrefUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import java.io.IOException; diff --git a/app/src/main/java/com/aurora/store/task/InstalledAppsTask.java b/app/src/main/java/com/aurora/store/task/InstalledAppsTask.java index a1e072846..c7bbbae8f 100644 --- a/app/src/main/java/com/aurora/store/task/InstalledAppsTask.java +++ b/app/src/main/java/com/aurora/store/task/InstalledAppsTask.java @@ -24,31 +24,30 @@ import android.content.Context; import android.text.TextUtils; import com.aurora.store.model.App; -import com.aurora.store.utility.PackageUtil; +import com.aurora.store.util.PackageUtil; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import java.io.IOException; import java.util.ArrayList; import java.util.List; public class InstalledAppsTask extends UpdatableAppsTask { - public InstalledAppsTask(Context context) { - super(context); + public InstalledAppsTask(GooglePlayAPI api, Context context) { + super(api, context); } - public List getInstalledApps(boolean removeSystemApps) throws Exception { + public List getInstalledApps() throws Exception { List appList = new ArrayList<>(); - List packageList = getInstalledApps(); - if (removeSystemApps) - packageList = filterSystemApps(packageList); + List packageList = getLocalInstalledApps(); packageList = filterBlacklistedApps(packageList); for (App app : getAppsFromPlayStore(packageList)) { final String packageName = app.getPackageName(); - if (TextUtils.isEmpty(packageName) || !packageList.contains(packageName)) { + + if (TextUtils.isEmpty(packageName)) { continue; } - final App installedApp = getInstalledApp(packageName); + final App installedApp = PackageUtil.getAppFromPackageName(getPackageManager(), packageName); app = addInstalledAppInfo(app, installedApp); appList.add(app); } @@ -57,27 +56,18 @@ public class InstalledAppsTask extends UpdatableAppsTask { public List getAllApps() throws Exception { List appList = new ArrayList<>(); - List packageList = getInstalledApps(); + List packageList = getLocalInstalledApps(); for (App app : getAppsFromPlayStore(packageList)) { final String packageName = app.getPackageName(); - if (TextUtils.isEmpty(packageName) || !packageList.contains(packageName)) { + + if (TextUtils.isEmpty(packageName)) { continue; } - final App installedApp = getInstalledApp(packageName); + final App installedApp = PackageUtil.getAppFromPackageName(getPackageManager(), packageName); app = addInstalledAppInfo(app, installedApp); appList.add(app); } return appList; } - - private List filterSystemApps(List packageList) { - List newPackageList = new ArrayList<>(); - for (String packageName : packageList) { - if (!PackageUtil.isSystemApp(getPackageManager(), packageName)) { - newPackageList.add(packageName); - } - } - return newPackageList; - } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/task/LiveUpdate.java b/app/src/main/java/com/aurora/store/task/LiveUpdate.java index 5bb62a20e..52a613adb 100644 --- a/app/src/main/java/com/aurora/store/task/LiveUpdate.java +++ b/app/src/main/java/com/aurora/store/task/LiveUpdate.java @@ -7,9 +7,9 @@ import com.aurora.store.download.DownloadManager; import com.aurora.store.download.RequestBuilder; import com.aurora.store.model.App; import com.aurora.store.notification.GeneralNotification; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.Util; import com.dragons.aurora.playstoreapiv2.AndroidAppDeliveryData; import com.tonyodev.fetch2.AbstractFetchGroupListener; import com.tonyodev.fetch2.Download; @@ -25,8 +25,9 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -public class LiveUpdate extends BaseTask { +public class LiveUpdate { + private Context context; private Fetch fetch; private FetchListener fetchListener; private GeneralNotification notification; @@ -35,11 +36,11 @@ public class LiveUpdate extends BaseTask { private int progress; public LiveUpdate(Context context) { - super(context); + this.context = context; } - public void enqueueUpdate(App mApp, AndroidAppDeliveryData deliveryData) { - app = mApp; + public void enqueueUpdate(App app, AndroidAppDeliveryData deliveryData) { + this.app = app; fetch = DownloadManager.getFetchInstance(context); notification = new GeneralNotification(context, app); hashCode = app.getPackageName().hashCode(); @@ -118,10 +119,11 @@ public class LiveUpdate extends BaseTask { } @Override - public void onCancelled(int groupId, @NotNull Download download, @NotNull FetchGroup fetchGroup) { + public void onDeleted(int groupId, @NotNull Download download, @NotNull FetchGroup fetchGroup) { + super.onDeleted(groupId, download, fetchGroup); if (groupId == hashCode) { notification.notifyCancelled(); - Log.e("Cancelled %s", app.getDisplayName()); + Log.i("Cancelled %s", app.getDisplayName()); } } }; diff --git a/app/src/main/java/com/aurora/store/task/NetworkTask.java b/app/src/main/java/com/aurora/store/task/NetworkTask.java index fe0b8af53..e9ac70ade 100644 --- a/app/src/main/java/com/aurora/store/task/NetworkTask.java +++ b/app/src/main/java/com/aurora/store/task/NetworkTask.java @@ -3,7 +3,7 @@ package com.aurora.store.task; import android.content.Context; import android.content.ContextWrapper; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Util; import okhttp3.OkHttpClient; import okhttp3.Request; diff --git a/app/src/main/java/com/aurora/store/task/ObservableDeliveryData.java b/app/src/main/java/com/aurora/store/task/ObservableDeliveryData.java index 886df4432..fdd8ccd0d 100644 --- a/app/src/main/java/com/aurora/store/task/ObservableDeliveryData.java +++ b/app/src/main/java/com/aurora/store/task/ObservableDeliveryData.java @@ -22,12 +22,12 @@ package com.aurora.store.task; import android.content.Context; +import com.aurora.store.AuroraApplication; import com.aurora.store.Constants; import com.aurora.store.exception.NotPurchasedException; import com.aurora.store.model.App; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PrefUtil; import com.dragons.aurora.playstoreapiv2.AndroidAppDeliveryData; import com.dragons.aurora.playstoreapiv2.BuyResponse; import com.dragons.aurora.playstoreapiv2.DeliveryResponse; @@ -48,7 +48,7 @@ public class ObservableDeliveryData extends BaseTask { public Observable getDeliveryData(App app) { return Observable.create(emitter -> { - GooglePlayAPI api = getApi(); + GooglePlayAPI api = AuroraApplication.api; purchase(api, app); delivery(api, app); DeliveryDataBundle deliveryDataBundle = new DeliveryDataBundle(app, deliveryData); diff --git a/app/src/main/java/com/aurora/store/task/ReviewsHelper.java b/app/src/main/java/com/aurora/store/task/ReviewsHelper.java index 0b25bf8c5..e944201d5 100644 --- a/app/src/main/java/com/aurora/store/task/ReviewsHelper.java +++ b/app/src/main/java/com/aurora/store/task/ReviewsHelper.java @@ -20,22 +20,19 @@ package com.aurora.store.task; -import android.content.Context; - import com.aurora.store.iterator.ReviewStorageIterator; import com.aurora.store.model.Review; import java.util.ArrayList; import java.util.List; -public class ReviewsHelper extends BaseTask { - - private List mReviewList = new ArrayList<>(); +public class ReviewsHelper { + private List reviewList = new ArrayList<>(); private ReviewStorageIterator iterator; - public ReviewsHelper(Context context) { - super(context); + public ReviewsHelper(ReviewStorageIterator iterator) { + this.iterator = iterator; } public void setIterator(ReviewStorageIterator iterator) { @@ -43,8 +40,8 @@ public class ReviewsHelper extends BaseTask { } public List getReviews() { - mReviewList.clear(); - mReviewList.addAll(iterator.next()); - return mReviewList; + reviewList.clear(); + reviewList.addAll(iterator.next()); + return reviewList; } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/task/SearchTask.java b/app/src/main/java/com/aurora/store/task/SearchTask.java index 7cc742c14..69292ac82 100644 --- a/app/src/main/java/com/aurora/store/task/SearchTask.java +++ b/app/src/main/java/com/aurora/store/task/SearchTask.java @@ -22,20 +22,25 @@ package com.aurora.store.task; import android.content.Context; -import com.aurora.store.Filter; import com.aurora.store.exception.InvalidApiException; import com.aurora.store.iterator.CustomAppListIterator; import com.aurora.store.manager.CategoryManager; +import com.aurora.store.manager.FilterManager; import com.aurora.store.model.App; -import com.aurora.store.utility.Util; +import com.aurora.store.model.FilterModel; +import com.aurora.store.util.Util; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; -public class SearchTask extends BaseTask { +public class SearchTask { + + private Context context; public SearchTask(Context context) { - super(context); + this.context = context; } public List getSearchResults(CustomAppListIterator iterator) throws Exception { @@ -51,12 +56,14 @@ public class SearchTask extends BaseTask { return apps; } - public List getNextBatch(CustomAppListIterator iterator) { - CategoryManager categoryManager = new CategoryManager(getContext()); - com.aurora.store.model.Filter filter = new Filter(getContext()).getFilterPreferences(); + private List getNextBatch(CustomAppListIterator iterator) { + CategoryManager categoryManager = new CategoryManager(context); + FilterModel filterModel = FilterManager.getFilterPreferences(context); List apps = new ArrayList<>(); + if (!iterator.hasNext()) + return apps; for (App app : iterator.next()) { - if (categoryManager.fits(app.getCategoryId(), filter.getCategory())) { + if (categoryManager.fits(app.getCategoryId(), filterModel.getCategory())) { apps.add(app); } } @@ -65,4 +72,22 @@ public class SearchTask extends BaseTask { else return apps; } + + private List filterGoogleApps(List apps) { + Set gAppsSet = new HashSet<>(); + gAppsSet.add("com.chrome.beta"); + gAppsSet.add("com.chrome.canary"); + gAppsSet.add("com.chrome.dev"); + gAppsSet.add("com.android.chrome"); + gAppsSet.add("com.niksoftware.snapseed"); + gAppsSet.add("com.google.toontastic"); + + List appList = new ArrayList<>(); + for (App app : apps) { + if (!app.getPackageName().startsWith("com.google") && !gAppsSet.contains(app.getPackageName())) { + appList.add(app); + } + } + return appList; + } } diff --git a/app/src/main/java/com/aurora/store/fragment/intro/IntroBaseFragment.java b/app/src/main/java/com/aurora/store/task/SuggestionTask.java similarity index 62% rename from app/src/main/java/com/aurora/store/fragment/intro/IntroBaseFragment.java rename to app/src/main/java/com/aurora/store/task/SuggestionTask.java index 1ba6c416c..d46b49a96 100644 --- a/app/src/main/java/com/aurora/store/fragment/intro/IntroBaseFragment.java +++ b/app/src/main/java/com/aurora/store/task/SuggestionTask.java @@ -18,20 +18,22 @@ * */ -package com.aurora.store.fragment.intro; +package com.aurora.store.task; -import android.content.Context; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; +import com.dragons.aurora.playstoreapiv2.SearchSuggestEntry; -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; +import java.util.List; -public class IntroBaseFragment extends Fragment { +public class SuggestionTask { - protected Context context; + private GooglePlayAPI api; - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.context = context; + public SuggestionTask(GooglePlayAPI api) { + this.api = api; } -} + + public List getSearchSuggestions(String query) throws Exception { + return api.searchSuggest(query).getEntryList(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/task/UpdatableAppsTask.java b/app/src/main/java/com/aurora/store/task/UpdatableAppsTask.java index 9ae0ece9b..b5ad64e39 100644 --- a/app/src/main/java/com/aurora/store/task/UpdatableAppsTask.java +++ b/app/src/main/java/com/aurora/store/task/UpdatableAppsTask.java @@ -21,42 +21,42 @@ package com.aurora.store.task; import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.text.TextUtils; +import com.aurora.store.exception.CredentialsEmptyException; import com.aurora.store.exception.MalformedRequestException; import com.aurora.store.manager.BlacklistManager; import com.aurora.store.model.App; import com.aurora.store.model.AppBuilder; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; import com.dragons.aurora.playstoreapiv2.BulkDetailsEntry; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import java.io.IOException; import java.util.ArrayList; import java.util.List; public class UpdatableAppsTask extends AllAppsTask { - public UpdatableAppsTask(Context context) { + private GooglePlayAPI api; + + public UpdatableAppsTask(GooglePlayAPI api, Context context) { super(context); + this.api = api; } public List getUpdatableApps() throws Exception { List appList = new ArrayList<>(); - List packageList = getInstalledApps(); + List packageList = getLocalInstalledApps(); packageList = filterBlacklistedApps(packageList); for (App app : getAppsFromPlayStore(packageList)) { final String packageName = app.getPackageName(); - if (TextUtils.isEmpty(packageName) || !packageList.contains(packageName)) { + if (TextUtils.isEmpty(packageName)) { continue; } - final App installedApp = getInstalledApp(packageName); + final App installedApp = PackageUtil.getAppFromPackageName(getPackageManager(), packageName); app = addInstalledAppInfo(app, installedApp); - if (installedApp != null && installedApp.getVersionCode() < app.getVersionCode()) { appList.add(app); } @@ -71,7 +71,7 @@ public class UpdatableAppsTask extends AllAppsTask { private List getRemoteAppList(List packageNames) throws Exception { final List appList = new ArrayList<>(); try { - final List bulkDetailsEntries = getApi().bulkDetails(packageNames).getEntryList(); + final List bulkDetailsEntries = api.bulkDetails(packageNames).getEntryList(); for (BulkDetailsEntry bulkDetailsEntry : bulkDetailsEntries) { if (!bulkDetailsEntry.hasDoc()) { continue; @@ -81,7 +81,9 @@ public class UpdatableAppsTask extends AllAppsTask { } catch (Exception e) { if (e instanceof MalformedRequestException) { Log.e("Malformed Request : %s", e.getMessage()); - } else + } else if (e instanceof NullPointerException) + throw new CredentialsEmptyException(); + else throw e; } return appList; @@ -97,17 +99,8 @@ public class UpdatableAppsTask extends AllAppsTask { return appFromMarket; } - public App getInstalledApp(String packageName) { - try { - PackageInfo packageInfo = getPackageManager().getPackageInfo(packageName, 0); - return PackageUtil.getInstalledApp(getPackageManager(), packageInfo.packageName); - } catch (PackageManager.NameNotFoundException e) { - return null; - } - } - public List filterBlacklistedApps(List packageList) { - packageList.removeAll(new BlacklistManager(context).get()); + packageList.removeAll(new BlacklistManager(getContext()).get()); return packageList; } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/task/UserProfiler.java b/app/src/main/java/com/aurora/store/task/UserProfiler.java deleted file mode 100644 index d3e6417f0..000000000 --- a/app/src/main/java/com/aurora/store/task/UserProfiler.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.task; - -import android.content.Context; - -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.PrefUtil; -import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; -import com.dragons.aurora.playstoreapiv2.Image; -import com.dragons.aurora.playstoreapiv2.UserProfile; - -public class UserProfiler extends BaseTask { - public UserProfiler(Context context) { - super(context); - } - - public boolean getUserProfile() throws Exception { - GooglePlayAPI api = getApi(); - UserProfile userProfile = api.userProfile().getUserProfile(); - if (userProfile == null) - return false; - else { - PrefUtil.putString(context, Accountant.PROFILE_NAME, userProfile.getName()); - for (Image image : userProfile.getImageList()) { - if (image.getImageType() == GooglePlayAPI.IMAGE_TYPE_APP_ICON) { - PrefUtil.putString(context, Accountant.PROFILE_AVATAR, image.getImageUrl()); - } - } - return true; - } - } -} diff --git a/app/src/main/java/com/aurora/store/activity/AccountsActivity.java b/app/src/main/java/com/aurora/store/ui/accounts/AccountsActivity.java similarity index 86% rename from app/src/main/java/com/aurora/store/activity/AccountsActivity.java rename to app/src/main/java/com/aurora/store/ui/accounts/AccountsActivity.java index 37e959ada..d1a7615b5 100644 --- a/app/src/main/java/com/aurora/store/activity/AccountsActivity.java +++ b/app/src/main/java/com/aurora/store/ui/accounts/AccountsActivity.java @@ -18,34 +18,30 @@ * */ -package com.aurora.store.activity; +package com.aurora.store.ui.accounts; import android.os.Bundle; import android.view.MenuItem; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.FragmentTransaction; import com.aurora.store.R; -import com.aurora.store.fragment.AccountsFragment; -import com.aurora.store.utility.ThemeUtil; +import com.aurora.store.ui.accounts.fragment.AccountsFragment; +import com.aurora.store.ui.single.activity.BaseActivity; import butterknife.BindView; import butterknife.ButterKnife; -public class AccountsActivity extends AppCompatActivity { +public class AccountsActivity extends BaseActivity { @BindView(R.id.toolbar) Toolbar toolbar; - private ThemeUtil themeUtil = new ThemeUtil(); - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - themeUtil.onCreate(this); setContentView(R.layout.activity_accounts); ButterKnife.bind(this); setupActionbar(); @@ -65,7 +61,6 @@ public class AccountsActivity extends AppCompatActivity { @Override protected void onResume() { super.onResume(); - themeUtil.onResume(this); } private void setupActionbar() { diff --git a/app/src/main/java/com/aurora/store/fragment/AccountsFragment.java b/app/src/main/java/com/aurora/store/ui/accounts/fragment/AccountsFragment.java similarity index 94% rename from app/src/main/java/com/aurora/store/fragment/AccountsFragment.java rename to app/src/main/java/com/aurora/store/ui/accounts/fragment/AccountsFragment.java index 510998192..30bb3dbd4 100644 --- a/app/src/main/java/com/aurora/store/fragment/AccountsFragment.java +++ b/app/src/main/java/com/aurora/store/ui/accounts/fragment/AccountsFragment.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.fragment; +package com.aurora.store.ui.accounts.fragment; import android.content.Context; import android.content.Intent; @@ -41,14 +41,14 @@ import androidx.fragment.app.Fragment; import com.aurora.store.GlideApp; import com.aurora.store.R; -import com.aurora.store.activity.GoogleLoginActivity; -import com.aurora.store.activity.SettingsActivity; import com.aurora.store.api.PlayStoreApiAuthenticator; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.NetworkUtil; -import com.aurora.store.utility.PrefUtil; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.ui.single.activity.GoogleLoginActivity; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.NetworkUtil; +import com.aurora.store.util.PrefUtil; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.dragons.aurora.playstoreapiv2.Image; import com.dragons.aurora.playstoreapiv2.UserProfile; @@ -86,7 +86,7 @@ public class AccountsFragment extends Fragment { LinearLayout logoutLayout; @BindView(R.id.login_google) RelativeLayout loginGoogle; - @BindView(R.id.avatar) + @BindView(R.id.img) ImageView imgAvatar; @BindView(R.id.user_name) TextView txtName; @@ -140,7 +140,7 @@ public class AccountsFragment extends Fragment { public void openLoginActivity() { context.startActivity(new Intent(context, GoogleLoginActivity.class)); if (getActivity() instanceof SettingsActivity) - ((SettingsActivity) getActivity()).finish(); + getActivity().finish(); } @OnClick(R.id.btn_negative) @@ -159,7 +159,7 @@ public class AccountsFragment extends Fragment { disposable.add(Observable.fromCallable(() -> PlayStoreApiAuthenticator .login(context)) .map(api -> api.userProfile().getUserProfile()) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe(d -> { btnAnonymous.setText(getText(R.string.action_logging_in)); @@ -227,7 +227,7 @@ public class AccountsFragment extends Fragment { GlideApp .with(this) .load(Accountant.getImageURL(context)) - .placeholder(R.drawable.ic_avatar_boy) + .placeholder(R.drawable.circle_bg) .circleCrop() .into(imgAvatar); txtName.setText(Accountant.isAnonymous(context) ? getText(R.string.account_dummy) : Accountant.getUserName(context)); diff --git a/app/src/main/java/com/aurora/store/ui/category/CategoryAppsActivity.java b/app/src/main/java/com/aurora/store/ui/category/CategoryAppsActivity.java new file mode 100644 index 000000000..3df0d76de --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/category/CategoryAppsActivity.java @@ -0,0 +1,110 @@ +package com.aurora.store.ui.category; + +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.graphics.ColorUtils; +import androidx.navigation.NavController; +import androidx.navigation.NavDestination; +import androidx.navigation.Navigation; +import androidx.navigation.ui.NavigationUI; + +import com.aurora.store.R; +import com.aurora.store.sheet.FilterBottomSheet; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.util.ViewUtil; +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; +import com.google.android.material.textfield.TextInputEditText; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +public class CategoryAppsActivity extends BaseActivity { + + public static String categoryId; + public static String categoryName; + + @BindView(R.id.search_view) + TextInputEditText searchView; + @BindView(R.id.bottom_navigation) + BottomNavigationView bottomNavigationView; + @BindView(R.id.filter_fab) + ExtendedFloatingActionButton filterFab; + @BindView(R.id.action2) + AppCompatImageView action2; + + static boolean matchDestination(@NonNull NavDestination destination, @IdRes int destId) { + NavDestination currentDestination = destination; + while (currentDestination.getId() != destId && currentDestination.getParent() != null) { + currentDestination = currentDestination.getParent(); + } + return currentDestination.getId() == destId; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_category_apps); + ButterKnife.bind(this); + action2.setVisibility(View.INVISIBLE); + onNewIntent(getIntent()); + searchView.setFocusable(false); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + if (intent != null) { + categoryId = intent.getStringExtra("CategoryId"); + categoryName = intent.getStringExtra("CategoryName"); + searchView.setText(categoryName); + setupNavigation(); + } + } + + @OnClick(R.id.action1) + public void goBack() { + onBackPressed(); + } + + @OnClick(R.id.filter_fab) + public void showFilterDialog() { + FilterBottomSheet filterSheet = new FilterBottomSheet(); + filterSheet.show(getSupportFragmentManager(), "FILTER"); + } + + private void setupNavigation() { + int backGroundColor = ViewUtil.getStyledAttribute(this, android.R.attr.colorBackground); + bottomNavigationView.setBackgroundColor(ColorUtils.setAlphaComponent(backGroundColor, 245)); + + NavController navController = Navigation.findNavController(this, R.id.nav_host_category); + + //Avoid Adding same fragment to NavController, if clicked on current BottomNavigation item + bottomNavigationView.setOnNavigationItemSelectedListener(item -> { + if (item.getItemId() == bottomNavigationView.getSelectedItemId()) + return false; + NavigationUI.onNavDestinationSelected(item, navController); + return true; + }); + + //Check correct BottomNavigation item, if navigation_main is done programmatically + navController.addOnDestinationChangedListener((controller, destination, arguments) -> { + final Menu menu = bottomNavigationView.getMenu(); + final int size = menu.size(); + for (int i = 0; i < size; i++) { + MenuItem item = menu.getItem(i); + if (matchDestination(destination, item.getItemId())) { + item.setChecked(true); + } + } + }); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/category/CategoryAppsModel.java b/app/src/main/java/com/aurora/store/ui/category/CategoryAppsModel.java new file mode 100644 index 000000000..6563a00ff --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/category/CategoryAppsModel.java @@ -0,0 +1,97 @@ +package com.aurora.store.ui.category; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.enums.ErrorType; +import com.aurora.store.exception.CredentialsEmptyException; +import com.aurora.store.exception.InvalidApiException; +import com.aurora.store.iterator.CustomAppListIterator; +import com.aurora.store.manager.FilterManager; +import com.aurora.store.model.App; +import com.aurora.store.task.CategoryAppsTask; +import com.dragons.aurora.playstoreapiv2.AuthException; +import com.dragons.aurora.playstoreapiv2.CategoryAppsIterator; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; + +import java.net.UnknownHostException; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class CategoryAppsModel extends AndroidViewModel { + + private Application application; + private CompositeDisposable disposable = new CompositeDisposable(); + + private GooglePlayAPI api; + private CategoryAppsTask categoryAppsTask; + private CustomAppListIterator iterator; + + + private MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + private MutableLiveData errorTypeMutableLiveData = new MutableLiveData<>(); + + public CategoryAppsModel(@NonNull Application application) { + super(application); + this.application = application; + this.api = AuroraApplication.api; + this.categoryAppsTask = new CategoryAppsTask(application); + } + + public LiveData getError() { + return errorTypeMutableLiveData; + } + + public LiveData> getCategoryApps() { + return listMutableLiveData; + } + + public void fetchCategoryApps(String categoryId, GooglePlayAPI.SUBCATEGORY subcategory, boolean shouldIterate) { + disposable.clear(); + if (!shouldIterate) + getIterator(categoryId, subcategory); + disposable.add(Observable.fromCallable(() -> categoryAppsTask + .getApps(iterator)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + listMutableLiveData.setValue(appList); + }, err -> { + err.printStackTrace(); + if (err instanceof CredentialsEmptyException || err instanceof InvalidApiException) + errorTypeMutableLiveData.setValue(ErrorType.LOGOUT_ERR); + else if (err instanceof AuthException) + errorTypeMutableLiveData.setValue(ErrorType.SESSION_EXPIRED); + else if (err instanceof UnknownHostException) + errorTypeMutableLiveData.setValue(ErrorType.NO_NETWORK); + else + errorTypeMutableLiveData.setValue(ErrorType.UNKNOWN); + })); + } + + private void getIterator(String categoryId, GooglePlayAPI.SUBCATEGORY subcategory) { + try { + CategoryAppsIterator categoryAppsIterator = new CategoryAppsIterator(api, categoryId, subcategory); + iterator = new CustomAppListIterator(categoryAppsIterator); + iterator.setFilterEnabled(true); + iterator.setFilterModel(FilterManager.getFilterPreferences(application)); + } catch (Exception err) { + err.printStackTrace(); + } + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java b/app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java new file mode 100644 index 000000000..b65a88c48 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java @@ -0,0 +1,193 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.category.fragment; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.Constants; +import com.aurora.store.EndlessScrollListener; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.section.EndlessResultSection; +import com.aurora.store.ui.category.CategoryAppsActivity; +import com.aurora.store.ui.category.CategoryAppsModel; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; + +public class SubCategoryFragment extends Fragment implements EndlessResultSection.ClickListener, + SharedPreferences.OnSharedPreferenceChangeListener { + + @BindView(R.id.recycler) + RecyclerView recyclerView; + + private Context context; + private GooglePlayAPI.SUBCATEGORY subcategory = GooglePlayAPI.SUBCATEGORY.TOP_FREE; + private SharedPreferences sharedPreferences; + + private CategoryAppsModel model; + private EndlessResultSection section; + private SectionedRecyclerViewAdapter adapter; + + private GooglePlayAPI.SUBCATEGORY getSubcategory() { + return subcategory; + } + + private void setSubcategory(Bundle bundle) { + String category = bundle.getString("SUBCATEGORY"); + if (category != null) + switch (category) { + case "TOP_FREE": + subcategory = GooglePlayAPI.SUBCATEGORY.TOP_FREE; + break; + case "TOP_GROSSING": + subcategory = GooglePlayAPI.SUBCATEGORY.TOP_GROSSING; + break; + default: + subcategory = GooglePlayAPI.SUBCATEGORY.MOVERS_SHAKERS; + } + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + this.context = context; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + sharedPreferences = Util.getPrefs(context); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_category_applist, container, false); + ButterKnife.bind(this, view); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + Bundle bundle = getArguments(); + if (bundle != null) + setSubcategory(bundle); + setupRecycler(); + + model = ViewModelProviders.of(this).get(CategoryAppsModel.class); + model.getCategoryApps().observe(this, appList -> { + dispatchAppsToAdapter(appList); + }); + model.fetchCategoryApps(CategoryAppsActivity.categoryId, getSubcategory(), false); + } + + @Override + public void onResume() { + super.onResume(); + sharedPreferences.registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onDestroy() { + sharedPreferences.registerOnSharedPreferenceChangeListener(this); + super.onDestroy(); + } + + private void dispatchAppsToAdapter(List newList) { + List oldList = section.getList(); + if (oldList.isEmpty()) { + section.updateList(newList); + adapter.notifyDataSetChanged(); + } else { + if (!newList.isEmpty()) { + for (App app : newList) + section.add(app); + adapter.notifyItemInserted(section.getCount() - 1); + } + } + } + + private void setupRecycler() { + LinearLayoutManager layoutManager = new LinearLayoutManager(context, RecyclerView.VERTICAL, false); + adapter = new SectionedRecyclerViewAdapter(); + section = new EndlessResultSection(context, this); + adapter.addSection(section); + + recyclerView.setAdapter(adapter); + + EndlessScrollListener endlessScrollListener = new EndlessScrollListener(layoutManager) { + @Override + public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { + model.fetchCategoryApps(CategoryAppsActivity.categoryId, getSubcategory(), true); + } + }; + recyclerView.addOnScrollListener(endlessScrollListener); + recyclerView.setLayoutManager(layoutManager); + } + + private void purgeAdapterData() { + section.purgeData(); + adapter.notifyDataSetChanged(); + } + + @Override + public void onClick(App app) { + DetailsActivity.app = app; + Intent intent = new Intent(context, DetailsActivity.class); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, app.getPackageName()); + context.startActivity(intent, ViewUtil.getEmptyActivityBundle((AppCompatActivity) context)); + } + + @Override + public void onLongClick(App app) { + + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(Constants.PREFERENCE_FILTER_APPS)) { + purgeAdapterData(); + model.fetchCategoryApps(CategoryAppsActivity.categoryId, getSubcategory(), false); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java b/app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java new file mode 100644 index 000000000..9a7d1cc0f --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java @@ -0,0 +1,279 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.details; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.lifecycle.ViewModelProviders; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.manager.BlacklistManager; +import com.aurora.store.manager.FavouriteListManager; +import com.aurora.store.model.App; +import com.aurora.store.ui.details.views.AbstractDetails; +import com.aurora.store.ui.details.views.ActionButton; +import com.aurora.store.ui.details.views.AppLinks; +import com.aurora.store.ui.details.views.Beta; +import com.aurora.store.ui.details.views.ExodusPrivacy; +import com.aurora.store.ui.details.views.GeneralDetails; +import com.aurora.store.ui.details.views.Reviews; +import com.aurora.store.ui.details.views.Screenshot; +import com.aurora.store.ui.details.views.Video; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.ui.single.activity.DownloadsActivity; +import com.aurora.store.ui.single.activity.ManualDownloadActivity; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.Util; +import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class DetailsActivity extends BaseActivity { + + public static App app; + + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.coordinator) + CoordinatorLayout coordinator; + @BindView(R.id.icon) + AppCompatImageView icon; + @BindView(R.id.displayName) + AppCompatTextView txtDisplayName; + @BindView(R.id.devName) + AppCompatTextView txtDevName; + @BindView(R.id.packageName) + AppCompatTextView txtPackageName; + + private ActionButton actionButton; + private String packageName; + private FavouriteListManager favouriteListManager; + private DetailsAppModel model; + + private CompositeDisposable disposable = new CompositeDisposable(); + + private BroadcastReceiver globalInstallReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getData() == null || !TextUtils.equals(packageName, intent.getData().getSchemeSpecificPart())) { + return; + } + ContextUtil.runOnUiThread(() -> drawButtons()); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_details); + ButterKnife.bind(this); + setupActionBar(); + + favouriteListManager = new FavouriteListManager(this); + + model = ViewModelProviders.of(this).get(DetailsAppModel.class); + model.getAppDetails().observe(this, detailApp -> { + draw(detailApp); + }); + + model.getError().observe(this, errorType -> { + switch (errorType) { + case NO_API: + case SESSION_EXPIRED: + Util.validateApi(this); + break; + case NO_NETWORK: { + showSnackBar(coordinator, R.string.error_no_network, -2, v -> { + model.fetchAppDetails(packageName); + }); + break; + } + } + }); + + registerReceiver(globalInstallReceiver, PackageUtil.getFilter()); + disposable.add(AuroraApplication + .getRxBus() + .getBus() + .subscribe(event -> { + switch (event.getSubType()) { + case INSTALLED: + case UNINSTALLED: + drawButtons(); + break; + case API_SUCCESS: + model.fetchAppDetails(packageName); + break; + } + })); + + onNewIntent(getIntent()); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + packageName = getIntentPackageName(intent); + if (TextUtils.isEmpty(packageName)) { + Log.d("No package name provided"); + finish(); + return; + } + Log.i("Getting info about %s", packageName); + model.fetchAppDetails(packageName); + if (app != null) + drawBasic(); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.menu_app_details, menu); + menu.findItem(R.id.action_favourite).setIcon(favouriteListManager.contains(packageName) + ? R.drawable.ic_favourite_red + : R.drawable.ic_favourite_remove); + MenuItem blackList = menu.findItem(R.id.action_blacklist); + if (!PackageUtil.isInstalled(this, packageName)) + blackList.setVisible(false); + return true; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + case R.id.action_favourite: + if (favouriteListManager.contains(packageName)) { + favouriteListManager.remove(packageName); + menuItem.setIcon(R.drawable.ic_favourite_remove); + } else { + favouriteListManager.add(packageName); + menuItem.setIcon(R.drawable.ic_favourite_red); + } + return true; + case R.id.action_manual: + startActivity(new Intent(this, ManualDownloadActivity.class)); + return true; + case R.id.action_downloads: + startActivity(new Intent(this, DownloadsActivity.class)); + return true; + case R.id.action_blacklist: + new BlacklistManager(this).add(packageName); + return true; + } + return super.onOptionsItemSelected(menuItem); + } + + @Override + protected void onDestroy() { + try { + app = null; + unregisterReceiver(globalInstallReceiver); + disposable.clear(); + } catch (Exception ignored) { + } + super.onDestroy(); + } + + private void setupActionBar() { + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowTitleEnabled(false); + } + } + + private String getIntentPackageName(Intent intent) { + if (intent.hasExtra(Constants.INTENT_PACKAGE_NAME)) { + return intent.getStringExtra(Constants.INTENT_PACKAGE_NAME); + } else if (intent.getScheme() != null + && (intent.getScheme().equals("market") + || intent.getScheme().equals("http") + || intent.getScheme().equals("https"))) { + return intent.getData().getQueryParameter("id"); + } else if (intent.getExtras() != null) { + Bundle bundle = intent.getExtras(); + return bundle.getString(Constants.INTENT_PACKAGE_NAME); + } + return null; + } + + private void drawBasic() { + GlideApp.with(this) + .asBitmap() + .load(app.getIconInfo().getUrl()) + .transition(new BitmapTransitionOptions().crossFade()) + .transforms(new CenterCrop(), new RoundedCorners(50)) + .into(icon); + txtDisplayName.setText(app.getDisplayName()); + txtPackageName.setText(app.getPackageName()); + } + + private void draw(App appFromMarket) { + app = appFromMarket; + actionButton = new ActionButton(this, app); + disposable.add(Observable.just( + new GeneralDetails(this, app), + new Screenshot(this, app), + new Reviews(this, app), + new ExodusPrivacy(this, app), + new Video(this, app), + new Beta(this, app), + new AppLinks(this, app)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext(AbstractDetails::draw) + .subscribe()); + drawButtons(); + } + + public void drawButtons() { + if (PackageUtil.isInstalled(this, app)) + app.setInstalled(true); + if (actionButton != null) + actionButton.draw(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/details/DetailsAppModel.java b/app/src/main/java/com/aurora/store/ui/details/DetailsAppModel.java new file mode 100644 index 000000000..1bef3d039 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/details/DetailsAppModel.java @@ -0,0 +1,46 @@ +package com.aurora.store.ui.details; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.model.App; +import com.aurora.store.task.AppDetailTask; +import com.aurora.store.viewmodel.BaseViewModel; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class DetailsAppModel extends BaseViewModel { + + private MutableLiveData listMutableLiveData = new MutableLiveData<>(); + + public DetailsAppModel(@NonNull Application application) { + super(application); + } + + public LiveData getAppDetails() { + return listMutableLiveData; + } + + public void fetchAppDetails(String packageName) { + api = AuroraApplication.api; + disposable.add(Observable.fromCallable(() -> new AppDetailTask(getApplication(), api) + .getInfo(packageName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(app -> { + listMutableLiveData.setValue(app); + }, err -> handleError(err))); + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/details/ReviewsActivity.java b/app/src/main/java/com/aurora/store/ui/details/ReviewsActivity.java new file mode 100644 index 000000000..c0dea2038 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/details/ReviewsActivity.java @@ -0,0 +1,159 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.details; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.Toolbar; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.Constants; +import com.aurora.store.EndlessScrollListener; +import com.aurora.store.R; +import com.aurora.store.model.Review; +import com.aurora.store.section.ReviewsSection; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.viewmodel.ReviewsModel; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; +import com.google.android.material.chip.ChipGroup; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; + +public class ReviewsActivity extends BaseActivity { + + private static final String TAG_REVIEWS = "TAG_REVIEWS"; + + @BindView(R.id.reviews_recycler) + RecyclerView recyclerView; + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.chip_group) + ChipGroup chipGroup; + + private String packageName; + private ReviewsModel reviewsModel; + private ReviewsSection reviewsSection; + private SectionedRecyclerViewAdapter viewAdapter; + + private GooglePlayAPI.REVIEW_SORT reviewSort = GooglePlayAPI.REVIEW_SORT.HELPFUL; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_reviews); + ButterKnife.bind(this); + setupActionBar(); + setupRecycler(); + + Intent intent = getIntent(); + if (intent != null) { + packageName = intent.getStringExtra(Constants.INTENT_PACKAGE_NAME); + if (packageName != null && !packageName.isEmpty()) { + reviewsModel = ViewModelProviders.of(this).get(ReviewsModel.class); + reviewsModel.getReviews().observe(this, reviewList -> { + dispatchToAdapter(reviewList); + }); + reviewsModel.fetchReviews(packageName, reviewSort, true); + } + } + + chipGroup.setOnCheckedChangeListener((group, checkedId) -> { + switch (checkedId) { + case R.id.chip_high: + reviewSort = GooglePlayAPI.REVIEW_SORT.HIGHRATING; + break; + case R.id.chip_helpful: + reviewSort = GooglePlayAPI.REVIEW_SORT.HELPFUL; + break; + case R.id.chip_new: + reviewSort = GooglePlayAPI.REVIEW_SORT.NEWEST; + break; + } + removeAllReviews(); + reviewsModel.fetchReviews(packageName, reviewSort, true); + }); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(menuItem); + } + + private void setupActionBar() { + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(getString(R.string.details_reviews)); + } + } + + private void dispatchToAdapter(List newList) { + List oldList = reviewsSection.getList(); + if (oldList.isEmpty()) { + reviewsSection.updateList(newList); + viewAdapter.notifyDataSetChanged(); + } else { + if (!newList.isEmpty()) { + for (Review review : newList) + reviewsSection.add(review); + viewAdapter.notifyItemInserted(reviewsSection.getCount() - 1); + } + } + } + + private void removeAllReviews() { + reviewsSection.clearReviews(); + viewAdapter.notifyDataSetChanged(); + } + + private void setupRecycler() { + reviewsSection = new ReviewsSection(this); + viewAdapter = new SectionedRecyclerViewAdapter(); + viewAdapter.addSection(TAG_REVIEWS, reviewsSection); + LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false); + EndlessScrollListener endlessScrollListener = new EndlessScrollListener(layoutManager) { + @Override + public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { + reviewsModel.fetchReviews(packageName, reviewSort, false); + } + }; + recyclerView.setLayoutManager(layoutManager); + recyclerView.addOnScrollListener(endlessScrollListener); + recyclerView.setAdapter(viewAdapter); + } +} diff --git a/app/src/main/java/com/aurora/store/fragment/details/AbstractHelper.java b/app/src/main/java/com/aurora/store/ui/details/views/AbstractDetails.java similarity index 57% rename from app/src/main/java/com/aurora/store/fragment/details/AbstractHelper.java rename to app/src/main/java/com/aurora/store/ui/details/views/AbstractDetails.java index 4248e5ef7..b67b9ed95 100644 --- a/app/src/main/java/com/aurora/store/fragment/details/AbstractHelper.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/AbstractDetails.java @@ -18,49 +18,46 @@ * */ -package com.aurora.store.fragment.details; +package com.aurora.store.ui.details.views; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.os.Bundle; +import android.transition.TransitionManager; import android.view.View; +import android.view.ViewGroup; import android.widget.TextView; -import androidx.fragment.app.FragmentTransaction; - import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.ManualDownloadActivity; -import com.aurora.store.fragment.DetailsFragment; -import com.aurora.store.fragment.DevAppsFragment; import com.aurora.store.model.App; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.devapps.DevAppsActivity; +import com.aurora.store.ui.single.activity.ManualDownloadActivity; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.ViewUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import butterknife.ButterKnife; -public abstract class AbstractHelper { +public abstract class AbstractDetails { static private final String PLAY_STORE_PACKAGE_NAME = "com.android.vending"; - protected DetailsFragment fragment; - protected App app; - protected View view; + protected DetailsActivity activity; protected Context context; + protected App app; - public AbstractHelper(DetailsFragment fragment, App app) { - this.fragment = fragment; + public AbstractDetails(DetailsActivity activity, App app) { + this.activity = activity; + this.context = activity; this.app = app; - this.view = fragment.getView(); - this.context = fragment.getContext(); - ButterKnife.bind(this, view); + ButterKnife.bind(this, activity); } - public AbstractHelper(ManualDownloadActivity activity, App app) { + public AbstractDetails(ManualDownloadActivity activity, App app) { this.app = app; - this.context = activity; ButterKnife.bind(activity); } @@ -75,44 +72,46 @@ public abstract class AbstractHelper { abstract public void draw(); protected void showDevApps() { - DevAppsFragment devAppsFragment = new DevAppsFragment(); - Bundle arguments = new Bundle(); - arguments.putString("SearchQuery", Constants.PUB_PREFIX + app.getDeveloperName()); - arguments.putString("SearchTitle", app.getDeveloperName()); - devAppsFragment.setArguments(arguments); - fragment.getChildFragmentManager() - .beginTransaction() - .replace(R.id.coordinator, devAppsFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); + Intent intent = new Intent(context, DevAppsActivity.class); + intent.putExtra("SearchQuery", Constants.PUB_PREFIX + app.getDeveloperName()); + intent.putExtra("SearchTitle", app.getDeveloperName()); + context.startActivity(intent, ViewUtil.getEmptyActivityBundle(activity)); } - protected void setText(View v, int viewId, String text) { - TextView textView = view.findViewById(viewId); - if (null != textView) + protected void setText(int viewId, String text) { + TextView textView = activity.findViewById(viewId); + if (null != textView) { textView.setText(text); + } } - protected void setText(View v, int viewId, int stringId, Object... text) { - if (v != null) - setText(v, viewId, v.getResources().getString(stringId, text)); + protected void setText(int viewId, int stringId, Object... text) { + setText(viewId, activity.getResources().getString(stringId, text)); } - protected void hide(View v, int viewID) { - v.findViewById(viewID).setVisibility(View.GONE); + protected void hide(int viewID) { + activity.findViewById(viewID).setVisibility(View.GONE); } - protected void show(View v, int viewID) { - v.findViewById(viewID).setVisibility(View.VISIBLE); + protected void show(ViewGroup viewGroup, int... viewIds) { + TransitionManager.beginDelayedTransition(viewGroup); + for (int viewId : viewIds) { + activity.findViewById(viewId).setVisibility(View.VISIBLE); + } + } + + protected void show(int... viewIds) { + for (int viewId : viewIds) { + activity.findViewById(viewId).setVisibility(View.VISIBLE); + } } protected boolean isPlayStoreInstalled() { - return PackageUtil.isInstalled(context, PLAY_STORE_PACKAGE_NAME); + return PackageUtil.isInstalled(activity, PLAY_STORE_PACKAGE_NAME); } protected void showPurchaseDialog() { - MaterialAlertDialogBuilder mBuilder = new MaterialAlertDialogBuilder(context) + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context) .setTitle(context.getString(R.string.dialog_purchase_title)) .setMessage(context.getString(R.string.dialog_purchase_desc)) .setPositiveButton(context.getString(R.string.dialog_purchase_positive), (dialog, which) -> { @@ -121,30 +120,30 @@ public abstract class AbstractHelper { .setNegativeButton(context.getString(R.string.action_later), (dialog, which) -> { dialog.dismiss(); }); - mBuilder.create(); - mBuilder.show(); + builder.create(); + builder.show(); } protected void showGeoRestrictionDialog() { - MaterialAlertDialogBuilder mBuilder = new MaterialAlertDialogBuilder(context) + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context) .setTitle(context.getString(R.string.dialog_geores_title)) .setMessage(context.getString(R.string.dialog_geores_desc)) .setPositiveButton(context.getString(R.string.action_close), (dialog, which) -> { dialog.dismiss(); }); - mBuilder.create(); - mBuilder.show(); + builder.create(); + builder.show(); } protected void showIncompatibleDialog() { - MaterialAlertDialogBuilder mBuilder = new MaterialAlertDialogBuilder(context) + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context) .setTitle(context.getString(R.string.dialog_incompat_title)) .setMessage(context.getString(R.string.dialog_incompat_desc)) .setPositiveButton(context.getString(R.string.action_close), (dialog, which) -> { dialog.dismiss(); }); - mBuilder.create(); - mBuilder.show(); + builder.create(); + builder.show(); } private void openWebView(String URL) { diff --git a/app/src/main/java/com/aurora/store/fragment/details/ActionButton.java b/app/src/main/java/com/aurora/store/ui/details/views/ActionButton.java similarity index 94% rename from app/src/main/java/com/aurora/store/fragment/details/ActionButton.java rename to app/src/main/java/com/aurora/store/ui/details/views/ActionButton.java index ac7fb373f..805ec2386 100644 --- a/app/src/main/java/com/aurora/store/fragment/details/ActionButton.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/ActionButton.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.fragment.details; +package com.aurora.store.ui.details.views; import android.content.ActivityNotFoundException; import android.content.Intent; @@ -39,17 +39,17 @@ import com.aurora.store.R; import com.aurora.store.download.DownloadManager; import com.aurora.store.download.RequestBuilder; import com.aurora.store.exception.NotPurchasedException; -import com.aurora.store.fragment.DetailsFragment; import com.aurora.store.model.App; import com.aurora.store.notification.GeneralNotification; import com.aurora.store.task.DeliveryData; import com.aurora.store.task.GZipTask; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PackageUtil; -import com.aurora.store.utility.PathUtil; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.PathUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; import com.dragons.aurora.playstoreapiv2.AndroidAppDeliveryData; import com.google.android.material.button.MaterialButton; import com.tonyodev.fetch2.AbstractFetchGroupListener; @@ -70,22 +70,23 @@ import java.util.ArrayList; import java.util.List; import butterknife.BindView; -import butterknife.ButterKnife; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -import static com.aurora.store.utility.ContextUtil.runOnUiThread; +import static com.aurora.store.util.ContextUtil.runOnUiThread; -public class ActionButton extends AbstractHelper { +public class ActionButton extends AbstractDetails { + @BindView(R.id.root_layout) + LinearLayout rootLayout; @BindView(R.id.btn_positive) MaterialButton btnPositive; @BindView(R.id.btn_negative) MaterialButton btnNegative; - @BindView(R.id.viewSwitcher) - ViewSwitcher mViewSwitcher; + @BindView(R.id.view_switcher_action) + ViewSwitcher viewSwitcher; @BindView(R.id.view1) LinearLayout actions_layout; @BindView(R.id.view2) @@ -108,9 +109,8 @@ public class ActionButton extends AbstractHelper { private GeneralNotification notification; private int progress = 0; - public ActionButton(DetailsFragment fragment, App app) { - super(fragment, app); - ButterKnife.bind(this, view); + public ActionButton(DetailsActivity activity, App app) { + super(activity, app); } @Override @@ -130,6 +130,7 @@ public class ActionButton extends AbstractHelper { runOrUpdate(); setupFetch(); + show(rootLayout, R.id.btn_positive); } private void setupFetch() { @@ -152,10 +153,10 @@ public class ActionButton extends AbstractHelper { } private void switchViews(boolean showDownloads) { - if (mViewSwitcher.getCurrentView() == actions_layout && showDownloads) - mViewSwitcher.showNext(); - else if (mViewSwitcher.getCurrentView() == progress_layout && !showDownloads) - mViewSwitcher.showPrevious(); + if (viewSwitcher.getCurrentView() == actions_layout && showDownloads) + viewSwitcher.showNext(); + else if (viewSwitcher.getCurrentView() == progress_layout && !showDownloads) + viewSwitcher.showPrevious(); } private void runOrUpdate() { @@ -440,8 +441,6 @@ public class ActionButton extends AbstractHelper { }); } } - } - - ; + }; } } diff --git a/app/src/main/java/com/aurora/store/fragment/details/AppLinks.java b/app/src/main/java/com/aurora/store/ui/details/views/AppLinks.java similarity index 86% rename from app/src/main/java/com/aurora/store/fragment/details/AppLinks.java rename to app/src/main/java/com/aurora/store/ui/details/views/AppLinks.java index 81e8ef810..99d37dbf7 100644 --- a/app/src/main/java/com/aurora/store/fragment/details/AppLinks.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/AppLinks.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.details; +package com.aurora.store.ui.details.views; import android.content.ActivityNotFoundException; import android.content.Intent; @@ -7,21 +7,21 @@ import android.widget.LinearLayout; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; import com.aurora.store.model.App; import com.aurora.store.sheet.PermissionBottomSheet; -import com.aurora.store.utility.Log; -import com.aurora.store.view.DetailsLinkView; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.view.DetailsLinkView; +import com.aurora.store.util.Log; import butterknife.BindView; -public class AppLinks extends AbstractHelper { +public class AppLinks extends AbstractDetails { @BindView(R.id.layout_link) LinearLayout linkLayout; - public AppLinks(DetailsFragment fragment, App app) { - super(fragment, app); + public AppLinks(DetailsActivity activity, App app) { + super(activity, app); } @Override @@ -54,7 +54,7 @@ public class AppLinks extends AbstractHelper { permLinkView.setOnClickListener(v -> { PermissionBottomSheet profileFragment = new PermissionBottomSheet(); profileFragment.setApp(app); - profileFragment.show(fragment.getChildFragmentManager(), "PERMISSION"); + profileFragment.show(activity.getSupportFragmentManager(), "PERMISSION"); }); permLinkView.build(); linkLayout.addView(permLinkView); @@ -70,7 +70,7 @@ public class AppLinks extends AbstractHelper { i.setType("text/plain"); i.putExtra(Intent.EXTRA_SUBJECT, app.getDisplayName()); i.putExtra(Intent.EXTRA_TEXT, Constants.APP_DETAIL_URL + app.getPackageName()); - context.startActivity(Intent.createChooser(i, fragment.getActivity().getString(R.string.details_share))); + context.startActivity(Intent.createChooser(i, activity.getString(R.string.details_share))); }); shareLinkView.build(); linkLayout.addView(shareLinkView); @@ -82,7 +82,7 @@ public class AppLinks extends AbstractHelper { } DetailsLinkView prefLinkView = new DetailsLinkView(context); prefLinkView.setLinkText(context.getString(R.string.link_setting)); - prefLinkView.setLinkImageId(R.drawable.app_settings); + prefLinkView.setLinkImageId(R.drawable.ic_menu_settings); prefLinkView.setColor(R.color.colorOrange); prefLinkView.setOnClickListener(v -> { try { diff --git a/app/src/main/java/com/aurora/store/ui/details/views/Beta.java b/app/src/main/java/com/aurora/store/ui/details/views/Beta.java new file mode 100644 index 000000000..e350035e3 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/details/views/Beta.java @@ -0,0 +1,237 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.details.views; + +import android.app.Activity; +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.task.BaseTask; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; +import com.dragons.aurora.playstoreapiv2.ReviewResponse; +import com.dragons.aurora.playstoreapiv2.TestingProgramResponse; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.textfield.TextInputEditText; + +import java.io.IOException; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class Beta extends AbstractDetails { + + @BindView(R.id.root_layout) + LinearLayout rootLayout; + @BindView(R.id.beta_comment) + TextInputEditText editText; + @BindView(R.id.beta_layout) + RelativeLayout beta_card; + @BindView(R.id.beta_feedback) + RelativeLayout beta_feedback; + @BindView(R.id.beta_message) + TextView txt_beta_message; + @BindView(R.id.beta_submit_button) + Button beta_submit_button; + @BindView(R.id.beta_delete_button) + Button beta_delete_button; + + private CompositeDisposable disposable = new CompositeDisposable(); + + public Beta(DetailsActivity activity, App app) { + super(activity, app); + } + + static private void restartActivity(Activity activity) { + activity.finish(); + activity.overridePendingTransition(0, 0); + activity.startActivity(activity.getIntent()); + activity.overridePendingTransition(0, 0); + } + + @Override + public void draw() { + ButterKnife.bind(this, activity); + if (Accountant.isAnonymous(context)) + return; + + if (app.isTestingProgramAvailable() && app.isTestingProgramOptedIn()) { + disposable.add(Observable.fromCallable(() -> new BetaFeedbackToggleTask(context) + .toggle(app)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe()); + } + + if (!app.isInstalled() || !app.isTestingProgramAvailable()) { + return; + } + + setText(R.id.beta_header, app.isTestingProgramOptedIn() + ? R.string.testing_program_section_opted_in_title + : R.string.testing_program_section_opted_out_title); + + setText(R.id.beta_message, app.isTestingProgramOptedIn() + ? R.string.testing_program_section_opted_in_message + : R.string.testing_program_section_opted_out_message); + + setText(R.id.beta_subscribe_button, app.isTestingProgramOptedIn() + ? R.string.testing_program_opt_out + : R.string.testing_program_opt_in); + + setText(R.id.beta_email, app.getTestingProgramEmail()); + + beta_card.setVisibility(View.VISIBLE); + beta_feedback.setVisibility(app.isTestingProgramOptedIn() ? View.VISIBLE : View.GONE); + + beta_delete_button.setOnClickListener(v -> + disposable.add(Observable.fromCallable(() -> new BetaFeedbackDeleteTask(context) + .deleteFeedback(app.getPackageName())) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((success) -> { + editText.setText(""); + ContextUtil.toastShort(context, context.getString(R.string.action_done)); + beta_delete_button.setEnabled(false); + }))); + + if (null != app.getUserReview() && !TextUtils.isEmpty(app.getUserReview().getComment())) { + editText.setText(app.getUserReview().getComment()); + show(rootLayout, R.id.beta_delete_button); + } + } + + @OnClick(R.id.beta_subscribe_button) + public void subscribeToBeta(MaterialButton button) { + button.setEnabled(false); + disposable.add(Observable.fromCallable(() -> new BetaFeedbackToggleTask(context) + .toggle(app)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> { + Log.e(response.toString()); + if (response != null && response.hasResult()) { + if (response.getResult().getDetails().hasFlag1()) { + ContextUtil.toastLong(context, context.getString(response.getResult().getDetails().getFlag1() + ? R.string.testing_program_opt_in_success + : R.string.testing_program_opt_in_failed)); + Beta.restartActivity(activity); + } + + if (response.getResult().getDetails().hasUnsubscribed()) { + ContextUtil.toastLong(context, context.getString(response.getResult().getDetails().getUnsubscribed() + ? R.string.testing_program_opt_out_success + : R.string.testing_program_opt_out_failed)); + Beta.restartActivity(activity); + } + } + }, err -> { + ContextUtil.toastLong(context, context.getString(R.string.download_failed)); + Log.d(err.getMessage()); + })); + } + + @OnClick(R.id.beta_submit_button) + public void submitBetaReview(MaterialButton button) { + button.setEnabled(false); + disposable.add(Observable.fromCallable(() -> new BetaFeedbackSubmitTask(context) + .addFeedback(app.getPackageName(), editText.getText().toString())) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> { + if (response != null && response.hasUserReview()) { + beta_delete_button.setVisibility(View.VISIBLE); + beta_delete_button.setEnabled(true); + } + }, err -> { + ContextUtil.toastLong(context, context.getString(R.string.download_failed)); + Log.d(err.getMessage()); + })); + } + + static private class BetaFeedbackToggleTask extends BaseTask { + + BetaFeedbackToggleTask(Context context) { + super(context); + } + + private TestingProgramResponse toggle(App app) { + try { + GooglePlayAPI api = AuroraApplication.api; + return api.testingProgram(app.getPackageName(), !app.isTestingProgramOptedIn()); + } catch (IOException e) { + return null; + } + } + } + + static private class BetaFeedbackSubmitTask extends BaseTask { + + BetaFeedbackSubmitTask(Context context) { + super(context); + } + + private ReviewResponse addFeedback(String packageName, String feedback) { + try { + GooglePlayAPI api = AuroraApplication.api; + return api.betaFeedback(packageName, feedback); + } catch (Exception e) { + Log.e(e.getMessage()); + return null; + } + } + } + + static private class BetaFeedbackDeleteTask extends BaseTask { + + BetaFeedbackDeleteTask(Context context) { + super(context); + } + + private boolean deleteFeedback(String packageName) { + try { + GooglePlayAPI api = AuroraApplication.api; + api.deleteBetaFeedback(packageName); + return true; + } catch (Exception e) { + Log.e(e.getMessage()); + return false; + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/ui/details/views/ExodusPrivacy.java b/app/src/main/java/com/aurora/store/ui/details/views/ExodusPrivacy.java new file mode 100644 index 000000000..4cbccf90d --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/details/views/ExodusPrivacy.java @@ -0,0 +1,127 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.details.views; + +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; + +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.model.ExodusReport; +import com.aurora.store.model.Report; +import com.aurora.store.sheet.ExodusBottomSheet; +import com.aurora.store.task.NetworkTask; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.Log; +import com.google.gson.Gson; + +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; + +import java.util.Collections; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class ExodusPrivacy extends AbstractDetails { + + private static final String EXODUS_PATH = "https://reports.exodus-privacy.eu.org/api/search/"; + + @BindView(R.id.root_layout) + LinearLayout rootLayout; + @BindView(R.id.exodus_card) + RelativeLayout exodus_card; + @BindView(R.id.moreButton) + Button moreButton; + + private Report report; + private CompositeDisposable disposable = new CompositeDisposable(); + + public ExodusPrivacy(DetailsActivity activity, App app) { + super(activity, app); + } + + @Override + public void draw() { + ButterKnife.bind(this, activity); + get(EXODUS_PATH + app.getPackageName()); + } + + private void get(String url) { + disposable.add(Observable.fromCallable(() -> new NetworkTask(context) + .get(url)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> parseResponse(response))); + } + + private void parseResponse(String response) { + try { + JSONObject jsonObject = new JSONObject(response); + JSONObject exodusObject = jsonObject.getJSONObject(app.getPackageName()); + Gson gson = new Gson(); + ExodusReport exodusReport = gson.fromJson(exodusObject.toString(), ExodusReport.class); + List reportList = exodusReport.getReports(); + Collections.sort(reportList, (Report1, Report2) -> Report2.getCreationDate().compareTo(Report1.getCreationDate())); + report = reportList.get(0); + } catch (Exception e) { + Log.d(e.getMessage()); + } finally { + drawExodus(); + } + } + + private void drawExodus() { + show(rootLayout, R.id.exodus_card); + + if (report == null) { + setText(R.id.exodus_description, R.string.exodus_noReport); + moreButton.setVisibility(View.GONE); + return; + } + + if (report.getTrackers().size() > 0) { + setText(R.id.exodus_description, new StringBuilder() + .append(context.getString(R.string.exodus_hasTracker)) + .append(StringUtils.SPACE) + .append(report.getTrackers().size()).toString()); + } else { + setText(R.id.exodus_description, R.string.exodus_noTracker); + } + + if (report.getTrackers().isEmpty()) + moreButton.setVisibility(View.GONE); + else + moreButton.setOnClickListener(v -> showBottomDialog()); + } + + private void showBottomDialog() { + ExodusBottomSheet bottomSheet = new ExodusBottomSheet(report); + bottomSheet.show(activity.getSupportFragmentManager(), "EXODUS"); + } +} diff --git a/app/src/main/java/com/aurora/store/fragment/details/GeneralDetails.java b/app/src/main/java/com/aurora/store/ui/details/views/GeneralDetails.java similarity index 73% rename from app/src/main/java/com/aurora/store/fragment/details/GeneralDetails.java rename to app/src/main/java/com/aurora/store/ui/details/views/GeneralDetails.java index 21d65c864..99c2953c4 100644 --- a/app/src/main/java/com/aurora/store/fragment/details/GeneralDetails.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/GeneralDetails.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.fragment.details; +package com.aurora.store.ui.details.views; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -30,9 +30,9 @@ import android.text.TextUtils; import android.text.format.Formatter; import android.text.util.Linkify; import android.view.View; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.TextView; import androidx.annotation.Nullable; @@ -41,16 +41,16 @@ import androidx.palette.graphics.Palette; import com.aurora.store.GlideApp; import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; import com.aurora.store.manager.CategoryManager; import com.aurora.store.model.App; import com.aurora.store.sheet.MoreInfoSheet; -import com.aurora.store.utility.ColorUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.TextUtil; -import com.aurora.store.utility.ThemeUtil; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.ColorUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.TextUtil; +import com.aurora.store.util.ThemeUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions; @@ -60,6 +60,7 @@ import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.google.android.material.button.MaterialButton; import com.google.android.material.chip.Chip; +import com.google.android.material.chip.ChipGroup; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; @@ -70,19 +71,24 @@ import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; -public class GeneralDetails extends AbstractHelper { +public class GeneralDetails extends AbstractDetails { + + @BindView(R.id.root_layout) + LinearLayout rootLayout; @BindView(R.id.icon) ImageView appIcon; @BindView(R.id.devName) TextView txtDevName; @BindView(R.id.app_desc_short) TextView txtDescShort; - @BindView(R.id.img_more) - ImageButton imgMore; + @BindView(R.id.more_layout) + RelativeLayout moreLayout; @BindView(R.id.versionString) TextView app_version; @BindView(R.id.txt_new) TextView txtNew; + @BindView(R.id.chip_group_info) + ChipGroup chipGroupInfo; @BindView(R.id.txt_updated) Chip txtUpdated; @BindView(R.id.txt_google_dependencies) @@ -102,13 +108,13 @@ public class GeneralDetails extends AbstractHelper { @BindView(R.id.btn_negative) MaterialButton btnNegative; - public GeneralDetails(DetailsFragment fragment, App app) { - super(fragment, app); + public GeneralDetails(DetailsActivity activity, App app) { + super(activity, app); } @Override public void draw() { - ButterKnife.bind(this, view); + ButterKnife.bind(this, activity); drawAppBadge(); if (app.isInPlayStore()) { drawGeneralDetails(); @@ -118,31 +124,29 @@ public class GeneralDetails extends AbstractHelper { } private void drawAppBadge() { - if (view != null) { - GlideApp.with(context) - .asBitmap() - .load(app.getIconInfo().getUrl()) - .transition(new BitmapTransitionOptions().crossFade()) - .transforms(new CenterCrop(), new RoundedCorners(50)) - .listener(new RequestListener() { - @Override - public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { - return false; - } + GlideApp.with(context) + .asBitmap() + .load(app.getIconInfo().getUrl()) + .transition(new BitmapTransitionOptions().crossFade()) + .transforms(new CenterCrop(), new RoundedCorners(50)) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + return false; + } - @Override - public boolean onResourceReady(Bitmap resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { - getPalette(resource); - return false; - } - }) - .into(appIcon); - setText(view, R.id.displayName, app.getDisplayName()); - setText(view, R.id.packageName, app.getPackageName()); - setText(view, R.id.devName, app.getDeveloperName()); - txtDevName.setOnClickListener(v -> showDevApps()); - drawVersion(); - } + @Override + public boolean onResourceReady(Bitmap resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + getPalette(resource); + return false; + } + }) + .into(appIcon); + setText(R.id.displayName, app.getDisplayName()); + setText(R.id.packageName, app.getPackageName()); + setText(R.id.devName, app.getDeveloperName()); + txtDevName.setOnClickListener(v -> showDevApps()); + drawVersion(); } private void getPalette(Bitmap bitmap) { @@ -190,22 +194,22 @@ public class GeneralDetails extends AbstractHelper { private void drawGeneralDetails() { if (context != null) { if (app.isEarlyAccess()) { - setText(view, R.id.rating, R.string.early_access); + setText(R.id.rating, R.string.early_access); } else { - setText(view, R.id.rating, R.string.details_rating, app.getRating().getAverage()); + setText(R.id.rating, R.string.details_rating, app.getRating().getAverage()); } final String category = new CategoryManager(context).getCategoryName(app.getCategoryId()); if (TextUtil.isEmpty(category)) - hide(view, R.id.category); + hide(R.id.category); else - setText(view, R.id.category, new CategoryManager(context).getCategoryName(app.getCategoryId())); + setText(R.id.category, new CategoryManager(context).getCategoryName(app.getCategoryId())); if (app.getPrice() != null && app.getPrice().isEmpty()) - setText(view, R.id.price, R.string.category_appFree); + setText(R.id.price, R.string.category_appFree); else - setText(view, R.id.price, app.getPrice()); - setText(view, R.id.contains_ads, app.containsAds() ? R.string.details_contains_ads : R.string.details_no_ads); + setText(R.id.price, app.getPrice()); + setText(R.id.contains_ads, app.containsAds() ? R.string.details_contains_ads : R.string.details_no_ads); txtUpdated.setText(app.getUpdated()); txtDependencies.setText(app.getDependencies().isEmpty() @@ -214,23 +218,23 @@ public class GeneralDetails extends AbstractHelper { txtRating.setText(app.getLabeledRating()); txtInstalls.setText(app.getInstalls() <= 100 ? "Unknown" : Util.addDiPrefix(app.getInstalls())); txtSize.setText(app.getSize() == 0 ? "Unknown" : Formatter.formatShortFileSize(context, app.getSize())); - setText(view, R.id.app_desc_short, TextUtil.emptyIfNull(app.getShortDescription())); + setText(R.id.app_desc_short, TextUtil.emptyIfNull(app.getShortDescription())); drawOfferDetails(); drawChanges(); - show(view, R.id.app_desc_short); - show(view, R.id.layout_main); + + show(rootLayout, R.id.chip_group_info, R.id.app_desc_short); } } private void drawChanges() { String changes = app.getChanges(); if (TextUtil.isEmpty(changes)) - setText(view, R.id.txt_changelog, context.getString(R.string.details_no_changes)); + setText(R.id.txt_changelog, context.getString(R.string.details_no_changes)); else - setText(view, R.id.txt_changelog, Html.fromHtml(changes).toString()); - show(view, R.id.changes_container); + setText(R.id.txt_changelog, Html.fromHtml(changes).toString()); + show(rootLayout, R.id.changes_container); } private void drawOfferDetails() { @@ -309,18 +313,18 @@ public class GeneralDetails extends AbstractHelper { private void drawDescription() { if (context != null) { if (TextUtils.isEmpty(app.getDescription())) { - hide(view, R.id.more_layout); + hide(R.id.more_layout); } else { - show(view, R.id.more_layout); + show(rootLayout, R.id.more_layout); } } } private void setupReadMore() { - imgMore.setOnClickListener(v -> { - MoreInfoSheet mDetailsFragmentMore = new MoreInfoSheet(); - mDetailsFragmentMore.setApp(app); - mDetailsFragmentMore.show(fragment.getChildFragmentManager(), "MORE"); + moreLayout.setOnClickListener(v -> { + MoreInfoSheet moreInfoSheet = new MoreInfoSheet(); + moreInfoSheet.setApp(app); + moreInfoSheet.show(activity.getSupportFragmentManager(), "MORE"); }); } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/details/Reviews.java b/app/src/main/java/com/aurora/store/ui/details/views/Reviews.java similarity index 52% rename from app/src/main/java/com/aurora/store/fragment/details/Reviews.java rename to app/src/main/java/com/aurora/store/ui/details/views/Reviews.java index c65622702..9fced1b76 100644 --- a/app/src/main/java/com/aurora/store/fragment/details/Reviews.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/Reviews.java @@ -18,65 +18,54 @@ * */ -package com.aurora.store.fragment.details; +package com.aurora.store.ui.details.views; import android.content.Context; +import android.content.Intent; import android.text.TextUtils; import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RatingBar; import android.widget.RelativeLayout; import android.widget.TextView; -import com.aurora.store.GlideApp; +import com.aurora.store.AuroraApplication; import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; -import com.aurora.store.iterator.ReviewStorageIterator; import com.aurora.store.model.App; import com.aurora.store.model.Review; -import com.aurora.store.sheet.ReviewsBottomSheet; import com.aurora.store.sheet.UserReviewBottomSheet; import com.aurora.store.task.BaseTask; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.ViewUtil; -import com.aurora.store.view.RatingView; -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.details.ReviewsActivity; +import com.aurora.store.ui.view.RatingView; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.Log; +import com.aurora.store.util.ViewUtil; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.google.android.material.chip.Chip; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import java.util.List; import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnClick; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -public class Reviews extends AbstractHelper { +public class Reviews extends AbstractDetails { - @BindView(R.id.img_review) - ImageButton imgReview; + @BindView(R.id.root_layout) + LinearLayout rootLayout; @BindView(R.id.average_rating) TextView txtAverageRating; @BindView(R.id.count_stars) TextView txtCountStars; @BindView(R.id.average_rating_star) RatingBar averageRatingBar; - @BindView(R.id.reviews_container) - LinearLayout reviewLayout; @BindView(R.id.avg_rating_layout) LinearLayout avgRatingLayout; - @BindView(R.id.reviews_list) - LinearLayout reviewListLayout; - @BindView(R.id.user_review_layout) - LinearLayout userReviewLayout; @BindView(R.id.user_stars) RatingBar userRatingBar; @BindView(R.id.user_comment_layout) @@ -84,28 +73,18 @@ public class Reviews extends AbstractHelper { @BindView(R.id.review_delete) Chip chipDelete; - private ReviewStorageIterator iterator; private CompositeDisposable disposable = new CompositeDisposable(); - public Reviews(DetailsFragment fragment, App app) { - super(fragment, app); - iterator = new ReviewStorageIterator(); - iterator.setPackageName(app.getPackageName()); - iterator.setContext(fragment.getActivity()); + public Reviews(DetailsActivity activity, App app) { + super(activity, app); } @Override public void draw() { - ButterKnife.bind(this, view); + ButterKnife.bind(this, activity); if (!app.isInPlayStore() || app.isEarlyAccess()) return; - else - disposable.add(Observable.fromCallable(() -> new ReviewLoader(context, iterator) - .getReviews()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::showReviews, err -> Log.e(err.getMessage()))); averageRatingBar.setRating(app.getRating().getAverage()); txtAverageRating.setText(String.format(Locale.getDefault(), "%.1f", app.getRating().getAverage())); @@ -116,14 +95,16 @@ public class Reviews extends AbstractHelper { } txtCountStars.setText(String.valueOf(totalStars)); + avgRatingLayout.removeAllViews(); avgRatingLayout.addView(addAvgReviews(5, totalStars, app.getRating().getStars(5))); avgRatingLayout.addView(addAvgReviews(4, totalStars, app.getRating().getStars(4))); avgRatingLayout.addView(addAvgReviews(3, totalStars, app.getRating().getStars(3))); avgRatingLayout.addView(addAvgReviews(2, totalStars, app.getRating().getStars(2))); avgRatingLayout.addView(addAvgReviews(1, totalStars, app.getRating().getStars(1))); - ViewUtil.setVisibility(reviewLayout, true); - ViewUtil.setVisibility(userReviewLayout, isReviewable(app)); + show(rootLayout, R.id.reviews_container); + if (isReviewable(app)) + show(rootLayout, R.id.user_review_layout); Review review = app.getUserReview(); if (null != review) { @@ -131,11 +112,10 @@ public class Reviews extends AbstractHelper { } initUserReviewControls(app); - setupLoadMore(); } private RelativeLayout addAvgReviews(int number, int max, int rating) { - return new RatingView(context, number, max, rating); + return new RatingView(activity, number, max, rating); } private boolean isReviewable(App app) { @@ -148,16 +128,16 @@ public class Reviews extends AbstractHelper { userRatingBar.setRating(review.getRating()); setTextOrHide(R.id.user_comment, review.getComment()); setTextOrHide(R.id.user_title, review.getTitle()); - setText(fragment.getView(), R.id.rate, R.string.details_you_rated_this_app); + setText(R.id.rate, R.string.details_you_rated_this_app); chipDelete.setVisibility(View.VISIBLE); userCommentLayout.setVisibility(View.VISIBLE); } private void clearUserReview() { userRatingBar.setRating(0); - setText(fragment.getView(), R.id.user_title, ""); - setText(fragment.getView(), R.id.user_comment, ""); - setText(fragment.getView(), R.id.rate, R.string.details_rate_this_app); + setText(R.id.user_title, ""); + setText(R.id.user_comment, ""); + setText(R.id.rate, R.string.details_rate_this_app); chipDelete.setVisibility(View.GONE); userCommentLayout.setVisibility(View.GONE); } @@ -172,44 +152,6 @@ public class Reviews extends AbstractHelper { return review; } - private void showReviews(List reviews) { - reviewListLayout.removeAllViews(); - addReviewToList(reviews.get(0), reviewListLayout); - addReviewToList(reviews.get(1), reviewListLayout); - } - - private void addReviewToList(Review review, ViewGroup parent) { - RelativeLayout reviewLayout = (RelativeLayout) fragment.getLayoutInflater() - .inflate(R.layout.item_review_list, parent, false); - TextView txtAuthor = reviewLayout.findViewById(R.id.author); - txtAuthor.setText(review.getUserName()); - RatingBar ratingBar = reviewLayout.findViewById(R.id.rating); - ratingBar.setRating(review.getRating()); - TextView txtComment = reviewLayout.findViewById(R.id.comment); - txtComment.setText(review.getComment()); - ImageView imageView = reviewLayout.findViewById(R.id.avatar); - - GlideApp - .with(context) - .load(review.getUserPhotoUrl()) - .placeholder(R.color.colorTransparent) - .circleCrop() - .transition(new DrawableTransitionOptions().crossFade()) - .into(imageView); - - reviewLayout.setOnClickListener(v -> { - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context) - .setIcon(imageView.getDrawable()) - .setTitle(review.getUserName()) - .setMessage(review.getComment()) - .setCancelable(false) - .setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); - builder.create(); - builder.show(); - }); - parent.addView(reviewLayout); - } - private void initUserReviewControls(final App app) { userRatingBar.setOnRatingBarChangeListener((ratingBar, rating, fromUser) -> { if (!fromUser) { @@ -218,24 +160,26 @@ public class Reviews extends AbstractHelper { UserReviewBottomSheet reviewsBottomSheet = new UserReviewBottomSheet(); reviewsBottomSheet.setApp(app); reviewsBottomSheet.setRating((int) rating); - reviewsBottomSheet.show(fragment.getChildFragmentManager(), "USER_REVIEWS"); + reviewsBottomSheet.show(activity.getSupportFragmentManager(), "USER_REVIEWS"); }); - chipDelete.setOnClickListener(v -> disposable.add(Observable.fromCallable(() -> new ReviewRemover(context) - .delete(app.getPackageName())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((success) -> { - if (success) { - clearUserReview(); - } else { - Log.e("Error deleting the review"); - } - }, err -> Log.e(err.getMessage())))); + chipDelete.setOnClickListener(v -> { + disposable.add(Observable.fromCallable(() -> new ReviewRemover(context) + .delete(app.getPackageName())) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((success) -> { + if (success) { + clearUserReview(); + } else { + Log.e("Error deleting the review"); + } + }, err -> Log.e(err.getMessage()))); + }); } private void setTextOrHide(int viewId, String text) { - TextView textView = view.findViewById(viewId); + TextView textView = activity.findViewById(viewId); if (!TextUtils.isEmpty(text)) { textView.setText(text); textView.setVisibility(View.VISIBLE); @@ -244,21 +188,22 @@ public class Reviews extends AbstractHelper { } } - private void setupLoadMore() { - imgReview.setOnClickListener(v -> { - ReviewsBottomSheet reviewsBottomSheet = new ReviewsBottomSheet(app); - reviewsBottomSheet.show(fragment.getChildFragmentManager(), "REVIEWS"); - }); + @OnClick(R.id.more_reviews_layout) + public void openReviewsActivity() { + Intent intent = new Intent(activity, ReviewsActivity.class); + intent.putExtra("INTENT_PACKAGE_NAME", app.getPackageName()); + activity.startActivity(intent, ViewUtil.getEmptyActivityBundle(activity)); } static class ReviewRemover extends BaseTask { + ReviewRemover(Context context) { super(context); } private boolean delete(String packageName) { try { - GooglePlayAPI api = getApi(); + GooglePlayAPI api = AuroraApplication.api; api.deleteReview(packageName); return true; } catch (Exception e) { @@ -267,17 +212,4 @@ public class Reviews extends AbstractHelper { } } } - - static class ReviewLoader extends BaseTask { - private ReviewStorageIterator iterator; - - ReviewLoader(Context context, ReviewStorageIterator iterator) { - super(context); - this.iterator = iterator; - } - - private List getReviews() { - return iterator.next(); - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/fragment/details/Screenshot.java b/app/src/main/java/com/aurora/store/ui/details/views/Screenshot.java similarity index 77% rename from app/src/main/java/com/aurora/store/fragment/details/Screenshot.java rename to app/src/main/java/com/aurora/store/ui/details/views/Screenshot.java index 8fd44e07f..39404d1a3 100644 --- a/app/src/main/java/com/aurora/store/fragment/details/Screenshot.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/Screenshot.java @@ -18,25 +18,29 @@ * */ -package com.aurora.store.fragment.details; +package com.aurora.store.ui.details.views; + +import android.widget.LinearLayout; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.aurora.store.R; import com.aurora.store.adapter.SmallScreenshotsAdapter; -import com.aurora.store.fragment.DetailsFragment; import com.aurora.store.model.App; +import com.aurora.store.ui.details.DetailsActivity; import butterknife.BindView; -public class Screenshot extends AbstractHelper { +public class Screenshot extends AbstractDetails { - @BindView(R.id.screenshots_gallery) + @BindView(R.id.root_layout) + LinearLayout rootLayout; + @BindView(R.id.recycler) RecyclerView recyclerView; - public Screenshot(DetailsFragment fragment, App app) { - super(fragment, app); + public Screenshot(DetailsActivity activity, App app) { + super(activity, app); } @Override @@ -47,6 +51,7 @@ public class Screenshot extends AbstractHelper { } private void drawGallery() { + show(rootLayout, R.id.recycler); recyclerView.setAdapter(new SmallScreenshotsAdapter(app.getScreenshotUrls(), context)); recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); } diff --git a/app/src/main/java/com/aurora/store/fragment/details/Video.java b/app/src/main/java/com/aurora/store/ui/details/views/Video.java similarity index 90% rename from app/src/main/java/com/aurora/store/fragment/details/Video.java rename to app/src/main/java/com/aurora/store/ui/details/views/Video.java index 39a857e63..7f6f30fe1 100644 --- a/app/src/main/java/com/aurora/store/fragment/details/Video.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/Video.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.fragment.details; +package com.aurora.store.ui.details.views; import android.content.ActivityNotFoundException; import android.content.Intent; @@ -30,10 +30,10 @@ import android.widget.RelativeLayout; import com.aurora.store.GlideApp; import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; import com.aurora.store.model.App; import com.aurora.store.task.NetworkTask; -import com.aurora.store.utility.Log; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.Log; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; @@ -47,7 +47,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -public class Video extends AbstractHelper { +public class Video extends AbstractDetails { @BindView(R.id.app_video) RelativeLayout video_layout; @@ -58,13 +58,13 @@ public class Video extends AbstractHelper { private CompositeDisposable disposable = new CompositeDisposable(); - public Video(DetailsFragment fragment, App app) { - super(fragment, app); + public Video(DetailsActivity activity, App app) { + super(activity, app); } @Override public void draw() { - ButterKnife.bind(this, view); + ButterKnife.bind(this, activity); if (TextUtils.isEmpty(app.getVideoUrl())) { return; } @@ -84,7 +84,7 @@ public class Video extends AbstractHelper { private void getThumb(String videoURL) { disposable.add(Observable.fromCallable(() -> new NetworkTask(context) .get("http://www.youtube.com/oembed?url=" + videoURL + "&format=json")) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(response -> { JSONObject jsonObject = new JSONObject(response); diff --git a/app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java b/app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java new file mode 100644 index 000000000..e3d1bec98 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java @@ -0,0 +1,138 @@ +package com.aurora.store.ui.devapps; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MenuItem; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.Toolbar; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.Constants; +import com.aurora.store.EndlessScrollListener; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.section.SearchResultSection; +import com.aurora.store.sheet.AppMenuSheet; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.util.ViewUtil; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; + +public class DevAppsActivity extends BaseActivity implements SearchResultSection.ClickListener { + + private static final String TAG_DEV_APPS = "TAG_DEV_APPS"; + + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.recycler) + RecyclerView recyclerView; + + private DevAppsModel model; + private SearchResultSection section; + private SectionedRecyclerViewAdapter adapter; + + private String query; + private String title; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_dev_apps); + ButterKnife.bind(this); + + Intent intent = getIntent(); + if (intent != null) { + query = intent.getStringExtra("SearchQuery"); + title = intent.getStringExtra("SearchTitle"); + + if (query != null) { + setupActionBar(); + setupRecycler(); + model = ViewModelProviders.of(this).get(DevAppsModel.class); + model.getQueriedApps().observe(this, appList -> { + dispatchAppsToAdapter(appList); + }); + model.fetchQueriedApps(query, false); + } else { + Toast.makeText(this, "No dev name received", Toast.LENGTH_SHORT).show(); + supportFinishAfterTransition(); + } + } + } + + @Override + public boolean onOptionsItemSelected(final MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(menuItem); + } + + private void setupActionBar() { + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(title); + } + } + + private void dispatchAppsToAdapter(List newList) { + List oldList = section.getList(); + if (oldList.isEmpty()) { + section.updateList(newList); + adapter.notifyDataSetChanged(); + } else { + if (!newList.isEmpty()) { + for (App app : newList) + section.add(app); + adapter.notifyItemInserted(section.getCount() - 1); + } + } + } + + private void setupRecycler() { + section = new SearchResultSection(this, this); + adapter = new SectionedRecyclerViewAdapter(); + adapter.addSection(TAG_DEV_APPS, section); + recyclerView.setAdapter(adapter); + + LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false); + EndlessScrollListener endlessScrollListener = new EndlessScrollListener(layoutManager) { + @Override + public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { + model.fetchQueriedApps(query, true); + } + }; + recyclerView.addOnScrollListener(endlessScrollListener); + recyclerView.setLayoutManager(layoutManager); + } + + @Override + public void onClick(App app) { + DetailsActivity.app = app; + Intent intent = new Intent(this, DetailsActivity.class); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, app.getPackageName()); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + } + + @Override + public void onLongClick(App app) { + AppMenuSheet menuSheet = new AppMenuSheet(); + menuSheet.setApp(app); + menuSheet.show(getSupportFragmentManager(), "BOTTOM_MENU_SHEET"); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/devapps/DevAppsModel.java b/app/src/main/java/com/aurora/store/ui/devapps/DevAppsModel.java new file mode 100644 index 000000000..8f630a8b9 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/devapps/DevAppsModel.java @@ -0,0 +1,32 @@ +package com.aurora.store.ui.devapps; + +import android.app.Application; + +import androidx.annotation.NonNull; + +import com.aurora.store.iterator.CustomAppListIterator; +import com.aurora.store.ui.search.SearchAppsModel; +import com.dragons.aurora.playstoreapiv2.SearchIterator; + +public class DevAppsModel extends SearchAppsModel { + + public DevAppsModel(@NonNull Application application) { + super(application); + } + + @Override + public void getIterator(String query) { + try { + searchIterator = new SearchIterator(api, query); + iterator = new CustomAppListIterator(searchIterator); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java b/app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java new file mode 100644 index 000000000..3ae2566f2 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java @@ -0,0 +1,155 @@ +package com.aurora.store.ui.installed; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.AppDiffCallback; +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.section.InstallAppSection; +import com.aurora.store.sheet.AppMenuSheet; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.google.android.material.switchmaterial.SwitchMaterial; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; +import io.reactivex.disposables.CompositeDisposable; + +public class InstalledAppActivity extends BaseActivity implements InstallAppSection.ClickListener { + + private static final String TAG_APPS = "TAG_APPS"; + + @BindView(R.id.switch_system) + SwitchMaterial switchSystem; + @BindView(R.id.recycler) + RecyclerView recycler; + @BindView(R.id.swipe_layout) + CustomSwipeToRefresh swipeLayout; + @BindView(R.id.coordinator) + CoordinatorLayout coordinator; + + private InstalledAppsModel model; + private InstallAppSection section; + private SectionedRecyclerViewAdapter adapter; + private CompositeDisposable disposable = new CompositeDisposable(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_all_apps); + ButterKnife.bind(this); + + setupRecycler(); + switchSystem.setChecked(PrefUtil.getBoolean(this, Constants.PREFERENCE_INCLUDE_SYSTEM)); + switchSystem.setOnCheckedChangeListener((buttonView, isChecked) -> { + PrefUtil.putBoolean(this, Constants.PREFERENCE_INCLUDE_SYSTEM, isChecked); + model.getInstalledApps(isChecked); + }); + + model = ViewModelProviders.of(this).get(InstalledAppsModel.class); + model.getListMutableLiveData().observe(this, appList -> { + dispatchAppsToAdapter(appList); + swipeLayout.setRefreshing(false); + + }); + + model.getError().observe(this, errorType -> { + switch (errorType) { + case NO_API: + case SESSION_EXPIRED: + Util.validateApi(this); + break; + case NO_NETWORK: { + showSnackBar(coordinator, R.string.error_no_network, v -> fetchApps()); + break; + } + } + }); + + model.getInstalledApps(switchSystem.isChecked()); + swipeLayout.setOnRefreshListener(() -> fetchApps()); + + disposable.add(AuroraApplication + .getRxBus() + .getBus() + .subscribe(event -> { + switch (event.getSubType()) { + case BLACKLIST: + int pos = section.removeApp(event.getPackageName()); + if (pos != -1) + adapter.notifyItemRemoved(pos); + break; + case API_SUCCESS: + fetchApps(); + break; + } + })); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(menuItem); + } + + private void fetchApps() { + model.fetchInstalledApps(switchSystem.isChecked()); + } + + private void dispatchAppsToAdapter(List newList) { + List oldList = section.getList(); + if (oldList.isEmpty()) { + section.updateList(newList); + adapter.notifyDataSetChanged(); + } else { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new AppDiffCallback(newList, oldList)); + diffResult.dispatchUpdatesTo(adapter); + section.updateList(newList); + } + } + + private void setupRecycler() { + section = new InstallAppSection(this, this); + adapter = new SectionedRecyclerViewAdapter(); + adapter.addSection(TAG_APPS, section); + recycler.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false)); + recycler.setAdapter(adapter); + } + + + @Override + public void onClick(App app) { + DetailsActivity.app = app; + Intent intent = new Intent(this, DetailsActivity.class); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, app.getPackageName()); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + } + + @Override + public void onLongClick(App app) { + AppMenuSheet menuSheet = new AppMenuSheet(); + menuSheet.setApp(app); + menuSheet.show(getSupportFragmentManager(), "BOTTOM_MENU_SHEET"); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/installed/InstalledAppsModel.java b/app/src/main/java/com/aurora/store/ui/installed/InstalledAppsModel.java new file mode 100644 index 000000000..dc315f1e2 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/installed/InstalledAppsModel.java @@ -0,0 +1,96 @@ +package com.aurora.store.ui.installed; + +import android.app.Application; +import android.content.SharedPreferences; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.model.App; +import com.aurora.store.task.InstalledAppsTask; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.viewmodel.BaseViewModel; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class InstalledAppsModel extends BaseViewModel implements SharedPreferences.OnSharedPreferenceChangeListener { + + private boolean userOnly; + private Gson gson = new Gson(); + + private MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + + public InstalledAppsModel(@NonNull Application application) { + super(application); + this.userOnly = PrefUtil.getBoolean(application, Constants.PREFERENCE_INCLUDE_SYSTEM); + } + + public LiveData> getListMutableLiveData() { + return listMutableLiveData; + } + + public void getInstalledApps(boolean userOnly) { + Type type = new TypeToken>() { + }.getType(); + String jsonString = PrefUtil.getString(getApplication(), Constants.PREFERENCE_INSTALLED_APPS); + List appList = gson.fromJson(jsonString, type); + if (appList == null || appList.isEmpty()) + fetchInstalledApps(userOnly); + else { + List filteredList = getFilteredList(appList, userOnly); + listMutableLiveData.setValue(filteredList); + } + } + + public void fetchInstalledApps(boolean userOnly) { + api = AuroraApplication.api; + disposable.add(Observable.fromCallable(() -> new InstalledAppsTask(api, getApplication()) + .getInstalledApps()) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + List filteredList = getFilteredList(appList, userOnly); + listMutableLiveData.setValue(filteredList); + saveToCache(appList); + }, err -> handleError(err))); + } + + private void saveToCache(List appList) { + String jsonString = gson.toJson(appList); + PrefUtil.putString(getApplication(), Constants.PREFERENCE_INSTALLED_APPS, jsonString); + } + + private List getFilteredList(List appList, boolean userOnly) { + List filteredList = new ArrayList<>(); + for (App app : appList) { + if (userOnly && app.isSystem()) + continue; + filteredList.add(app); + } + return filteredList; + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(Accountant.DATA) && Accountant.isLoggedIn(getApplication())) + getInstalledApps(userOnly); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/intro/IntroActivity.java b/app/src/main/java/com/aurora/store/ui/intro/IntroActivity.java new file mode 100644 index 000000000..bd1b28d25 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/intro/IntroActivity.java @@ -0,0 +1,242 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.intro; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; + +import com.aurora.store.R; +import com.aurora.store.api.PlayStoreApiAuthenticator; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.ui.single.activity.GoogleLoginActivity; +import com.aurora.store.ui.single.activity.SplashActivity; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.NetworkUtil; +import com.aurora.store.util.ViewUtil; +import com.google.android.material.button.MaterialButton; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class IntroActivity extends BaseActivity { + + @BindView(R.id.toolbar) + Toolbar toolbar; + + NavController navController; + @BindView(R.id.btn_next) + MaterialButton btnNext; + @BindView(R.id.btn_anonymous) + MaterialButton btnAnonymous; + @BindView(R.id.progress_bar) + ProgressBar progressBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_intro); + ButterKnife.bind(this); + setupActionbar(); + setupNavigation(); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.menu_intro, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.action_setting: + startActivity(new Intent(this, SettingsActivity.class), ViewUtil.getEmptyActivityBundle(this)); + return true; + } + return super.onOptionsItemSelected(menuItem); + } + + @Override + protected void onResume() { + super.onResume(); + if (Accountant.isLoggedIn(this)) { + startActivity(new Intent(this, SplashActivity.class)); + supportFinishAfterTransition(); + } + } + + private void setupActionbar() { + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowCustomEnabled(true); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setElevation(0f); + } + } + + private void setupNavigation() { + navController = Navigation.findNavController(this, R.id.nav_host_intro); + navController.addOnDestinationChangedListener((controller, destination, arguments) -> { + switch (destination.getId()) { + case R.id.welcomeFragment: { + btnNext.setOnClickListener(v -> moveForward(2)); + break; + } + case R.id.permFragment: { + btnNext.setOnClickListener(askPermListener()); + if (isPermissionGranted()) + moveForward(3); + break; + } + case R.id.loginFragment: { + btnNext.setText(R.string.account_google); + btnAnonymous.setVisibility(View.VISIBLE); + btnNext.setOnClickListener(v -> { + loginGoogle(); + }); + + btnAnonymous.setOnClickListener(v -> { + loginAnonymous(); + }); + } + + } + }); + } + + private void moveForward(int pos) { + switch (pos) { + case 1: + navController.navigate(R.id.welcomeFragment); + break; + case 2: + navController.navigate(R.id.permFragment); + break; + case 3: + navController.navigate(R.id.loginFragment); + break; + case 4: + finishAfterTransition(); + break; + } + } + + public void loginAnonymous() { + if (!NetworkUtil.isConnected(this)) { + Toast.makeText(this, getString(R.string.error_no_network), Toast.LENGTH_SHORT).show(); + return; + } + + CompositeDisposable disposable = new CompositeDisposable(); + disposable.add(Observable.fromCallable(() -> PlayStoreApiAuthenticator + .login(this)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnSubscribe(d -> { + btnAnonymous.setText(getText(R.string.action_logging_in)); + btnAnonymous.setEnabled(false); + progressBar.setVisibility(View.VISIBLE); + }) + .subscribe(api -> { + if (api != null) { + Toast.makeText(this, getText(R.string.toast_login_success), Toast.LENGTH_SHORT).show(); + Intent intent = new Intent(this, SplashActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + supportFinishAfterTransition(); + } else { + Toast.makeText(this, getText(R.string.toast_login_failed), Toast.LENGTH_LONG).show(); + ContextUtil.runOnUiThread(this::resetAnonymousLogin); + } + }, err -> { + Toast.makeText(this, getText(R.string.toast_login_failed), Toast.LENGTH_LONG).show(); + ContextUtil.runOnUiThread(this::resetAnonymousLogin); + })); + } + + public void loginGoogle() { + if (!NetworkUtil.isConnected(this)) { + Toast.makeText(this, getString(R.string.error_no_network), Toast.LENGTH_SHORT).show(); + return; + } + startActivity(new Intent(this, GoogleLoginActivity.class), ViewUtil.getEmptyActivityBundle(this)); + supportFinishAfterTransition(); + } + + private void resetAnonymousLogin() { + btnAnonymous.setEnabled(true); + btnAnonymous.setText(getText(R.string.account_dummy)); + progressBar.setVisibility(View.INVISIBLE); + } + + private View.OnClickListener askPermListener() { + btnNext.setText(R.string.action_ask); + return v -> { + checkPermissions(); + }; + } + + private boolean isPermissionGranted() { + return ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; + } + + private void checkPermissions() { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + 1337); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + switch (requestCode) { + case 1337: { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + navController.navigate(R.id.loginFragment); + } else { + Toast.makeText(this, "Denied", Toast.LENGTH_SHORT).show(); + } + } + } + } +} diff --git a/app/src/main/java/com/aurora/store/ActionType.java b/app/src/main/java/com/aurora/store/ui/intro/fragment/LoginFragment.java similarity index 51% rename from app/src/main/java/com/aurora/store/ActionType.java rename to app/src/main/java/com/aurora/store/ui/intro/fragment/LoginFragment.java index 41809ef1b..7e8183b1b 100644 --- a/app/src/main/java/com/aurora/store/ActionType.java +++ b/app/src/main/java/com/aurora/store/ui/intro/fragment/LoginFragment.java @@ -18,10 +18,28 @@ * */ -package com.aurora.store; +package com.aurora.store.ui.intro.fragment; -public enum ActionType { - LOGIN, - LOGOUT, - REFRESH +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.aurora.store.R; + +import butterknife.ButterKnife; + +public class LoginFragment extends Fragment { + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_intro_login, container, false); + ButterKnife.bind(this, view); + return view; + } } diff --git a/app/src/main/java/com/aurora/store/fragment/intro/PermissionFragment.java b/app/src/main/java/com/aurora/store/ui/intro/fragment/PermissionFragment.java similarity index 75% rename from app/src/main/java/com/aurora/store/fragment/intro/PermissionFragment.java rename to app/src/main/java/com/aurora/store/ui/intro/fragment/PermissionFragment.java index 26c60bf47..1b844703b 100644 --- a/app/src/main/java/com/aurora/store/fragment/intro/PermissionFragment.java +++ b/app/src/main/java/com/aurora/store/ui/intro/fragment/PermissionFragment.java @@ -18,9 +18,8 @@ * */ -package com.aurora.store.fragment.intro; +package com.aurora.store.ui.intro.fragment; -import android.Manifest; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -30,17 +29,14 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; import com.aurora.store.PermissionGroup; import com.aurora.store.R; -import com.aurora.store.activity.IntroActivity; import java.util.ArrayList; import java.util.Collections; @@ -51,18 +47,18 @@ import java.util.Map; import butterknife.BindView; import butterknife.ButterKnife; -public class PermissionFragment extends IntroBaseFragment { +public class PermissionFragment extends Fragment { @BindView(R.id.permissions_container) LinearLayout container; - @BindView(R.id.btn_next) - Button btnNext; - private PackageManager pm; + private Context context; + private PackageManager packageManager; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); + this.context = context; } @Nullable @@ -76,21 +72,19 @@ public class PermissionFragment extends IntroBaseFragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - pm = context.getPackageManager(); + packageManager = context.getPackageManager(); addPermissionWidgets(); - setupNext(); } @Override public void onResume() { super.onResume(); - setupNext(); } private void addPermissionWidgets() { Map permissionGroupWidgets = new HashMap<>(); try { - PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); + PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); String[] allPermissionInfo = packageInfo.requestedPermissions; for (String permissionName : allPermissionInfo) { PermissionInfo permissionInfo = getPermissionInfo(permissionName); @@ -126,7 +120,7 @@ public class PermissionFragment extends IntroBaseFragment { private PermissionInfo getPermissionInfo(String permissionName) { try { - return pm.getPermissionInfo(permissionName, 0); + return packageManager.getPermissionInfo(permissionName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } @@ -138,7 +132,7 @@ public class PermissionFragment extends IntroBaseFragment { permissionGroupInfo = getFakePermissionGroupInfo(permissionInfo.packageName); } else { try { - permissionGroupInfo = pm.getPermissionGroupInfo(permissionInfo.group, 0); + permissionGroupInfo = packageManager.getPermissionGroupInfo(permissionInfo.group, 0); } catch (PackageManager.NameNotFoundException e) { permissionGroupInfo = getFakePermissionGroupInfo(permissionInfo.packageName); } @@ -169,38 +163,4 @@ public class PermissionFragment extends IntroBaseFragment { return permissionGroupInfo; } - - private void setupNext() { - if (isPermissionGranted()) - btnNext.setOnClickListener(forwardListener()); - else { - btnNext.setOnClickListener(askPermListener()); - } - } - - private View.OnClickListener forwardListener() { - btnNext.setText(context.getString(R.string.action_next)); - return v -> { - if (getActivity() instanceof IntroActivity) - ((IntroActivity) getActivity()).moveForward(); - }; - } - - private View.OnClickListener askPermListener() { - btnNext.setText(R.string.action_ask); - return v -> { - checkPermissions(); - }; - } - - private boolean isPermissionGranted() { - return ContextCompat.checkSelfPermission(context, - Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; - } - - private void checkPermissions() { - ActivityCompat.requestPermissions(getActivity(), - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - 1337); - } } diff --git a/app/src/main/java/com/aurora/store/fragment/intro/WelcomeFragment.java b/app/src/main/java/com/aurora/store/ui/intro/fragment/WelcomeFragment.java similarity index 79% rename from app/src/main/java/com/aurora/store/fragment/intro/WelcomeFragment.java rename to app/src/main/java/com/aurora/store/ui/intro/fragment/WelcomeFragment.java index f5d1f47aa..eb49ba9ea 100644 --- a/app/src/main/java/com/aurora/store/fragment/intro/WelcomeFragment.java +++ b/app/src/main/java/com/aurora/store/ui/intro/fragment/WelcomeFragment.java @@ -18,28 +18,23 @@ * */ -package com.aurora.store.fragment.intro; +package com.aurora.store.ui.intro.fragment; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import com.aurora.store.R; -import com.aurora.store.activity.IntroActivity; -import butterknife.BindView; import butterknife.ButterKnife; -public class WelcomeFragment extends IntroBaseFragment { - - @BindView(R.id.btn_next) - Button btnNext; +public class WelcomeFragment extends Fragment { @Override public void onAttach(@NonNull Context context) { @@ -57,9 +52,5 @@ public class WelcomeFragment extends IntroBaseFragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - btnNext.setOnClickListener(v -> { - if (getActivity() instanceof IntroActivity) - ((IntroActivity) getActivity()).moveForward(); - }); } } diff --git a/app/src/main/java/com/aurora/store/ui/main/AuroraActivity.java b/app/src/main/java/com/aurora/store/ui/main/AuroraActivity.java new file mode 100644 index 000000000..266940300 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/main/AuroraActivity.java @@ -0,0 +1,421 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.main; + +import android.Manifest; +import android.app.ActivityOptions; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.navigation.NavController; +import androidx.navigation.NavDestination; +import androidx.navigation.Navigation; +import androidx.navigation.ui.NavigationUI; + +import com.aurora.store.BuildConfig; +import com.aurora.store.Constants; +import com.aurora.store.GlideApp; +import com.aurora.store.R; +import com.aurora.store.SelfUpdateService; +import com.aurora.store.model.Update; +import com.aurora.store.task.NetworkTask; +import com.aurora.store.ui.accounts.AccountsActivity; +import com.aurora.store.ui.installed.InstalledAppActivity; +import com.aurora.store.ui.intro.IntroActivity; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.ui.search.activity.SearchActivity; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.ui.single.activity.DownloadsActivity; +import com.aurora.store.ui.single.activity.GenericActivity; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.CertUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.NetworkUtil; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.TextUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.navigation.NavigationView; +import com.google.gson.Gson; + +import java.util.Calendar; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class AuroraActivity extends BaseActivity { + + public static String externalQuery; + + @BindView(R.id.bottom_navigation) + BottomNavigationView bottomNavigationView; + @BindView(R.id.navigation) + NavigationView navigation; + @BindView(R.id.drawer_layout) + DrawerLayout drawerLayout; + @BindView(R.id.action1) + AppCompatImageView action1; + @BindView(R.id.search_bar) + RelativeLayout searchBar; + + private CompositeDisposable disposable = new CompositeDisposable(); + private int fragmentCur = 0; + + static boolean matchDestination(@NonNull NavDestination destination, @IdRes int destId) { + NavDestination currentDestination = destination; + while (currentDestination.getId() != destId && currentDestination.getParent() != null) { + currentDestination = currentDestination.getParent(); + } + return currentDestination.getId() == destId; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + ButterKnife.bind(this); + fragmentCur = Util.getDefaultTab(this); + onNewIntent(getIntent()); + + if (!PrefUtil.getBoolean(this, Constants.PREFERENCE_DO_NOT_SHOW_INTRO)) { + PrefUtil.putBoolean(this, Constants.PREFERENCE_DO_NOT_SHOW_INTRO, true); + startActivity(new Intent(this, IntroActivity.class)); + finish(); + } else { + if (Accountant.isLoggedIn(this)) + init(); + else + startActivity(new Intent(this, AccountsActivity.class)); + } + + if (NetworkUtil.isConnected(this)) { + if (Util.isCacheObsolete(this)) + Util.clearCache(this); + + if (Util.shouldCheckUpdate(this) && !SelfUpdateService.isServiceRunning()) + checkSelfUpdate(); + } + checkPermissions(); + createNotificationChannel(); + } + + private void init() { + setupNavigation(); + setupDrawer(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Bundle bundle = intent.getExtras(); + if (bundle != null) + fragmentCur = bundle.getInt(Constants.INTENT_FRAGMENT_POSITION); + else if (intent.getScheme() != null && intent.getScheme().equals("market")) { + fragmentCur = 2; + if (intent.getData() != null) + externalQuery = intent.getData().getQueryParameter("q"); + } else + fragmentCur = Util.getDefaultTab(this); + } + + @Override + public boolean onSupportNavigateUp() { + return super.onSupportNavigateUp(); + } + + @Override + protected void onResume() { + super.onResume(); + Util.toggleSoftInput(this, false); + } + + @Override + protected void onUserLeaveHint() { + super.onUserLeaveHint(); + Util.toggleSoftInput(this, false); + } + + @Override + public void onBackPressed() { + if (drawerLayout.isDrawerOpen(GravityCompat.START)) { + drawerLayout.closeDrawer(GravityCompat.START, true); + return; + } + super.onBackPressed(); + } + + @Override + protected void onDestroy() { + disposable.clear(); + super.onDestroy(); + } + + @OnClick(R.id.search_bar) + public void openSearchActivity() { + Intent intent = new Intent(this, SearchActivity.class); + ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this); + startActivity(intent, options.toBundle()); + } + + private void setupNavigation() { + int backGroundColor = ViewUtil.getStyledAttribute(this, android.R.attr.colorBackground); + bottomNavigationView.setBackgroundColor(ColorUtils.setAlphaComponent(backGroundColor, 245)); + + NavController navController = Navigation.findNavController(this, R.id.nav_host_main); + + //Avoid Adding same fragment to NavController, if clicked on current BottomNavigation item + bottomNavigationView.setOnNavigationItemSelectedListener(item -> { + if (item.getItemId() == bottomNavigationView.getSelectedItemId()) + return false; + NavigationUI.onNavDestinationSelected(item, navController); + return true; + }); + + //Check correct BottomNavigation item, if navigation_main is done programmatically + navController.addOnDestinationChangedListener((controller, destination, arguments) -> { + final Menu menu = bottomNavigationView.getMenu(); + final int size = menu.size(); + for (int i = 0; i < size; i++) { + MenuItem item = menu.getItem(i); + if (matchDestination(destination, item.getItemId())) { + item.setChecked(true); + } + } + }); + + //Check default tab to open, if configured + switch (fragmentCur) { + case 0: + navController.navigate(R.id.homeFragment); + break; + case 1: + navController.navigate(R.id.updatesFragment); + break; + case 2: + navController.navigate(R.id.categoriesFragment); + break; + } + } + + private void setupDrawer() { + action1.setOnClickListener(v -> { + if (!drawerLayout.isDrawerOpen(GravityCompat.START)) + drawerLayout.openDrawer(GravityCompat.START, true); + }); + + drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() { + @Override + public void onDrawerSlide(@NonNull View drawerView, float slideOffset) { + + } + + @Override + public void onDrawerOpened(@NonNull View drawerView) { + ImageView imageView = drawerView.findViewById(R.id.img); + TextView textView1 = drawerView.findViewById(R.id.line1); + TextView textView2 = drawerView.findViewById(R.id.line2); + + GlideApp + .with(AuroraActivity.this) + .load(Accountant.getImageURL(AuroraActivity.this)) + .placeholder(R.drawable.circle_bg) + .circleCrop() + .into(imageView); + + textView1.setText(Accountant.isAnonymous(AuroraActivity.this) + ? getText(R.string.account_dummy) + : Accountant.getUserName(AuroraActivity.this)); + textView2.setText(Accountant.isAnonymous(AuroraActivity.this) + ? "auroraoss@gmail.com" + : Accountant.getEmail(AuroraActivity.this)); + } + + @Override + public void onDrawerClosed(@NonNull View drawerView) { + + } + + @Override + public void onDrawerStateChanged(int newState) { + + } + }); + + navigation.setNavigationItemSelectedListener(item -> { + Intent intent = new Intent(this, GenericActivity.class); + switch (item.getItemId()) { + case R.id.action_accounts: + intent.putExtra(Constants.FRAGMENT_NAME, Constants.FRAGMENT_ACCOUNTS); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + break; + case R.id.action_all_apps: + startActivity(new Intent(this, InstalledAppActivity.class), + ViewUtil.getEmptyActivityBundle(this)); + break; + case R.id.action_download: + startActivity(new Intent(this, DownloadsActivity.class), + ViewUtil.getEmptyActivityBundle(this)); + break; + case R.id.action_setting: + startActivity(new Intent(this, SettingsActivity.class), + ViewUtil.getEmptyActivityBundle(this)); + break; + case R.id.action_about: + intent.putExtra(Constants.FRAGMENT_NAME, Constants.FRAGMENT_ABOUT); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + break; + case R.id.action_favourite: + intent.putExtra(Constants.FRAGMENT_NAME, Constants.FRAGMENT_FAV_LIST); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + break; + case R.id.action_blacklist: + intent.putExtra(Constants.FRAGMENT_NAME, Constants.FRAGMENT_BLACKLIST); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + break; + case R.id.action_spoof: + intent.putExtra(Constants.FRAGMENT_NAME, Constants.FRAGMENT_SPOOF); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + break; + } + return false; + }); + } + + private void checkSelfUpdate() { + Log.d("Checking updates for Aurora Store"); + disposable.add(Observable.fromCallable(() -> new NetworkTask(this) + .get(Constants.UPDATE_URL)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> { + try { + Util.setSelfUpdateTime(this, Calendar.getInstance().getTimeInMillis()); + Gson gson = new Gson(); + Update update = gson.fromJson(response, Update.class); + + if (update.getVersionCode() > BuildConfig.VERSION_CODE) { + if (CertUtil.isFDroidApp(this, BuildConfig.APPLICATION_ID) + && TextUtil.emptyIfNull(update.getFdroidBuild()).isEmpty()) { + Log.d("FDroid build of latest version is not published yet"); + return; + } + + if (!update.getAuroraBuild().isEmpty()) + showUpdatesDialog(update); + else + Log.d("No new update available"); + + } + } catch (Exception e) { + Log.e("Error checking updates"); + } + })); + } + + private void checkPermissions() { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + 1337); + } + } + + private void createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel alertChannel = new NotificationChannel( + Constants.NOTIFICATION_CHANNEL_ALERT, + getString(R.string.notification_channel_alert), + NotificationManager.IMPORTANCE_HIGH); + + NotificationChannel generalChannel = new NotificationChannel( + Constants.NOTIFICATION_CHANNEL_GENERAL, + getString(R.string.notification_channel_general), + NotificationManager.IMPORTANCE_MIN); + + alertChannel.enableLights(true); + alertChannel.enableVibration(true); + alertChannel.setShowBadge(true); + alertChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC); + + generalChannel.enableLights(false); + generalChannel.enableVibration(false); + generalChannel.setShowBadge(false); + generalChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PRIVATE); + + NotificationManager notificationManager = getSystemService(NotificationManager.class); + if (notificationManager != null) { + notificationManager.createNotificationChannel(alertChannel); + notificationManager.createNotificationChannel(generalChannel); + } + } + checkPermissions(); + } + + + protected void showUpdatesDialog(Update update) { + final String changelog = TextUtil.emptyIfNull(update.getChangelog()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this) + .setTitle(getString(R.string.dialog_title_self_update)) + .setMessage(new StringBuilder() + .append(update.getVersionName()) + .append("\n\n") + .append(changelog.isEmpty() ? getString(R.string.details_no_changes) : changelog) + .append("\n\n") + .append(getString(R.string.dialog_desc_self_update)) + .toString()) + .setPositiveButton(getString(android.R.string.yes), (dialog, which) -> { + Intent intent = new Intent(this, SelfUpdateService.class); + startService(intent); + }) + .setNegativeButton(getString(android.R.string.no), (dialog, which) -> { + dialog.dismiss(); + }); + builder.create(); + builder.show(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java new file mode 100644 index 000000000..a2d70bd8f --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java @@ -0,0 +1,111 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.main.fragment.category; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.Constants; +import com.aurora.store.R; +import com.aurora.store.manager.CategoryManager; +import com.aurora.store.section.CategoriesSection; +import com.aurora.store.ui.category.CategoryAppsActivity; +import com.aurora.store.ui.main.AuroraActivity; +import com.aurora.store.util.ViewUtil; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; + +public class CategoriesFragment extends Fragment implements CategoriesSection.ClickListener { + + private static final String TAG_CATEGORIES_ALL = "TAG_CATEGORIES_ALL"; + private static final String TAG_CATEGORIES_GAME = "TAG_CATEGORIES_GAME"; + private static final String TAG_CATEGORIES_FAMILY = "TAG_CATEGORIES_FAMILY"; + + @BindView(R.id.category_recycler) + RecyclerView recyclerView; + @BindView(R.id.progress_bar) + ProgressBar progressBar; + + private Context context; + private CategoryManager categoryManager; + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + this.context = context; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + View view = inflater.inflate(R.layout.fragment_categories, container, false); + ButterKnife.bind(this, view); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + categoryManager = new CategoryManager(context); + CategoriesModel categoriesModel = ViewModelProviders.of(this).get(CategoriesModel.class); + categoriesModel.getFetchCompleted().observe(this, success -> { + if (success) { + setupRecycler(); + progressBar.setVisibility(View.GONE); + } + }); + categoriesModel.fetchCategories(); + } + + private void setupRecycler() { + SectionedRecyclerViewAdapter viewAdapter = new SectionedRecyclerViewAdapter(); + viewAdapter.addSection(TAG_CATEGORIES_ALL, new CategoriesSection(context, + categoryManager.getCategories(Constants.CATEGORY_APPS), getString(R.string.category_all), this)); + viewAdapter.addSection(TAG_CATEGORIES_GAME, new CategoriesSection(context, + categoryManager.getCategories(Constants.CATEGORY_GAME), getString(R.string.category_games), this)); + viewAdapter.addSection(TAG_CATEGORIES_FAMILY, new CategoriesSection(context, + categoryManager.getCategories(Constants.CATEGORY_FAMILY), getString(R.string.category_family), this)); + recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); + recyclerView.setAdapter(viewAdapter); + } + + @Override + public void onClick(String categoryId, String categoryName) { + Intent intent = new Intent(context, CategoryAppsActivity.class); + intent.putExtra("CategoryId", categoryId); + intent.putExtra("CategoryName", categoryName); + context.startActivity(intent, ViewUtil.getEmptyActivityBundle((AuroraActivity) context)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java new file mode 100644 index 000000000..c636cdd90 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java @@ -0,0 +1,63 @@ +package com.aurora.store.ui.main.fragment.category; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.manager.CategoryManager; +import com.aurora.store.task.CategoryListTask; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class CategoriesModel extends AndroidViewModel { + + private Application application; + private CompositeDisposable disposable = new CompositeDisposable(); + + private GooglePlayAPI api; + private CategoryManager categoryManager; + private MutableLiveData fetchCompleted = new MutableLiveData<>(); + + public CategoriesModel(@NonNull Application application) { + super(application); + this.application = application; + this.api = AuroraApplication.api; + this.categoryManager = new CategoryManager(application); + } + + public MutableLiveData getFetchCompleted() { + return fetchCompleted; + } + + public void fetchCategories() { + if (categoryManager.categoryListEmpty()) + getCategoriesFromAPI(); + else + fetchCompleted.setValue(true); + } + + private void getCategoriesFromAPI() { + disposable.add(Observable.fromCallable(() -> new CategoryListTask(application, api) + .getResult()) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(status -> { + fetchCompleted.setValue(status); + }, err -> { + + })); + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeAppsModel.java b/app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeAppsModel.java new file mode 100644 index 000000000..12faf4a0f --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeAppsModel.java @@ -0,0 +1,137 @@ +package com.aurora.store.ui.main.fragment.home; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.enums.ErrorType; +import com.aurora.store.model.App; +import com.aurora.store.task.FeaturedAppsTask; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.Calendar; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class HomeAppsModel extends AndroidViewModel { + + private Application application; + private CompositeDisposable disposable = new CompositeDisposable(); + + private GooglePlayAPI api; + private Gson gson = new Gson(); + + private MutableLiveData> mutableTopGames = new MutableLiveData<>(); + private MutableLiveData> mutableTopApps = new MutableLiveData<>(); + private MutableLiveData> mutableTopFamily = new MutableLiveData<>(); + private MutableLiveData mutableError = new MutableLiveData<>(); + + public HomeAppsModel(@NonNull Application application) { + super(application); + this.application = application; + this.api = AuroraApplication.api; + + //Fetch top chart apps + fetchAppsFromCache(Constants.TOP_APPS); + fetchAppsFromCache(Constants.TOP_GAME); + fetchAppsFromCache(Constants.TOP_FAMILY); + } + + public LiveData getError() { + return mutableError; + } + + public LiveData> getTopGames() { + return mutableTopGames; + } + + public LiveData> getTopApps() { + return mutableTopApps; + } + + public LiveData> getTopFamily() { + return mutableTopFamily; + } + + private void fetchAppsFromCache(String categoryId) { + Type type = new TypeToken>() { + }.getType(); + String jsonString = PrefUtil.getString(application, categoryId); + List appList = gson.fromJson(jsonString, type); + if (appList != null && !appList.isEmpty()) { + switch (categoryId) { + case Constants.TOP_APPS: + mutableTopApps.setValue(appList); + break; + case Constants.TOP_GAME: + mutableTopGames.setValue(appList); + break; + case Constants.TOP_FAMILY: + mutableTopFamily.setValue(appList); + break; + } + } else + fetchApps(categoryId); + } + + private void fetchApps(String categoryId) { + disposable.add(Observable.fromCallable(() -> new FeaturedAppsTask(application) + .getApps(api, getPlayCategoryId(categoryId), GooglePlayAPI.SUBCATEGORY.TOP_FREE)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + switch (categoryId) { + case Constants.TOP_APPS: + mutableTopApps.setValue(appList); + break; + case Constants.TOP_GAME: + mutableTopGames.setValue(appList); + break; + case Constants.TOP_FAMILY: + mutableTopFamily.setValue(appList); + break; + } + saveToCache(appList, categoryId); + Util.setCacheCreateTime(application, Calendar.getInstance().getTimeInMillis()); + }, err -> { + mutableError.setValue(ErrorType.UNKNOWN); + })); + } + + private String getPlayCategoryId(String categoryId) { + switch (categoryId) { + case Constants.TOP_FAMILY: + return Constants.CATEGORY_FAMILY; + case Constants.TOP_GAME: + return Constants.CATEGORY_GAME; + default: + return Constants.CATEGORY_APPS; + } + } + + private void saveToCache(List appList, String key) { + Gson gson = new Gson(); + String jsonString = gson.toJson(appList); + PrefUtil.putString(application, key, jsonString); + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeFragment.java b/app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeFragment.java new file mode 100644 index 000000000..748384a0e --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/home/HomeFragment.java @@ -0,0 +1,171 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.main.fragment.home; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.Constants; +import com.aurora.store.R; +import com.aurora.store.SharedPreferencesTranslator; +import com.aurora.store.adapter.FeaturedAppsAdapter; +import com.aurora.store.ui.category.CategoryAppsActivity; +import com.aurora.store.ui.main.AuroraActivity; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.google.android.material.button.MaterialButton; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.disposables.CompositeDisposable; + +public class HomeFragment extends Fragment { + + @BindView(R.id.recycler_top_apps) + RecyclerView recyclerTopApps; + @BindView(R.id.recycler_top_games) + RecyclerView recyclerTopGames; + @BindView(R.id.recycler_top_family) + RecyclerView recyclerTopFamily; + + @BindView(R.id.btn_top_apps) + MaterialButton btnTopApps; + @BindView(R.id.btn_top_games) + MaterialButton btnTopGames; + @BindView(R.id.btn_top_family) + MaterialButton btnTopFamily; + + private Context context; + private FeaturedAppsAdapter topAppsAdapter; + private FeaturedAppsAdapter topGamesAdapter; + private FeaturedAppsAdapter topFamilyAdapter; + private SharedPreferencesTranslator translator; + private CompositeDisposable disposable = new CompositeDisposable(); + + @Override + public void onStart() { + super.onStart(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + this.context = context; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + translator = new SharedPreferencesTranslator(Util.getPrefs(context)); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_home, container, false); + ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + init(); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setupRecyclers(); + HomeAppsModel homeAppsModel = ViewModelProviders.of(this).get(HomeAppsModel.class); + homeAppsModel.getTopApps().observe(this, appList -> { + topAppsAdapter.addData(appList); + }); + homeAppsModel.getTopGames().observe(this, appList -> { + topGamesAdapter.addData(appList); + }); + homeAppsModel.getTopFamily().observe(this, appList -> { + topFamilyAdapter.addData(appList); + }); + homeAppsModel.getError().observe(this, errorType -> { + + }); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onDestroy() { + disposable.clear(); + super.onDestroy(); + } + + private void init() { + setupButtons(); + } + + private void setupButtons() { + btnTopApps.setOnClickListener(v -> openCategoryAppsActivity(Constants.CATEGORY_APPS)); + btnTopGames.setOnClickListener(v -> openCategoryAppsActivity(Constants.CATEGORY_GAME)); + btnTopFamily.setOnClickListener(v -> openCategoryAppsActivity(Constants.CATEGORY_FAMILY)); + } + + private void setupRecyclers() { + topAppsAdapter = new FeaturedAppsAdapter(context); + topGamesAdapter = new FeaturedAppsAdapter(context); + topFamilyAdapter = new FeaturedAppsAdapter(context); + + recyclerTopApps.setAdapter(topAppsAdapter); + recyclerTopApps.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); + + recyclerTopGames.setAdapter(topGamesAdapter); + recyclerTopGames.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); + + recyclerTopFamily.setAdapter(topFamilyAdapter); + recyclerTopFamily.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); + + Util.attachSnapPager(context, recyclerTopApps); + Util.attachSnapPager(context, recyclerTopGames); + Util.attachSnapPager(context, recyclerTopFamily); + } + + private void openCategoryAppsActivity(String categoryId) { + Intent intent = new Intent(context, CategoryAppsActivity.class); + intent.putExtra("CategoryId", categoryId); + intent.putExtra("CategoryName", translator.getString(categoryId)); + context.startActivity(intent, ViewUtil.getEmptyActivityBundle((AuroraActivity) context)); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java new file mode 100644 index 000000000..c7a867645 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java @@ -0,0 +1,77 @@ +package com.aurora.store.ui.main.fragment.updates; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.enums.ErrorType; +import com.aurora.store.exception.CredentialsEmptyException; +import com.aurora.store.exception.InvalidApiException; +import com.aurora.store.model.App; +import com.aurora.store.task.UpdatableAppsTask; +import com.dragons.aurora.playstoreapiv2.AuthException; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; + +import java.net.UnknownHostException; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class UpdatableAppsModel extends AndroidViewModel { + + private Application application; + private CompositeDisposable disposable = new CompositeDisposable(); + + private GooglePlayAPI api; + + + private MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + private MutableLiveData errorTypeMutableLiveData = new MutableLiveData<>(); + + public UpdatableAppsModel(@NonNull Application application) { + super(application); + this.application = application; + this.api = AuroraApplication.api; + fetchUpdatableApps(); + } + + public LiveData getErrorTypeMutableLiveData() { + return errorTypeMutableLiveData; + } + + public LiveData> getListMutableLiveData() { + return listMutableLiveData; + } + + public void fetchUpdatableApps() { + disposable.add(Observable.fromCallable(() -> new UpdatableAppsTask(api, application) + .getUpdatableApps()) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + listMutableLiveData.setValue(appList); + }, err -> { + if (err instanceof CredentialsEmptyException || err instanceof InvalidApiException) + errorTypeMutableLiveData.setValue(ErrorType.LOGOUT_ERR); + else if (err instanceof AuthException) + errorTypeMutableLiveData.setValue(ErrorType.SESSION_EXPIRED); + else if (err instanceof UnknownHostException) + errorTypeMutableLiveData.setValue(ErrorType.NO_NETWORK); + else + errorTypeMutableLiveData.setValue(ErrorType.UNKNOWN); + })); + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java new file mode 100644 index 000000000..f4a953267 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java @@ -0,0 +1,243 @@ +/* + * Aurora Store + * Copyright (C) 2019, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + * + */ + +package com.aurora.store.ui.main.fragment.updates; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.AppDiffCallback; +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.R; +import com.aurora.store.download.DownloadManager; +import com.aurora.store.model.App; +import com.aurora.store.section.UpdateAppSection; +import com.aurora.store.sheet.AppMenuSheet; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.main.AuroraActivity; +import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.google.android.material.button.MaterialButton; +import com.tonyodev.fetch2.Fetch; + +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; +import io.reactivex.disposables.CompositeDisposable; + + +public class UpdatesFragment extends Fragment implements UpdateAppSection.ClickListener { + + @BindView(R.id.swipe_layout) + CustomSwipeToRefresh customSwipeToRefresh; + @BindView(R.id.recycler) + RecyclerView recyclerView; + @BindView(R.id.txt_update_all) + AppCompatTextView txtUpdateAll; + @BindView(R.id.btn_action) + MaterialButton btnAction; + + private Context context; + private Fetch fetch; + private CompositeDisposable disposable = new CompositeDisposable(); + + private UpdatableAppsModel model; + private UpdateAppSection section; + private SectionedRecyclerViewAdapter adapter; + + @Override + public void onAttach(@NotNull Context context) { + super.onAttach(context); + this.context = context; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_updates, container, false); + ButterKnife.bind(this, view); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + fetch = DownloadManager.getFetchInstance(context); + setupRecycler(); + + model = ViewModelProviders.of(this).get(UpdatableAppsModel.class); + model.getListMutableLiveData().observe(this, appList -> { + dispatchAppsToAdapter(appList); + customSwipeToRefresh.setRefreshing(false); + }); + + model.getErrorTypeMutableLiveData().observe(this, errorType -> { + switch (errorType) { + case NO_API: + case SESSION_EXPIRED: + Util.validateApi(context); + break; + } + }); + + customSwipeToRefresh.setOnRefreshListener(() -> model.fetchUpdatableApps()); + + disposable.add(AuroraApplication + .getRxBus() + .getBus() + .subscribe(event -> { + switch (event.getSubType()) { + case BLACKLIST: + case INSTALLED: + removeAppFromAdapter(event.getPackageName()); + break; + case API_SUCCESS: + case NETWORK_AVAILABLE: + model.fetchUpdatableApps(); + break; + case BULK_UPDATE_NOTIFY: + drawButtons(); + break; + } + })); + } + + @Override + public void onPause() { + super.onPause(); + customSwipeToRefresh.setRefreshing(false); + } + + @Override + public void onDestroy() { + try { + disposable.clear(); + } catch (Exception ignored) { + } + super.onDestroy(); + } + + private void removeAppFromAdapter(String packageName) { + int position = section.removeApp(packageName); + adapter.notifyItemRemoved(position); + AuroraApplication.removeFromOngoingUpdateList(packageName); + drawButtons(); + updateCounter(); + } + + private void dispatchAppsToAdapter(List newList) { + List oldList = section.getList(); + if (oldList.isEmpty()) { + section.updateList(newList); + adapter.notifyDataSetChanged(); + } else { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new AppDiffCallback(newList, oldList)); + diffResult.dispatchUpdatesTo(adapter); + section.updateList(newList); + } + updateCounter(); + drawButtons(); + } + + private void setupRecycler() { + customSwipeToRefresh.setRefreshing(false); + adapter = new SectionedRecyclerViewAdapter(); + section = new UpdateAppSection(context, this); + adapter.addSection(section); + recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); + recyclerView.setAdapter(adapter); + } + + private void drawButtons() { + if (AuroraApplication.isBulkUpdateAlive()) { + btnAction.setText(getString(R.string.action_cancel)); + btnAction.setOnClickListener(v -> { + cancelAllRequests(); + AuroraApplication.setOngoingUpdateList(new ArrayList<>()); + Util.stopBulkUpdate(context); + }); + } else { + btnAction.setText(getString(R.string.list_update_all)); + btnAction.setOnClickListener(v -> { + AuroraApplication.setOngoingUpdateList(section.getList()); + Util.bulkUpdate(context); + }); + } + } + + private void updateCounter() { + int size = section.getList().size(); + if (size == 0) { + btnAction.setVisibility(View.INVISIBLE); + txtUpdateAll.setVisibility(View.INVISIBLE); + } else { + txtUpdateAll.setText(new StringBuilder() + .append(size) + .append(StringUtils.SPACE) + .append(size == 1 ? context.getString(R.string.list_update_all_txt_one) : + context.getString(R.string.list_update_all_txt))); + btnAction.setVisibility(View.VISIBLE); + txtUpdateAll.setVisibility(View.VISIBLE); + } + } + + private void cancelAllRequests() { + List ongoingUpdateList = AuroraApplication.getOngoingUpdateList(); + for (App app : ongoingUpdateList) { + fetch.deleteGroup(app.getPackageName().hashCode()); + } + } + + @Override + public void onClick(App app) { + DetailsActivity.app = app; + Intent intent = new Intent(context, DetailsActivity.class); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, app.getPackageName()); + context.startActivity(intent, ViewUtil.getEmptyActivityBundle((AuroraActivity) context)); + } + + @Override + public void onLongClick(App app) { + AppMenuSheet menuSheet = new AppMenuSheet(); + menuSheet.setApp(app); + menuSheet.show(getChildFragmentManager(), "BOTTOM_MENU_SHEET"); + } +} diff --git a/app/src/main/java/com/aurora/store/activity/SettingsActivity.java b/app/src/main/java/com/aurora/store/ui/preference/SettingsActivity.java similarity index 90% rename from app/src/main/java/com/aurora/store/activity/SettingsActivity.java rename to app/src/main/java/com/aurora/store/ui/preference/SettingsActivity.java index ccaa84290..4b97274fa 100644 --- a/app/src/main/java/com/aurora/store/activity/SettingsActivity.java +++ b/app/src/main/java/com/aurora/store/ui/preference/SettingsActivity.java @@ -18,27 +18,26 @@ * */ -package com.aurora.store.activity; +package com.aurora.store.ui.preference; import android.os.Bundle; import android.view.MenuItem; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import com.aurora.store.R; -import com.aurora.store.utility.ThemeUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.util.Util; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import butterknife.BindView; import butterknife.ButterKnife; -public class SettingsActivity extends AppCompatActivity implements +public class SettingsActivity extends BaseActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { public static boolean shouldRestart = false; @@ -46,12 +45,9 @@ public class SettingsActivity extends AppCompatActivity implements @BindView(R.id.toolbar) Toolbar toolbar; - private ThemeUtil themeUtil = new ThemeUtil(); - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - themeUtil.onCreate(this); setContentView(R.layout.activity_settings); ButterKnife.bind(this); setupActionBar(); @@ -82,7 +78,6 @@ public class SettingsActivity extends AppCompatActivity implements @Override protected void onResume() { super.onResume(); - themeUtil.onResume(this); } @Override @@ -120,7 +115,7 @@ public class SettingsActivity extends AppCompatActivity implements } private void askRestart() { - MaterialAlertDialogBuilder mBuilder = new MaterialAlertDialogBuilder(this) + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this) .setTitle(getString(R.string.action_restart)) .setMessage(getString(R.string.pref_dialog_to_apply_restart)) .setPositiveButton(getString(R.string.action_restart), (dialog, which) -> { @@ -129,8 +124,8 @@ public class SettingsActivity extends AppCompatActivity implements .setNegativeButton(getString(R.string.action_later), (dialog, which) -> { dialog.dismiss(); }); - mBuilder.create(); - mBuilder.show(); + builder.create(); + builder.show(); } public static class SettingsFragment extends PreferenceFragmentCompat { diff --git a/app/src/main/java/com/aurora/store/fragment/preference/AboutFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/AboutFragment.java similarity index 97% rename from app/src/main/java/com/aurora/store/fragment/preference/AboutFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/AboutFragment.java index 08ddcd1f3..a3b03a0e0 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/AboutFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/AboutFragment.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.pm.PackageInfo; @@ -34,7 +34,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.aurora.store.R; -import com.aurora.store.view.LinkView; +import com.aurora.store.ui.view.LinkView; import butterknife.BindView; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/aurora/store/fragment/preference/BlacklistFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/BlacklistFragment.java similarity index 51% rename from app/src/main/java/com/aurora/store/fragment/preference/BlacklistFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/BlacklistFragment.java index 151e8959e..9b99a5df5 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/BlacklistFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/BlacklistFragment.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.os.Bundle; @@ -30,19 +30,20 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.aurora.store.ErrorType; +import com.aurora.store.AppDiffCallback; import com.aurora.store.R; -import com.aurora.store.adapter.BlacklistAdapter; -import com.aurora.store.fragment.BaseFragment; import com.aurora.store.manager.BlacklistManager; import com.aurora.store.model.App; -import com.aurora.store.task.InstalledAppsTask; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.ViewUtil; -import com.aurora.store.view.CustomSwipeToRefresh; +import com.aurora.store.section.BlackListedAppSection; +import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.util.ViewUtil; +import com.aurora.store.viewmodel.BlackListedAppsModel; import java.util.ArrayList; import java.util.Collections; @@ -50,12 +51,12 @@ import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; -public class BlacklistFragment extends BaseFragment implements BlacklistAdapter.ItemClickListener { +public class BlacklistFragment extends Fragment implements BlackListedAppSection.ClickListener { + + private static final String TAG_BLACKED = "TAG_BLACKED"; @BindView(R.id.swipe_layout) CustomSwipeToRefresh customSwipeToRefresh; @@ -67,13 +68,16 @@ public class BlacklistFragment extends BaseFragment implements BlacklistAdapter. TextView txtBlacklist; private Context context; - private BlacklistAdapter blacklistAdapter; private BlacklistManager blacklistManager; + private BlackListedAppsModel model; + private BlackListedAppSection section; + private SectionedRecyclerViewAdapter adapter; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); this.context = context; + this.blacklistManager = new BlacklistManager(context); } @Override @@ -81,56 +85,21 @@ public class BlacklistFragment extends BaseFragment implements BlacklistAdapter. super.onCreate(savedInstanceState); View view = inflater.inflate(R.layout.fragment_blacklist, container, false); ButterKnife.bind(this, view); - customSwipeToRefresh.setOnRefreshListener(() -> fetchData()); - blacklistManager = new BlacklistManager(context); return view; } @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setErrorView(ErrorType.UNKNOWN); - fetchData(); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); setupClearAll(); - } - - @Override - public void onResume() { - super.onResume(); - } - - private void updateBlackListedApps() { - blacklistAdapter.addSelectionsToBlackList(); - } - - private void clearBlackListedApps() { - if (blacklistAdapter != null) { - blacklistAdapter.removeSelectionsFromBlackList(); - blacklistAdapter.notifyDataSetChanged(); - txtBlacklist.setText(getString(R.string.list_blacklist_none)); - } - } - - @Override - protected void fetchData() { - InstalledAppsTask mTaskHelper = new InstalledAppsTask(context); - disposable.add(Observable.fromCallable(mTaskHelper::getAllApps) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe(subscription -> customSwipeToRefresh.setRefreshing(true)) - .doOnTerminate(() -> customSwipeToRefresh.setRefreshing(false)) - .subscribe((appList) -> { - if (appList.isEmpty()) { - setErrorView(ErrorType.NO_APPS); - switchViews(true); - } else { - switchViews(false); - setupRecycler(appList); - } - }, err -> { - Log.e(err.getMessage()); - processException(err); - })); + setupRecycler(); + model = ViewModelProviders.of(this).get(BlackListedAppsModel.class); + model.getAllApps().observe(this, appList -> { + appList = sortBlackListedApps(appList); + dispatchAppsToAdapter(appList); + }); + model.getAllBlackListedApps(); + customSwipeToRefresh.setOnRefreshListener(() -> model.fetchBlackListedApps()); } private List sortBlackListedApps(List appList) { @@ -148,36 +117,45 @@ public class BlacklistFragment extends BaseFragment implements BlacklistAdapter. else whiteListedApps.add(app); } + sortListedApps.addAll(blackListedApps); sortListedApps.addAll(whiteListedApps); return sortListedApps; } - private void setupRecycler(List appList) { - appList = sortBlackListedApps(appList); - blacklistAdapter = new BlacklistAdapter(context, appList, this); - recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); - recyclerView.setAdapter(blacklistAdapter); + private void dispatchAppsToAdapter(List newList) { + List oldList = section.getList(); + if (oldList.isEmpty()) { + section.updateList(newList); + adapter.notifyDataSetChanged(); + } else { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new AppDiffCallback(newList, oldList)); + diffResult.dispatchUpdatesTo(adapter); + section.updateList(newList); + } updateCount(); } - @Override - protected View.OnClickListener errRetry() { - return v -> { - fetchData(); - ((Button) v).setText(getString(R.string.action_retry_ing)); - ((Button) v).setEnabled(false); - }; + private void setupRecycler() { + customSwipeToRefresh.setRefreshing(false); + section = new BlackListedAppSection(context, blacklistManager.get(), this); + adapter = new SectionedRecyclerViewAdapter(); + adapter.addSection(TAG_BLACKED, section); + recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); + recyclerView.setAdapter(adapter); } private void setupClearAll() { btnClearAll.setOnClickListener(v -> { - clearBlackListedApps(); + blacklistManager.removeAll(); + section.getBlacklist().clear(); + adapter.notifyDataSetChanged(); + updateCount(); }); } private void updateCount() { - int count = blacklistAdapter.getSelectedCount(); + int count = section.getBlacklist().size(); String txtCount = new StringBuilder() .append(context.getResources().getString(R.string.list_blacklist)) .append(" : ") @@ -187,36 +165,17 @@ public class BlacklistFragment extends BaseFragment implements BlacklistAdapter. } @Override - public void onItemClicked(int position) { - blacklistAdapter.toggleSelection(position); - updateBlackListedApps(); - updateCount(); - } - - @Override - public void notifyLoggedIn() { - fetchData(); - } - - @Override - public void notifyLoggedOut() { - - } - - @Override - public void notifyPermanentFailure() { - setErrorView(ErrorType.UNKNOWN); - switchViews(true); - } - - @Override - public void notifyNetworkFailure() { - setErrorView(ErrorType.NO_NETWORK); - switchViews(true); - } - - @Override - public void notifyTokenExpired() { - + public void onClick(int position, String packageName) { + recyclerView.post(() -> { + if (blacklistManager.contains(packageName) || section.getBlacklist().contains(packageName)) { + blacklistManager.remove(packageName); + section.remove(packageName); + } else { + blacklistManager.add(packageName); + section.add(packageName); + } + adapter.notifyItemChanged(position); + updateCount(); + }); } } diff --git a/app/src/main/java/com/aurora/store/fragment/preference/DownloaderFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/DownloaderFragment.java similarity index 95% rename from app/src/main/java/com/aurora/store/fragment/preference/DownloaderFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/DownloaderFragment.java index d20dee838..b15325de7 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/DownloaderFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/DownloaderFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.Manifest; import android.content.Context; @@ -19,11 +19,11 @@ import androidx.preference.SwitchPreferenceCompat; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.SettingsActivity; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.PathUtil; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.PathUtil; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; import java.io.File; import java.io.IOException; diff --git a/app/src/main/java/com/aurora/store/fragment/preference/FavouriteFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/FavouriteFragment.java similarity index 54% rename from app/src/main/java/com/aurora/store/fragment/preference/FavouriteFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/FavouriteFragment.java index 89e676801..4f0d13102 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/FavouriteFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/FavouriteFragment.java @@ -18,45 +18,39 @@ * */ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.widget.Button; -import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.aurora.store.AppDiffCallback; import com.aurora.store.Constants; -import com.aurora.store.ErrorType; -import com.aurora.store.FavouriteItemTouchHelper; import com.aurora.store.R; -import com.aurora.store.adapter.FavouriteAppsAdapter; -import com.aurora.store.adapter.SelectableViewHolder; import com.aurora.store.exception.MalformedRequestException; -import com.aurora.store.fragment.BaseFragment; import com.aurora.store.manager.FavouriteListManager; import com.aurora.store.model.App; -import com.aurora.store.task.BulkDetails; +import com.aurora.store.section.FavouriteAppSection; import com.aurora.store.task.LiveUpdate; import com.aurora.store.task.ObservableDeliveryData; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.NetworkUtil; -import com.aurora.store.utility.PathUtil; -import com.aurora.store.view.CustomSwipeToRefresh; - -import org.apache.commons.lang3.StringUtils; +import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.util.Log; +import com.aurora.store.util.PathUtil; +import com.aurora.store.util.ViewUtil; +import com.aurora.store.viewmodel.FavouriteAppsModel; +import com.google.android.material.button.MaterialButton; import java.io.File; import java.io.FileInputStream; @@ -71,51 +65,35 @@ import java.util.Scanner; import butterknife.BindView; import butterknife.ButterKnife; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -public class FavouriteFragment extends BaseFragment implements SelectableViewHolder.ItemClickListener, - FavouriteItemTouchHelper.RecyclerItemTouchHelperListener { +public class FavouriteFragment extends Fragment implements FavouriteAppSection.ClickListener { - private static final int FAV_GROUP_ID = 1338; + + private static final String TAG_FAV = "TAG_FAV"; @BindView(R.id.swipe_refresh_layout) - CustomSwipeToRefresh swipeRefreshLayout; - @BindView(R.id.fav_apps_list) - RecyclerView favRecyclerView; - @BindView(R.id.empty_favourites) - RelativeLayout emptyLayout; + CustomSwipeToRefresh customSwipeToRefresh; + @BindView(R.id.recycler) + RecyclerView recyclerView; @BindView(R.id.export_list) - Button buttonExport; - @BindView(R.id.import_list) - Button buttonImport; + MaterialButton buttonExport; @BindView(R.id.install_list) - Button buttonInstall; + MaterialButton buttonInstall; @BindView(R.id.count_selection) TextView txtCount; private Context context; - private FavouriteListManager manager; - private List favouriteApps; - private List selectedApps; - private ArrayList favouriteList; - private FavouriteAppsAdapter favouriteAppsAdapter; private CompositeDisposable disposable = new CompositeDisposable(); - @Override - protected View.OnClickListener errRetry() { - return v -> { - favouriteList = importList(); - if (!favouriteList.isEmpty()) { - manager.addAll(favouriteList); - fetchData(); - } else { - Toast.makeText(context, "No favourite list to import", Toast.LENGTH_SHORT).show(); - } - }; - } + private FavouriteListManager favouriteListManager; + private FavouriteAppsModel model; + private FavouriteAppSection section; + private SectionedRecyclerViewAdapter adapter; @Override public void onAttach(@NonNull Context context) { @@ -126,7 +104,7 @@ public class FavouriteFragment extends BaseFragment implements SelectableViewHol @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - manager = new FavouriteListManager(context); + favouriteListManager = new FavouriteListManager(context); } @Override @@ -138,41 +116,34 @@ public class FavouriteFragment extends BaseFragment implements SelectableViewHol } @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setErrorView(ErrorType.IMPORT); - swipeRefreshLayout.setOnRefreshListener(() -> { - if (Accountant.isLoggedIn(context) && NetworkUtil.isConnected(context)) - fetchData(); - else - swipeRefreshLayout.setRefreshing(false); - }); - + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); buttonInstall.setOnClickListener(bulkInstallListener()); buttonExport.setOnClickListener(v -> { exportList(); }); - fetchData(); - } - - @Override - public void onResume() { - super.onResume(); - if (favouriteAppsAdapter != null && favouriteAppsAdapter.isEmpty()) - fetchData(); + setupRecycler(); + model = ViewModelProviders.of(this).get(FavouriteAppsModel.class); + model.getFavouriteApps().observe(this, appList -> { + dispatchAppsToAdapter(appList); + }); + model.fetchFavouriteApps(); + customSwipeToRefresh.setOnRefreshListener(() -> { + model.fetchFavouriteApps(); + }); } @Override public void onPause() { super.onPause(); - swipeRefreshLayout.setRefreshing(false); + customSwipeToRefresh.setRefreshing(false); } private View.OnClickListener bulkInstallListener() { return v -> { buttonInstall.setText(getString(R.string.details_installing)); buttonInstall.setEnabled(false); - disposable.add(Observable.fromIterable(selectedApps) + disposable.add(Observable.fromIterable(section.getSelectedList()) .flatMap(app -> new ObservableDeliveryData(context).getDeliveryData(app)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -191,7 +162,7 @@ public class FavouriteFragment extends BaseFragment implements SelectableViewHol private void exportList() { try { - ArrayList packageList = manager.get(); + ArrayList packageList = favouriteListManager.get(); File file = verifyAndGetFile(); if (file != null) { OutputStream fileOutputStream = new FileOutputStream(file, false); @@ -250,67 +221,47 @@ public class FavouriteFragment extends BaseFragment implements SelectableViewHol return null; } - @Override - protected void fetchData() { - favouriteList = manager.get(); - if (favouriteList.isEmpty()) { - setErrorView(ErrorType.IMPORT); - switchViews(true); - } else - disposable.add(Observable.fromCallable(() -> new BulkDetails(context) - .getRemoteAppList(favouriteList)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe(start -> swipeRefreshLayout.setRefreshing(true)) - .doOnTerminate(() -> swipeRefreshLayout.setRefreshing(false)) - .doOnComplete(() -> buttonExport.setEnabled(true)) - .subscribe((appList) -> { - if (appList.isEmpty()) { - setErrorView(ErrorType.NO_APPS); - switchViews(true); - } else { - switchViews(false); - favouriteApps = appList; - setupFavourites(favouriteApps); - } - }, err -> Log.e(Constants.TAG, err.getMessage()))); - } - - private void setupFavourites(List appsToAdd) { - favouriteAppsAdapter = new FavouriteAppsAdapter(context, this, appsToAdd); - favRecyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); - favRecyclerView.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(context, R.anim.anim_falldown)); - favRecyclerView.setAdapter(favouriteAppsAdapter); - new ItemTouchHelper( - new FavouriteItemTouchHelper(0, ItemTouchHelper.LEFT, this)) - .attachToRecyclerView(favRecyclerView); - } - - @Override - public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position) { - if (viewHolder instanceof SelectableViewHolder) { - favouriteAppsAdapter.remove(position); - if (favouriteAppsAdapter.getItemCount() < 1) { - setErrorView(ErrorType.IMPORT); - switchViews(true); - } - } - } - - @Override - public void onItemClicked(int position) { - favouriteAppsAdapter.toggleSelection(position); - selectedApps = favouriteAppsAdapter.getSelectedList(); - if (selectedApps.isEmpty()) { - buttonInstall.setEnabled(false); - txtCount.setText(""); + private void dispatchAppsToAdapter(List newList) { + List oldList = section.getAppList(); + if (oldList.isEmpty()) { + section.updateList(newList); + adapter.notifyDataSetChanged(); } else { - buttonInstall.setEnabled(true); - txtCount.setText(new StringBuilder() - .append(getString(R.string.list_selected)) - .append(StringUtils.SPACE) - .append(selectedApps.size()) - ); + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new AppDiffCallback(newList, oldList)); + diffResult.dispatchUpdatesTo(adapter); + section.updateList(newList); } + updateCount(section.getSelections().size()); + } + + private void updateCount(int count) { + String ss = new StringBuilder() + .append(context.getResources().getString(R.string.list_selected)) + .append(" : ") + .append(count).toString(); + txtCount.setText(count > 0 ? ss : getString(R.string.list_empty_fav)); + ViewUtil.setVisibility(buttonInstall, count > 0, true); + } + + private void setupRecycler() { + customSwipeToRefresh.setRefreshing(false); + section = new FavouriteAppSection(context, this); + adapter = new SectionedRecyclerViewAdapter(); + adapter.addSection(TAG_FAV, section); + recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); + recyclerView.setAdapter(adapter); + } + + @Override + public void onClick(int position, String packageName) { + recyclerView.post(() -> { + if (section.getSelections().contains(packageName)) { + section.remove(packageName); + } else { + section.add(packageName); + } + adapter.notifyItemChanged(position); + updateCount(section.getSelections().size()); + }); } } diff --git a/app/src/main/java/com/aurora/store/fragment/preference/FilterFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/FilterFragment.java similarity index 90% rename from app/src/main/java/com/aurora/store/fragment/preference/FilterFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/FilterFragment.java index c8161de39..27d74e8ad 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/FilterFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/FilterFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.os.Bundle; diff --git a/app/src/main/java/com/aurora/store/fragment/preference/InstallationFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/InstallationFragment.java similarity index 75% rename from app/src/main/java/com/aurora/store/fragment/preference/InstallationFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/InstallationFragment.java index 1a34f2a2d..ec2ff9183 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/InstallationFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/InstallationFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.Intent; @@ -15,13 +15,13 @@ import androidx.preference.PreferenceFragmentCompat; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.SettingsActivity; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.PackageUtil; -import com.aurora.store.utility.PathUtil; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Root; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.PackageUtil; +import com.aurora.store.util.PathUtil; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Root; +import com.aurora.store.util.Util; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.scottyab.rootbeer.RootBeer; @@ -31,12 +31,18 @@ import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + public class InstallationFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String ROOT = "1"; private static final String SERVICES = "2"; private Context context; + private CompositeDisposable disposable = new CompositeDisposable(); @Override public void onAttach(@NonNull Context context) { @@ -53,8 +59,8 @@ public class InstallationFragment extends PreferenceFragmentCompat implements Sh @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - SharedPreferences mPrefs = Util.getPrefs(context); - mPrefs.registerOnSharedPreferenceChangeListener(this); + SharedPreferences preferences = Util.getPrefs(context); + preferences.registerOnSharedPreferenceChangeListener(this); ListPreference listInstallMethod = findPreference(Constants.PREFERENCE_INSTALLATION_METHOD); assert listInstallMethod != null; @@ -63,8 +69,8 @@ public class InstallationFragment extends PreferenceFragmentCompat implements Sh if (installMethod.equals(ROOT)) { RootBeer rootBeer = new RootBeer(context); if (rootBeer.isRooted()) { - PrefUtil.putString(context, Constants.PREFERENCE_INSTALLATION_METHOD, installMethod); Root.requestRoot(); + PrefUtil.putString(context, Constants.PREFERENCE_INSTALLATION_METHOD, installMethod); showDownloadDialog(); return true; } else { @@ -96,9 +102,13 @@ public class InstallationFragment extends PreferenceFragmentCompat implements Sh if (PackageUtil.isInstalled(context, Constants.SERVICE_PACKAGE)) { servicePreference.setEnabled(true); servicePreference.setOnPreferenceClickListener(preference -> { - Intent intent = context.getPackageManager().getLaunchIntentForPackage(Constants.SERVICE_PACKAGE); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - context.startActivity(intent); + try { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(Constants.SERVICE_PACKAGE); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + context.startActivity(intent); + } catch (Exception e) { + ContextUtil.toastLong(context, "Could not launch services"); + } return false; }); } else { @@ -149,9 +159,34 @@ public class InstallationFragment extends PreferenceFragmentCompat implements Sh return; } - List entryList = new ArrayList<>(); - List entryValueList = new ArrayList<>(); + disposable.add(Observable.fromCallable(() -> getUserInfo(root)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(rawUserList -> { + List entryList = new ArrayList<>(); + List entryValueList = new ArrayList<>(); + + for (String rawUser : rawUserList) { + String[] rawUserArray = rawUser.split(":"); + entryValueList.add(rawUserArray[0]); + entryList.add(rawUserArray[1]); + } + + CharSequence[] entries = new CharSequence[entryList.size()]; + CharSequence[] entryValues = new CharSequence[entryValueList.size()]; + for (int i = 0; i < entryList.size(); i++) { + entries[i] = entryList.get(i); + entryValues[i] = entryValueList.get(i); + } + + listPreference.setEntries(entries); + listPreference.setEntryValues(entryValues); + })); + } + + private List getUserInfo(Root root) { + List rawUserList = new ArrayList<>(); String result = root.exec("pm list users"); Scanner scanner = new Scanner(result); while (scanner.hasNextLine()) { @@ -160,21 +195,10 @@ public class InstallationFragment extends PreferenceFragmentCompat implements Sh Matcher m = p.matcher(line); while (m.find()) { String rawUser = m.group(1); - String[] rawUserArray = rawUser.split(":"); - entryValueList.add(rawUserArray[0]); - entryList.add(rawUserArray[1]); + rawUserList.add(rawUser); } } - - CharSequence[] entries = new CharSequence[entryList.size()]; - CharSequence[] entryValues = new CharSequence[entryValueList.size()]; - for (int i = 0; i < entryList.size(); i++) { - entries[i] = entryList.get(i); - entryValues[i] = entryValueList.get(i); - } - - listPreference.setEntries(entries); - listPreference.setEntryValues(entryValues); + return rawUserList; } private void showInternalDialog() { diff --git a/app/src/main/java/com/aurora/store/fragment/preference/LanguageFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/LanguageFragment.java similarity index 81% rename from app/src/main/java/com/aurora/store/fragment/preference/LanguageFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/LanguageFragment.java index 3114bfd11..b4544d862 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/LanguageFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/LanguageFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.SharedPreferences; @@ -12,11 +12,12 @@ import androidx.preference.PreferenceFragmentCompat; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.SettingsActivity; +import com.aurora.store.manager.CategoryManager; import com.aurora.store.manager.LocaleManager; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.TextUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.TextUtil; +import com.aurora.store.util.Util; import java.util.Locale; @@ -41,8 +42,8 @@ public class LanguageFragment extends PreferenceFragmentCompat implements Shared @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - SharedPreferences mPrefs = Util.getPrefs(context); - mPrefs.registerOnSharedPreferenceChangeListener(this); + SharedPreferences preferences = Util.getPrefs(context); + preferences.registerOnSharedPreferenceChangeListener(this); ListPreference localeList = findPreference(Constants.PREFERENCE_LOCALE_LIST); assert localeList != null; @@ -65,9 +66,11 @@ public class LanguageFragment extends PreferenceFragmentCompat implements Shared public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { switch (key) { case Constants.PREFERENCE_LOCALE_CUSTOM: - case Constants.PREFERENCE_LOCALE_LIST: + case Constants.PREFERENCE_LOCALE_LIST: { + CategoryManager.clear(context); SettingsActivity.shouldRestart = true; break; + } } } } diff --git a/app/src/main/java/com/aurora/store/fragment/preference/NetworkFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/NetworkFragment.java similarity index 91% rename from app/src/main/java/com/aurora/store/fragment/preference/NetworkFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/NetworkFragment.java index b4a8cdd70..8ce62dda2 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/NetworkFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/NetworkFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.SharedPreferences; @@ -11,8 +11,8 @@ import androidx.preference.PreferenceFragmentCompat; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.SettingsActivity; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.util.Util; public class NetworkFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { diff --git a/app/src/main/java/com/aurora/store/fragment/preference/NotificationFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/NotificationFragment.java similarity index 92% rename from app/src/main/java/com/aurora/store/fragment/preference/NotificationFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/NotificationFragment.java index 1244829dd..0a3d7aa35 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/NotificationFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/NotificationFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.SharedPreferences; @@ -12,9 +12,9 @@ import androidx.preference.PreferenceFragmentCompat; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.SettingsActivity; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; public class NotificationFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { diff --git a/app/src/main/java/com/aurora/store/fragment/preference/SpoofFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/SpoofFragment.java similarity index 93% rename from app/src/main/java/com/aurora/store/fragment/preference/SpoofFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/SpoofFragment.java index f1e9b895b..8bed521ea 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/SpoofFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/SpoofFragment.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.Intent; @@ -35,23 +35,25 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; +import com.aurora.store.AuroraApplication; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.AccountsActivity; -import com.aurora.store.activity.DeviceInfoActivity; -import com.aurora.store.api.PlayStoreApiAuthenticator; import com.aurora.store.manager.CategoryManager; import com.aurora.store.manager.SpoofManager; import com.aurora.store.notification.QuickNotification; import com.aurora.store.task.DeviceInfoBuilder; import com.aurora.store.task.GeoSpoofTask; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.single.activity.DeviceInfoActivity; +import com.aurora.store.ui.single.activity.GenericActivity; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; @@ -216,7 +218,7 @@ public class SpoofFragment extends Fragment { public void onItemSelected(AdapterView parent, View view, int position, long id) { if (position > 0) { try { - GooglePlayAPI api = PlayStoreApiAuthenticator.getInstance(context); + GooglePlayAPI api = AuroraApplication.api; api.setLocale(new Locale(localeKeys[position])); PrefUtil.putString(context, Constants.PREFERENCE_REQUESTED_LANGUAGE, localeKeys[position]); @@ -232,7 +234,7 @@ public class SpoofFragment extends Fragment { PrefUtil.putInteger(context, Constants.PREFERENCE_REQUESTED_LANGUAGE_INDEX, 0); } - new CategoryManager(context).clearAll(); + CategoryManager.clear(context); } @Override @@ -308,7 +310,9 @@ public class SpoofFragment extends Fragment { Constants.PREFERENCE_DEVICE_TO_PRETEND_TO_BE_INDEX, 0); Accountant.completeCheckout(context); Util.clearCache(context); - startActivity(new Intent(context, AccountsActivity.class)); + Intent intent = new Intent(context, GenericActivity.class); + intent.putExtra(Constants.FRAGMENT_NAME, Constants.FRAGMENT_ACCOUNTS); + startActivity(intent, ViewUtil.getEmptyActivityBundle((AppCompatActivity) context)); }) .setNegativeButton(getString(android.R.string.cancel), (dialog, which) -> { diff --git a/app/src/main/java/com/aurora/store/fragment/preference/UIFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/UIFragment.java similarity index 89% rename from app/src/main/java/com/aurora/store/fragment/preference/UIFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/UIFragment.java index 9db7af87a..2e3bbe094 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/UIFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/UIFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.SharedPreferences; @@ -12,9 +12,9 @@ import androidx.preference.PreferenceFragmentCompat; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.SettingsActivity; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.ui.preference.SettingsActivity; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; public class UIFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -62,8 +62,6 @@ public class UIFragment extends PreferenceFragmentCompat implements SharedPrefer switch (key) { case Constants.PREFERENCE_FEATURED_SNAP: case Constants.PREFERENCE_UI_CARD_STYLE: - case Constants.PREFERENCE_TAB_MODE: - case Constants.PREFERENCE_UI_TRANSPARENT: SettingsActivity.shouldRestart = true; break; } diff --git a/app/src/main/java/com/aurora/store/fragment/preference/UpdatesPrefFragment.java b/app/src/main/java/com/aurora/store/ui/preference/fragment/UpdatesPrefFragment.java similarity index 91% rename from app/src/main/java/com/aurora/store/fragment/preference/UpdatesPrefFragment.java rename to app/src/main/java/com/aurora/store/ui/preference/fragment/UpdatesPrefFragment.java index c76d0553c..891f0786b 100644 --- a/app/src/main/java/com/aurora/store/fragment/preference/UpdatesPrefFragment.java +++ b/app/src/main/java/com/aurora/store/ui/preference/fragment/UpdatesPrefFragment.java @@ -1,4 +1,4 @@ -package com.aurora.store.fragment.preference; +package com.aurora.store.ui.preference.fragment; import android.content.Context; import android.content.Intent; @@ -14,9 +14,8 @@ import androidx.preference.PreferenceFragmentCompat; import com.aurora.store.Constants; import com.aurora.store.R; import com.aurora.store.SelfUpdateService; -import com.aurora.store.receiver.UpdatesReceiver; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; public class UpdatesPrefFragment extends PreferenceFragmentCompat { diff --git a/app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java b/app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java new file mode 100644 index 000000000..b6f746380 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java @@ -0,0 +1,76 @@ +package com.aurora.store.ui.search; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.enums.ErrorType; +import com.aurora.store.iterator.CustomAppListIterator; +import com.aurora.store.manager.FilterManager; +import com.aurora.store.model.App; +import com.aurora.store.task.SearchTask; +import com.aurora.store.util.NetworkUtil; +import com.aurora.store.viewmodel.BaseViewModel; +import com.dragons.aurora.playstoreapiv2.SearchIterator; + +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class SearchAppsModel extends BaseViewModel { + + protected CustomAppListIterator iterator; + protected SearchIterator searchIterator; + protected MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + protected MutableLiveData> relatedMutableLiveData = new MutableLiveData<>(); + + public SearchAppsModel(@NonNull Application application) { + super(application); + } + + public MutableLiveData> getRelatedTags() { + return relatedMutableLiveData; + } + + public LiveData> getQueriedApps() { + return listMutableLiveData; + } + + public void fetchQueriedApps(String query, boolean shouldIterate) { + + if (!NetworkUtil.isConnected(getApplication())) { + errorTypeMutableLiveData.setValue(ErrorType.NO_NETWORK); + return; + } + + api = AuroraApplication.api; + if (!shouldIterate) + getIterator(query); + + disposable.clear(); + disposable.add(Observable.fromCallable(() -> new SearchTask(getApplication()) + .getSearchResults(iterator)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + listMutableLiveData.setValue(appList); + }, err -> handleError(err))); + } + + public void getIterator(String query) { + try { + searchIterator = new SearchIterator(api, query); + iterator = new CustomAppListIterator(searchIterator); + iterator.setFilterEnabled(true); + iterator.setFilterModel(FilterManager.getFilterPreferences(getApplication())); + //relatedMutableLiveData.setValue(iterator.getRelatedTags()); + } catch (Exception err) { + handleError(err); + } + } +} diff --git a/app/src/main/java/com/aurora/store/ui/search/SearchSuggestionModel.java b/app/src/main/java/com/aurora/store/ui/search/SearchSuggestionModel.java new file mode 100644 index 000000000..9d16a2331 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/search/SearchSuggestionModel.java @@ -0,0 +1,53 @@ +package com.aurora.store.ui.search; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.task.SuggestionTask; +import com.aurora.store.viewmodel.BaseViewModel; +import com.dragons.aurora.playstoreapiv2.SearchSuggestEntry; + +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class SearchSuggestionModel extends BaseViewModel { + + private MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + + public SearchSuggestionModel(@NonNull Application application) { + super(application); + } + + public LiveData> getSuggestions() { + return listMutableLiveData; + } + + public void fetchSuggestions(String query) { + api = AuroraApplication.api; + disposable.clear(); + disposable.add(Observable.fromCallable(() -> new SuggestionTask(api) + .getSearchSuggestions(query)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + listMutableLiveData.setValue(appList); + }, err -> handleError(err))); + } + + public void discardRequests() { + disposable.clear(); + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/search/activity/SearchActivity.java b/app/src/main/java/com/aurora/store/ui/search/activity/SearchActivity.java new file mode 100644 index 000000000..fead0b601 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/search/activity/SearchActivity.java @@ -0,0 +1,188 @@ +package com.aurora.store.ui.search.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.inputmethod.EditorInfo; +import android.widget.Toast; + +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.Constants; +import com.aurora.store.R; +import com.aurora.store.SuggestionDiffCallback; +import com.aurora.store.section.SearchSuggestionSection; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.search.SearchSuggestionModel; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.dragons.aurora.playstoreapiv2.SearchSuggestEntry; +import com.google.android.material.textfield.TextInputEditText; + +import java.util.List; +import java.util.regex.Pattern; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; + +public class SearchActivity extends BaseActivity implements SearchSuggestionSection.ClickListener { + + @BindView(R.id.search_view) + TextInputEditText searchView; + @BindView(R.id.recycler) + RecyclerView recyclerView; + @BindView(R.id.coordinator) + CoordinatorLayout coordinator; + + private String query; + private SearchSuggestionModel model; + private SearchSuggestionSection section; + private SectionedRecyclerViewAdapter adapter; + + private static boolean isPackageName(String query) { + if (TextUtils.isEmpty(query)) { + return false; + } + String pattern = "([\\p{L}_$][\\p{L}\\p{N}_$]*\\.)+[\\p{L}_$][\\p{L}\\p{N}_$]*"; + Pattern r = Pattern.compile(pattern); + return r.matcher(query).matches(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_search); + ButterKnife.bind(this); + setupSearch(); + setupSuggestionRecycler(); + model = ViewModelProviders.of(this).get(SearchSuggestionModel.class); + model.getSuggestions().observe(this, searchSuggestEntries -> { + dispatchAppsToAdapter(searchSuggestEntries); + }); + + model.getError().observe(this, errorType -> { + switch (errorType) { + case NO_API: + case SESSION_EXPIRED: { + Util.validateApi(this); + break; + } + case NO_NETWORK: { + showSnackBar(coordinator, R.string.error_no_network, v -> { + model.fetchSuggestions(query); + }); + break; + } + } + }); + onNewIntent(getIntent()); + } + + @OnClick(R.id.action1) + public void goBack() { + onBackPressed(); + } + + @Override + protected void onResume() { + super.onResume(); + searchView.requestFocus(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + if (intent.getScheme() != null && intent.getScheme().equals("market")) { + if (intent.getData() != null) { + query = intent.getData().getQueryParameter("q"); + searchView.setText(query); + } else { + Toast.makeText(this, "Empty query received", Toast.LENGTH_SHORT).show(); + finishAfterTransition(); + } + } + } + + private void setupSearch() { + searchView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + query = searchView.getText().toString(); + if (!query.isEmpty()) + model.fetchSuggestions(s.toString()); + } + + @Override + public void afterTextChanged(Editable s) { + + } + }); + + searchView.setOnEditorActionListener((v, actionId, event) -> { + if (actionId == EditorInfo.IME_ACTION_SEARCH) { + model.discardRequests(); + query = searchView.getText().toString(); + if (!query.isEmpty()) { + openSearchResultActivity(query); + return true; + } + } + return false; + }); + } + + private void dispatchAppsToAdapter(List suggestEntryList) { + List oldList = section.getList(); + if (oldList.isEmpty()) { + section.addData(suggestEntryList); + adapter.notifyDataSetChanged(); + } else { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new SuggestionDiffCallback(suggestEntryList, oldList)); + diffResult.dispatchUpdatesTo(adapter); + section.addData(suggestEntryList); + } + } + + private void setupSuggestionRecycler() { + section = new SearchSuggestionSection(this, this); + adapter = new SectionedRecyclerViewAdapter(); + adapter.addSection(section); + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false)); + } + + private void openDetailsActivity(String packageName) { + Intent intent = new Intent(this, DetailsActivity.class); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, packageName); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + } + + private void openSearchResultActivity(String query) { + Intent intent = new Intent(this, SearchResultActivity.class); + intent.putExtra("QUERY", query); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + } + + @Override + public void onClick(String query) { + if (Util.isSearchByPackageEnabled(this) && isPackageName(query)) { + openDetailsActivity(query); + } else { + openSearchResultActivity(query); + } + } +} diff --git a/app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java b/app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java new file mode 100644 index 000000000..70f441bb1 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java @@ -0,0 +1,215 @@ +package com.aurora.store.ui.search.activity; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; + +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.EndlessScrollListener; +import com.aurora.store.R; +import com.aurora.store.model.App; +import com.aurora.store.section.SearchResultSection; +import com.aurora.store.sheet.AppMenuSheet; +import com.aurora.store.sheet.FilterBottomSheet; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.search.SearchAppsModel; +import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; +import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; +import com.google.android.material.textfield.TextInputEditText; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter; +import io.reactivex.disposables.CompositeDisposable; + +public class SearchResultActivity extends BaseActivity implements SearchResultSection.ClickListener, + SharedPreferences.OnSharedPreferenceChangeListener { + + @BindView(R.id.search_view) + TextInputEditText searchView; + @BindView(R.id.recycler) + RecyclerView recyclerView; + @BindView(R.id.filter_fab) + ExtendedFloatingActionButton filterFab; + @BindView(R.id.coordinator) + CoordinatorLayout coordinator; + + private String query; + private SearchAppsModel model; + private SearchResultSection section; + private SectionedRecyclerViewAdapter adapter; + private CompositeDisposable disposable = new CompositeDisposable(); + private SharedPreferences sharedPreferences; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_search_result); + ButterKnife.bind(this); + setupSearch(); + setupResultRecycler(); + sharedPreferences = Util.getPrefs(this); + sharedPreferences.registerOnSharedPreferenceChangeListener(this); + + model = ViewModelProviders.of(this).get(SearchAppsModel.class); + model.getQueriedApps().observe(this, appList -> { + dispatchAppsToAdapter(appList); + }); + + model.getRelatedTags().observe(this, strings -> { + }); + + model.getError().observe(this, errorType -> { + switch (errorType) { + case NO_API: + case SESSION_EXPIRED: { + Util.validateApi(this); + break; + } + case NO_NETWORK: { + showSnackBar(coordinator, R.string.error_no_network, v -> { + model.fetchQueriedApps(query, false); + }); + break; + } + } + }); + + disposable.add(AuroraApplication + .getRxBus() + .getBus() + .subscribe(event -> { + switch (event.getSubType()) { + case API_SUCCESS: + model.fetchQueriedApps(query, false); + break; + } + })); + + onNewIntent(getIntent()); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Bundle bundle = intent.getExtras(); + if (bundle != null) { + query = bundle.getString("QUERY"); + searchView.setText(query); + model.fetchQueriedApps(query, false); + } else + finishAfterTransition(); + } + + @Override + protected void onDestroy() { + model = null; + sharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + super.onDestroy(); + } + + @OnClick(R.id.action1) + public void goBack() { + onBackPressed(); + } + + @OnClick(R.id.filter_fab) + public void showFilterDialog() { + FilterBottomSheet filterSheet = new FilterBottomSheet(); + filterSheet.show(getSupportFragmentManager(), "FILTER"); + } + + private void purgeAdapterData() { + section.purgeData(); + adapter.notifyDataSetChanged(); + } + + private void setupSearch() { + searchView.setFocusable(false); + searchView.setOnClickListener(v -> { + Intent intent = new Intent(this, SearchActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + finishAfterTransition(); + }); + } + + private void dispatchAppsToAdapter(List newList) { + List oldList = section.getList(); + if (oldList.isEmpty()) { + section.updateList(newList); + adapter.notifyDataSetChanged(); + } else { + if (!newList.isEmpty()) { + for (App app : newList) + section.add(app); + adapter.notifyItemInserted(section.getCount() - 1); + } + } + } + + private void setupResultRecycler() { + adapter = new SectionedRecyclerViewAdapter(); + section = new SearchResultSection(this, this); + adapter.addSection(section); + recyclerView.setAdapter(adapter); + + LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false); + EndlessScrollListener endlessScrollListener = new EndlessScrollListener(layoutManager) { + @Override + public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { + model.fetchQueriedApps(query, true); + } + }; + + recyclerView.addOnScrollListener(endlessScrollListener); + recyclerView.setOnFlingListener(new RecyclerView.OnFlingListener() { + @Override + public boolean onFling(int velocityX, int velocityY) { + if (velocityY < 0) { + filterFab.show(); + } else if (velocityY > 0) { + filterFab.hide(); + } + return false; + } + }); + recyclerView.setLayoutManager(layoutManager); + } + + @Override + public void onClick(App app) { + Intent intent = new Intent(this, DetailsActivity.class); + intent.putExtra(Constants.INTENT_PACKAGE_NAME, app.getPackageName()); + startActivity(intent, ViewUtil.getEmptyActivityBundle(this)); + } + + @Override + public void onLongClick(App app) { + AppMenuSheet menuSheet = new AppMenuSheet(); + menuSheet.setApp(app); + menuSheet.show(getSupportFragmentManager(), "BOTTOM_MENU_SHEET"); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case Constants.PREFERENCE_FILTER_APPS: { + purgeAdapterData(); + model.fetchQueriedApps(query, false); + break; + } + } + } +} diff --git a/app/src/main/java/com/aurora/store/ui/single/activity/BaseActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/BaseActivity.java new file mode 100644 index 000000000..aefbece85 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/single/activity/BaseActivity.java @@ -0,0 +1,47 @@ +package com.aurora.store.ui.single.activity; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AppCompatActivity; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.R; +import com.aurora.store.events.Event; +import com.aurora.store.util.ThemeUtil; +import com.aurora.store.viewmodel.ConnectionLiveData; +import com.google.android.material.snackbar.Snackbar; + +public abstract class BaseActivity extends AppCompatActivity { + + ThemeUtil themeUtil = new ThemeUtil(); + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + themeUtil.onCreate(this); + new ConnectionLiveData(this).observe(this, connectionModel -> { + AuroraApplication.rxNotify(new Event(connectionModel.isConnected() + ? Event.SubType.NETWORK_AVAILABLE + : Event.SubType.NETWORK_UNAVAILABLE)); + }); + } + + @Override + protected void onResume() { + super.onResume(); + themeUtil.onResume(this); + } + + protected void showSnackBar(View view, @StringRes int message, int duration, View.OnClickListener onClickListener) { + Snackbar snackbar = Snackbar.make(view, message, duration); + snackbar.setAction(R.string.action_retry, onClickListener); + snackbar.show(); + } + + protected void showSnackBar(View view, @StringRes int message, View.OnClickListener onClickListener) { + showSnackBar(view, message, 0, onClickListener); + } +} diff --git a/app/src/main/java/com/aurora/store/activity/DeviceInfoActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/DeviceInfoActivity.java similarity index 86% rename from app/src/main/java/com/aurora/store/activity/DeviceInfoActivity.java rename to app/src/main/java/com/aurora/store/ui/single/activity/DeviceInfoActivity.java index 42c2a9616..60f0b9bbf 100644 --- a/app/src/main/java/com/aurora/store/activity/DeviceInfoActivity.java +++ b/app/src/main/java/com/aurora/store/ui/single/activity/DeviceInfoActivity.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.activity; +package com.aurora.store.ui.single.activity; import android.content.Intent; import android.os.Bundle; @@ -28,18 +28,17 @@ import android.widget.LinearLayout; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import com.aurora.store.Constants; import com.aurora.store.R; import com.aurora.store.manager.SpoofManager; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.PrefUtil; -import com.aurora.store.utility.ThemeUtil; -import com.aurora.store.view.PropertyView; +import com.aurora.store.ui.accounts.AccountsActivity; +import com.aurora.store.ui.view.PropertyView; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.PrefUtil; import com.dragons.aurora.playstoreapiv2.PropertiesDeviceInfoProvider; import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; @@ -52,29 +51,26 @@ import java.util.Properties; import butterknife.BindView; import butterknife.ButterKnife; -public class DeviceInfoActivity extends AppCompatActivity { +public class DeviceInfoActivity extends BaseActivity { @BindView(R.id.toolbar) - Toolbar mToolbar; + Toolbar toolbar; @BindView(R.id.incognito_fab) ExtendedFloatingActionButton incognito_fab; @BindView(R.id.device_info) LinearLayout root; - private ActionBar actionBar; - private ThemeUtil themeUtil = new ThemeUtil(); private String deviceName; private int deviceIndex; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - themeUtil.onCreate(this); setContentView(R.layout.activity_device_info); ButterKnife.bind(this); - setSupportActionBar(mToolbar); - actionBar = getSupportActionBar(); + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); @@ -87,7 +83,6 @@ public class DeviceInfoActivity extends AppCompatActivity { @Override protected void onResume() { super.onResume(); - themeUtil.onResume(this); } @Override @@ -106,13 +101,13 @@ public class DeviceInfoActivity extends AppCompatActivity { deviceName = intent.getStringExtra(Constants.INTENT_DEVICE_NAME); deviceIndex = intent.getIntExtra(Constants.INTENT_DEVICE_INDEX, 0); if (TextUtils.isEmpty(deviceName)) { - Log.e("No device name given"); + Log.d("No device name given"); finish(); return; } Properties properties = new SpoofManager(this).getProperties(deviceName); - mToolbar.setTitle(properties.getProperty("UserReadableName")); + toolbar.setTitle(properties.getProperty("UserReadableName")); List keys = new ArrayList<>(); for (Object key : properties.keySet()) { keys.add((String) key); diff --git a/app/src/main/java/com/aurora/store/activity/DownloadsActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/DownloadsActivity.java similarity index 87% rename from app/src/main/java/com/aurora/store/activity/DownloadsActivity.java rename to app/src/main/java/com/aurora/store/ui/single/activity/DownloadsActivity.java index 34efa8bc8..0f6248a11 100644 --- a/app/src/main/java/com/aurora/store/activity/DownloadsActivity.java +++ b/app/src/main/java/com/aurora/store/ui/single/activity/DownloadsActivity.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.activity; +package com.aurora.store.ui.single.activity; import android.os.Bundle; import android.view.Menu; @@ -27,18 +27,15 @@ import android.view.ViewGroup; import android.widget.ViewSwitcher; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.aurora.store.ErrorType; import com.aurora.store.R; import com.aurora.store.adapter.DownloadsAdapter; import com.aurora.store.download.DownloadManager; -import com.aurora.store.utility.ThemeUtil; -import com.aurora.store.view.ErrorView; +import com.aurora.store.enums.ErrorType; import com.tonyodev.fetch2.AbstractFetchListener; import com.tonyodev.fetch2.Download; import com.tonyodev.fetch2.Error; @@ -54,7 +51,7 @@ import java.util.Collections; import butterknife.BindView; import butterknife.ButterKnife; -public class DownloadsActivity extends AppCompatActivity { +public class DownloadsActivity extends BaseActivity { private static final long UNKNOWN_REMAINING_TIME = -1; private static final long UNKNOWN_DOWNLOADED_BYTES_PER_SECOND = 0; @@ -124,12 +121,10 @@ public class DownloadsActivity extends AppCompatActivity { downloadsAdapter.update(download, UNKNOWN_REMAINING_TIME, UNKNOWN_DOWNLOADED_BYTES_PER_SECOND); } }; - private ThemeUtil themeUtil = new ThemeUtil(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - themeUtil.onCreate(this); setContentView(R.layout.activity_downloads); ButterKnife.bind(this); fetch = DownloadManager.getFetchInstance(this); @@ -172,7 +167,6 @@ public class DownloadsActivity extends AppCompatActivity { @Override protected void onResume() { super.onResume(); - themeUtil.onResume(this); fetch.getDownloads(downloads -> { final ArrayList list = new ArrayList<>(downloads); Collections.sort(list, (first, second) -> Long.compare(first.getCreated(), second.getCreated())); @@ -200,8 +194,8 @@ public class DownloadsActivity extends AppCompatActivity { } protected void setErrorView(ErrorType errorType) { - layoutError.removeAllViews(); - layoutError.addView(new ErrorView(this, errorType, null)); + /*layoutError.removeAllViews(); + layoutError.addView(new ErrorView(this, errorType, null));*/ } protected void switchViews(boolean showError) { @@ -213,12 +207,12 @@ public class DownloadsActivity extends AppCompatActivity { private void setupActionbar() { setSupportActionBar(toolbar); - ActionBar mActionBar = getSupportActionBar(); - if (mActionBar != null) { - mActionBar.setDisplayShowCustomEnabled(true); - mActionBar.setDisplayHomeAsUpEnabled(true); - mActionBar.setElevation(0f); - mActionBar.setTitle(R.string.menu_downloads); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowCustomEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setElevation(0f); + actionBar.setTitle(R.string.menu_downloads); } } @@ -231,13 +225,7 @@ public class DownloadsActivity extends AppCompatActivity { } private void forceClearAll() { - fetch.deleteAllWithStatus(Status.ADDED); - fetch.deleteAllWithStatus(Status.QUEUED); - fetch.deleteAllWithStatus(Status.CANCELLED); - fetch.deleteAllWithStatus(Status.COMPLETED); - fetch.deleteAllWithStatus(Status.DOWNLOADING); - fetch.deleteAllWithStatus(Status.FAILED); - fetch.deleteAllWithStatus(Status.PAUSED); + fetch.deleteAll(); } private void setupRecycler() { diff --git a/app/src/main/java/com/aurora/store/activity/FullscreenImageActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/FullscreenImageActivity.java similarity index 83% rename from app/src/main/java/com/aurora/store/activity/FullscreenImageActivity.java rename to app/src/main/java/com/aurora/store/ui/single/activity/FullscreenImageActivity.java index 4cb26ffc8..6e83bf885 100644 --- a/app/src/main/java/com/aurora/store/activity/FullscreenImageActivity.java +++ b/app/src/main/java/com/aurora/store/ui/single/activity/FullscreenImageActivity.java @@ -18,14 +18,13 @@ * */ -package com.aurora.store.activity; +package com.aurora.store.ui.single.activity; import android.content.Intent; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; -import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.PagerSnapHelper; import androidx.recyclerview.widget.RecyclerView; @@ -33,27 +32,22 @@ import androidx.recyclerview.widget.SnapHelper; import com.aurora.store.R; import com.aurora.store.adapter.BigScreenshotsAdapter; -import com.aurora.store.fragment.DetailsFragment; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.ThemeUtil; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.Log; import butterknife.BindView; import butterknife.ButterKnife; -public class FullscreenImageActivity extends AppCompatActivity { +public class FullscreenImageActivity extends BaseActivity { static public final String INTENT_SCREENSHOT_NUMBER = "INTENT_SCREENSHOT_NUMBER"; @BindView(R.id.gallery) RecyclerView recyclerView; - - private ThemeUtil themeUtil = new ThemeUtil(); - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - themeUtil.onCreate(this); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, @@ -67,13 +61,12 @@ public class FullscreenImageActivity extends AppCompatActivity { @Override protected void onResume() { super.onResume(); - themeUtil.onResume(this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - if (null == DetailsFragment.app) { + if (null == DetailsActivity.app) { Log.w("No app stored"); finish(); return; @@ -81,7 +74,7 @@ public class FullscreenImageActivity extends AppCompatActivity { SnapHelper snapHelper = new PagerSnapHelper(); snapHelper.attachToRecyclerView(recyclerView); LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false); - recyclerView.setAdapter(new BigScreenshotsAdapter(DetailsFragment.app.getScreenshotUrls(), this)); + recyclerView.setAdapter(new BigScreenshotsAdapter(DetailsActivity.app.getScreenshotUrls(), this)); recyclerView.setLayoutManager(layoutManager); recyclerView.scrollToPosition(intent.getIntExtra(INTENT_SCREENSHOT_NUMBER, 0)); } diff --git a/app/src/main/java/com/aurora/store/ui/single/activity/GenericActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/GenericActivity.java new file mode 100644 index 000000000..f48b4df3a --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/single/activity/GenericActivity.java @@ -0,0 +1,93 @@ +package com.aurora.store.ui.single.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; + +import com.aurora.store.Constants; +import com.aurora.store.R; +import com.aurora.store.ui.accounts.fragment.AccountsFragment; +import com.aurora.store.ui.preference.fragment.AboutFragment; +import com.aurora.store.ui.preference.fragment.BlacklistFragment; +import com.aurora.store.ui.preference.fragment.FavouriteFragment; +import com.aurora.store.ui.preference.fragment.SpoofFragment; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class GenericActivity extends BaseActivity { + + @BindView(R.id.toolbar) + Toolbar toolbar; + + private ActionBar actionBar; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_generic); + ButterKnife.bind(this); + setupActionBar(); + onNewIntent(getIntent()); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(menuItem); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + String fragmentName = intent.getStringExtra(Constants.FRAGMENT_NAME); + Fragment fragment = null; + + switch (fragmentName) { + case Constants.FRAGMENT_ABOUT: + actionBar.setTitle(getString(R.string.action_about)); + fragment = new AboutFragment(); + break; + case Constants.FRAGMENT_BLACKLIST: + actionBar.setTitle(getString(R.string.action_blacklist)); + fragment = new BlacklistFragment(); + break; + case Constants.FRAGMENT_FAV_LIST: + actionBar.setTitle(getString(R.string.action_favourites)); + fragment = new FavouriteFragment(); + break; + case Constants.FRAGMENT_SPOOF: + actionBar.setTitle(getString(R.string.action_spoofed)); + fragment = new SpoofFragment(); + break; + default: + actionBar.setTitle(getString(R.string.action_accounts)); + fragment = new AccountsFragment(); + } + + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.content, fragment) + .commit(); + } + + + private void setupActionBar() { + setSupportActionBar(toolbar); + actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowTitleEnabled(true); + } + } +} diff --git a/app/src/main/java/com/aurora/store/activity/GoogleLoginActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/GoogleLoginActivity.java similarity index 74% rename from app/src/main/java/com/aurora/store/activity/GoogleLoginActivity.java rename to app/src/main/java/com/aurora/store/ui/single/activity/GoogleLoginActivity.java index 3ecff0250..cc3346d2c 100644 --- a/app/src/main/java/com/aurora/store/activity/GoogleLoginActivity.java +++ b/app/src/main/java/com/aurora/store/ui/single/activity/GoogleLoginActivity.java @@ -1,21 +1,22 @@ -package com.aurora.store.activity; +package com.aurora.store.ui.single.activity; import android.annotation.SuppressLint; -import android.app.Activity; import android.app.ActivityOptions; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import android.webkit.CookieManager; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; +import com.aurora.store.AuroraApplication; import com.aurora.store.R; import com.aurora.store.task.AuthTask; -import com.aurora.store.utility.Accountant; -import com.aurora.store.utility.NetworkUtil; -import com.aurora.store.utility.Util; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.Util; import java.util.Map; @@ -26,7 +27,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -public class GoogleLoginActivity extends Activity { +public class GoogleLoginActivity extends BaseActivity { public static final String EMBEDDED_SETUP_URL = "https://accounts.google.com/EmbeddedSetup"; public static final String OAUTH_TOKEN = "oauth_token"; @@ -40,14 +41,29 @@ public class GoogleLoginActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Window window = getWindow(); + window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + setContentView(R.layout.activity_login); ButterKnife.bind(this); - if (NetworkUtil.isConnected(this)) - setupWebView(); - else { - Toast.makeText(this, getString(R.string.error_no_network), Toast.LENGTH_LONG).show(); - finish(); - } + + disposable.add(AuroraApplication + .getRxBus() + .getBus() + .subscribe(event -> { + switch (event.getSubType()) { + case NETWORK_AVAILABLE: + setupWebView(); + break; + case NETWORK_UNAVAILABLE: + Toast.makeText(this, getString(R.string.error_no_network), Toast.LENGTH_LONG).show(); + break; + } + })); } @SuppressLint("SetJavaScriptEnabled") @@ -89,11 +105,11 @@ public class GoogleLoginActivity extends Activity { if (success) { Toast.makeText(this, getText(R.string.toast_login_success), Toast.LENGTH_SHORT).show(); Accountant.setAnonymous(this, false); - Intent intent = new Intent(this, AuroraActivity.class); + Intent intent = new Intent(this, SplashActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(this); startActivity(intent, activityOptions.toBundle()); - finish(); + supportFinishAfterTransition(); } else { Toast.makeText(this, getText(R.string.toast_login_failed), Toast.LENGTH_LONG).show(); } diff --git a/app/src/main/java/com/aurora/store/activity/ManualDownloadActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/ManualDownloadActivity.java similarity index 93% rename from app/src/main/java/com/aurora/store/activity/ManualDownloadActivity.java rename to app/src/main/java/com/aurora/store/ui/single/activity/ManualDownloadActivity.java index c088ca08b..8fb3e5739 100644 --- a/app/src/main/java/com/aurora/store/activity/ManualDownloadActivity.java +++ b/app/src/main/java/com/aurora/store/ui/single/activity/ManualDownloadActivity.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.activity; +package com.aurora.store.ui.single.activity; import android.os.Bundle; import android.text.Editable; @@ -33,22 +33,20 @@ import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import com.aurora.store.R; -import com.aurora.store.fragment.DetailsFragment; import com.aurora.store.manager.CategoryManager; import com.aurora.store.model.App; import com.aurora.store.model.ImageSource; import com.aurora.store.task.DeliveryData; import com.aurora.store.task.LiveUpdate; -import com.aurora.store.utility.ContextUtil; -import com.aurora.store.utility.Log; -import com.aurora.store.utility.TextUtil; -import com.aurora.store.utility.ThemeUtil; -import com.aurora.store.utility.Util; -import com.aurora.store.utility.ViewUtil; +import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.util.ContextUtil; +import com.aurora.store.util.Log; +import com.aurora.store.util.TextUtil; +import com.aurora.store.util.Util; +import com.aurora.store.util.ViewUtil; import com.bumptech.glide.Glide; import com.bumptech.glide.Priority; import com.bumptech.glide.load.engine.DiskCacheStrategy; @@ -64,7 +62,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -public class ManualDownloadActivity extends AppCompatActivity { +public class ManualDownloadActivity extends BaseActivity { @BindView(R.id.toolbar) Toolbar mToolbar; @@ -79,14 +77,12 @@ public class ManualDownloadActivity extends AppCompatActivity { @BindView(R.id.btn_positive) Button btnPositive; - private ThemeUtil themeUtil = new ThemeUtil(); private App app; private CompositeDisposable disposable = new CompositeDisposable(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - themeUtil.onCreate(this); setContentView(R.layout.activity_manual); ButterKnife.bind(this); @@ -98,7 +94,7 @@ public class ManualDownloadActivity extends AppCompatActivity { actionBar.setDisplayHomeAsUpEnabled(true); } - app = DetailsFragment.app; + app = DetailsActivity.app; drawAppBadge(); } @@ -115,7 +111,6 @@ public class ManualDownloadActivity extends AppCompatActivity { @Override public void onResume() { super.onResume(); - themeUtil.onResume(this); } private void drawAppBadge() { diff --git a/app/src/main/java/com/aurora/store/ui/single/activity/SplashActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/SplashActivity.java new file mode 100644 index 000000000..fed3dbafa --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/single/activity/SplashActivity.java @@ -0,0 +1,115 @@ +package com.aurora.store.ui.single.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.ProgressBar; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.R; +import com.aurora.store.ui.intro.IntroActivity; +import com.aurora.store.ui.main.AuroraActivity; +import com.aurora.store.util.Accountant; +import com.aurora.store.util.PrefUtil; +import com.aurora.store.util.Util; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.disposables.CompositeDisposable; + +public class SplashActivity extends BaseActivity { + + @BindView(R.id.img) + AppCompatImageView img; + @BindView(R.id.title) + AppCompatTextView title; + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.status) + AppCompatTextView status; + + private CompositeDisposable disposable = new CompositeDisposable(); + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash); + ButterKnife.bind(this); + + if (!PrefUtil.getBoolean(this, Constants.PREFERENCE_DO_NOT_SHOW_INTRO)) { + PrefUtil.putBoolean(this, Constants.PREFERENCE_DO_NOT_SHOW_INTRO, true); + startActivity(new Intent(this, IntroActivity.class)); + supportFinishAfterTransition(); + return; + } + + disposable.add(AuroraApplication + .getRxBus() + .getBus() + .subscribe(event -> { + switch (event.getSubType()) { + case NETWORK_AVAILABLE: { + buildAndTestApi(); + break; + } + case NETWORK_UNAVAILABLE: { + status.setText(getString(R.string.error_no_network)); + break; + } + case API_SUCCESS: { + status.setText(getString(R.string.toast_api_all_ok)); + launchAuroraActivity(); + break; + } + case API_FAILED: { + status.setText(getString(R.string.toast_api_build_retrying)); + break; + } + case API_ERROR: { + status.setText(getString(R.string.toast_api_build_failed)); + launchAccountsActivity(); + break; + } + } + })); + } + + private void buildAndTestApi() { + if (Accountant.isLoggedIn(this)) { + status.setText(R.string.toast_api_build_api); + Util.validateApi(this); + } else + launchAccountsActivity(); + } + + private void launchAuroraActivity() { + disposable.clear(); + Intent intent = new Intent(this, AuroraActivity.class); + startActivity(intent); + supportFinishAfterTransition(); + } + + private void launchAccountsActivity() { + disposable.clear(); + Intent intent = new Intent(this, GenericActivity.class); + intent.putExtra(Constants.FRAGMENT_NAME, Constants.FRAGMENT_ACCOUNTS); + startActivity(intent); + supportFinishAfterTransition(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onDestroy() { + disposable.clear(); + disposable.dispose(); + super.onDestroy(); + } +} diff --git a/app/src/main/java/com/aurora/store/view/CustomGridLayoutManager.java b/app/src/main/java/com/aurora/store/ui/view/CustomGridLayoutManager.java similarity index 98% rename from app/src/main/java/com/aurora/store/view/CustomGridLayoutManager.java rename to app/src/main/java/com/aurora/store/ui/view/CustomGridLayoutManager.java index 6adc70e33..f1ea4a1a5 100644 --- a/app/src/main/java/com/aurora/store/view/CustomGridLayoutManager.java +++ b/app/src/main/java/com/aurora/store/ui/view/CustomGridLayoutManager.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.content.Context; import android.util.TypedValue; diff --git a/app/src/main/java/com/aurora/store/view/CustomLayoutManager.java b/app/src/main/java/com/aurora/store/ui/view/CustomLayoutManager.java similarity index 99% rename from app/src/main/java/com/aurora/store/view/CustomLayoutManager.java rename to app/src/main/java/com/aurora/store/ui/view/CustomLayoutManager.java index 224dfd56b..72d2cd342 100644 --- a/app/src/main/java/com/aurora/store/view/CustomLayoutManager.java +++ b/app/src/main/java/com/aurora/store/ui/view/CustomLayoutManager.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.graphics.PointF; import android.os.Parcel; diff --git a/app/src/main/java/com/aurora/store/view/CustomSnapHelper.java b/app/src/main/java/com/aurora/store/ui/view/CustomSnapHelper.java similarity index 98% rename from app/src/main/java/com/aurora/store/view/CustomSnapHelper.java rename to app/src/main/java/com/aurora/store/ui/view/CustomSnapHelper.java index 3ac2f193e..833051ee3 100644 --- a/app/src/main/java/com/aurora/store/view/CustomSnapHelper.java +++ b/app/src/main/java/com/aurora/store/ui/view/CustomSnapHelper.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.view.View; diff --git a/app/src/main/java/com/aurora/store/view/CustomSwipeToRefresh.java b/app/src/main/java/com/aurora/store/ui/view/CustomSwipeToRefresh.java similarity index 77% rename from app/src/main/java/com/aurora/store/view/CustomSwipeToRefresh.java rename to app/src/main/java/com/aurora/store/ui/view/CustomSwipeToRefresh.java index df73349e2..69496d885 100644 --- a/app/src/main/java/com/aurora/store/view/CustomSwipeToRefresh.java +++ b/app/src/main/java/com/aurora/store/ui/view/CustomSwipeToRefresh.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.content.Context; import android.util.AttributeSet; @@ -27,29 +27,26 @@ import android.view.ViewConfiguration; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import com.aurora.store.R; - public class CustomSwipeToRefresh extends SwipeRefreshLayout { - private int mTouchSlop; - private float mPrevX; + private int touchSlop; + private float prevX; public CustomSwipeToRefresh(Context context, AttributeSet attrs) { super(context, attrs); - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - setColorSchemeColors(context.getResources().getIntArray(R.array.colorShades)); + touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - mPrevX = MotionEvent.obtain(event).getX(); + prevX = MotionEvent.obtain(event).getX(); break; case MotionEvent.ACTION_MOVE: final float eventX = event.getX(); - float xDiff = Math.abs(eventX - mPrevX); - if (xDiff > mTouchSlop) { + float xDiff = Math.abs(eventX - prevX); + if (xDiff > touchSlop) { return false; } } diff --git a/app/src/main/java/com/aurora/store/view/CustomViewPager.java b/app/src/main/java/com/aurora/store/ui/view/CustomViewPager.java similarity index 98% rename from app/src/main/java/com/aurora/store/view/CustomViewPager.java rename to app/src/main/java/com/aurora/store/ui/view/CustomViewPager.java index 731605801..9c9b63e84 100644 --- a/app/src/main/java/com/aurora/store/view/CustomViewPager.java +++ b/app/src/main/java/com/aurora/store/ui/view/CustomViewPager.java @@ -19,7 +19,7 @@ * along with Aurora Store. If not, see . */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.content.Context; import android.util.AttributeSet; @@ -27,10 +27,10 @@ import android.view.MotionEvent; import android.view.animation.DecelerateInterpolator; import android.widget.Scroller; -import java.lang.reflect.Field; - import androidx.viewpager.widget.ViewPager; +import java.lang.reflect.Field; + public class CustomViewPager extends ViewPager { private boolean viewScroll = false; diff --git a/app/src/main/java/com/aurora/store/view/DetailsLinkView.java b/app/src/main/java/com/aurora/store/ui/view/DetailsLinkView.java similarity index 88% rename from app/src/main/java/com/aurora/store/view/DetailsLinkView.java rename to app/src/main/java/com/aurora/store/ui/view/DetailsLinkView.java index dae177c45..2a15564e4 100644 --- a/app/src/main/java/com/aurora/store/view/DetailsLinkView.java +++ b/app/src/main/java/com/aurora/store/ui/view/DetailsLinkView.java @@ -1,8 +1,7 @@ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.content.Context; import android.content.res.ColorStateList; -import android.graphics.Color; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; @@ -13,7 +12,6 @@ import androidx.annotation.ColorRes; import androidx.core.graphics.ColorUtils; import com.aurora.store.R; -import com.aurora.store.utility.Util; import butterknife.BindView; import butterknife.ButterKnife; @@ -92,13 +90,12 @@ public class DetailsLinkView extends RelativeLayout { } public void build() { - boolean isTransparent = Util.isTransparentStyle(getContext()); int color = getColor(); txtLinkTitle.setText(getLinkText()); imgLink.setImageDrawable(getContext().getDrawable(getLinkImageId())); layoutLink.setOnClickListener(getOnClickListener()); - imgLink.setColorFilter(isTransparent ? color : Color.WHITE); + imgLink.setColorFilter(color); layoutLink.setBackgroundTintList(ColorStateList.valueOf( - ColorUtils.setAlphaComponent(getColor(), isTransparent ? 60 : 255))); + ColorUtils.setAlphaComponent(getColor(), 60))); } } diff --git a/app/src/main/java/com/aurora/store/view/LinkView.java b/app/src/main/java/com/aurora/store/ui/view/LinkView.java similarity index 98% rename from app/src/main/java/com/aurora/store/view/LinkView.java rename to app/src/main/java/com/aurora/store/ui/view/LinkView.java index 54ea9bf6f..8ef6c6a03 100644 --- a/app/src/main/java/com/aurora/store/view/LinkView.java +++ b/app/src/main/java/com/aurora/store/ui/view/LinkView.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.content.Context; import android.content.Intent; diff --git a/app/src/main/java/com/aurora/store/view/PropertyView.java b/app/src/main/java/com/aurora/store/ui/view/PropertyView.java similarity index 98% rename from app/src/main/java/com/aurora/store/view/PropertyView.java rename to app/src/main/java/com/aurora/store/ui/view/PropertyView.java index 5770147fd..09f7e2434 100644 --- a/app/src/main/java/com/aurora/store/view/PropertyView.java +++ b/app/src/main/java/com/aurora/store/ui/view/PropertyView.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/com/aurora/store/view/RatingView.java b/app/src/main/java/com/aurora/store/ui/view/RatingView.java similarity index 98% rename from app/src/main/java/com/aurora/store/view/RatingView.java rename to app/src/main/java/com/aurora/store/ui/view/RatingView.java index b538d7cb8..4da2c6ddb 100644 --- a/app/src/main/java/com/aurora/store/view/RatingView.java +++ b/app/src/main/java/com/aurora/store/ui/view/RatingView.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.view; +package com.aurora.store.ui.view; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/com/aurora/store/utility/Accountant.java b/app/src/main/java/com/aurora/store/util/Accountant.java similarity index 98% rename from app/src/main/java/com/aurora/store/utility/Accountant.java rename to app/src/main/java/com/aurora/store/util/Accountant.java index b6784fe1c..8d01cf716 100644 --- a/app/src/main/java/com/aurora/store/utility/Accountant.java +++ b/app/src/main/java/com/aurora/store/util/Accountant.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; @@ -46,6 +46,7 @@ public class Accountant { } public static String getEmail(Context context) { + return PrefUtil.getString(context, EMAIL); } diff --git a/app/src/main/java/com/aurora/store/utility/ApiBuilderUtil.java b/app/src/main/java/com/aurora/store/util/ApiBuilderUtil.java similarity index 69% rename from app/src/main/java/com/aurora/store/utility/ApiBuilderUtil.java rename to app/src/main/java/com/aurora/store/util/ApiBuilderUtil.java index 2aef6ed23..08f9b4d38 100644 --- a/app/src/main/java/com/aurora/store/utility/ApiBuilderUtil.java +++ b/app/src/main/java/com/aurora/store/util/ApiBuilderUtil.java @@ -1,4 +1,4 @@ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; import android.content.SharedPreferences; @@ -6,6 +6,7 @@ import android.text.TextUtils; import com.aurora.store.Constants; import com.aurora.store.adapter.NativeHttpClientAdapter; +import com.aurora.store.api.PlayStoreApiAuthenticator; import com.aurora.store.exception.CredentialsEmptyException; import com.aurora.store.manager.LocaleManager; import com.aurora.store.manager.SpoofManager; @@ -17,46 +18,52 @@ import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import com.dragons.aurora.playstoreapiv2.PlayStoreApiBuilder; import com.dragons.aurora.playstoreapiv2.PropertiesDeviceInfoProvider; +import org.apache.commons.lang3.StringUtils; + import java.io.IOException; import java.util.Locale; public class ApiBuilderUtil { - public static GooglePlayAPI buildFromPreferences(Context context) throws IOException { + public static GooglePlayAPI buildFromPreferences(Context context) throws Exception { LoginInfo loginInfo = LoginInfo.getSavedInstance(context); if (TextUtils.isEmpty(loginInfo.getEmail()) || TextUtils.isEmpty(loginInfo.getAuthToken())) { throw new CredentialsEmptyException(); } - if (Accountant.isAnonymous(context)) - return buildAnonymousApi(context, loginInfo); - else - return buildApi(context, loginInfo); + + PlayStoreApiBuilder builder = getBuilder(context, loginInfo); + return builder.build(); } - public static GooglePlayAPI buildAnonymousApi(Context context, LoginInfo loginInfo) throws IOException { - try { + public static GooglePlayAPI generateApiWithNewAuthToken(Context context) throws Exception { + GooglePlayAPI api; + LoginInfo loginInfo; + if (Accountant.isAnonymous(context)) { + api = PlayStoreApiAuthenticator.login(context); + loginInfo = LoginInfo.getSavedInstance(context); + } else { + loginInfo = LoginInfo.getSavedInstance(context); + loginInfo.setAuthToken(null); PlayStoreApiBuilder builder = getBuilder(context, loginInfo); - builder.setTokenDispenserUrl(loginInfo.getTokenDispenserUrl()); - GooglePlayAPI api = builder.build(); - loginInfo.setEmail(builder.getEmail()); - if (api != null) { - loginInfo.setGsfId(api.getGsfId()); - loginInfo.setAuthToken(api.getToken()); - loginInfo.setDfeCookie(api.getDfeCookie()); - loginInfo.setDeviceConfigToken(api.getDeviceConfigToken()); - loginInfo.setDeviceCheckinConsistencyToken(api.getDeviceCheckinConsistencyToken()); - LoginInfo.save(context, loginInfo); - Accountant.setAnonymous(context, true); - } - return api; - } catch (ApiBuilderException e) { - throw new RuntimeException(e); + api = builder.build(); } + if (api != null) { + loginInfo.setGsfId(api.getGsfId()); + loginInfo.setAuthToken(api.getToken()); + loginInfo.setDfeCookie(api.getDfeCookie()); + loginInfo.setDeviceConfigToken(api.getDeviceConfigToken()); + loginInfo.setDeviceCheckinConsistencyToken(api.getDeviceCheckinConsistencyToken()); + LoginInfo.save(context, loginInfo); + } + Accountant.setAnonymous(context, Accountant.isAnonymous(context)); + return api; } - public static GooglePlayAPI buildApi(Context context, LoginInfo loginInfo) throws IOException { + public static GooglePlayAPI buildApi(Context context, LoginInfo loginInfo, boolean isAnonymous) throws IOException { try { PlayStoreApiBuilder builder = getBuilder(context, loginInfo); + if (isAnonymous) + builder.setTokenDispenserUrl(loginInfo.getTokenDispenserUrl()); GooglePlayAPI api = builder.build(); loginInfo.setEmail(builder.getEmail()); if (api != null) { @@ -66,7 +73,7 @@ public class ApiBuilderUtil { loginInfo.setDeviceConfigToken(api.getDeviceConfigToken()); loginInfo.setDeviceCheckinConsistencyToken(api.getDeviceCheckinConsistencyToken()); LoginInfo.save(context, loginInfo); - Accountant.setAnonymous(context, false); + Accountant.setAnonymous(context, isAnonymous); } return api; } catch (ApiBuilderException e) { @@ -75,9 +82,9 @@ public class ApiBuilderUtil { } private static PlayStoreApiBuilder getBuilder(Context context, LoginInfo loginInfo) { - SharedPreferences prefs = Util.getPrefs(context); - String locale = prefs.getString(Constants.PREFERENCE_REQUESTED_LANGUAGE, ""); - loginInfo.setLocale(TextUtils.isEmpty(locale) ? Locale.getDefault().toString() : locale); + SharedPreferences sharedPreferences = Util.getPrefs(context); + String locale = sharedPreferences.getString(Constants.PREFERENCE_REQUESTED_LANGUAGE, StringUtils.EMPTY); + loginInfo.setLocale(TextUtils.isEmpty(locale) ? Locale.getDefault().getLanguage() : locale); PlayStoreApiBuilder builder = new PlayStoreApiBuilder(); builder.setHttpClient(new NativeHttpClientAdapter(context)); diff --git a/app/src/main/java/com/aurora/store/utility/ApkCopier.java b/app/src/main/java/com/aurora/store/util/ApkCopier.java similarity index 99% rename from app/src/main/java/com/aurora/store/utility/ApkCopier.java rename to app/src/main/java/com/aurora/store/util/ApkCopier.java index d615819d4..7f88a1e49 100644 --- a/app/src/main/java/com/aurora/store/utility/ApkCopier.java +++ b/app/src/main/java/com/aurora/store/util/ApkCopier.java @@ -21,7 +21,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; import android.content.pm.PackageInfo; diff --git a/app/src/main/java/com/aurora/store/utility/CertUtil.java b/app/src/main/java/com/aurora/store/util/CertUtil.java similarity index 95% rename from app/src/main/java/com/aurora/store/utility/CertUtil.java rename to app/src/main/java/com/aurora/store/util/CertUtil.java index a7c3461fc..c0d2484a6 100644 --- a/app/src/main/java/com/aurora/store/utility/CertUtil.java +++ b/app/src/main/java/com/aurora/store/util/CertUtil.java @@ -21,17 +21,15 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; diff --git a/app/src/main/java/com/aurora/store/utility/ColorUtil.java b/app/src/main/java/com/aurora/store/util/ColorUtil.java similarity index 97% rename from app/src/main/java/com/aurora/store/utility/ColorUtil.java rename to app/src/main/java/com/aurora/store/util/ColorUtil.java index ed0958578..b835e9881 100644 --- a/app/src/main/java/com/aurora/store/utility/ColorUtil.java +++ b/app/src/main/java/com/aurora/store/util/ColorUtil.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.graphics.Color; diff --git a/app/src/main/java/com/aurora/store/utility/ContextUtil.java b/app/src/main/java/com/aurora/store/util/ContextUtil.java similarity index 98% rename from app/src/main/java/com/aurora/store/utility/ContextUtil.java rename to app/src/main/java/com/aurora/store/util/ContextUtil.java index 99a17f9dc..8c4e8d041 100644 --- a/app/src/main/java/com/aurora/store/utility/ContextUtil.java +++ b/app/src/main/java/com/aurora/store/util/ContextUtil.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.app.Activity; import android.content.Context; diff --git a/app/src/main/java/com/aurora/store/util/ImageUtil.java b/app/src/main/java/com/aurora/store/util/ImageUtil.java new file mode 100644 index 000000000..4e63a4613 --- /dev/null +++ b/app/src/main/java/com/aurora/store/util/ImageUtil.java @@ -0,0 +1,74 @@ +package com.aurora.store.util; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; + +import java.util.ArrayList; +import java.util.List; + +public class ImageUtil { + + + private static final List gradientInts = new ArrayList<>(); + private static final List solidColors = new ArrayList<>(); + + static { + gradientInts.add(new int[]{0xFFEA5455, 0xFFEA5455}); + gradientInts.add(new int[]{0xFF7367F0, 0xFF7367F0}); + gradientInts.add(new int[]{0xFFF38181, 0xFFF38181}); + gradientInts.add(new int[]{0xFF32CCBC, 0xFF32CCBC}); + gradientInts.add(new int[]{0xFF28C76F, 0xFF28C76F}); + gradientInts.add(new int[]{0xFFFF6C00, 0xFFFF6C00}); + } + + static { + solidColors.add(0xFFEA5455); + solidColors.add(0xFF7367F0); + solidColors.add(0xFFF38181); + solidColors.add(0xFF32CCBC); + solidColors.add(0xFF28C76F); + solidColors.add(0xFFFF6C00); + } + + @ColorInt + public static int getSolidColor(int colorIndex) { + return solidColors.get(colorIndex % solidColors.size()); + } + + public static GradientDrawable getDrawable(int position, int shape) { + GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TR_BL, + gradientInts.get(position % gradientInts.size())); + gradientDrawable.setAlpha(200); + gradientDrawable.setShape(shape); + if (shape == GradientDrawable.RECTANGLE) + gradientDrawable.setCornerRadius(32f); + return gradientDrawable; + } + + public static GradientDrawable getDrawable(int position) { + GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TR_BL, + gradientInts.get(position % gradientInts.size())); + gradientDrawable.setShape(GradientDrawable.RECTANGLE); + gradientDrawable.setAlpha(200); + return gradientDrawable; + } + + @NonNull + public static Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) { + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(bmp); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bmp; + } + +} diff --git a/app/src/main/java/com/aurora/store/utility/Log.java b/app/src/main/java/com/aurora/store/util/Log.java similarity index 97% rename from app/src/main/java/com/aurora/store/utility/Log.java rename to app/src/main/java/com/aurora/store/util/Log.java index 2173a810f..694a874c4 100644 --- a/app/src/main/java/com/aurora/store/utility/Log.java +++ b/app/src/main/java/com/aurora/store/util/Log.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import com.aurora.store.Constants; diff --git a/app/src/main/java/com/aurora/store/utility/NetworkUtil.java b/app/src/main/java/com/aurora/store/util/NetworkUtil.java similarity index 98% rename from app/src/main/java/com/aurora/store/utility/NetworkUtil.java rename to app/src/main/java/com/aurora/store/util/NetworkUtil.java index ec036e7e2..068d0d4ad 100644 --- a/app/src/main/java/com/aurora/store/utility/NetworkUtil.java +++ b/app/src/main/java/com/aurora/store/util/NetworkUtil.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; import android.net.ConnectivityManager; diff --git a/app/src/main/java/com/aurora/store/utility/NotificationUtil.java b/app/src/main/java/com/aurora/store/util/NotificationUtil.java similarity index 88% rename from app/src/main/java/com/aurora/store/utility/NotificationUtil.java rename to app/src/main/java/com/aurora/store/util/NotificationUtil.java index 3c954fd77..f2cb738c7 100644 --- a/app/src/main/java/com/aurora/store/utility/NotificationUtil.java +++ b/app/src/main/java/com/aurora/store/util/NotificationUtil.java @@ -1,13 +1,10 @@ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; import androidx.core.app.NotificationCompat; import com.aurora.store.Constants; -import com.aurora.store.NotificationProvider; - -import java.util.Map; public class NotificationUtil { diff --git a/app/src/main/java/com/aurora/store/utility/PackageUtil.java b/app/src/main/java/com/aurora/store/util/PackageUtil.java similarity index 73% rename from app/src/main/java/com/aurora/store/utility/PackageUtil.java rename to app/src/main/java/com/aurora/store/util/PackageUtil.java index 092b66e00..f1e40b791 100644 --- a/app/src/main/java/com/aurora/store/utility/PackageUtil.java +++ b/app/src/main/java/com/aurora/store/util/PackageUtil.java @@ -18,21 +18,25 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import androidx.annotation.NonNull; - import com.aurora.store.model.App; import java.util.Map; public class PackageUtil { + private static final String ACTION_PACKAGE_REPLACED_NON_SYSTEM = "ACTION_PACKAGE_REPLACED_NON_SYSTEM"; + private static final String ACTION_PACKAGE_INSTALLATION_FAILED = "ACTION_PACKAGE_INSTALLATION_FAILED"; + private static final String ACTION_UNINSTALL_PACKAGE_FAILED = "ACTION_UNINSTALL_PACKAGE_FAILED"; + private static final String PSEUDO_PACKAGE_MAP = "PSEUDO_PACKAGE_MAP"; private static final String PSEUDO_URL_MAP = "PSEUDO_URL_MAP"; @@ -66,14 +70,15 @@ public class PackageUtil { PrefUtil.saveMap(context, pseudoMap, PSEUDO_URL_MAP); } - public static App getInstalledApp(PackageManager packageManager, String packageName) { + public static App getAppFromPackageName(PackageManager packageManager, String packageName) { try { final App app = new App(); - final PackageInfo packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS); + final PackageInfo packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA); app.setPackageName(packageName); app.setDisplayName(packageManager.getApplicationLabel(packageInfo.applicationInfo).toString()); app.setVersionName(packageInfo.versionName); app.setVersionCode(packageInfo.versionCode); + app.setSystem((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); return app; } catch (PackageManager.NameNotFoundException e) { return null; @@ -89,17 +94,6 @@ public class PackageUtil { } } - @NonNull - public static String getAppLabel(Context c, String packageName) { - try { - PackageManager pm = c.getPackageManager(); - ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0); - return pm.getApplicationLabel(appInfo).toString(); - } catch (Exception e) { - return ""; - } - } - public static boolean isInstalled(Context context, App app) { try { context.getPackageManager().getPackageInfo(app.getPackageName(), 0); @@ -117,4 +111,19 @@ public class PackageUtil { return false; } } + + public static IntentFilter getFilter() { + IntentFilter filter = new IntentFilter(); + filter.addDataScheme("package"); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_INSTALL); + filter.addAction(Intent.ACTION_UNINSTALL_PACKAGE); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + filter.addAction(ACTION_PACKAGE_REPLACED_NON_SYSTEM); + filter.addAction(ACTION_PACKAGE_INSTALLATION_FAILED); + filter.addAction(ACTION_UNINSTALL_PACKAGE_FAILED); + return filter; + } } diff --git a/app/src/main/java/com/aurora/store/utility/PathUtil.java b/app/src/main/java/com/aurora/store/util/PathUtil.java similarity index 97% rename from app/src/main/java/com/aurora/store/utility/PathUtil.java rename to app/src/main/java/com/aurora/store/util/PathUtil.java index 30084f7b2..1bc0ef3e7 100644 --- a/app/src/main/java/com/aurora/store/utility/PathUtil.java +++ b/app/src/main/java/com/aurora/store/util/PathUtil.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; import android.os.Build; @@ -32,7 +32,7 @@ import java.io.File; public class PathUtil { static public File getApkPath(String packageName, int version) { - String filename = packageName + "." + String.valueOf(version) + ".apk"; + String filename = packageName + "." + version + ".apk"; return new File(getRootApkCopyPath(), filename); } diff --git a/app/src/main/java/com/aurora/store/utility/PrefUtil.java b/app/src/main/java/com/aurora/store/util/PrefUtil.java similarity index 98% rename from app/src/main/java/com/aurora/store/utility/PrefUtil.java rename to app/src/main/java/com/aurora/store/util/PrefUtil.java index 6eccc5a04..7eea0a659 100644 --- a/app/src/main/java/com/aurora/store/utility/PrefUtil.java +++ b/app/src/main/java/com/aurora/store/util/PrefUtil.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; import android.content.SharedPreferences; @@ -36,7 +36,7 @@ import java.util.Set; public class PrefUtil { - public static void remove(Context context, String key){ + public static void remove(Context context, String key) { Util.getPrefs(context).edit().remove(key).apply(); } diff --git a/app/src/main/java/com/aurora/store/utility/Root.java b/app/src/main/java/com/aurora/store/util/Root.java similarity index 99% rename from app/src/main/java/com/aurora/store/utility/Root.java rename to app/src/main/java/com/aurora/store/util/Root.java index 07f813154..55c975ccc 100644 --- a/app/src/main/java/com/aurora/store/utility/Root.java +++ b/app/src/main/java/com/aurora/store/util/Root.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.util.Log; diff --git a/app/src/main/java/com/aurora/store/utility/TextUtil.java b/app/src/main/java/com/aurora/store/util/TextUtil.java similarity index 97% rename from app/src/main/java/com/aurora/store/utility/TextUtil.java rename to app/src/main/java/com/aurora/store/util/TextUtil.java index 5d1cbb6c8..bd3cc56f1 100644 --- a/app/src/main/java/com/aurora/store/utility/TextUtil.java +++ b/app/src/main/java/com/aurora/store/util/TextUtil.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import androidx.annotation.Nullable; diff --git a/app/src/main/java/com/aurora/store/utility/ThemeUtil.java b/app/src/main/java/com/aurora/store/util/ThemeUtil.java similarity index 84% rename from app/src/main/java/com/aurora/store/utility/ThemeUtil.java rename to app/src/main/java/com/aurora/store/util/ThemeUtil.java index 547ea4c91..92c7e9ab9 100644 --- a/app/src/main/java/com/aurora/store/utility/ThemeUtil.java +++ b/app/src/main/java/com/aurora/store/util/ThemeUtil.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.content.Context; import android.content.Intent; @@ -32,23 +32,7 @@ public class ThemeUtil { private int currentTheme; - public void onCreate(AppCompatActivity activity) { - new LocaleManager(activity).setLocale(); - currentTheme = getSelectedTheme(activity); - activity.setTheme(currentTheme); - } - - public void onResume(AppCompatActivity activity) { - if (currentTheme != getSelectedTheme(activity)) { - Intent intent = activity.getIntent(); - activity.finish(); - OverridePendingTransition.invoke(activity); - activity.startActivity(intent); - OverridePendingTransition.invoke(activity); - } - } - - private int getSelectedTheme(AppCompatActivity activity) { + public static int getSelectedTheme(AppCompatActivity activity) { String theme = Util.getTheme(activity); switch (theme) { case "light": @@ -73,9 +57,17 @@ public class ThemeUtil { } } - private static final class OverridePendingTransition { - static void invoke(AppCompatActivity activity) { - activity.overridePendingTransition(0, 0); + public void onCreate(AppCompatActivity activity) { + new LocaleManager(activity).setLocale(); + currentTheme = getSelectedTheme(activity); + activity.setTheme(currentTheme); + } + + public void onResume(AppCompatActivity activity) { + if (currentTheme != getSelectedTheme(activity)) { + Intent intent = activity.getIntent(); + activity.finish(); + activity.startActivity(intent); } } } diff --git a/app/src/main/java/com/aurora/store/utility/Util.java b/app/src/main/java/com/aurora/store/util/Util.java similarity index 91% rename from app/src/main/java/com/aurora/store/utility/Util.java rename to app/src/main/java/com/aurora/store/util/Util.java index 9a497b64f..fba1fd9eb 100644 --- a/app/src/main/java/com/aurora/store/utility/Util.java +++ b/app/src/main/java/com/aurora/store/util/Util.java @@ -18,7 +18,7 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.app.AlarmManager; import android.app.PendingIntent; @@ -38,10 +38,13 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.PagerSnapHelper; import androidx.recyclerview.widget.RecyclerView; +import com.aurora.store.BulkUpdateService; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.activity.AuroraActivity; +import com.aurora.store.ValidateApiService; import com.aurora.store.receiver.UpdatesReceiver; +import com.aurora.store.ui.main.AuroraActivity; +import com.aurora.store.ui.single.activity.SplashActivity; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.tonyodev.fetch2.Status; import com.tonyodev.fetch2core.Downloader; @@ -58,7 +61,6 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; -import java.util.StringTokenizer; import java.util.TreeMap; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -160,6 +162,14 @@ public class Util { } } + public static int parseFloatToInt(Float val) { + try { + return (int) (val * 10); + } catch (NumberFormatException e) { + return -1; + } + } + public static boolean noNetwork(Throwable e) { return e instanceof UnknownHostException || e instanceof SSLHandshakeException @@ -276,10 +286,6 @@ public class Util { return getPrefs(context).getBoolean(Constants.PREFERENCE_SEARCH_PACKAGE, true); } - public static boolean isTransparentStyle(Context context) { - return getPrefs(context).getBoolean(Constants.PREFERENCE_UI_TRANSPARENT, true); - } - public static boolean isExtendedUpdatesEnabled(Context context) { return getPrefs(context).getBoolean(Constants.PREFERENCE_UPDATES_EXTENDED, false); } @@ -348,18 +354,6 @@ public class Util { return getPrefs(context).getBoolean(Constants.PREFERENCE_UPDATES_AUTO, false); } - public static boolean isTabScrollable(Context context) { - return getPrefs(context).getBoolean(Constants.PREFERENCE_TAB_MODE, false); - } - - public static boolean isPasswordSaved(Context context) { - return getPrefs(context).getBoolean(Constants.PREFERENCE_ACCOUNTS_PASSWORD_SWITCH, false); - } - - public static void setPasswordSaved(Context context, boolean value) { - PrefUtil.putBoolean(context, Constants.PREFERENCE_ACCOUNTS_PASSWORD_SWITCH, value); - } - public static boolean isRootInstallEnabled(Context context) { String installMethod = getPrefs(context).getString(Constants.PREFERENCE_INSTALLATION_METHOD, "0"); return installMethod.equals("1"); @@ -453,18 +447,19 @@ public class Util { } public static void clearCache(Context context) { - PrefUtil.putString(context, Constants.PREFERENCE_TOP_APPS, ""); - PrefUtil.putString(context, Constants.PREFERENCE_TOP_GAMES, ""); - PrefUtil.putString(context, Constants.PREFERENCE_TOP_FAMILY, ""); + PrefUtil.putString(context, Constants.TOP_APPS, ""); + PrefUtil.putString(context, Constants.TOP_FAMILY, ""); + PrefUtil.putString(context, Constants.TOP_GAME, ""); } public static void restartApp(Context context) { - Intent mStartActivity = new Intent(context, AuroraActivity.class); - int mPendingIntentId = 1337; - PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId, mStartActivity, + Intent activity = new Intent(context, SplashActivity.class); + int id = 1337; + PendingIntent intent = PendingIntent.getActivity(context, id, activity, PendingIntent.FLAG_CANCEL_CURRENT); - AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent); + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + if (alarmManager != null) + alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 100, intent); System.exit(0); } @@ -541,18 +536,6 @@ public class Util { PrefUtil.putString(context, Constants.PREFERENCE_SELF_UPDATE_DATE, String.valueOf(dateInMillis)); } - public static Map parseResponse(String response) { - Map keyValueMap = new HashMap(); - StringTokenizer st = new StringTokenizer(response, "\n\r"); - while (st.hasMoreTokens()) { - String[] keyValue = st.nextToken().split("=", 2); - if (keyValue.length >= 2) { - keyValueMap.put(keyValue[0], keyValue[1]); - } - } - return keyValueMap; - } - public static Map parseCookieString(String cookies) { Map cookieList = new HashMap<>(); Pattern cookiePattern = Pattern.compile("([^=]+)=([^;]*);?\\s?"); @@ -564,4 +547,20 @@ public class Util { } return cookieList; } + + public static void validateApi(Context context) { + if (!ValidateApiService.isServiceRunning()) + context.startService(new Intent(context, ValidateApiService.class)); + } + + public static void bulkUpdate(Context context) { + if (!BulkUpdateService.isServiceRunning()) + context.startService(new Intent(context, BulkUpdateService.class)); + } + + public static void stopBulkUpdate(Context context) { + if (BulkUpdateService.isServiceRunning()) { + context.stopService(new Intent(context, BulkUpdateService.class)); + } + } } diff --git a/app/src/main/java/com/aurora/store/utility/ViewUtil.java b/app/src/main/java/com/aurora/store/util/ViewUtil.java similarity index 64% rename from app/src/main/java/com/aurora/store/utility/ViewUtil.java rename to app/src/main/java/com/aurora/store/util/ViewUtil.java index 8f2df7ee0..c0e0e0b39 100644 --- a/app/src/main/java/com/aurora/store/utility/ViewUtil.java +++ b/app/src/main/java/com/aurora/store/util/ViewUtil.java @@ -18,63 +18,28 @@ * */ -package com.aurora.store.utility; +package com.aurora.store.util; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; +import android.app.ActivityOptions; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.view.animation.DecelerateInterpolator; import android.view.animation.RotateAnimation; -import android.widget.TextView; -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -import com.aurora.store.R; - -import java.util.ArrayList; -import java.util.List; +import androidx.appcompat.app.AppCompatActivity; public class ViewUtil { - private static final List gradientColors = new ArrayList<>(); - private static final List solidColors = new ArrayList<>(); private static int ANIMATION_DURATION_SHORT = 250; - static { - gradientColors.add(new int[]{0xFFFEB692, 0xFFEA5455}); - gradientColors.add(new int[]{0xFFC9CFFC, 0xFF7367F0}); - gradientColors.add(new int[]{0xFFFCE38A, 0xFFF38181}); - gradientColors.add(new int[]{0xFF90F7EC, 0xFF32CCBC}); - gradientColors.add(new int[]{0xFF81FBB8, 0xFF28C76F}); - gradientColors.add(new int[]{0xFFFDEB71, 0xFFFF6C00}); - } - - static { - solidColors.add(0xFFFFB900); - solidColors.add(0xFF28C76F); - solidColors.add(0xFFEE3440); - solidColors.add(0xFF7367F0); - solidColors.add(0xFF00AEFF); - solidColors.add(0xFF32CCBC); - } - - @ColorInt - public static int getSolidColors(int colorIndex) { - return solidColors.get(colorIndex % solidColors.size()); - } - public static int dpToPx(Context context, int dp) { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)); @@ -85,24 +50,6 @@ public class ViewUtil { return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)); } - public static void setCustomColors(Context mContext, SwipeRefreshLayout swipeRefreshLayout) { - swipeRefreshLayout.setColorSchemeColors(mContext - .getResources() - .getIntArray(R.array.colorShades)); - } - - @NonNull - public static Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) { - if (drawable instanceof BitmapDrawable) { - return ((BitmapDrawable) drawable).getBitmap(); - } - final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(bmp); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - return bmp; - } - public static int getStyledAttribute(Context context, int styleID) { TypedArray arr = context.obtainStyledAttributes(new TypedValue().data, new int[]{styleID}); int styledColor = arr.getColor(0, Color.WHITE); @@ -110,25 +57,6 @@ public class ViewUtil { return styledColor; } - public static void setText(TextView textView, String text) { - if (null != textView) - textView.setText(text); - } - - public static void setText(View v, TextView textView, int stringId, Object... text) { - setText(textView, v.getResources().getString(stringId, text)); - } - - public static void setText(View v, int viewId, String text) { - TextView textView = v.findViewById(viewId); - if (null != textView) - textView.setText(text); - } - - public static void setText(View v, int viewId, int stringId, Object... text) { - setText(v, viewId, v.getResources().getString(stringId, text)); - } - public static void showWithAnimation(View view) { final int mShortAnimationDuration = view.getResources().getInteger( android.R.integer.config_shortAnimTime); @@ -170,11 +98,11 @@ public class ViewUtil { int prevHeight = v.getHeight(); v.setVisibility(View.VISIBLE); ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight); + valueAnimator.setInterpolator(new DecelerateInterpolator()); valueAnimator.addUpdateListener(animation -> { v.getLayoutParams().height = (int) animation.getAnimatedValue(); v.requestLayout(); }); - valueAnimator.setInterpolator(new DecelerateInterpolator()); valueAnimator.setDuration(ANIMATION_DURATION_SHORT); valueAnimator.start(); } @@ -205,4 +133,8 @@ public class ViewUtil { else setVisibility(view, visibility); } + + public static Bundle getEmptyActivityBundle(AppCompatActivity activity) { + return ActivityOptions.makeSceneTransitionAnimation(activity).toBundle(); + } } diff --git a/app/src/main/java/com/aurora/store/utility/ResponseUtil.java b/app/src/main/java/com/aurora/store/utility/ResponseUtil.java deleted file mode 100644 index e58e32edf..000000000 --- a/app/src/main/java/com/aurora/store/utility/ResponseUtil.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Raccoon 4 - * Copyright 2019 Patrick Ahlbrecht - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.utility; - -import com.dragons.aurora.playstoreapiv2.BulkDetailsResponse; -import com.dragons.aurora.playstoreapiv2.DeliveryResponse; -import com.dragons.aurora.playstoreapiv2.DetailsResponse; -import com.dragons.aurora.playstoreapiv2.ListResponse; -import com.dragons.aurora.playstoreapiv2.Payload; -import com.dragons.aurora.playstoreapiv2.ResponseWrapper; -import com.dragons.aurora.playstoreapiv2.SearchResponse; -import com.dragons.aurora.playstoreapiv2.TocResponse; -import com.dragons.aurora.playstoreapiv2.UploadDeviceConfigResponse; - -public class ResponseUtil { - - public static Payload payload(ResponseWrapper responseWrapper) { - if (responseWrapper != null && responseWrapper.hasPayload()) { - return responseWrapper.getPayload(); - } - return Payload.getDefaultInstance(); - } - - public static SearchResponse searchResponse(ResponseWrapper responseWrapper) { - Payload payload = payload(responseWrapper); - if (payload(responseWrapper).hasSearchResponse()) { - return payload.getSearchResponse(); - } - return SearchResponse.getDefaultInstance(); - } - - public static ListResponse listResponse(ResponseWrapper responseWrapper) { - Payload payload = payload(responseWrapper); - if (payload.hasListResponse()) { - return payload.getListResponse(); - } - return ListResponse.getDefaultInstance(); - } - - public static DeliveryResponse deliveryResponse(ResponseWrapper responseWrapper) { - Payload payload = payload(responseWrapper); - if (payload.hasDeliveryResponse()) { - return payload.getDeliveryResponse(); - } - return DeliveryResponse.getDefaultInstance(); - } - - public static BulkDetailsResponse bulkDetailsResponse(ResponseWrapper responseWrapper) { - Payload payload = payload(responseWrapper); - if (payload.hasBulkDetailsResponse()) { - return payload.getBulkDetailsResponse(); - } - return BulkDetailsResponse.getDefaultInstance(); - } - - public static DetailsResponse detailsResponse(ResponseWrapper responseWrapper) { - Payload payload = payload(responseWrapper); - if (payload.hasDetailsResponse()) { - return payload.getDetailsResponse(); - } - return DetailsResponse.getDefaultInstance(); - } - - public static TocResponse tocResponse(ResponseWrapper responseWrapper) { - Payload payload = payload(responseWrapper); - if (payload.hasTocResponse()) { - return payload.getTocResponse(); - } - return TocResponse.getDefaultInstance(); - } - - public static UploadDeviceConfigResponse uploadDeviceConfigResponse(ResponseWrapper responseWrapper) { - Payload payload = payload(responseWrapper); - if (payload.hasUploadDeviceConfigResponse()) { - return payload.getUploadDeviceConfigResponse(); - } - return UploadDeviceConfigResponse.getDefaultInstance(); - } -} diff --git a/app/src/main/java/com/aurora/store/view/ErrorView.java b/app/src/main/java/com/aurora/store/view/ErrorView.java deleted file mode 100644 index 61f24fb65..000000000 --- a/app/src/main/java/com/aurora/store/view/ErrorView.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2019, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - * - */ - -package com.aurora.store.view; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.aurora.store.ErrorType; -import com.aurora.store.R; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class ErrorView extends RelativeLayout { - - @BindView(R.id.img_err) - ImageView imgError; - @BindView(R.id.txt_err) - TextView txtError; - @BindView(R.id.btn_err) - Button btnError; - - private ErrorType errorType; - private View.OnClickListener errorListener; - - public ErrorView(Context context, ErrorType errorType, - OnClickListener errorListener) { - super(context); - this.errorType = errorType; - this.errorListener = errorListener; - init(context); - } - - @SuppressLint("ClickableViewAccessibility") - private void init(Context context) { - View view = inflate(context, R.layout.view_error, this); - ButterKnife.bind(this, view); - btnError.setOnClickListener(errorListener); - switch (errorType) { - case NO_NETWORK: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_no_network)); - txtError.setText(R.string.error_no_network); - break; - case NO_APPS: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_empty_box)); - txtError.setText(R.string.error_app_not_found); - break; - case NO_UPDATES: - btnError.setText(context.getString(R.string.action_recheck)); - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_no_updates)); - txtError.setText(R.string.list_empty_updates); - break; - case NO_SEARCH: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_search_alt)); - txtError.setText(R.string.error_search_not_found); - break; - case UNKNOWN: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_unknown)); - txtError.setText(R.string.error_unknown); - break; - case APP_NOT_FOUND: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_unknown)); - txtError.setText(R.string.error_app_not_found); - btnError.setText(R.string.action_close); - break; - case LOGOUT_ERR: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_login)); - txtError.setText(R.string.error_logged_out); - btnError.setText(R.string.action_login); - break; - case NO_DOWNLOADS: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_download_alt)); - txtError.setText(R.string.download_none); - btnError.setVisibility(GONE); - break; - case SESSION_EXPIRED: - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_unknown)); - txtError.setText(R.string.error_session_expired); - btnError.setVisibility(GONE); - break; - case IMPORT: - btnError.setText(context.getString(R.string.action_import)); - imgError.setImageDrawable(context.getDrawable(R.drawable.ic_empty_box)); - txtError.setText(R.string.list_empty_fav); - break; - } - } -} diff --git a/app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java b/app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java new file mode 100644 index 000000000..b9f6a5cf8 --- /dev/null +++ b/app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java @@ -0,0 +1,49 @@ +package com.aurora.store.viewmodel; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.enums.ErrorType; +import com.aurora.store.exception.CredentialsEmptyException; +import com.aurora.store.exception.InvalidApiException; +import com.aurora.store.exception.TooManyRequestsException; +import com.aurora.store.util.Log; +import com.dragons.aurora.playstoreapiv2.AuthException; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; + +import java.net.UnknownHostException; + +import io.reactivex.disposables.CompositeDisposable; + +public class BaseViewModel extends AndroidViewModel { + + protected GooglePlayAPI api; + protected CompositeDisposable disposable = new CompositeDisposable(); + protected MutableLiveData errorTypeMutableLiveData = new MutableLiveData<>(); + + public BaseViewModel(@NonNull Application application) { + super(application); + } + + public LiveData getError() { + return errorTypeMutableLiveData; + } + + public void handleError(Throwable err) { + if (err instanceof NullPointerException) + errorTypeMutableLiveData.setValue(ErrorType.NO_API); + else if (err instanceof CredentialsEmptyException || err instanceof InvalidApiException) + errorTypeMutableLiveData.setValue(ErrorType.LOGOUT_ERR); + else if (err instanceof AuthException | err instanceof TooManyRequestsException) + errorTypeMutableLiveData.setValue(ErrorType.SESSION_EXPIRED); + else if (err instanceof UnknownHostException) + errorTypeMutableLiveData.setValue(ErrorType.NO_NETWORK); + else + errorTypeMutableLiveData.setValue(ErrorType.UNKNOWN); + Log.d(err.getMessage()); + } +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/BlackListedAppsModel.java b/app/src/main/java/com/aurora/store/viewmodel/BlackListedAppsModel.java new file mode 100644 index 000000000..da94559ef --- /dev/null +++ b/app/src/main/java/com/aurora/store/viewmodel/BlackListedAppsModel.java @@ -0,0 +1,66 @@ +package com.aurora.store.viewmodel; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.Constants; +import com.aurora.store.model.App; +import com.aurora.store.task.InstalledAppsTask; +import com.aurora.store.util.PrefUtil; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class BlackListedAppsModel extends BaseViewModel { + + private Gson gson = new Gson(); + + private MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + + public BlackListedAppsModel(@NonNull Application application) { + super(application); + } + + public LiveData> getAllApps() { + return listMutableLiveData; + } + + public void getAllBlackListedApps() { + Type type = new TypeToken>() { + }.getType(); + String jsonString = PrefUtil.getString(getApplication(), Constants.PREFERENCE_INSTALLED_APPS); + List appList = gson.fromJson(jsonString, type); + if (appList == null || appList.isEmpty()) + fetchBlackListedApps(); + else { + listMutableLiveData.setValue(appList); + } + } + + public void fetchBlackListedApps() { + api = AuroraApplication.api; + disposable.add(Observable.fromCallable(() -> new InstalledAppsTask(api, getApplication()) + .getAllApps()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + listMutableLiveData.setValue(appList); + }, err -> handleError(err))); + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/ConnectionLiveData.java b/app/src/main/java/com/aurora/store/viewmodel/ConnectionLiveData.java new file mode 100644 index 000000000..e792f73d0 --- /dev/null +++ b/app/src/main/java/com/aurora/store/viewmodel/ConnectionLiveData.java @@ -0,0 +1,50 @@ +package com.aurora.store.viewmodel; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +import androidx.lifecycle.LiveData; + +import com.aurora.store.model.ConnectionModel; + +public class ConnectionLiveData extends LiveData { + + private Context context; + + private BroadcastReceiver networkReceiver = new BroadcastReceiver() { + @SuppressWarnings("deprecation") + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getExtras() != null) { + NetworkInfo activeNetwork = (NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO); + boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); + if (isConnected) { + postValue(new ConnectionModel(activeNetwork.getTypeName(), true)); + } else { + postValue(new ConnectionModel("", false)); + } + } + } + }; + + public ConnectionLiveData(Context context) { + this.context = context; + } + + @Override + protected void onActive() { + super.onActive(); + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + context.registerReceiver(networkReceiver, filter); + } + + @Override + protected void onInactive() { + super.onInactive(); + context.unregisterReceiver(networkReceiver); + } +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/FavouriteAppsModel.java b/app/src/main/java/com/aurora/store/viewmodel/FavouriteAppsModel.java new file mode 100644 index 000000000..bd36ddeb9 --- /dev/null +++ b/app/src/main/java/com/aurora/store/viewmodel/FavouriteAppsModel.java @@ -0,0 +1,53 @@ +package com.aurora.store.viewmodel; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.AuroraApplication; +import com.aurora.store.manager.FavouriteListManager; +import com.aurora.store.model.App; +import com.aurora.store.task.BulkDetailsTask; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class FavouriteAppsModel extends BaseViewModel { + + private ArrayList packageList; + + private MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + + public FavouriteAppsModel(@NonNull Application application) { + super(application); + FavouriteListManager favouriteListManager = new FavouriteListManager(application); + this.packageList = favouriteListManager.get(); + } + + public LiveData> getFavouriteApps() { + return listMutableLiveData; + } + + public void fetchFavouriteApps() { + api = AuroraApplication.api; + disposable.add(Observable.fromCallable(() -> new BulkDetailsTask(api) + .getRemoteAppList(packageList)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((appList) -> { + listMutableLiveData.setValue(appList); + }, err -> handleError(err))); + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/ReviewsModel.java b/app/src/main/java/com/aurora/store/viewmodel/ReviewsModel.java new file mode 100644 index 000000000..776aa74d9 --- /dev/null +++ b/app/src/main/java/com/aurora/store/viewmodel/ReviewsModel.java @@ -0,0 +1,70 @@ +package com.aurora.store.viewmodel; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.aurora.store.iterator.ReviewRetrieverIterator; +import com.aurora.store.iterator.ReviewStorageIterator; +import com.aurora.store.model.Review; +import com.aurora.store.task.ReviewsHelper; +import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; + +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class ReviewsModel extends BaseViewModel { + + private ReviewStorageIterator iterator; + + private MutableLiveData> listMutableLiveData = new MutableLiveData<>(); + + public ReviewsModel(@NonNull Application application) { + super(application); + } + + public LiveData> getReviews() { + return listMutableLiveData; + } + + public void fetchReviews(String packageName, GooglePlayAPI.REVIEW_SORT reviewSort, boolean rebuild) { + + if (iterator == null || rebuild) + getIterator(packageName, reviewSort); + + disposable.add(Observable.fromCallable(() -> new ReviewsHelper(iterator) + .getReviews()) + .subscribeOn(Schedulers.computation()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((reviewList) -> { + listMutableLiveData.setValue(reviewList); + }, err -> handleError(err))); + } + + private void getIterator(String packageName, GooglePlayAPI.REVIEW_SORT reviewSort) { + try { + iterator = new ReviewStorageIterator(); + iterator.setPackageName(packageName); + + ReviewRetrieverIterator retrieverIterator = new ReviewRetrieverIterator(); + retrieverIterator.setPackageName(packageName); + retrieverIterator.setReviewSort(reviewSort); + + iterator.setRetrievingIterator(retrieverIterator); + } catch (Exception err) { + handleError(err); + } + } + + @Override + protected void onCleared() { + disposable.dispose(); + super.onCleared(); + } +} diff --git a/app/src/main/res/drawable/app_settings.xml b/app/src/main/res/drawable/app_settings.xml deleted file mode 100644 index 9562f0727..000000000 --- a/app/src/main/res/drawable/app_settings.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/bottomsheet_bg.xml b/app/src/main/res/drawable/bottomsheet_bg.xml deleted file mode 100644 index b5b41d980..000000000 --- a/app/src/main/res/drawable/bottomsheet_bg.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/circle_bg.xml b/app/src/main/res/drawable/circle_bg.xml index 89b9700f6..50d2eeb7c 100644 --- a/app/src/main/res/drawable/circle_bg.xml +++ b/app/src/main/res/drawable/circle_bg.xml @@ -25,5 +25,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/downloads_anim.xml b/app/src/main/res/drawable/downloads_anim.xml deleted file mode 100644 index 663b9d676..000000000 --- a/app/src/main/res/drawable/downloads_anim.xml +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/generic_padded_bg.xml b/app/src/main/res/drawable/generic_padded_bg.xml index e3988dc2b..1443df7fc 100644 --- a/app/src/main/res/drawable/generic_padded_bg.xml +++ b/app/src/main/res/drawable/generic_padded_bg.xml @@ -22,6 +22,7 @@ + - + diff --git a/app/src/main/res/drawable/gradient_bg_bottom.xml b/app/src/main/res/drawable/gradient_bg_bottom.xml deleted file mode 100644 index 82b54c6fc..000000000 --- a/app/src/main/res/drawable/gradient_bg_bottom.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_about.xml b/app/src/main/res/drawable/ic_about.xml index 3ca9c4aef..5b919114f 100644 --- a/app/src/main/res/drawable/ic_about.xml +++ b/app/src/main/res/drawable/ic_about.xml @@ -5,10 +5,10 @@ android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_account.xml b/app/src/main/res/drawable/ic_account.xml index ceb7d5abe..55115c471 100644 --- a/app/src/main/res/drawable/ic_account.xml +++ b/app/src/main/res/drawable/ic_account.xml @@ -1,34 +1,9 @@ - - - - + diff --git a/app/src/main/res/drawable/ic_android_wear.xml b/app/src/main/res/drawable/ic_android_wear.xml deleted file mode 100644 index 75f2e4c0e..000000000 --- a/app/src/main/res/drawable/ic_android_wear.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_apps.xml b/app/src/main/res/drawable/ic_apps.xml index 231bfd9e4..f02896dfa 100644 --- a/app/src/main/res/drawable/ic_apps.xml +++ b/app/src/main/res/drawable/ic_apps.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml index 47b9b34ef..b9e6c4431 100644 --- a/app/src/main/res/drawable/ic_arrow.xml +++ b/app/src/main/res/drawable/ic_arrow.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml new file mode 100644 index 000000000..0522c7211 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_back.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_art_design.xml b/app/src/main/res/drawable/ic_art_design.xml deleted file mode 100644 index a44a546e2..000000000 --- a/app/src/main/res/drawable/ic_art_design.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_auto_vehicles.xml b/app/src/main/res/drawable/ic_auto_vehicles.xml deleted file mode 100644 index bcec3b811..000000000 --- a/app/src/main/res/drawable/ic_auto_vehicles.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_avatar_boy.xml b/app/src/main/res/drawable/ic_avatar_boy.xml deleted file mode 100644 index 37fd39705..000000000 --- a/app/src/main/res/drawable/ic_avatar_boy.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_beauty.xml b/app/src/main/res/drawable/ic_beauty.xml deleted file mode 100644 index a4caf1de2..000000000 --- a/app/src/main/res/drawable/ic_beauty.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_books_reference.xml b/app/src/main/res/drawable/ic_books_reference.xml deleted file mode 100644 index 5436fbb4e..000000000 --- a/app/src/main/res/drawable/ic_books_reference.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_business.xml b/app/src/main/res/drawable/ic_business.xml deleted file mode 100644 index 4e156d521..000000000 --- a/app/src/main/res/drawable/ic_business.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_cancel.xml b/app/src/main/res/drawable/ic_cancel.xml index f3a79ee73..de884c887 100644 --- a/app/src/main/res/drawable/ic_cancel.xml +++ b/app/src/main/res/drawable/ic_cancel.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/app/src/main/res/drawable/ic_categories.xml b/app/src/main/res/drawable/ic_categories.xml new file mode 100644 index 000000000..791806f78 --- /dev/null +++ b/app/src/main/res/drawable/ic_categories.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 000000000..3ef5301da --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_checked.xml b/app/src/main/res/drawable/ic_checked.xml index e148bd0ed..f00ae5f20 100644 --- a/app/src/main/res/drawable/ic_checked.xml +++ b/app/src/main/res/drawable/ic_checked.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/app/src/main/res/drawable/ic_comics.xml b/app/src/main/res/drawable/ic_comics.xml deleted file mode 100644 index 1d4882a62..000000000 --- a/app/src/main/res/drawable/ic_comics.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_communication.xml b/app/src/main/res/drawable/ic_communication.xml deleted file mode 100644 index a92d1bc86..000000000 --- a/app/src/main/res/drawable/ic_communication.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_copy.xml b/app/src/main/res/drawable/ic_copy.xml deleted file mode 100644 index 662b4cf11..000000000 --- a/app/src/main/res/drawable/ic_copy.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_dating.xml b/app/src/main/res/drawable/ic_dating.xml deleted file mode 100644 index d5bd86100..000000000 --- a/app/src/main/res/drawable/ic_dating.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_device_avatar.xml b/app/src/main/res/drawable/ic_device_avatar.xml deleted file mode 100644 index 674101786..000000000 --- a/app/src/main/res/drawable/ic_device_avatar.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_dot.xml b/app/src/main/res/drawable/ic_dot.xml index b1b1c6e8a..c80a9a815 100644 --- a/app/src/main/res/drawable/ic_dot.xml +++ b/app/src/main/res/drawable/ic_dot.xml @@ -1,9 +1,9 @@ diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml deleted file mode 100644 index aef2ed80a..000000000 --- a/app/src/main/res/drawable/ic_download.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_download_cancel.xml b/app/src/main/res/drawable/ic_download_cancel.xml deleted file mode 100644 index 5605fc031..000000000 --- a/app/src/main/res/drawable/ic_download_cancel.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_download_clear.xml b/app/src/main/res/drawable/ic_download_clear.xml deleted file mode 100644 index 99f65ad13..000000000 --- a/app/src/main/res/drawable/ic_download_clear.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_download_manager.xml b/app/src/main/res/drawable/ic_download_manager.xml deleted file mode 100644 index 1c1baee87..000000000 --- a/app/src/main/res/drawable/ic_download_manager.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_download_pause.xml b/app/src/main/res/drawable/ic_download_pause.xml deleted file mode 100644 index 81af18893..000000000 --- a/app/src/main/res/drawable/ic_download_pause.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_download_resume.xml b/app/src/main/res/drawable/ic_download_resume.xml deleted file mode 100644 index 67ea8ee1c..000000000 --- a/app/src/main/res/drawable/ic_download_resume.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_downloads.xml b/app/src/main/res/drawable/ic_downloads.xml deleted file mode 100644 index 705dee5a8..000000000 --- a/app/src/main/res/drawable/ic_downloads.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_edit.xml b/app/src/main/res/drawable/ic_edit.xml deleted file mode 100644 index 47374b67e..000000000 --- a/app/src/main/res/drawable/ic_edit.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_education.xml b/app/src/main/res/drawable/ic_education.xml deleted file mode 100644 index 147908ddd..000000000 --- a/app/src/main/res/drawable/ic_education.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_entertainment.xml b/app/src/main/res/drawable/ic_entertainment.xml deleted file mode 100644 index f41b40457..000000000 --- a/app/src/main/res/drawable/ic_entertainment.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_events.xml b/app/src/main/res/drawable/ic_events.xml deleted file mode 100644 index d95ac302a..000000000 --- a/app/src/main/res/drawable/ic_events.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_family.xml b/app/src/main/res/drawable/ic_family.xml deleted file mode 100644 index 98912c37a..000000000 --- a/app/src/main/res/drawable/ic_family.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_fav.xml b/app/src/main/res/drawable/ic_fav.xml index f19d18054..fdd9bb064 100644 --- a/app/src/main/res/drawable/ic_fav.xml +++ b/app/src/main/res/drawable/ic_fav.xml @@ -25,10 +25,10 @@ android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_filter.xml b/app/src/main/res/drawable/ic_filter.xml index cc6f7ec5f..be37f6188 100644 --- a/app/src/main/res/drawable/ic_filter.xml +++ b/app/src/main/res/drawable/ic_filter.xml @@ -1,29 +1,9 @@ - - - + android:viewportWidth="24" + android:viewportHeight="24"> + diff --git a/app/src/main/res/drawable/ic_filter_apps.xml b/app/src/main/res/drawable/ic_filter_apps.xml deleted file mode 100644 index ccc94fe95..000000000 --- a/app/src/main/res/drawable/ic_filter_apps.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_filter_check.xml b/app/src/main/res/drawable/ic_filter_check.xml new file mode 100644 index 000000000..ef3cb828e --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_check.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_finance.xml b/app/src/main/res/drawable/ic_finance.xml deleted file mode 100644 index d9ef095c0..000000000 --- a/app/src/main/res/drawable/ic_finance.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_food_drink.xml b/app/src/main/res/drawable/ic_food_drink.xml deleted file mode 100644 index d14877964..000000000 --- a/app/src/main/res/drawable/ic_food_drink.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_free.xml b/app/src/main/res/drawable/ic_free.xml new file mode 100644 index 000000000..ddaca78ae --- /dev/null +++ b/app/src/main/res/drawable/ic_free.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_games.xml b/app/src/main/res/drawable/ic_games.xml deleted file mode 100644 index 5bd14d495..000000000 --- a/app/src/main/res/drawable/ic_games.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_google_play.xml b/app/src/main/res/drawable/ic_google_play.xml deleted file mode 100644 index 36f58d5b9..000000000 --- a/app/src/main/res/drawable/ic_google_play.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_open.xml b/app/src/main/res/drawable/ic_grossing.xml similarity index 53% rename from app/src/main/res/drawable/ic_open.xml rename to app/src/main/res/drawable/ic_grossing.xml index 44a2aad46..5d96266f0 100644 --- a/app/src/main/res/drawable/ic_open.xml +++ b/app/src/main/res/drawable/ic_grossing.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:pathData="M7,8L7,6a5,5 0,1 1,10 0v2h3a1,1 0,0 1,1 1v12a1,1 0,0 1,-1 1L4,22a1,1 0,0 1,-1 -1L3,9a1,1 0,0 1,1 -1h3zM7,10L5,10v10h14L19,10h-2v2h-2v-2L9,10v2L7,12v-2zM9,8h6L15,6a3,3 0,0 0,-6 0v2z" /> diff --git a/app/src/main/res/drawable/ic_health_fitness.xml b/app/src/main/res/drawable/ic_health_fitness.xml deleted file mode 100644 index 2eecdd794..000000000 --- a/app/src/main/res/drawable/ic_health_fitness.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml index 543603f18..97b691547 100644 --- a/app/src/main/res/drawable/ic_home.xml +++ b/app/src/main/res/drawable/ic_home.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/app/src/main/res/drawable/ic_house_home.xml b/app/src/main/res/drawable/ic_house_home.xml deleted file mode 100644 index 6274872fa..000000000 --- a/app/src/main/res/drawable/ic_house_home.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_installation.xml b/app/src/main/res/drawable/ic_installation.xml index 92e9fc2a6..79eedd140 100644 --- a/app/src/main/res/drawable/ic_installation.xml +++ b/app/src/main/res/drawable/ic_installation.xml @@ -1,34 +1,9 @@ - - - - + diff --git a/app/src/main/res/drawable/ic_installation_alt.xml b/app/src/main/res/drawable/ic_installation_alt.xml deleted file mode 100644 index 854d57c49..000000000 --- a/app/src/main/res/drawable/ic_installation_alt.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_language.xml b/app/src/main/res/drawable/ic_language.xml index cd3d2b562..bc824bfe3 100644 --- a/app/src/main/res/drawable/ic_language.xml +++ b/app/src/main/res/drawable/ic_language.xml @@ -1,34 +1,9 @@ - - - - + diff --git a/app/src/main/res/drawable/ic_libraries_demo.xml b/app/src/main/res/drawable/ic_libraries_demo.xml deleted file mode 100644 index 67fce92a3..000000000 --- a/app/src/main/res/drawable/ic_libraries_demo.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_lifestyle.xml b/app/src/main/res/drawable/ic_lifestyle.xml deleted file mode 100644 index ea296c194..000000000 --- a/app/src/main/res/drawable/ic_lifestyle.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_maps_navigation.xml b/app/src/main/res/drawable/ic_maps_navigation.xml deleted file mode 100644 index 238b2cb15..000000000 --- a/app/src/main/res/drawable/ic_maps_navigation.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_medical.xml b/app/src/main/res/drawable/ic_medical.xml deleted file mode 100644 index fdfafec3e..000000000 --- a/app/src/main/res/drawable/ic_medical.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_menu_about.xml b/app/src/main/res/drawable/ic_menu_about.xml new file mode 100644 index 000000000..194d03e35 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_about.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_account.xml b/app/src/main/res/drawable/ic_menu_account.xml new file mode 100644 index 000000000..55115c471 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_account.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_blacklist.xml b/app/src/main/res/drawable/ic_menu_blacklist.xml new file mode 100644 index 000000000..5d5747f78 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_blacklist.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_download.xml b/app/src/main/res/drawable/ic_menu_download.xml new file mode 100644 index 000000000..dae8a4f9f --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_download.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_fav.xml b/app/src/main/res/drawable/ic_menu_fav.xml new file mode 100644 index 000000000..61ba28d0a --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_fav.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_line.xml b/app/src/main/res/drawable/ic_menu_line.xml new file mode 100644 index 000000000..583b7b702 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_line.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_settings.xml b/app/src/main/res/drawable/ic_menu_settings.xml new file mode 100644 index 000000000..5bd01c22d --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_settings.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_spoof.xml b/app/src/main/res/drawable/ic_menu_spoof.xml new file mode 100644 index 000000000..9948d8a07 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_spoof.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_music__audio.xml b/app/src/main/res/drawable/ic_music__audio.xml deleted file mode 100644 index 7769c4299..000000000 --- a/app/src/main/res/drawable/ic_music__audio.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_network.xml b/app/src/main/res/drawable/ic_network.xml index 36a13f926..fb5a18730 100644 --- a/app/src/main/res/drawable/ic_network.xml +++ b/app/src/main/res/drawable/ic_network.xml @@ -1,33 +1,9 @@ - - - - + diff --git a/app/src/main/res/drawable/ic_news_magazines.xml b/app/src/main/res/drawable/ic_news_magazines.xml deleted file mode 100644 index 4bd3f8824..000000000 --- a/app/src/main/res/drawable/ic_news_magazines.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_no_network.xml b/app/src/main/res/drawable/ic_no_network.xml index 994a90159..65fbf377e 100644 --- a/app/src/main/res/drawable/ic_no_network.xml +++ b/app/src/main/res/drawable/ic_no_network.xml @@ -1,61 +1,9 @@ - - - - - - - - - - - - - + android:viewportWidth="24" + android:viewportHeight="24"> + diff --git a/app/src/main/res/drawable/ic_notification.xml b/app/src/main/res/drawable/ic_notification.xml index f83a4b01d..8e24a79ea 100644 --- a/app/src/main/res/drawable/ic_notification.xml +++ b/app/src/main/res/drawable/ic_notification.xml @@ -1,30 +1,9 @@ - - - + diff --git a/app/src/main/res/drawable/ic_notifications.xml b/app/src/main/res/drawable/ic_notifications.xml index 72db5533d..fb436ff3c 100644 --- a/app/src/main/res/drawable/ic_notifications.xml +++ b/app/src/main/res/drawable/ic_notifications.xml @@ -1,34 +1,9 @@ - - - - + diff --git a/app/src/main/res/drawable/ic_parenting.xml b/app/src/main/res/drawable/ic_parenting.xml deleted file mode 100644 index 237787c21..000000000 --- a/app/src/main/res/drawable/ic_parenting.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_perm.xml b/app/src/main/res/drawable/ic_perm.xml deleted file mode 100644 index 582f74405..000000000 --- a/app/src/main/res/drawable/ic_perm.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_personalization.xml b/app/src/main/res/drawable/ic_personalization.xml deleted file mode 100644 index 771f68342..000000000 --- a/app/src/main/res/drawable/ic_personalization.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_photography.xml b/app/src/main/res/drawable/ic_photography.xml deleted file mode 100644 index 3b498faa8..000000000 --- a/app/src/main/res/drawable/ic_photography.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_play.xml b/app/src/main/res/drawable/ic_play.xml index 7b09a9c71..7296abee8 100644 --- a/app/src/main/res/drawable/ic_play.xml +++ b/app/src/main/res/drawable/ic_play.xml @@ -24,7 +24,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_productivity.xml b/app/src/main/res/drawable/ic_productivity.xml deleted file mode 100644 index 5168ac8b0..000000000 --- a/app/src/main/res/drawable/ic_productivity.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_rating_negative.xml b/app/src/main/res/drawable/ic_rating_negative.xml deleted file mode 100644 index cd4a71eaa..000000000 --- a/app/src/main/res/drawable/ic_rating_negative.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_rating_positive.xml b/app/src/main/res/drawable/ic_rating_positive.xml deleted file mode 100644 index 3a1059bb7..000000000 --- a/app/src/main/res/drawable/ic_rating_positive.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml deleted file mode 100644 index 3fccd6e92..000000000 --- a/app/src/main/res/drawable/ic_search.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml deleted file mode 100644 index 6073977d8..000000000 --- a/app/src/main/res/drawable/ic_settings.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_shopping.xml b/app/src/main/res/drawable/ic_shopping.xml deleted file mode 100644 index 91babe03f..000000000 --- a/app/src/main/res/drawable/ic_shopping.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_size.xml b/app/src/main/res/drawable/ic_size.xml deleted file mode 100644 index ed2dfe541..000000000 --- a/app/src/main/res/drawable/ic_size.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_social.xml b/app/src/main/res/drawable/ic_social.xml deleted file mode 100644 index d15f34538..000000000 --- a/app/src/main/res/drawable/ic_social.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_spoof_alt.xml b/app/src/main/res/drawable/ic_spoof_alt.xml deleted file mode 100644 index 715a54d69..000000000 --- a/app/src/main/res/drawable/ic_spoof_alt.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/drawable/ic_sports.xml b/app/src/main/res/drawable/ic_sports.xml deleted file mode 100644 index 43a8bad8a..000000000 --- a/app/src/main/res/drawable/ic_sports.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_star.xml b/app/src/main/res/drawable/ic_star.xml deleted file mode 100644 index e51900b76..000000000 --- a/app/src/main/res/drawable/ic_star.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_tab_explore.xml b/app/src/main/res/drawable/ic_tab_explore.xml deleted file mode 100644 index d52fd2e61..000000000 --- a/app/src/main/res/drawable/ic_tab_explore.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_tab_games.xml b/app/src/main/res/drawable/ic_tab_games.xml deleted file mode 100644 index cbebc879e..000000000 --- a/app/src/main/res/drawable/ic_tab_games.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/drawable/ic_tools.xml b/app/src/main/res/drawable/ic_tools.xml deleted file mode 100644 index 3846b84bd..000000000 --- a/app/src/main/res/drawable/ic_tools.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_travel_local.xml b/app/src/main/res/drawable/ic_travel_local.xml deleted file mode 100644 index b98a9d6fd..000000000 --- a/app/src/main/res/drawable/ic_travel_local.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_trending.xml b/app/src/main/res/drawable/ic_trending.xml new file mode 100644 index 000000000..cbf11d617 --- /dev/null +++ b/app/src/main/res/drawable/ic_trending.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_ui.xml b/app/src/main/res/drawable/ic_ui.xml index 0172f4018..df512373c 100644 --- a/app/src/main/res/drawable/ic_ui.xml +++ b/app/src/main/res/drawable/ic_ui.xml @@ -1,46 +1,9 @@ - - - - - - - + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M12,2c5.522,0 10,3.978 10,8.889a5.558,5.558 0,0 1,-5.556 5.555h-1.966c-0.922,0 -1.667,0.745 -1.667,1.667 0,0.422 0.167,0.811 0.422,1.1 0.267,0.3 0.434,0.689 0.434,1.122C13.667,21.256 12.9,22 12,22 6.478,22 2,17.522 2,12S6.478,2 12,2zM10.811,18.111a3.664,3.664 0,0 1,3.667 -3.667h1.966A3.558,3.558 0,0 0,20 10.89C20,7.139 16.468,4 12,4a8,8 0,0 0,-0.676 15.972,3.648 3.648,0 0,1 -0.513,-1.86zM7.5,12a1.5,1.5 0,1 1,0 -3,1.5 1.5,0 0,1 0,3zM16.5,12a1.5,1.5 0,1 1,0 -3,1.5 1.5,0 0,1 0,3zM12,9a1.5,1.5 0,1 1,0 -3,1.5 1.5,0 0,1 0,3z" /> diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml index 78df3750a..0f9a8bfba 100644 --- a/app/src/main/res/drawable/ic_update.xml +++ b/app/src/main/res/drawable/ic_update.xml @@ -1,34 +1,9 @@ - - - - + diff --git a/app/src/main/res/drawable/ic_updates.xml b/app/src/main/res/drawable/ic_updates.xml index 647deb483..05bf67be7 100644 --- a/app/src/main/res/drawable/ic_updates.xml +++ b/app/src/main/res/drawable/ic_updates.xml @@ -1,34 +1,9 @@ - - - + android:pathData="M12,22C6.477,22 2,17.523 2,12S6.477,2 12,2s10,4.477 10,10 -4.477,10 -10,10zM12,20a8,8 0,1 0,0 -16,8 8,0 0,0 0,16zM13,12h4v2h-6L11,7h2v5z" /> diff --git a/app/src/main/res/drawable/ic_video_editors.xml b/app/src/main/res/drawable/ic_video_editors.xml deleted file mode 100644 index 00df23fc3..000000000 --- a/app/src/main/res/drawable/ic_video_editors.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_weather.xml b/app/src/main/res/drawable/ic_weather.xml deleted file mode 100644 index 354ca7e62..000000000 --- a/app/src/main/res/drawable/ic_weather.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/installed_bg.xml b/app/src/main/res/drawable/installed_bg.xml deleted file mode 100644 index 4eead3528..000000000 --- a/app/src/main/res/drawable/installed_bg.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/outline_bg_rounded.xml b/app/src/main/res/drawable/outline_bg_rounded.xml new file mode 100644 index 000000000..7db99a1f7 --- /dev/null +++ b/app/src/main/res/drawable/outline_bg_rounded.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_indicator.xml b/app/src/main/res/drawable/tab_indicator.xml deleted file mode 100644 index 287349d7a..000000000 --- a/app/src/main/res/drawable/tab_indicator.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/drawable/vd_downloading.xml b/app/src/main/res/drawable/vd_downloading.xml deleted file mode 100644 index 3f182a79f..000000000 --- a/app/src/main/res/drawable/vd_downloading.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/font/open_sans_semibold.xml b/app/src/main/res/font/open_sans_semibold.xml deleted file mode 100644 index 13a062dea..000000000 --- a/app/src/main/res/font/open_sans_semibold.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_accounts.xml b/app/src/main/res/layout/activity_accounts.xml index d275d3d8f..0147eda73 100644 --- a/app/src/main/res/layout/activity_accounts.xml +++ b/app/src/main/res/layout/activity_accounts.xml @@ -24,7 +24,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".activity.AccountsActivity"> + tools:context=".ui.accounts.AccountsActivity"> diff --git a/app/src/main/res/layout/fragment_installed.xml b/app/src/main/res/layout/activity_all_apps.xml similarity index 53% rename from app/src/main/res/layout/fragment_installed.xml rename to app/src/main/res/layout/activity_all_apps.xml index 05f4f9372..575160214 100644 --- a/app/src/main/res/layout/fragment_installed.xml +++ b/app/src/main/res/layout/activity_all_apps.xml @@ -25,22 +25,35 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:orientation="vertical" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + android:layout_height="wrap_content" + android:paddingStart="@dimen/margin_medium" + android:paddingEnd="@dimen/margin_medium"> + + + - - - - - - - - - + android:layout_height="match_parent"> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_category_apps.xml b/app/src/main/res/layout/activity_category_apps.xml new file mode 100644 index 000000000..86f7fb9ee --- /dev/null +++ b/app/src/main/res/layout/activity_category_apps.xml @@ -0,0 +1,42 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_details.xml b/app/src/main/res/layout/activity_details.xml index b7d0ba088..5e08571eb 100644 --- a/app/src/main/res/layout/activity_details.xml +++ b/app/src/main/res/layout/activity_details.xml @@ -1,5 +1,4 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_apps.xml b/app/src/main/res/layout/activity_dev_apps.xml similarity index 57% rename from app/src/main/res/layout/fragment_apps.xml rename to app/src/main/res/layout/activity_dev_apps.xml index 3b1b74a32..0f47df7cd 100644 --- a/app/src/main/res/layout/fragment_apps.xml +++ b/app/src/main/res/layout/activity_dev_apps.xml @@ -20,31 +20,26 @@ - + + + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> - - - - + android:layout_height="match_parent" + android:clipToPadding="false" + android:paddingTop="@dimen/margin_small" + android:scrollbarStyle="outsideOverlay" + android:scrollbars="vertical" + tools:listitem="@layout/item_installed" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_device_info.xml b/app/src/main/res/layout/activity_device_info.xml index 87671ceb5..56ee81a67 100644 --- a/app/src/main/res/layout/activity_device_info.xml +++ b/app/src/main/res/layout/activity_device_info.xml @@ -28,6 +28,7 @@ + tools:context=".ui.single.activity.DownloadsActivity"> diff --git a/app/src/main/res/drawable/category_bg.xml b/app/src/main/res/layout/activity_generic.xml similarity index 57% rename from app/src/main/res/drawable/category_bg.xml rename to app/src/main/res/layout/activity_generic.xml index 8071481ab..544885ca0 100644 --- a/app/src/main/res/drawable/category_bg.xml +++ b/app/src/main/res/layout/activity_generic.xml @@ -18,11 +18,17 @@ ~ --> - - - - - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_intro.xml b/app/src/main/res/layout/activity_intro.xml index b8a8df4bc..20e7a7ca8 100644 --- a/app/src/main/res/layout/activity_intro.xml +++ b/app/src/main/res/layout/activity_intro.xml @@ -23,13 +23,63 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".activity.IntroActivity"> + tools:context=".ui.intro.IntroActivity"> - + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index c2a64ac28..c01bb15b0 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -23,7 +23,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="false" - tools:context=".activity.GoogleLoginActivity"> + tools:context=".ui.single.activity.GoogleLoginActivity"> - + android:layout_height="match_parent"> - - - + tools:context=".ui.main.AuroraActivity"> - - \ No newline at end of file + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_manual.xml b/app/src/main/res/layout/activity_manual.xml index 2decc7791..ea1e8d05b 100644 --- a/app/src/main/res/layout/activity_manual.xml +++ b/app/src/main/res/layout/activity_manual.xml @@ -63,7 +63,7 @@ + android:textAppearance="@style/TextAppearance.Aurora.Button" /> + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml new file mode 100644 index 000000000..45f63e056 --- /dev/null +++ b/app/src/main/res/layout/activity_search.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search_result.xml b/app/src/main/res/layout/activity_search_result.xml new file mode 100644 index 000000000..d286bd142 --- /dev/null +++ b/app/src/main/res/layout/activity_search_result.xml @@ -0,0 +1,32 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 000000000..bd7f210bc --- /dev/null +++ b/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index a4fab1d6d..ac69c299e 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -1,5 +1,4 @@ - - + android:layout_height="match_parent"> + android:layout_height="match_parent"> + + diff --git a/app/src/main/res/layout/fragment_category_applist.xml b/app/src/main/res/layout/fragment_category_applist.xml index a1dcfb92e..0b562097d 100644 --- a/app/src/main/res/layout/fragment_category_applist.xml +++ b/app/src/main/res/layout/fragment_category_applist.xml @@ -17,42 +17,19 @@ ~ ~ --> - - + android:layout_height="match_parent"> - - - - - - - - - - - \ No newline at end of file + android:layout_height="match_parent" + android:clipToPadding="false" + android:overScrollMode="never" + android:paddingTop="@dimen/margin_bottom" + android:paddingBottom="@dimen/margin_bottom" + tools:itemCount="4" + tools:listitem="@layout/item_installed" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_category_container.xml b/app/src/main/res/layout/fragment_category_container.xml deleted file mode 100644 index 56edfc772..000000000 --- a/app/src/main/res/layout/fragment_category_container.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml deleted file mode 100644 index bfcfee9d3..000000000 --- a/app/src/main/res/layout/fragment_details.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_dev_applist.xml b/app/src/main/res/layout/fragment_dev_applist.xml index beb9687b1..bd89a4ac0 100644 --- a/app/src/main/res/layout/fragment_dev_applist.xml +++ b/app/src/main/res/layout/fragment_dev_applist.xml @@ -19,57 +19,18 @@ --> + android:layout_height="match_parent"> - - - - - - - - - - - - - - + android:layout_height="wrap_content" + android:clipToPadding="false" + android:paddingTop="@dimen/margin_small" + android:scrollbarStyle="outsideOverlay" + android:scrollbars="vertical" + tools:listitem="@layout/item_installed" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_favourites.xml b/app/src/main/res/layout/fragment_favourites.xml index c44ad601e..81d9aa825 100755 --- a/app/src/main/res/layout/fragment_favourites.xml +++ b/app/src/main/res/layout/fragment_favourites.xml @@ -19,123 +19,70 @@ --> + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:orientation="vertical"> - + android:layout_height="wrap_content" + android:minHeight="?actionBarSize"> - + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:layout_marginStart="@dimen/margin_normal" + android:layout_marginEnd="@dimen/margin_small" + android:layout_toStartOf="@id/install_list" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.Aurora.Line1" /> - + -