Rahul Kumar Patel
2019-12-10 02:20:08 +05:30
parent 7c18bfe320
commit 02a02b96cf
431 changed files with 9554 additions and 12854 deletions

View File

@@ -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)
[<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="60">](https://f-droid.org/packages/com.dragons.aurora/) [<img src="https://poeditor.com/public/images/logo_small.png" alt="Join POEditor">](https://poeditor.com/join/project/54swaCpFXJ)
[<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="60">](https://f-droid.org/packages/com.dragons.aurora/) [<img src="https://poeditor.com/public/images/logo_small.png" alt="Join POEditor">](https://poeditor.com/join/project/54swaCpFXJ)

View File

@@ -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"

View File

@@ -51,4 +51,6 @@
# is used to reflectively look up the generated ViewBinding.
-keep class butterknife.*
-keepclasseswithmembernames class * { @butterknife.* <methods>; }
-keepclasseswithmembernames class * { @butterknife.* <fields>; }
-keepclasseswithmembernames class * { @butterknife.* <fields>; }
-keep public class com.aurora.store.ui.preference.fragment.*

View File

@@ -67,34 +67,12 @@
tools:targetApi="q">
<activity
android:name=".activity.AuroraActivity"
android:name=".ui.main.AuroraActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="search"
android:scheme="market" />
</intent-filter>
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
<action android:name="android.intent.action.MAIN" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<activity
android:name=".activity.DetailsActivity"
android:name=".ui.details.DetailsActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -121,36 +99,61 @@
</activity>
<activity
android:name=".activity.FullscreenImageActivity"
android:name=".ui.single.activity.FullscreenImageActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale" />
<activity
android:name=".activity.DownloadsActivity"
android:name=".ui.single.activity.DownloadsActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale" />
<activity
android:name=".activity.AccountsActivity"
android:name=".ui.accounts.AccountsActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale" />
<activity
android:name=".activity.SettingsActivity"
android:name=".ui.preference.SettingsActivity"
android:configChanges="locale|orientation|fontScale"
android:theme="@style/AppTheme" />
<activity
android:name=".activity.IntroActivity"
android:name=".ui.intro.IntroActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale" />
<activity
android:name=".activity.ManualDownloadActivity"
android:name=".ui.single.activity.ManualDownloadActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale" />
<activity
android:name=".activity.DeviceInfoActivity"
android:name=".ui.single.activity.DeviceInfoActivity"
android:configChanges="keyboardHidden|locale|orientation|fontScale" />
<activity
android:name=".activity.GoogleLoginActivity"
android:theme="@style/LoginTheme" />
<activity android:name=".ui.single.activity.GoogleLoginActivity" />
<activity android:name=".ui.single.activity.SplashActivity">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".ui.search.activity.SearchActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="search"
android:scheme="market" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
<activity android:name=".ui.search.activity.SearchResultActivity" />
<activity android:name=".ui.category.CategoryAppsActivity" />
<activity android:name=".ui.installed.InstalledAppActivity" />
<activity android:name=".ui.single.activity.GenericActivity" />
<activity android:name=".ui.devapps.DevAppsActivity" />
<activity android:name=".ui.details.ReviewsActivity" />
<provider
android:name=".provider.AuroraSuggestionProvider"
android:authorities="com.aurora.store.provider.AuroraSuggestionProvider"
android:enabled="true"
android:exported="false" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.aurora.store.fileProvider"
@@ -177,11 +180,7 @@
<service android:name=".installer.InstallerService" />
<service android:name=".SelfUpdateService" />
<service android:name=".AnonymousLoginService" />
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
<service android:name=".ValidateApiService" />
<service android:name=".BulkUpdateService" />
</application>
</manifest>

View File

@@ -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();
}
}

View File

@@ -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<App> newList;
private List<App> oldList;
public AppDiffCallback(List<App> newList, List<App> 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));
}
}

View File

@@ -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<App> ongoingUpdateList = new ArrayList<>();
public static GooglePlayAPI api = null;
private static RxBus rxBus = null;
private static boolean bulkUpdateAlive = false;
private static List<App> 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<App> 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();
}
}

View File

@@ -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;

View File

@@ -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<App> 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();
}
}

View File

@@ -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";
}

View File

@@ -1,93 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -1,63 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* Yalp Store
* Copyright (C) 2018 Sergey Yeriomin <yeriomin@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -1,91 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -1,27 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
package com.aurora.store;
public enum ListType {
INSTALLED,
UPDATES,
ENDLESS
}

View File

@@ -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));
}

View File

@@ -1,74 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* Yalp Store
* Copyright (C) 2018 Sergey Yeriomin <yeriomin@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<String> oldPermissions = getOldPermissions(app.getPackageName());
if (null == oldPermissions) {
return true;
}
Set<String> 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<String> 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;
}
}

View File

@@ -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<Review> newList;
private List<Review> oldList;
public ReviewsDiffCallback(List<Review> newList, List<Review> 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));
}
}

View File

@@ -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();
}
}

View File

@@ -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<SearchSuggestEntry> newList;
private List<SearchSuggestEntry> oldList;
public SuggestionDiffCallback(List<SearchSuggestEntry> newList, List<SearchSuggestEntry> 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));
}
}

View File

@@ -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;

View File

@@ -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<TocResponse> getTocResponse(GooglePlayAPI api) {
return Observable.create(emitter -> {
TocResponse tocResponse = api.toc();
emitter.onNext(tocResponse);
emitter.onComplete();
});
}
@Override
public void onDestroy() {
instance = null;
super.onDestroy();
}
}

View File

@@ -1,321 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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();
}
}

View File

@@ -1,189 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<Fragment> 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();
}
}

View File

@@ -1,113 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -1,128 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<BlacklistAdapter.ViewHolder> {
private List<App> appList;
private ItemClickListener itemClickListener;
public BlacklistAdapter(Context context, List<App> 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());
}
}
}
}

View File

@@ -1,157 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<CategoriesListAdapter.ViewHolder> {
private Context context;
private Fragment fragment;
private Map<String, String> 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<String, String> 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);
}
}
}

View File

@@ -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<DownloadsAdapter.View
GlideApp
.with(context)
.load(iconURL)
.transforms(new CenterCrop(), new RoundedCorners(30))
.into(viewHolder.imgDownload);
viewHolder.txtTitle.setText(displayName);
@@ -138,8 +144,8 @@ public class DownloadsAdapter extends RecyclerView.Adapter<DownloadsAdapter.View
viewHolder.itemView.setOnClickListener(v -> {
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 -> {

View File

@@ -1,61 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<String> Version, List<String> 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());
}
}

View File

@@ -41,36 +41,36 @@ import butterknife.ButterKnife;
public class ExodusAdapter extends RecyclerView.Adapter<ExodusAdapter.ViewHolder> {
private Context mContext;
private List<ExodusTracker> mExodusTrackers;
private Context context;
private List<ExodusTracker> exodusTrackers;
public ExodusAdapter(Context mContext, List<ExodusTracker> mExodusTrackers) {
this.mContext = mContext;
this.mExodusTrackers = mExodusTrackers;
public ExodusAdapter(Context context, List<ExodusTracker> 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 {

View File

@@ -1,137 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<App> appList = new ArrayList<>();
private List<App> selectedList = new ArrayList<>();
private Context context;
private FavouriteListManager manager;
private SelectableViewHolder.ItemClickListener itemClickListener;
public FavouriteAppsAdapter(Context context, SelectableViewHolder.ItemClickListener itemClickListener, List<App> 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<App> getSelectedList() {
return new ArrayList<>(selectedList);
}
}

View File

@@ -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<FeaturedAppsAdapte
if (app.getPageBackgroundImage() != null)
drawBackground(app, viewHolder);
viewHolder.itemView.setOnClickListener(v -> {
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) {

View File

@@ -1,198 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<InstalledAppsAdapter.ViewHolder> {
public List<App> 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<App> appList) {
this.appList.clear();
this.appList = appList;
final Set<App> 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<String> Version = new ArrayList<>();
List<String> 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<String> Version, List<String> 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);
}
}
}

View File

@@ -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<String, String> 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();
}

View File

@@ -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;

View File

@@ -1,144 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<ReviewsAdapter.ViewHolder> {
private Context context;
private List<Review> reviewList;
public ReviewsAdapter(Context context, List<Review> 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);
}
}
}

View File

@@ -1,135 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<SearchHistoryAdapter.ViewHolder> {
private Context context;
private ArrayList<String> queryList;
private ClickListener clickListener;
public SearchHistoryAdapter(Context context, ArrayList<String> 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);
}
}
}

View File

@@ -0,0 +1,106 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<SearchSuggestionAdapter.ViewHolder> {
public List<SearchSuggestEntry> 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<SearchSuggestEntry> 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);
}
}
}

View File

@@ -1,62 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
protected ArrayList<String> mSelections;
protected Context context;
protected BlacklistManager mBlacklistManager;
SelectableAdapter(Context context) {
this.context = context;
mBlacklistManager = new BlacklistManager(context);
ArrayList<String> 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<>();
}
}

View File

@@ -1,73 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -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;

View File

@@ -1,80 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}
}

View File

@@ -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<Fragment> fragmentList = new ArrayList<>();
private final List<String> 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();
}
}

View File

@@ -1,148 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<TopCategoriesAdapter.ViewHolder> {
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);
}
}
}

View File

@@ -1,215 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<UpdatableAppsAdapter.ViewHolder> {
private List<App> appList = new ArrayList<>();
private Context context;
private AppMenuSheet menuSheet;
public UpdatableAppsAdapter(Context context) {
this.context = context;
this.menuSheet = new AppMenuSheet();
}
public List<App> 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<App> 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<App> 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<String> Version = new ArrayList<>();
List<String> 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<String> Version, List<String> 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);
}
}
}

View File

@@ -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<Fragment> 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -18,7 +18,7 @@
*
*/
package com.aurora.store;
package com.aurora.store.enums;
public enum CardType {
LEGACY,

View File

@@ -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
}

View File

@@ -18,7 +18,7 @@
*
*/
package com.aurora.store;
package com.aurora.store.enums;
public enum NotificationProvider {
NATIVE,

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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<Object> bus = PublishRelay.create().toSerialized();
private final Relay<Event> 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<Object> toObservable() {
public Relay<Event> getBus() {
return bus;
}
public boolean hasObservers() {
return bus.hasObservers();
}
}

View File

@@ -1,84 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -1,260 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -1,161 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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())));
}
}

View File

@@ -1,121 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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");
}
}

View File

@@ -1,220 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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;
}
}

View File

@@ -1,188 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<App> 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);
};
}
}

View File

@@ -1,318 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<App> 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<List<App>>() {
}.getType();
String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_TOP_APPS);
List<App> 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<List<App>>() {
}.getType();
String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_TOP_GAMES);
List<App> 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<List<App>>() {
}.getType();
String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_TOP_FAMILY);
List<App> 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();
});
}
}

View File

@@ -1,188 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<App> 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<List<App>>() {
}.getType();
String jsonString = PrefUtil.getString(context, Constants.PREFERENCE_INSTALLED_APPS);
List<App> 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);
};
}
}

View File

@@ -1,345 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<String> 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<App> 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);
};
}
}

View File

@@ -1,259 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<String> 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<String> 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);
}
}

View File

@@ -1,236 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<App> 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);
}
}

View File

@@ -1,297 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<App> 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<App> 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();
}
}

View File

@@ -1,211 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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;
}
}
}
}

View File

@@ -1,116 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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<Report> 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");
}
}

View File

@@ -1,124 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -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;

View File

@@ -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<File> apkFiles);
protected abstract void installApkFiles(String packageName, List<File> apkFiles);
public interface InstallationStatusListener {
void onStatusChanged(int status, @Nullable String packageName);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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":

View File

@@ -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");
}

View File

@@ -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<String> 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<App> apps, App app) {

View File

@@ -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<List<Review>> {
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;
}
}

View File

@@ -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<Review> 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<Review> getReviews(String packageId, int offset, int numberOfResults) throws Exception {
private List<Review> getReviews(String packageId, int offset, GooglePlayAPI.REVIEW_SORT reviewSort) throws Exception {
List<Review> 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));
}

View File

@@ -33,28 +33,31 @@ public class ReviewStorageIterator extends ReviewIterator {
static private final int PAGE_SIZE = 15;
private List<Review> list = new ArrayList<>();
private List<Review> 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<Review> 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<Review> current() {
int from = PAGE_SIZE * page;
int to = from + PAGE_SIZE;
return (from < 0 || to > list.size()) ? new ArrayList<Review>() : list.subList(from, to);
return (from < 0 || to > reviewList.size()) ? new ArrayList<Review>() : reviewList.subList(from, to);
}
}

View File

@@ -1,91 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* Yalp Store
* Copyright (C) 2018 Sergey Yeriomin <yeriomin@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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");
}
}

View File

@@ -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<String> arrayList = new ArrayList<>();
arrayList.add(s);
boolean result = addAll(arrayList);
arrayList.add(packageName);
addAll(arrayList);
save();
return result;
}
public boolean addAll(ArrayList<String> arrayList) {
boolean result = blackList.addAll(arrayList);
public void addAll(ArrayList<String> arrayList) {
blackList.addAll(arrayList);
Set<String> mAppSet = new HashSet<>(blackList);
blackList.clear();
blackList.addAll(mAppSet);
save();
return result;
}
public ArrayList<String> 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<String> packageList) {
boolean result = blackList.removeAll(packageList);
public void removeAll(ArrayList<String> packageList) {
blackList.removeAll(packageList);
save();
}
public void removeAll() {
blackList = new ArrayList<>();
save();
return result;
}
private void save() {

View File

@@ -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<String, String> 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<String> 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<String, String> getAllCategories() {
Map<String, String> categories = new TreeMap<>();
Set<String> topSet = PrefUtil.getStringSet(context, Constants.TOP);
for (String topCategoryId : topSet) {
categories.put(topCategoryId, translator.getString(topCategoryId));
}
return categories;
public List<CategoryModel> getCategories(String categoryId) {
return getCategoryById(categoryId);
}
public Map<String, String> getAllGames() {
Map<String, String> games = new TreeMap<>();
Set<String> topSet = PrefUtil.getStringSet(context, Constants.TOP);
for (String topCategoryId : topSet) {
Set<String> 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<String, String> getAllFamily() {
Map<String, String> family = new TreeMap<>();
Set<String> topSet = PrefUtil.getStringSet(context, Constants.TOP);
for (String topCategoryId : topSet) {
Set<String> 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<String> emptySet = new TreeSet<>();
PrefUtil.putStringSet(context, Constants.TOP, emptySet);
public List<CategoryModel> getCategoryById(String categoryId) {
Type type = new TypeToken<List<CategoryModel>>() {
}.getType();
String jsonString = PrefUtil.getString(context, categoryId);
List<CategoryModel> categoryList = gson.fromJson(jsonString, type);
if (categoryList == null || categoryList.isEmpty())
return new ArrayList<>();
else
return categoryList;
}
}

View File

@@ -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<String> favouriteList;
private ArrayList<String> favouriteList = new ArrayList<>();
public FavouriteListManager(Context context) {
this.context = context;

View File

@@ -0,0 +1,52 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* Yalp Store
* Copyright (C) 2018 Sergey Yeriomin <yeriomin@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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())

View File

@@ -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)

View File

@@ -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());
}
}

View File

@@ -1,121 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
*
* Yalp Store
* Copyright (C) 2018 Sergey Yeriomin <yeriomin@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
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};
}
}

View File

@@ -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";

View File

@@ -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 {

View File

@@ -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<App> 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())

View File

@@ -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<App> appList = new ArrayList<>();
private List<String> blackList;
private ClickListener clickListener;
public BlackListedAppSection(Context context, List<String> 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<App> 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<App> getList() {
return appList;
}
public List<String> 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);
}
}
}

Some files were not shown because too many files have changed in this diff Show More