From 8c3471fcf112e14af709dcc3eefb16a4d8ea08b7 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Patel Date: Mon, 13 Apr 2020 04:27:18 +0530 Subject: [PATCH] Replace placeholder layouts with ViewFlipper --- .../aurora/store/RecyclerDataObserver.java | 55 ------------- .../fragment/SubCategoryFragment.java | 25 +++--- .../store/ui/details/DetailsActivity.java | 4 +- .../store/ui/details/views/ActionButton.java | 7 +- .../store/ui/devapps/DevAppsActivity.java | 24 ++---- .../ui/installed/InstalledAppActivity.java | 35 ++++---- .../fragment/category/CategoriesFragment.java | 61 ++++++++++---- .../fragment/category/CategoriesModel.java | 18 ++--- .../fragment/updates/UpdatableAppsModel.java | 9 +-- .../fragment/updates/UpdatesFragment.java | 80 +++++++++--------- .../store/ui/search/SearchAppsModel.java | 6 +- .../search/activity/SearchResultActivity.java | 28 +++---- .../ui/single/activity/DownloadsActivity.java | 42 +++++----- .../ui/single/fragment/BlacklistFragment.java | 41 +++++----- .../ui/single/fragment/FavouriteFragment.java | 66 +++++++++------ .../aurora/store/ui/view/ViewFlipper2.java | 47 +++++++++++ .../store/ui/view/placeholder/EmptyView.java | 77 ++++++++++++++++++ .../ui/view/placeholder/ProgressView.java | 71 ++++++++++++++++ .../aurora/store/viewmodel/BaseViewModel.java | 3 + app/src/main/res/drawable/ic_delete.xml | 28 +++++++ ..._favourite_remove.xml => ic_favourite.xml} | 0 app/src/main/res/layout/activity_all_apps.xml | 78 +++++++----------- app/src/main/res/layout/activity_dev_apps.xml | 49 +++-------- .../main/res/layout/activity_downloads.xml | 53 +++++------- app/src/main/res/layout/activity_main.xml | 46 ++++++----- .../res/layout/activity_search_result.xml | 51 +++++------- .../main/res/layout/fragment_blacklist.xml | 81 ++++++++----------- .../main/res/layout/fragment_categories.xml | 44 ++++++---- .../res/layout/fragment_category_applist.xml | 55 +++++-------- .../main/res/layout/fragment_favourites.xml | 73 +++++++---------- app/src/main/res/layout/fragment_home.xml | 1 - app/src/main/res/layout/fragment_updates.xml | 77 +++++++----------- .../layout/include_placeholder_layouts.xml | 24 ------ app/src/main/res/layout/view_empty.xml | 43 ++++++++++ app/src/main/res/layout/view_progress.xml | 40 +++++++++ app/src/main/res/values/attrs.xml | 30 +++++++ app/src/main/res/values/strings.xml | 2 + 37 files changed, 812 insertions(+), 662 deletions(-) delete mode 100644 app/src/main/java/com/aurora/store/RecyclerDataObserver.java create mode 100644 app/src/main/java/com/aurora/store/ui/view/ViewFlipper2.java create mode 100644 app/src/main/java/com/aurora/store/ui/view/placeholder/EmptyView.java create mode 100644 app/src/main/java/com/aurora/store/ui/view/placeholder/ProgressView.java create mode 100644 app/src/main/res/drawable/ic_delete.xml rename app/src/main/res/drawable/{ic_favourite_remove.xml => ic_favourite.xml} (100%) delete mode 100644 app/src/main/res/layout/include_placeholder_layouts.xml create mode 100644 app/src/main/res/layout/view_empty.xml create mode 100644 app/src/main/res/layout/view_progress.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/src/main/java/com/aurora/store/RecyclerDataObserver.java b/app/src/main/java/com/aurora/store/RecyclerDataObserver.java deleted file mode 100644 index 6c9904361..000000000 --- a/app/src/main/java/com/aurora/store/RecyclerDataObserver.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.aurora.store; - -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -public class RecyclerDataObserver extends RecyclerView.AdapterDataObserver { - - private RecyclerView recyclerView; - private ViewGroup emptyView; - private ViewGroup progressView; - - public RecyclerDataObserver(@NonNull RecyclerView recyclerView, @NonNull ViewGroup emptyView, @NonNull ViewGroup progressView) { - this.recyclerView = recyclerView; - this.emptyView = emptyView; - this.progressView = progressView; - showProgress(); - } - - - public void showProgress() { - progressView.setVisibility(View.VISIBLE); - } - - public void hideProgress() { - progressView.setVisibility(View.GONE); - } - - public void checkIfEmpty() { - if (recyclerView.getAdapter() != null) { - if (recyclerView.getAdapter().getItemCount() == 0) - emptyView.setVisibility(View.VISIBLE); - else - emptyView.setVisibility(View.GONE); - progressView.setVisibility(View.GONE); - } - } - - @Override - public void onChanged() { - checkIfEmpty(); - } - - @Override - public void onItemRangeInserted(int positionStart, int itemCount) { - checkIfEmpty(); - } - - @Override - public void onItemRangeRemoved(int positionStart, int itemCount) { - checkIfEmpty(); - } -} diff --git a/app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java b/app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java index 903c50cb7..2017ac047 100644 --- a/app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java +++ b/app/src/main/java/com/aurora/store/ui/category/fragment/SubCategoryFragment.java @@ -26,7 +26,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -38,7 +37,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.RecyclerDataObserver; import com.aurora.store.model.App; import com.aurora.store.model.items.EndlessItem; import com.aurora.store.sheet.AppMenuSheet; @@ -46,6 +44,7 @@ import com.aurora.store.ui.category.CategoryAppsActivity; import com.aurora.store.ui.category.CategoryAppsModel; import com.aurora.store.ui.details.DetailsActivity; import com.aurora.store.ui.single.fragment.BaseFragment; +import com.aurora.store.ui.view.ViewFlipper2; import com.aurora.store.util.Util; import com.aurora.store.util.ViewUtil; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; @@ -64,16 +63,13 @@ public class SubCategoryFragment extends BaseFragment implements @BindView(R.id.recycler) RecyclerView recyclerView; - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; - @BindView(R.id.progress_layout) - RelativeLayout progressLayout; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; private GooglePlayAPI.SUBCATEGORY subcategory = GooglePlayAPI.SUBCATEGORY.TOP_FREE; private SharedPreferences sharedPreferences; private CategoryAppsModel model; - private RecyclerDataObserver dataObserver; private FastAdapter fastAdapter; private ItemAdapter itemAdapter; @@ -129,9 +125,6 @@ public class SubCategoryFragment extends BaseFragment implements @Override public void onResume() { super.onResume(); - if (dataObserver != null && !itemAdapter.getAdapterItems().isEmpty()) { - dataObserver.hideProgress(); - } sharedPreferences.registerOnSharedPreferenceChangeListener(this); } @@ -146,6 +139,12 @@ public class SubCategoryFragment extends BaseFragment implements recyclerView.post(() -> { progressItemAdapter.clear(); }); + + if (itemAdapter != null && itemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } } private void purgeAdapterData() { @@ -153,9 +152,6 @@ public class SubCategoryFragment extends BaseFragment implements progressItemAdapter.clear(); itemAdapter.clear(); }); - - if (dataObserver != null) - dataObserver.checkIfEmpty(); } private void setupRecycler() { @@ -201,9 +197,6 @@ public class SubCategoryFragment extends BaseFragment implements } }; - dataObserver = new RecyclerDataObserver(recyclerView, emptyLayout, progressLayout); - fastAdapter.registerAdapterDataObserver(dataObserver); - recyclerView.addOnScrollListener(endlessScrollListener); recyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)); recyclerView.setItemAnimator(new DefaultItemAnimator()); diff --git a/app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java b/app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java index 8cb09f13b..139bde4e2 100644 --- a/app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java +++ b/app/src/main/java/com/aurora/store/ui/details/DetailsActivity.java @@ -193,7 +193,7 @@ public class DetailsActivity extends BaseActivity { getMenuInflater().inflate(R.menu.menu_app_details, menu); menu.findItem(R.id.action_favourite).setIcon(favouritesManager.isFavourite(packageName) ? R.drawable.ic_favourite_red - : R.drawable.ic_favourite_remove); + : R.drawable.ic_favourite); MenuItem blackList = menu.findItem(R.id.action_blacklist); if (!PackageUtil.isInstalled(this, packageName)) blackList.setVisible(false); @@ -209,7 +209,7 @@ public class DetailsActivity extends BaseActivity { case R.id.action_favourite: if (favouritesManager.isFavourite(packageName)) { favouritesManager.removeFromFavourites(packageName); - menuItem.setIcon(R.drawable.ic_favourite_remove); + menuItem.setIcon(R.drawable.ic_favourite); } else { favouritesManager.addToFavourites(packageName); menuItem.setIcon(R.drawable.ic_favourite_red); diff --git a/app/src/main/java/com/aurora/store/ui/details/views/ActionButton.java b/app/src/main/java/com/aurora/store/ui/details/views/ActionButton.java index 8e1895601..407b06e1f 100644 --- a/app/src/main/java/com/aurora/store/ui/details/views/ActionButton.java +++ b/app/src/main/java/com/aurora/store/ui/details/views/ActionButton.java @@ -158,10 +158,13 @@ public class ActionButton extends AbstractDetails { PackageInfo info = context.getPackageManager().getPackageInfo(app.getPackageName(), 0); String currentVersion = info.versionName; btnPositive.setText(R.string.details_update); - if (info.versionCode == app.getVersionCode() || null == currentVersion) { + + if (info.versionCode >= app.getVersionCode() || null == currentVersion) { btnPositive.setText(R.string.details_run); btnPositive.setOnClickListener(openAppListener()); - btnPositive.setVisibility(PackageUtil.isPackageLaunchable(context, app.getPackageName()) ? View.VISIBLE : View.GONE); + btnPositive.setVisibility(PackageUtil.isPackageLaunchable(context, app.getPackageName()) + ? View.VISIBLE + : View.GONE); } else if (new File(PathUtil.getLocalApkPath(context, app.getPackageName(), app.getVersionCode())).exists()) { btnPositive.setOnClickListener(installAppListener()); diff --git a/app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java b/app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java index 11996dfb3..6ba832192 100644 --- a/app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java +++ b/app/src/main/java/com/aurora/store/ui/devapps/DevAppsActivity.java @@ -3,7 +3,6 @@ package com.aurora.store.ui.devapps; import android.content.Intent; import android.os.Bundle; import android.view.MenuItem; -import android.widget.RelativeLayout; import android.widget.Toast; import androidx.annotation.Nullable; @@ -16,12 +15,12 @@ import androidx.recyclerview.widget.RecyclerView; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.RecyclerDataObserver; import com.aurora.store.model.App; import com.aurora.store.model.items.EndlessItem; import com.aurora.store.sheet.AppMenuSheet; import com.aurora.store.ui.details.DetailsActivity; import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.ui.view.ViewFlipper2; import com.aurora.store.util.ViewUtil; import com.mikepenz.fastadapter.FastAdapter; import com.mikepenz.fastadapter.adapters.ItemAdapter; @@ -37,16 +36,12 @@ public class DevAppsActivity extends BaseActivity { @BindView(R.id.toolbar) Toolbar toolbar; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; @BindView(R.id.recycler) RecyclerView recyclerView; - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; - @BindView(R.id.progress_layout) - RelativeLayout progressLayout; - private DevAppsModel model; - private RecyclerDataObserver dataObserver; private FastAdapter fastAdapter; private ItemAdapter itemAdapter; private ItemAdapter progressItemAdapter; @@ -81,9 +76,6 @@ public class DevAppsActivity extends BaseActivity { @Override public void onResume() { super.onResume(); - if (dataObserver != null && !itemAdapter.getAdapterItems().isEmpty()) { - dataObserver.hideProgress(); - } } @Override @@ -101,8 +93,11 @@ public class DevAppsActivity extends BaseActivity { progressItemAdapter.clear(); }); - if (dataObserver != null) - dataObserver.checkIfEmpty(); + if (itemAdapter != null && itemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } } private void setupActionBar() { @@ -158,9 +153,6 @@ public class DevAppsActivity extends BaseActivity { } }; - dataObserver = new RecyclerDataObserver(recyclerView, emptyLayout, progressLayout); - fastAdapter.registerAdapterDataObserver(dataObserver); - recyclerView.addOnScrollListener(endlessScrollListener); recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false)); recyclerView.setItemAnimator(new DefaultItemAnimator()); diff --git a/app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java b/app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java index c9d1628c1..9cb99c905 100644 --- a/app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java +++ b/app/src/main/java/com/aurora/store/ui/installed/InstalledAppActivity.java @@ -3,7 +3,6 @@ package com.aurora.store.ui.installed; import android.content.Intent; import android.os.Bundle; import android.view.MenuItem; -import android.widget.RelativeLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.lifecycle.ViewModelProvider; @@ -11,17 +10,17 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.aurora.store.AuroraApplication; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.RecyclerDataObserver; import com.aurora.store.model.App; import com.aurora.store.model.items.InstalledItem; import com.aurora.store.sheet.AppMenuSheet; import com.aurora.store.ui.details.DetailsActivity; import com.aurora.store.ui.single.activity.BaseActivity; -import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.ui.view.ViewFlipper2; import com.aurora.store.util.PrefUtil; import com.aurora.store.util.Util; import com.aurora.store.util.ViewUtil; @@ -43,18 +42,13 @@ public class InstalledAppActivity extends BaseActivity { CoordinatorLayout coordinator; @BindView(R.id.switch_system) SwitchMaterial switchSystem; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; @BindView(R.id.swipe_layout) - CustomSwipeToRefresh swipeToRefresh; + SwipeRefreshLayout swipeToRefresh; @BindView(R.id.recycler) RecyclerView recyclerView; - - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; - @BindView(R.id.progress_layout) - RelativeLayout progressLayout; - private InstalledAppsModel model; - private RecyclerDataObserver dataObserver; private FastAdapter fastAdapter; private ItemAdapter itemAdapter; @@ -114,9 +108,12 @@ public class InstalledAppActivity extends BaseActivity { @Override public void onResume() { super.onResume(); - if (dataObserver != null && !itemAdapter.getAdapterItems().isEmpty()) { - dataObserver.hideProgress(); - } + } + + @Override + protected void onPause() { + swipeToRefresh.setRefreshing(false); + super.onPause(); } @Override @@ -138,8 +135,11 @@ public class InstalledAppActivity extends BaseActivity { final DiffUtil.DiffResult diffResult = fastAdapterDiffUtil.calculateDiff(itemAdapter, installedItemList, diffCallback); fastAdapterDiffUtil.set(itemAdapter, diffResult); - if (dataObserver != null) - dataObserver.checkIfEmpty(); + if (itemAdapter != null && itemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } } private void removeItemByPackageName(String packageName) { @@ -180,9 +180,6 @@ public class InstalledAppActivity extends BaseActivity { return true; }); - dataObserver = new RecyclerDataObserver(recyclerView, emptyLayout, progressLayout); - fastAdapter.registerAdapterDataObserver(dataObserver); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(fastAdapter); diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java index 83a1591c5..47a3e796d 100644 --- a/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesFragment.java @@ -25,7 +25,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -33,6 +32,7 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.aurora.store.Constants; import com.aurora.store.R; @@ -40,6 +40,8 @@ import com.aurora.store.manager.CategoryManager; import com.aurora.store.model.items.CategoryItem; import com.aurora.store.ui.category.CategoryAppsActivity; import com.aurora.store.ui.main.AuroraActivity; +import com.aurora.store.ui.view.ViewFlipper2; +import com.aurora.store.util.Log; import com.aurora.store.util.ViewUtil; import com.mikepenz.fastadapter.FastAdapter; import com.mikepenz.fastadapter.adapters.ItemAdapter; @@ -47,18 +49,22 @@ import com.mikepenz.fastadapter.adapters.ItemAdapter; import butterknife.BindView; import butterknife.ButterKnife; import io.reactivex.Observable; +import io.reactivex.disposables.CompositeDisposable; public class CategoriesFragment extends Fragment { - @BindView(R.id.category_recycler) + @BindView(R.id.swipe_layout) + SwipeRefreshLayout swipeLayout; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; + @BindView(R.id.recycler) RecyclerView recyclerView; - @BindView(R.id.progress_bar) - ProgressBar progressBar; private CategoryManager categoryManager; private FastAdapter fastAdapter; - private ItemAdapter categoryItemAdapter; + private ItemAdapter itemAdapter; + private CompositeDisposable disposable = new CompositeDisposable(); public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -71,32 +77,53 @@ public class CategoriesFragment extends Fragment { public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); categoryManager = new CategoryManager(requireContext()); + setupRecycler(); + CategoriesModel categoriesModel = new ViewModelProvider(this).get(CategoriesModel.class); - categoriesModel.getFetchCompleted().observe(getViewLifecycleOwner(), success -> { + categoriesModel.getData().observe(getViewLifecycleOwner(), success -> { if (success) { - setupRecycler(); - progressBar.setVisibility(View.GONE); + dispatchDataToAdapter(); } + swipeLayout.setRefreshing(false); }); categoriesModel.fetchCategories(); + + swipeLayout.setOnRefreshListener(categoriesModel::fetchCategories); } - private void setupRecycler() { - fastAdapter = new FastAdapter<>(); - categoryItemAdapter = new ItemAdapter<>(); + @Override + public void onPause() { + swipeLayout.setRefreshing(false); + super.onPause(); + } - Observable.fromIterable(categoryManager.getCategories(Constants.CATEGORY_APPS)) + private void dispatchDataToAdapter() { + disposable.add(Observable.fromIterable(categoryManager.getCategories(Constants.CATEGORY_APPS)) .mergeWith(Observable.fromIterable(categoryManager.getCategories(Constants.CATEGORY_GAME))) .mergeWith(Observable.fromIterable(categoryManager.getCategories(Constants.CATEGORY_FAMILY))) .map(CategoryItem::new) .toList() - .doOnSuccess(categoryItems -> { - categoryItemAdapter.add(categoryItems); - }) - .subscribe(); + .subscribe(categoryItems -> { + itemAdapter.add(categoryItems); + updatePageData(); + }, + throwable -> Log.e(throwable.getMessage()))); + } + + private void updatePageData() { + if (itemAdapter != null && itemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } + } + + private void setupRecycler() { + fastAdapter = new FastAdapter<>(); + itemAdapter = new ItemAdapter<>(); //TODO:Add section headers - fastAdapter.addAdapter(0, categoryItemAdapter); + fastAdapter.addAdapter(0, itemAdapter); fastAdapter.setOnClickListener((view, categoryItemIAdapter, categoryItem, integer) -> { Intent intent = new Intent(requireContext(), CategoryAppsActivity.class); intent.putExtra("CategoryId", categoryItem.getCategoryModel().getCategoryId()); diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java index c636cdd90..0c13c515d 100644 --- a/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/category/CategoriesModel.java @@ -3,12 +3,12 @@ package com.aurora.store.ui.main.fragment.category; import android.app.Application; import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.MutableLiveData; import com.aurora.store.AuroraApplication; import com.aurora.store.manager.CategoryManager; import com.aurora.store.task.CategoryListTask; +import com.aurora.store.viewmodel.BaseViewModel; import com.dragons.aurora.playstoreapiv2.GooglePlayAPI; import io.reactivex.Observable; @@ -16,14 +16,14 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -public class CategoriesModel extends AndroidViewModel { +public class CategoriesModel extends BaseViewModel { private Application application; private CompositeDisposable disposable = new CompositeDisposable(); private GooglePlayAPI api; private CategoryManager categoryManager; - private MutableLiveData fetchCompleted = new MutableLiveData<>(); + private MutableLiveData data = new MutableLiveData<>(); public CategoriesModel(@NonNull Application application) { super(application); @@ -32,15 +32,15 @@ public class CategoriesModel extends AndroidViewModel { this.categoryManager = new CategoryManager(application); } - public MutableLiveData getFetchCompleted() { - return fetchCompleted; + public MutableLiveData getData() { + return data; } public void fetchCategories() { if (categoryManager.categoryListEmpty()) getCategoriesFromAPI(); else - fetchCompleted.setValue(true); + data.setValue(true); } private void getCategoriesFromAPI() { @@ -48,11 +48,7 @@ public class CategoriesModel extends AndroidViewModel { .getResult()) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(status -> { - fetchCompleted.setValue(status); - }, err -> { - - })); + .subscribe(status -> data.setValue(status), this::handleError)); } @Override diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java index 2b8837081..aded70f26 100644 --- a/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatableAppsModel.java @@ -32,22 +32,21 @@ public class UpdatableAppsModel extends BaseViewModel { } public void fetchUpdatableApps() { - Observable.fromCallable(() -> new UpdatableAppsTask(api, getApplication()) + disposable.add(Observable.fromCallable(() -> new UpdatableAppsTask(api, getApplication()) .getUpdatableApps()) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) - .map(apps -> sortList(apps)) + .map(this::sortList) .flatMap(apps -> Observable .fromIterable(apps) .map(UpdatesItem::new)) .toList() - .doOnSuccess(updatesItems -> data.setValue(updatesItems)) - .doOnError(this::handleError) - .subscribe(); + .subscribe(updatesItems -> data.setValue(updatesItems), this::handleError)); } @Override protected void onCleared() { + disposable.dispose(); super.onCleared(); } } diff --git a/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java index acef71592..2169087f8 100644 --- a/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java +++ b/app/src/main/java/com/aurora/store/ui/main/fragment/updates/UpdatesFragment.java @@ -25,7 +25,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -37,11 +36,11 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.aurora.store.AuroraApplication; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.RecyclerDataObserver; import com.aurora.store.download.DownloadManager; import com.aurora.store.manager.IgnoreListManager; import com.aurora.store.model.App; @@ -49,7 +48,7 @@ import com.aurora.store.model.items.UpdatesItem; import com.aurora.store.sheet.AppMenuSheet; import com.aurora.store.ui.details.DetailsActivity; import com.aurora.store.ui.single.fragment.BaseFragment; -import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.ui.view.ViewFlipper2; import com.aurora.store.util.Util; import com.aurora.store.util.ViewUtil; import com.aurora.store.util.diff.UpdatesDiffCallback; @@ -58,9 +57,10 @@ import com.mikepenz.fastadapter.FastAdapter; import com.mikepenz.fastadapter.adapters.ItemAdapter; import com.mikepenz.fastadapter.diff.FastAdapterDiffUtil; import com.mikepenz.fastadapter.select.SelectExtension; -import com.tonyodev.fetch2.AbstractFetchListener; +import com.tonyodev.fetch2.AbstractFetchGroupListener; import com.tonyodev.fetch2.Download; import com.tonyodev.fetch2.Fetch; +import com.tonyodev.fetch2.FetchGroup; import com.tonyodev.fetch2.FetchListener; import org.apache.commons.lang3.StringUtils; @@ -80,7 +80,9 @@ public class UpdatesFragment extends BaseFragment { @BindView(R.id.coordinator) CoordinatorLayout coordinator; @BindView(R.id.swipe_layout) - CustomSwipeToRefresh swipeToRefresh; + SwipeRefreshLayout swipeLayout; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; @BindView(R.id.recycler) RecyclerView recyclerView; @BindView(R.id.txt_update_all) @@ -88,17 +90,10 @@ public class UpdatesFragment extends BaseFragment { @BindView(R.id.btn_action) MaterialButton btnAction; - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; - @BindView(R.id.progress_layout) - RelativeLayout progressLayout; - private Fetch fetch; private Set selectedItems = new HashSet<>(); private UpdatableAppsModel model; - private RecyclerDataObserver dataObserver; - private FastAdapter fastAdapter; private ItemAdapter itemAdapter; private SelectExtension selectExtension; @@ -118,10 +113,12 @@ public class UpdatesFragment extends BaseFragment { setupRecycler(); model = new ViewModelProvider(this).get(UpdatableAppsModel.class); + model.getData().observe(getViewLifecycleOwner(), updatesItems -> { dispatchAppsToAdapter(updatesItems); - swipeToRefresh.setRefreshing(false); + swipeLayout.setRefreshing(false); }); + model.getError().observe(getViewLifecycleOwner(), errorType -> { switch (errorType) { case NO_API: @@ -135,8 +132,8 @@ public class UpdatesFragment extends BaseFragment { } }); - swipeToRefresh.setRefreshing(true); - swipeToRefresh.setOnRefreshListener(() -> model.fetchUpdatableApps()); + swipeLayout.setRefreshing(true); + swipeLayout.setOnRefreshListener(() -> model.fetchUpdatableApps()); AuroraApplication .getRelayBus() @@ -180,14 +177,11 @@ public class UpdatesFragment extends BaseFragment { @Override public void onResume() { super.onResume(); - if (dataObserver != null && !itemAdapter.getAdapterItems().isEmpty()) { - dataObserver.hideProgress(); - } } @Override public void onPause() { - swipeToRefresh.setRefreshing(false); + swipeLayout.setRefreshing(false); super.onPause(); } @@ -228,8 +222,12 @@ public class UpdatesFragment extends BaseFragment { updateText(); updateButtons(); updateButtonActions(); - if (dataObserver != null) - dataObserver.checkIfEmpty(); + + if (itemAdapter != null && itemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } } private void dispatchAppsToAdapter(List updatesItems) { @@ -269,9 +267,6 @@ public class UpdatesFragment extends BaseFragment { fastAdapter.addExtension(selectExtension); fastAdapter.addEventHook(new UpdatesItem.CheckBoxClickEvent()); - dataObserver = new RecyclerDataObserver(recyclerView, emptyLayout, progressLayout); - fastAdapter.registerAdapterDataObserver(dataObserver); - selectExtension.setMultiSelect(true); selectExtension.setSelectionListener((item, selected) -> { if (selected) { @@ -315,30 +310,39 @@ public class UpdatesFragment extends BaseFragment { Observable.fromIterable(selectiveUpdate ? selectedItems : itemAdapter.getAdapterItems()) - .map(UpdatesItem::getPackageName) - .toList() - .doOnSuccess(packages -> { - final List packageList = new ArrayList<>(packages); - final FetchListener fetchListener = new AbstractFetchListener() { + .map(updatesItem -> updatesItem.getPackageName().hashCode()) + .doOnNext(hashcode -> { + final FetchListener fetchListener = new AbstractFetchGroupListener() { @Override - public void onAdded(@NotNull Download download) { - DownloadManager.updateOngoingDownloads(fetch, packageList, download, this); + public void onAdded(int groupId, @NotNull Download download, @NotNull FetchGroup fetchGroup) { + super.onAdded(groupId, download, fetchGroup); + if (hashcode == groupId) { + fetch.cancelGroup(groupId); + fetch.removeListener(this); + } } @Override - public void onQueued(@NotNull Download download, boolean b) { - DownloadManager.updateOngoingDownloads(fetch, packageList, download, this); + public void onProgress(int groupId, @NotNull Download download, long etaInMilliSeconds, long downloadedBytesPerSecond, @NotNull FetchGroup fetchGroup) { + super.onProgress(groupId, download, etaInMilliSeconds, downloadedBytesPerSecond, fetchGroup); + if (hashcode == groupId) { + fetch.cancelGroup(groupId); + fetch.removeListener(this); + } } @Override - public void onProgress(@NotNull Download download, long etaInMilliSeconds, long downloadedBytesPerSecond) { - super.onProgress(download, etaInMilliSeconds, downloadedBytesPerSecond); - DownloadManager.updateOngoingDownloads(fetch, packageList, download, this); + public void onQueued(int groupId, @NotNull Download download, boolean waitingNetwork, @NotNull FetchGroup fetchGroup) { + super.onQueued(groupId, download, waitingNetwork, fetchGroup); + if (hashcode == groupId) { + fetch.cancelGroup(groupId); + fetch.removeListener(this); + } } }; - fetch.addListener(fetchListener); - + }) + .doOnComplete(() -> { //Clear ongoing update list AuroraApplication.setOngoingUpdateList(new ArrayList<>()); //Start BulkUpdate cancellation request diff --git a/app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java b/app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java index cf095b6b4..134235003 100644 --- a/app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java +++ b/app/src/main/java/com/aurora/store/ui/search/SearchAppsModel.java @@ -53,7 +53,7 @@ public class SearchAppsModel extends BaseViewModel { if (!shouldIterate) getIterator(query); - Observable.fromCallable(() -> new SearchTask(getApplication()) + disposable.add(Observable.fromCallable(() -> new SearchTask(getApplication()) .getSearchResults(iterator)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -62,9 +62,7 @@ public class SearchAppsModel extends BaseViewModel { .toList() .toObservable() ) - .doOnNext(searchItems -> listMutableLiveData.setValue(searchItems)) - .doOnError(this::handleError) - .subscribe(); + .subscribe(searchItems -> listMutableLiveData.setValue(searchItems), this::handleError)); } public void getIterator(String query) { diff --git a/app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java b/app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java index 719115a41..b397ea97f 100644 --- a/app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java +++ b/app/src/main/java/com/aurora/store/ui/search/activity/SearchResultActivity.java @@ -3,7 +3,6 @@ package com.aurora.store.ui.search.activity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.widget.RelativeLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.lifecycle.ViewModelProvider; @@ -14,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.aurora.store.AuroraApplication; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.RecyclerDataObserver; import com.aurora.store.manager.FilterManager; import com.aurora.store.model.App; import com.aurora.store.model.FilterModel; @@ -24,6 +22,7 @@ import com.aurora.store.sheet.FilterBottomSheet; import com.aurora.store.ui.details.DetailsActivity; import com.aurora.store.ui.search.SearchAppsModel; import com.aurora.store.ui.single.activity.BaseActivity; +import com.aurora.store.ui.view.ViewFlipper2; import com.aurora.store.util.Util; import com.aurora.store.util.ViewUtil; import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; @@ -42,24 +41,21 @@ import butterknife.OnClick; public class SearchResultActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener { + @BindView(R.id.coordinator) + CoordinatorLayout coordinator; @BindView(R.id.search_view) TextInputEditText searchView; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; @BindView(R.id.recycler) RecyclerView recyclerView; @BindView(R.id.filter_fab) ExtendedFloatingActionButton filterFab; - @BindView(R.id.coordinator) - CoordinatorLayout coordinator; - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; - @BindView(R.id.progress_layout) - RelativeLayout progressLayout; private String query; private SharedPreferences sharedPreferences; private SearchAppsModel model; - private RecyclerDataObserver dataObserver; private FastAdapter fastAdapter; private ItemAdapter itemAdapter; @@ -80,6 +76,7 @@ public class SearchResultActivity extends BaseActivity implements model.getQueriedApps().observe(this, this::dispatchAppsToAdapter); model.getRelatedTags().observe(this, strings -> { }); + model.getError().observe(this, errorType -> { switch (errorType) { case NO_API: @@ -131,9 +128,6 @@ public class SearchResultActivity extends BaseActivity implements @Override public void onResume() { super.onResume(); - if (dataObserver != null && !itemAdapter.getAdapterItems().isEmpty()) { - dataObserver.hideProgress(); - } } @Override @@ -173,8 +167,11 @@ public class SearchResultActivity extends BaseActivity implements progressItemAdapter.clear(); }); - if (dataObserver != null) - dataObserver.checkIfEmpty(); + if (itemAdapter != null && itemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } } private void setupResultRecycler() { @@ -220,9 +217,6 @@ public class SearchResultActivity extends BaseActivity implements } }; - dataObserver = new RecyclerDataObserver(recyclerView, emptyLayout, progressLayout); - fastAdapter.registerAdapterDataObserver(dataObserver); - recyclerView.addOnScrollListener(endlessScrollListener); recyclerView.setOnFlingListener(new RecyclerView.OnFlingListener() { @Override diff --git a/app/src/main/java/com/aurora/store/ui/single/activity/DownloadsActivity.java b/app/src/main/java/com/aurora/store/ui/single/activity/DownloadsActivity.java index 18833c4f9..b54975f55 100644 --- a/app/src/main/java/com/aurora/store/ui/single/activity/DownloadsActivity.java +++ b/app/src/main/java/com/aurora/store/ui/single/activity/DownloadsActivity.java @@ -24,9 +24,6 @@ import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; import androidx.appcompat.app.ActionBar; import androidx.appcompat.widget.Toolbar; @@ -34,6 +31,7 @@ import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.aurora.store.Constants; import com.aurora.store.R; @@ -41,6 +39,8 @@ import com.aurora.store.download.DownloadManager; import com.aurora.store.model.items.DownloadItem; import com.aurora.store.sheet.DownloadMenuSheet; import com.aurora.store.ui.details.DetailsActivity; +import com.aurora.store.ui.view.ViewFlipper2; +import com.aurora.store.util.Log; import com.aurora.store.util.Util; import com.aurora.store.util.ViewUtil; import com.aurora.store.util.diff.DownloadDiffCallback; @@ -65,24 +65,25 @@ 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 DownloadsActivity extends BaseActivity { @BindView(R.id.toolbar) Toolbar toolbar; - @BindView(R.id.recyclerDownloads) + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; + @BindView(R.id.swipe_layout) + SwipeRefreshLayout swipeLayout; + @BindView(R.id.recycler) RecyclerView recyclerView; - @BindView(R.id.content_view) - ViewGroup layoutContent; - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; private FastAdapter fastAdapter; private ItemAdapter itemAdapter; private Fetch fetch; - + private CompositeDisposable disposable = new CompositeDisposable(); private final FetchListener fetchListener = new AbstractFetchListener() { @Override public void onAdded(@NotNull Download download) { @@ -147,6 +148,8 @@ public class DownloadsActivity extends BaseActivity { fetch = DownloadManager.getFetchInstance(this); updateDownloadsList(); + + swipeLayout.setOnRefreshListener(this::updateDownloadsList); } @Override @@ -191,6 +194,7 @@ public class DownloadsActivity extends BaseActivity { @Override protected void onPause() { + swipeLayout.setRefreshing(false); fetch.removeListener(fetchListener); super.onPause(); } @@ -217,20 +221,13 @@ public class DownloadsActivity extends BaseActivity { final List downloadList = new ArrayList<>(downloads); Collections.sort(downloadList, (first, second) -> Long.compare(first.getCreated(), second.getCreated())); - Observable.fromIterable(downloadList) + disposable.add(Observable.fromIterable(downloadList) .subscribeOn(Schedulers.io()) .map(DownloadItem::new) .toList() .observeOn(AndroidSchedulers.mainThread()) - .doOnSuccess(this::dispatchAppsToAdapter) - .doFinally(() -> { - if (itemAdapter != null) { - emptyLayout.setVisibility(itemAdapter.getAdapterItems().isEmpty() - ? View.VISIBLE - : View.GONE); - } - }) - .subscribe(); + .subscribe(this::dispatchAppsToAdapter, + throwable -> Log.e(throwable.getMessage()))); }); } @@ -239,6 +236,13 @@ public class DownloadsActivity extends BaseActivity { final DownloadDiffCallback diffCallback = new DownloadDiffCallback(); final DiffUtil.DiffResult diffResult = fastAdapterDiffUtil.calculateDiff(itemAdapter, installedItemList, diffCallback); fastAdapterDiffUtil.set(itemAdapter, diffResult); + + if (itemAdapter != null && itemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } + swipeLayout.setRefreshing(false); } private void setupRecycler() { diff --git a/app/src/main/java/com/aurora/store/ui/single/fragment/BlacklistFragment.java b/app/src/main/java/com/aurora/store/ui/single/fragment/BlacklistFragment.java index db3cdbf5b..0d1b50e73 100644 --- a/app/src/main/java/com/aurora/store/ui/single/fragment/BlacklistFragment.java +++ b/app/src/main/java/com/aurora/store/ui/single/fragment/BlacklistFragment.java @@ -25,7 +25,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; -import android.widget.RelativeLayout; import android.widget.TextView; import androidx.annotation.NonNull; @@ -34,12 +33,12 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.aurora.store.R; -import com.aurora.store.RecyclerDataObserver; import com.aurora.store.manager.BlacklistManager; import com.aurora.store.model.items.BlacklistItem; -import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.ui.view.ViewFlipper2; import com.aurora.store.util.Log; import com.aurora.store.util.ViewUtil; import com.aurora.store.viewmodel.BlackListedAppsModel; @@ -56,8 +55,11 @@ import butterknife.OnClick; public class BlacklistFragment extends Fragment { + @BindView(R.id.swipe_layout) - CustomSwipeToRefresh swipeToRefresh; + SwipeRefreshLayout refreshLayout; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; @BindView(R.id.recycler) RecyclerView recyclerView; @BindView(R.id.btn_clear_all) @@ -65,14 +67,8 @@ public class BlacklistFragment extends Fragment { @BindView(R.id.txt_blacklist) TextView txtBlacklist; - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; - @BindView(R.id.progress_layout) - RelativeLayout progressLayout; - private BlacklistManager blacklistManager; private BlackListedAppsModel model; - private RecyclerDataObserver dataObserver; private FastItemAdapter fastItemAdapter; private SelectExtension selectExtension; @@ -95,24 +91,18 @@ public class BlacklistFragment extends Fragment { model.getBlacklistedItems().observe(getViewLifecycleOwner(), blacklistItems -> { final List sortedList = sortBlackListedApps(blacklistItems); fastItemAdapter.add(sortedList); - swipeToRefresh.setRefreshing(false); - - if (dataObserver != null) - dataObserver.checkIfEmpty(); - + refreshLayout.setRefreshing(false); + updatePageData(); updateCount(); }); - swipeToRefresh.setRefreshing(true); - swipeToRefresh.setOnRefreshListener(() -> model.fetchBlackListedApps()); + refreshLayout.setRefreshing(true); + refreshLayout.setOnRefreshListener(() -> model.fetchBlackListedApps()); } @Override public void onResume() { super.onResume(); - if (dataObserver != null && !fastItemAdapter.getAdapterItems().isEmpty()) { - dataObserver.hideProgress(); - } } @OnClick(R.id.btn_clear_all) @@ -148,6 +138,14 @@ public class BlacklistFragment extends Fragment { return sortedList; } + private void updatePageData() { + if (fastItemAdapter != null && fastItemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } + } + private void setupRecycler() { blacklistManager = new BlacklistManager(requireContext()); fastItemAdapter = new FastItemAdapter<>(); @@ -159,9 +157,6 @@ public class BlacklistFragment extends Fragment { fastItemAdapter.addExtension(selectExtension); fastItemAdapter.addEventHook(new BlacklistItem.CheckBoxClickEvent()); - dataObserver = new RecyclerDataObserver(recyclerView, emptyLayout, progressLayout); - fastItemAdapter.registerAdapterDataObserver(dataObserver); - selectExtension.setMultiSelect(true); selectExtension.setSelectionListener((item, selected) -> { if (blacklistManager.isBlacklisted(item.getApp().getPackageName())) { diff --git a/app/src/main/java/com/aurora/store/ui/single/fragment/FavouriteFragment.java b/app/src/main/java/com/aurora/store/ui/single/fragment/FavouriteFragment.java index e8b3e131d..3c9eec7e9 100644 --- a/app/src/main/java/com/aurora/store/ui/single/fragment/FavouriteFragment.java +++ b/app/src/main/java/com/aurora/store/ui/single/fragment/FavouriteFragment.java @@ -25,20 +25,21 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.ColorUtils; import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.aurora.store.Constants; import com.aurora.store.R; -import com.aurora.store.RecyclerDataObserver; import com.aurora.store.exception.MalformedRequestException; import com.aurora.store.manager.FavouritesManager; import com.aurora.store.model.App; @@ -46,7 +47,8 @@ import com.aurora.store.model.items.FavouriteItem; import com.aurora.store.task.LiveUpdate; import com.aurora.store.task.ObservableDeliveryData; import com.aurora.store.ui.details.DetailsActivity; -import com.aurora.store.ui.view.CustomSwipeToRefresh; +import com.aurora.store.ui.view.ViewFlipper2; +import com.aurora.store.util.ImageUtil; import com.aurora.store.util.Log; import com.aurora.store.util.PackageUtil; import com.aurora.store.util.PathUtil; @@ -55,6 +57,7 @@ import com.aurora.store.viewmodel.FavouriteAppsModel; import com.google.android.material.button.MaterialButton; import com.mikepenz.fastadapter.adapters.FastItemAdapter; import com.mikepenz.fastadapter.select.SelectExtension; +import com.mikepenz.fastadapter.swipe.SimpleSwipeCallback; import org.apache.commons.lang3.StringUtils; @@ -75,10 +78,12 @@ import butterknife.ButterKnife; import io.reactivex.Observable; import io.reactivex.schedulers.Schedulers; -public class FavouriteFragment extends BaseFragment { +public class FavouriteFragment extends BaseFragment implements SimpleSwipeCallback.ItemSwipeCallback { - @BindView(R.id.swipe_refresh_layout) - CustomSwipeToRefresh swipeToRefresh; + @BindView(R.id.viewFlipper) + ViewFlipper2 viewFlipper; + @BindView(R.id.swipe_layout) + SwipeRefreshLayout swipeLayout; @BindView(R.id.recycler) RecyclerView recyclerView; @BindView(R.id.export_list) @@ -88,14 +93,8 @@ public class FavouriteFragment extends BaseFragment { @BindView(R.id.count_selection) TextView txtCount; - @BindView(R.id.empty_layout) - RelativeLayout emptyLayout; - @BindView(R.id.progress_layout) - RelativeLayout progressLayout; - private Set selectedAppSet = new HashSet<>(); private FavouriteAppsModel model; - private RecyclerDataObserver dataObserver; private FavouritesManager favouritesManager; private FastItemAdapter fastItemAdapter; @@ -124,12 +123,12 @@ public class FavouriteFragment extends BaseFragment { model = new ViewModelProvider(this).get(FavouriteAppsModel.class); model.getFavouriteApps().observe(getViewLifecycleOwner(), favouriteItems -> { fastItemAdapter.add(favouriteItems); - swipeToRefresh.setRefreshing(false); + swipeLayout.setRefreshing(false); updatePageData(); }); - swipeToRefresh.setRefreshing(true); - swipeToRefresh.setOnRefreshListener(() -> { + swipeLayout.setRefreshing(true); + swipeLayout.setOnRefreshListener(() -> { model.fetchFavouriteApps(); }); } @@ -137,14 +136,11 @@ public class FavouriteFragment extends BaseFragment { @Override public void onResume() { super.onResume(); - if (dataObserver != null && !fastItemAdapter.getAdapterItems().isEmpty()) { - dataObserver.hideProgress(); - } } @Override public void onPause() { - swipeToRefresh.setRefreshing(false); + swipeLayout.setRefreshing(false); super.onPause(); } @@ -208,8 +204,11 @@ public class FavouriteFragment extends BaseFragment { updateButtons(); updateActions(); - if (dataObserver != null) - dataObserver.checkIfEmpty(); + if (fastItemAdapter != null && fastItemAdapter.getAdapterItems().size() > 0) { + viewFlipper.switchState(ViewFlipper2.DATA); + } else { + viewFlipper.switchState(ViewFlipper2.EMPTY); + } } private void updateText() { @@ -228,6 +227,10 @@ public class FavouriteFragment extends BaseFragment { private void updateActions() { btnInstall.setOnClickListener(bulkInstallListener()); + btnAction.setText(fastItemAdapter.getAdapterItems().size() == 0 + ? getString(R.string.action_import) + : getString(R.string.action_export)); + btnAction.setOnClickListener(v -> { if (fastItemAdapter.getAdapterItems().size() == 0) { importList(); @@ -254,9 +257,6 @@ public class FavouriteFragment extends BaseFragment { fastItemAdapter.addExtension(selectExtension); fastItemAdapter.addEventHook(new FavouriteItem.CheckBoxClickEvent()); - dataObserver = new RecyclerDataObserver(recyclerView, emptyLayout, progressLayout); - fastItemAdapter.registerAdapterDataObserver(dataObserver); - selectExtension.setMultiSelect(true); selectExtension.setSelectionListener((item, selected) -> { if (selected) { @@ -267,7 +267,25 @@ public class FavouriteFragment extends BaseFragment { updatePageData(); }); + final SimpleSwipeCallback callback = new SimpleSwipeCallback( + this, + getResources().getDrawable(R.drawable.ic_delete), + ItemTouchHelper.LEFT, + ColorUtils.setAlphaComponent(ImageUtil.getSolidColor(0), 120)); + + final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback); + itemTouchHelper.attachToRecyclerView(recyclerView); + recyclerView.setAdapter(fastItemAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); } + + @Override + public void itemSwiped(int position, int direction) { + final FavouriteItem item = fastItemAdapter.getAdapterItem(position); + new FavouritesManager(requireContext()).removeFromFavourites(item.getPackageName()); + fastItemAdapter.remove(position); + fastItemAdapter.notifyAdapterItemChanged(position); + updatePageData(); + } } diff --git a/app/src/main/java/com/aurora/store/ui/view/ViewFlipper2.java b/app/src/main/java/com/aurora/store/ui/view/ViewFlipper2.java new file mode 100644 index 000000000..b3506fffa --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/view/ViewFlipper2.java @@ -0,0 +1,47 @@ +/* + * Aurora Droid + * Copyright (C) 2019-20, Rahul Kumar Patel + * + * Aurora Droid 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 3 of the License, or + * (at your option) any later version. + * + * Aurora Droid 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 Droid. If not, see . + * + */ + +package com.aurora.store.ui.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ViewFlipper; + +public class ViewFlipper2 extends ViewFlipper { + + public static final int PROGRESS = 0; + public static final int DATA = 1; + public static final int EMPTY = 2; + public static final int ERROR = 3; + public static final int NO_NETWORK = 4; + + public ViewFlipper2(Context context) { + super(context); + setDisplayedChild(PROGRESS); + } + + public ViewFlipper2(Context context, AttributeSet attrs) { + super(context, attrs); + setDisplayedChild(PROGRESS); + } + + public void switchState(int state) { + setDisplayedChild(state); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/view/placeholder/EmptyView.java b/app/src/main/java/com/aurora/store/ui/view/placeholder/EmptyView.java new file mode 100644 index 000000000..2d3d1512c --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/view/placeholder/EmptyView.java @@ -0,0 +1,77 @@ +/* + * Aurora Droid + * Copyright (C) 2019-20, Rahul Kumar Patel + * + * Aurora Droid 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 3 of the License, or + * (at your option) any later version. + * + * Aurora Droid 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 Droid. If not, see . + * + */ + +package com.aurora.store.ui.view.placeholder; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RelativeLayout; + +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; + +import com.aurora.store.R; + +import org.apache.commons.lang3.StringUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class EmptyView extends RelativeLayout { + + @BindView(R.id.img_empty) + AppCompatImageView imgEmpty; + @BindView(R.id.txt_empty) + AppCompatTextView txtEmpty; + + public EmptyView(Context context) { + super(context); + } + + public EmptyView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public EmptyView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + public EmptyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + View view = inflate(context, R.layout.view_empty, this); + ButterKnife.bind(this, view); + + final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.EmptyView); + final String txt = typedArray.getString(R.styleable.EmptyView_emptyText); + final Drawable drawable = typedArray.getDrawable(R.styleable.EmptyView_emptyImage); + + txtEmpty.setText(StringUtils.isEmpty(txt) ? getResources().getString(R.string.action_loading) : txt); + imgEmpty.setImageDrawable(drawable); + typedArray.recycle(); + } +} diff --git a/app/src/main/java/com/aurora/store/ui/view/placeholder/ProgressView.java b/app/src/main/java/com/aurora/store/ui/view/placeholder/ProgressView.java new file mode 100644 index 000000000..6f96c7b76 --- /dev/null +++ b/app/src/main/java/com/aurora/store/ui/view/placeholder/ProgressView.java @@ -0,0 +1,71 @@ +/* + * Aurora Droid + * Copyright (C) 2019-20, Rahul Kumar Patel + * + * Aurora Droid 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 3 of the License, or + * (at your option) any later version. + * + * Aurora Droid 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 Droid. If not, see . + * + */ + +package com.aurora.store.ui.view.placeholder; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RelativeLayout; + +import androidx.appcompat.widget.AppCompatTextView; + +import com.aurora.store.R; + +import org.apache.commons.lang3.StringUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class ProgressView extends RelativeLayout { + + @BindView(R.id.txt_progress) + AppCompatTextView txtProgress; + + public ProgressView(Context context) { + super(context); + } + + public ProgressView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + public ProgressView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + View view = inflate(context, R.layout.view_progress, this); + ButterKnife.bind(this, view); + + final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressView); + final String txt = typedArray.getString(R.styleable.ProgressView_progressText); + + txtProgress.setText(StringUtils.isEmpty(txt) ? getResources().getString(R.string.action_loading) : txt); + typedArray.recycle(); + } +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java b/app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java index ae1e0821a..f08f9c903 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java +++ b/app/src/main/java/com/aurora/store/viewmodel/BaseViewModel.java @@ -21,10 +21,13 @@ import java.net.UnknownHostException; import java.util.Collections; import java.util.List; +import io.reactivex.disposables.CompositeDisposable; + public class BaseViewModel extends AndroidViewModel { protected GooglePlayAPI api; protected MutableLiveData errorData = new MutableLiveData<>(); + protected CompositeDisposable disposable = new CompositeDisposable(); public BaseViewModel(@NonNull Application application) { super(application); diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 000000000..8cff04d08 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_favourite_remove.xml b/app/src/main/res/drawable/ic_favourite.xml similarity index 100% rename from app/src/main/res/drawable/ic_favourite_remove.xml rename to app/src/main/res/drawable/ic_favourite.xml diff --git a/app/src/main/res/layout/activity_all_apps.xml b/app/src/main/res/layout/activity_all_apps.xml index 724b550a5..fc6903eda 100644 --- a/app/src/main/res/layout/activity_all_apps.xml +++ b/app/src/main/res/layout/activity_all_apps.xml @@ -25,14 +25,14 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - - - - - - - + android:layout_below="@id/layout_top" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> - + - - + - + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_dev_apps.xml b/app/src/main/res/layout/activity_dev_apps.xml index d6f9a25e8..8bd30c917 100644 --- a/app/src/main/res/layout/activity_dev_apps.xml +++ b/app/src/main/res/layout/activity_dev_apps.xml @@ -26,54 +26,29 @@ - + + - - - - - - - - - - - - - + app:emptyImage="@drawable/ic_round_search" + app:emptyText="@string/error_search_not_found" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_downloads.xml b/app/src/main/res/layout/activity_downloads.xml index d090154fa..26f8714af 100644 --- a/app/src/main/res/layout/activity_downloads.xml +++ b/app/src/main/res/layout/activity_downloads.xml @@ -27,44 +27,35 @@ - - - + app:progressText="@string/action_loading" /> - + - + + - - + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ed56b5cd1..3d781de22 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -21,36 +21,40 @@ + android:layout_height="match_parent"> - - - + android:layout_height="match_parent"> - + + + + + + - + android:layout_below="@id/layout_top" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> - - - + app:progressText="@string/action_loading" /> - + - - - - - + + - + android:layout_height="match_parent"> @@ -41,14 +41,14 @@ android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_centerVertical="true" - android:layout_marginStart="@dimen/margin_large" + android:layout_marginStart="@dimen/margin_normal" android:layout_marginEnd="@dimen/margin_small" android:layout_toStartOf="@id/btn_clear_all" android:textAppearance="@style/TextAppearance.Aurora.SubTitle" /> + android:visibility="gone" + tools:visibility="visible" /> + - - - - - - - - - + android:layout_below="@id/layout_top"> - + - - + - + + + + diff --git a/app/src/main/res/layout/fragment_categories.xml b/app/src/main/res/layout/fragment_categories.xml index 7b2569110..aab4faad5 100644 --- a/app/src/main/res/layout/fragment_categories.xml +++ b/app/src/main/res/layout/fragment_categories.xml @@ -20,29 +20,39 @@ - + android:layout_height="match_parent" + android:layout_below="@id/layout_top"> - - - - + app:progressText="@string/action_loading" /> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_category_applist.xml b/app/src/main/res/layout/fragment_category_applist.xml index bcc3aa701..0a193fe5a 100644 --- a/app/src/main/res/layout/fragment_category_applist.xml +++ b/app/src/main/res/layout/fragment_category_applist.xml @@ -23,48 +23,29 @@ android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> - + android:layout_below="@id/layout_top" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> - - - + app:progressText="@string/action_loading" /> - + - - - - - - + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_favourites.xml b/app/src/main/res/layout/fragment_favourites.xml index 12a9e540a..5f9b00ed0 100755 --- a/app/src/main/res/layout/fragment_favourites.xml +++ b/app/src/main/res/layout/fragment_favourites.xml @@ -19,19 +19,19 @@ --> - + android:layout_height="match_parent"> @@ -72,52 +72,35 @@ - - - - - - - - - + android:layout_below="@id/layout_top"> - + - - + - + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index e457ee035..d346c219d 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -30,7 +30,6 @@ android:layout_height="match_parent" android:clipToPadding="false" android:overScrollMode="never" - android:paddingTop="@dimen/margin_bottom" android:paddingBottom="@dimen/margin_bottom" android:scrollbars="none"> diff --git a/app/src/main/res/layout/fragment_updates.xml b/app/src/main/res/layout/fragment_updates.xml index 22a57fc23..cd551f3a7 100644 --- a/app/src/main/res/layout/fragment_updates.xml +++ b/app/src/main/res/layout/fragment_updates.xml @@ -23,16 +23,14 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/coordinator" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingTop="@dimen/margin_bottom"> + android:layout_height="match_parent"> - + android:layout_height="match_parent"> - - - - - - - - - + android:layout_below="@id/layout_top"> - + - - + - + + + + - \ No newline at end of file diff --git a/app/src/main/res/layout/include_placeholder_layouts.xml b/app/src/main/res/layout/include_placeholder_layouts.xml deleted file mode 100644 index 6c2f6c682..000000000 --- a/app/src/main/res/layout/include_placeholder_layouts.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_empty.xml b/app/src/main/res/layout/view_empty.xml new file mode 100644 index 000000000..351af53e7 --- /dev/null +++ b/app/src/main/res/layout/view_empty.xml @@ -0,0 +1,43 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_progress.xml b/app/src/main/res/layout/view_progress.xml new file mode 100644 index 000000000..b09fdf808 --- /dev/null +++ b/app/src/main/res/layout/view_progress.xml @@ -0,0 +1,40 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 000000000..b3612b92c --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f136ccd89..c156b66d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -16,6 +16,7 @@ "Done" "Enable" "Export" + "Import" "Favourite apps" "Filters" "All" @@ -106,6 +107,7 @@ "User app" "Blacklisted apps" "No apps blacklisted" + "No categories available" "No favourites" "No updates available" "Installed"