Skip to content

Commit

Permalink
add feature badges to apps in backup fragments
Browse files Browse the repository at this point in the history
  • Loading branch information
Aefyr committed Feb 1, 2020
1 parent 00cdc12 commit 1ac126c
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 66 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ dependencies {
//Google services
normalImplementation 'com.google.firebase:firebase-core:17.2.2'
normalImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.1'
}

//Cancel google services/fabric plugins for fdroid flavor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.aefyr.sai.adapters;

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.aefyr.sai.R;
import com.aefyr.sai.model.common.AppFeature;
import com.google.android.material.chip.Chip;

import java.util.List;

public class BackupAppFeatureAdapter extends RecyclerView.Adapter<BackupAppFeatureAdapter.ViewHolder> {

private List<AppFeature> mFeatures;

private LayoutInflater mInflater;

public BackupAppFeatureAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}


public void setFeatures(List<AppFeature> features) {
mFeatures = features;
notifyDataSetChanged();
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(mInflater.inflate(R.layout.item_backup_app_feature, parent, false));
}

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.bind(mFeatures.get(position));
}

@Override
public int getItemCount() {
return mFeatures == null ? 0 : mFeatures.size();
}

class ViewHolder extends RecyclerView.ViewHolder {

private Chip mChip;

ViewHolder(@NonNull View itemView) {
super(itemView);

mChip = (Chip) itemView;
}

void bind(AppFeature feature) {
mChip.setText(feature.toText());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -12,10 +13,21 @@
import androidx.recyclerview.widget.RecyclerView;

import com.aefyr.sai.R;
import com.aefyr.sai.model.backup.BackupPackagesFilterConfig;
import com.aefyr.sai.model.backup.SimpleAppFeature;
import com.aefyr.sai.model.common.AppFeature;
import com.aefyr.sai.model.common.PackageMeta;
import com.bumptech.glide.Glide;

import com.google.android.flexbox.FlexDirection;
import com.google.android.flexbox.FlexWrap;
import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.flexbox.JustifyContent;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

public class BackupPackagesAdapter extends RecyclerView.Adapter<BackupPackagesAdapter.ViewHolder> {

Expand All @@ -24,17 +36,33 @@ public class BackupPackagesAdapter extends RecyclerView.Adapter<BackupPackagesAd

private OnItemInteractionListener mListener;

private BackupPackagesFilterConfig mFilterConfig;

private RecyclerView.RecycledViewPool mFeatureViewPool;

private SimpleDateFormat mInstallOrUpdateDateSdf = new SimpleDateFormat("d MMM yyyy, HH:mm", Locale.getDefault());


public BackupPackagesAdapter(Context c) {
mInflater = LayoutInflater.from(c);
setHasStableIds(true);

mFeatureViewPool = new RecyclerView.RecycledViewPool();
mFeatureViewPool.setMaxRecycledViews(0, 16);
}

public void setData(List<PackageMeta> packages) {
mPackages = packages;
notifyDataSetChanged();
}

public void setFilterConfig(BackupPackagesFilterConfig config, boolean applyNow) {
mFilterConfig = config;

if (applyNow)
notifyDataSetChanged();
}

public void setInteractionListener(OnItemInteractionListener listener) {
mListener = listener;
}
Expand Down Expand Up @@ -73,6 +101,8 @@ class ViewHolder extends RecyclerView.ViewHolder {
private TextView mAppPackage;
private AppCompatImageView mAppIcon;

private BackupAppFeatureAdapter mFeatureAdapter;

private ViewHolder(@NonNull View itemView) {
super(itemView);

Expand All @@ -89,6 +119,16 @@ private ViewHolder(@NonNull View itemView) {
if (mListener != null)
mListener.onBackupButtonClicked(mPackages.get(adapterPosition));
});

RecyclerView featureRecycler = itemView.findViewById(R.id.rv_backup_app_features);
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(itemView.getContext(), FlexDirection.ROW, FlexWrap.WRAP);
layoutManager.setJustifyContent(JustifyContent.FLEX_START);
featureRecycler.setLayoutManager(layoutManager);

featureRecycler.setRecycledViewPool(mFeatureViewPool);

mFeatureAdapter = new BackupAppFeatureAdapter(itemView.getContext());
featureRecycler.setAdapter(mFeatureAdapter);
}

@SuppressLint("DefaultLocale")
Expand All @@ -101,11 +141,43 @@ void bindTo(PackageMeta packageMeta) {
.load(packageMeta.iconUri != null ? packageMeta.iconUri : R.drawable.placeholder_app_icon)
.placeholder(R.drawable.placeholder_app_icon)
.into(mAppIcon);

mFeatureAdapter.setFeatures(createContextualFeatures(packageMeta));
}

private List<AppFeature> createContextualFeatures(PackageMeta packageMeta) {
if (mFilterConfig == null)
return Collections.emptyList();

ArrayList<AppFeature> features = new ArrayList<>();

Resources res = itemView.getResources();

if (mFilterConfig.getSplitApkFilter() == BackupPackagesFilterConfig.SimpleFilterMode.WHATEVER && packageMeta.hasSplits)
features.add(new SimpleAppFeature(res.getString(R.string.backup_app_feature_split)));

if (mFilterConfig.getSystemAppFilter() == BackupPackagesFilterConfig.SimpleFilterMode.WHATEVER && packageMeta.isSystemApp)
features.add(new SimpleAppFeature(res.getString(R.string.backup_app_feature_system_app)));

switch (mFilterConfig.getSort()) {
case NAME:
break;
case INSTALL_TIME:
features.add(new SimpleAppFeature(res.getString(R.string.backup_app_feature_install_date, mInstallOrUpdateDateSdf.format(packageMeta.installTime))));
break;
case UPDATE_TIME:
features.add(new SimpleAppFeature(res.getString(R.string.backup_app_feature_update_date, mInstallOrUpdateDateSdf.format(packageMeta.installTime))));
break;
}

return features;
}

void recycle() {
Glide.with(mAppIcon)
.clear(mAppIcon);

mFeatureAdapter.setFeatures(null);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.aefyr.sai.model.backup;

import com.aefyr.flexfilter.builtin.filter.singlechoice.SingleChoiceFilterConfig;
import com.aefyr.flexfilter.builtin.filter.singlechoice.SingleChoiceFilterConfigOption;
import com.aefyr.flexfilter.builtin.filter.sort.SortFilterConfig;
import com.aefyr.flexfilter.config.core.ComplexFilterConfig;
import com.aefyr.flexfilter.config.core.FilterConfig;

public class BackupPackagesFilterConfig {

public static final String SORT_NAME = "name";
public static final String SORT_INSTALL = "install";
public static final String SORT_UPDATE = "update";

public static final String FILTER_SPLIT = "split";
public static final String FILTER_SYSTEM_APP = "system_app";

public static final String FILTER_MODE_YES = "yes";
public static final String FILTER_MODE_NO = "no";
public static final String FILTER_MODE_WHATEVER = "whatever";

public enum SimpleFilterMode {
YES, NO, WHATEVER;

public static SimpleFilterMode from(SingleChoiceFilterConfigOption option) {
switch (option.id()) {
case FILTER_MODE_YES:
return SimpleFilterMode.YES;
case FILTER_MODE_NO:
return SimpleFilterMode.NO;
}

return SimpleFilterMode.WHATEVER;
}
}

public enum SortMode {
NAME, INSTALL_TIME, UPDATE_TIME
}

private SimpleFilterMode mSplitApkFilter;
private SimpleFilterMode mSystemAppFilter;

private SortMode mSortMode;

public BackupPackagesFilterConfig(ComplexFilterConfig config) {
for (FilterConfig filterConfig : config.filters()) {
if (filterConfig instanceof SingleChoiceFilterConfig) {
switch (((SingleChoiceFilterConfig) filterConfig).id()) {
case FILTER_SPLIT:
mSplitApkFilter = SimpleFilterMode.from(((SingleChoiceFilterConfig) filterConfig).getSelectedOption());
break;
case FILTER_SYSTEM_APP:
mSystemAppFilter = SimpleFilterMode.from(((SingleChoiceFilterConfig) filterConfig).getSelectedOption());
break;
}
continue;
}

if (filterConfig instanceof SortFilterConfig) {
switch (((SortFilterConfig) filterConfig).getSelectedOption().id()) {
case SORT_NAME:
mSortMode = SortMode.NAME;
break;
case SORT_INSTALL:
mSortMode = SortMode.INSTALL_TIME;
break;
case SORT_UPDATE:
mSortMode = SortMode.UPDATE_TIME;
break;
}
}

}
}

public SimpleFilterMode getSplitApkFilter() {
return mSplitApkFilter;
}

public SimpleFilterMode getSystemAppFilter() {
return mSystemAppFilter;
}

public SortMode getSort() {
return mSortMode;
}


}
17 changes: 17 additions & 0 deletions app/src/main/java/com/aefyr/sai/model/backup/SimpleAppFeature.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.aefyr.sai.model.backup;

import com.aefyr.sai.model.common.AppFeature;

public class SimpleAppFeature implements AppFeature {

private String mText;

public SimpleAppFeature(String text) {
mText = text;
}

@Override
public CharSequence toText() {
return mText;
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/com/aefyr/sai/model/common/AppFeature.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.aefyr.sai.model.common;

public interface AppFeature {

CharSequence toText();

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import androidx.annotation.Nullable;
import androidx.appcompat.widget.PopupMenu;
import androidx.cardview.widget.CardView;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

Expand Down Expand Up @@ -41,7 +41,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat

OneTimeWarningDialogFragment.showIfNeeded(requireContext(), getChildFragmentManager(), R.string.help, R.string.backup_warning, "backup_faq");

mViewModel = ViewModelProviders.of(this).get(BackupViewModel.class);
mViewModel = new ViewModelProvider(this).get(BackupViewModel.class);


RecyclerView recyclerView = findViewById(R.id.rv_packages);
Expand All @@ -58,10 +58,11 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
setupToolbar();

findViewById(R.id.button_backup_filter).setOnClickListener(v -> {
FilterDialog.newInstance(getString(R.string.backup_filter), mViewModel.getFilterConfig(), DefaultFilterConfigViewHolderFactory.class).show(getChildFragmentManager(), null);
FilterDialog.newInstance(getString(R.string.backup_filter), mViewModel.getRawFilterConfig(), DefaultFilterConfigViewHolderFactory.class).show(getChildFragmentManager(), null);
});

mViewModel.getPackages().observe(this, adapter::setData);
mViewModel.getBackupFilterConfig().observe(getViewLifecycleOwner(), config -> adapter.setFilterConfig(config, false));
mViewModel.getPackages().observe(getViewLifecycleOwner(), adapter::setData);
}

private void setupToolbar() {
Expand Down
Loading

0 comments on commit 1ac126c

Please sign in to comment.