Skip to content

Commit

Permalink
[app] sort smart freeze apps
Browse files Browse the repository at this point in the history
  • Loading branch information
Tornaco committed Aug 26, 2022
1 parent f661ca1 commit f9ffab6
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import static com.nononsenseapps.filepicker.FilePickerActivityUtils.pickSingleDirIntent;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -20,13 +22,16 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.menu.MenuBuilder;
import androidx.appcompat.view.menu.MenuPopupHelper;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.GridLayoutManager;

import com.elvishew.xlog.XLog;
import com.google.android.material.chip.Chip;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
Expand All @@ -47,6 +52,7 @@
import github.tornaco.android.thanos.apps.PackageSetChooserDialog;
import github.tornaco.android.thanos.common.AppItemActionListener;
import github.tornaco.android.thanos.common.AppListModel;
import github.tornaco.android.thanos.common.sort.AppSort;
import github.tornaco.android.thanos.core.app.ThanosManager;
import github.tornaco.android.thanos.core.pm.AppInfo;
import github.tornaco.android.thanos.core.pm.PackageManager;
Expand Down Expand Up @@ -91,6 +97,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
Bundle data = getArguments();
String pkgSetId = Objects.requireNonNull(data, "Missing arg: " + ARG_PKG_SET).getString(ARG_PKG_SET, null);
setupViewModel(pkgSetId);
onSetupSorter(binding.sortChipContainer.sortChip);
return binding.getRoot();
}

Expand Down Expand Up @@ -147,7 +154,60 @@ public void onAppItemSwitchStateChange(AppInfo appInfo, boolean checked) {

binding.swipe.setOnRefreshListener(() -> viewModel.start());
binding.swipe.setColorSchemeColors(getResources().getIntArray(github.tornaco.android.thanos.module.common.R.array.common_swipe_refresh_colors));
}

@SuppressLint("RestrictedApi")
protected void onSetupSorter(Chip sorterAnchor) {
AppSort[] appSortArray = AppSort.values();
AppSort currentSort = viewModel.getCurrentAppSort();
sorterAnchor.setText(currentSort.labelRes);

sorterAnchor.setOnClickListener(view -> {
MenuBuilder menuBuilder = new MenuBuilder(requireActivity());
MenuPopupHelper menuPopupHelper = new MenuPopupHelper(requireActivity(), menuBuilder, view);
menuPopupHelper.setForceShowIcon(true);

int reverseItemId = 10086;
MenuItem reverseItem = menuBuilder.add(1000,
reverseItemId,
Menu.NONE,
github.tornaco.android.thanos.module.common.R.string.common_sort_reverse);
reverseItem.setCheckable(true);
reverseItem.setChecked(viewModel.isSortReverse());
reverseItem.setIcon(github.tornaco.android.thanos.module.common.R.drawable.module_common_ic_arrow_up_down_line);

for (int i = 0; i < appSortArray.length; i++) {
AppSort sort = appSortArray[i];
MenuItem sortItem = menuBuilder.add(1000,
i,
Menu.NONE,
sort.labelRes);
boolean isSelected = viewModel.getCurrentAppSort() == sort;
if (isSelected) {
sortItem.setTitle(getString(sort.labelRes) + " \uD83C\uDFAF");
}
}
menuBuilder.setCallback(new MenuBuilder.Callback() {
@Override
public boolean onMenuItemSelected(@NonNull MenuBuilder menu, @NonNull MenuItem item) {
int index = item.getItemId();
if (index == reverseItemId) {
viewModel.setSortReverse(!viewModel.isSortReverse());
item.setChecked(viewModel.isSortReverse());
} else {
viewModel.setAppSort(appSortArray[index]);
sorterAnchor.setText(appSortArray[index].labelRes);
}
return true;
}

@Override
public void onMenuModeChange(@NonNull MenuBuilder menu) {
// Noop
}
});
menuPopupHelper.show();
});
}

@Verify
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package github.tornaco.android.thanos.power;

import android.app.Application;
import android.app.usage.UsageStats;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
Expand Down Expand Up @@ -30,14 +31,17 @@
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import github.tornaco.android.rhino.plugin.Verify;
import github.tornaco.android.thanos.common.AppLabelSearchFilter;
import github.tornaco.android.thanos.common.AppListModel;
import github.tornaco.android.thanos.common.sort.AppSort;
import github.tornaco.android.thanos.core.app.ThanosManager;
import github.tornaco.android.thanos.core.pm.AppInfo;
import github.tornaco.android.thanos.core.pm.PackageSet;
Expand All @@ -58,7 +62,6 @@
import util.Consumer;
import util.IoUtils;
import util.JsonFormatter;
import util.PinyinComparatorUtils;

@SuppressWarnings("UnstableApiUsage")
public class SmartFreezeAppsViewModel extends AndroidViewModel {
Expand All @@ -72,6 +75,9 @@ public class SmartFreezeAppsViewModel extends AndroidViewModel {
private final ObservableField<String> queryText = new ObservableField<>("");
private final AppLabelSearchFilter appLabelSearchFilter = new AppLabelSearchFilter();

private final ObservableBoolean sortReverse = new ObservableBoolean(false);
private final ObservableField<AppSort> currentSort = new ObservableField<>(AppSort.Default);

public SmartFreezeAppsViewModel(@NonNull Application application) {
super(application);
}
Expand Down Expand Up @@ -99,10 +105,6 @@ private void loadModels() {
disposables.add(Single
.create((SingleOnSubscribe<List<AppListModel>>) emitter ->
emitter.onSuccess(getSmartFreezeApps()))
.map(listModels -> {
listModels.sort((o1, o2) -> PinyinComparatorUtils.compare(o1.appInfo.getAppLabel(), o2.appInfo.getAppLabel()));
return listModels;
})
.flatMapObservable((Function<List<AppListModel>, ObservableSource<AppListModel>>) Observable::fromIterable)
.filter(listModel -> {
String query = queryText.get();
Expand Down Expand Up @@ -130,9 +132,43 @@ private List<AppListModel> getSmartFreezeApps() {
res.add(model);
}
}

AppSort sort = currentSort.get();
if (sort != null) {
// inflate usage stats if necessary.
if (sort.relyOnUsageStats()) {
inflateAppUsageStats(res);
}

AppSort.AppSorterProvider appSorterProvider = sort.provider;
if (appSorterProvider != null) {
res.sort(appSorterProvider.comparator(getApplication()));
if (sortReverse.get()) {
Collections.reverse(res);
}
}
}

return res;
}

private void inflateAppUsageStats(List<AppListModel> res) {
XLog.d("inflateAppUsageStats");
ThanosManager thanox = ThanosManager.from(getApplication());
if (thanox.isServiceInstalled()) {
Map<String, UsageStats> statsMap = thanox.getUsageStatsManager().queryAndAggregateUsageStats(0, System.currentTimeMillis());
for (AppListModel app : res) {
if (statsMap.containsKey(app.appInfo.getPkgName())) {
UsageStats stats = statsMap.get(app.appInfo.getPkgName());
if (stats != null) {
app.lastUsedTimeMills = stats.getLastTimeUsed();
app.totalUsedTimeMills = stats.getTotalTimeInForeground();
}
}
}
}
}

void createShortcutStubApkForAsync(AppInfo appInfo,
String appLabel,
String versionName,
Expand Down Expand Up @@ -366,4 +402,22 @@ public void importPackageListFromFile(Uri uri, Consumer<Boolean> onRes) {
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(onRes::accept));
}

public boolean isSortReverse() {
return sortReverse.get();
}

public void setSortReverse(boolean reverse) {
sortReverse.set(reverse);
start();
}

public AppSort getCurrentAppSort() {
return currentSort.get();
}

public void setAppSort(AppSort sort) {
currentSort.set(sort);
start();
}
}
14 changes: 14 additions & 0 deletions android/app/src/main/res/layout/activity_smart_freeze_apps.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/common_view_margin_default"
android:paddingEnd="@dimen/common_view_margin_default">
<include
android:id="@+id/sort_chip_container"
layout="@layout/module_common_sort_chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe"
android:layout_width="wrap_content"
Expand Down

0 comments on commit f9ffab6

Please sign in to comment.