1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-09-01 03:55:47 +02:00

Data Management: Add basic search to file manager

This commit is contained in:
José Rebelo 2024-08-29 22:00:18 +01:00
parent c9e4379346
commit d033c5e33e
6 changed files with 132 additions and 2 deletions

View File

@ -17,10 +17,16 @@
package nodomain.freeyourgadget.gadgetbridge.activities.files; package nodomain.freeyourgadget.gadgetbridge.activities.files;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.core.view.MenuProvider;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -35,15 +41,18 @@ import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class FileManagerActivity extends AbstractGBActivity { public class FileManagerActivity extends AbstractGBActivity implements MenuProvider {
private static final Logger LOG = LoggerFactory.getLogger(FileManagerActivity.class); private static final Logger LOG = LoggerFactory.getLogger(FileManagerActivity.class);
public static final String EXTRA_PATH = "path"; public static final String EXTRA_PATH = "path";
private SearchView searchView;
@Override @Override
protected void onCreate(final Bundle savedInstanceState) { protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_manager); setContentView(R.layout.activity_file_manager);
addMenuProvider(this);
final RecyclerView fileListView = findViewById(R.id.fileListView); final RecyclerView fileListView = findViewById(R.id.fileListView);
fileListView.setLayoutManager(new LinearLayoutManager(this)); fileListView.setLayoutManager(new LinearLayoutManager(this));
@ -76,6 +85,40 @@ public class FileManagerActivity extends AbstractGBActivity {
final FileManagerAdapter appListAdapter = new FileManagerAdapter(this, directory); final FileManagerAdapter appListAdapter = new FileManagerAdapter(this, directory);
fileListView.setAdapter(appListAdapter); fileListView.setAdapter(appListAdapter);
searchView = findViewById(R.id.fileListSearchView);
searchView.setIconifiedByDefault(false);
searchView.setVisibility(View.GONE);
searchView.setIconified(false);
searchView.setQuery("", false);
searchView.clearFocus();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(final String query) {
return false;
}
@Override
public boolean onQueryTextChange(final String newText) {
appListAdapter.getFilter().filter(newText);
return true;
}
});
}
@Override
public void onCreateMenu(@NonNull final Menu menu, @NonNull final MenuInflater menuInflater) {
menuInflater.inflate(R.menu.menu_file_manager, menu);
}
@Override
public boolean onMenuItemSelected(@NonNull final MenuItem menuItem) {
final int itemId = menuItem.getItemId();
if (itemId == R.id.file_manager_search) {
searchView.setVisibility(View.VISIBLE);
searchView.requestFocus();
}
return false;
} }
@Override @Override

View File

@ -21,6 +21,7 @@ import android.content.Intent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -36,6 +37,7 @@ import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -49,11 +51,13 @@ public class FileManagerAdapter extends RecyclerView.Adapter<FileManagerAdapter.
private final List<File> fileList; private final List<File> fileList;
private final Context mContext; private final Context mContext;
private final FileFilter fileFilter;
public FileManagerAdapter(final Context context, final File directory) { public FileManagerAdapter(final Context context, final File directory) {
mContext = context; mContext = context;
// FIXME: This can be slow, make it async // FIXME: This can be slow, make it async
fileList = Arrays.asList(directory.listFiles()); fileList = new ArrayList<>(Arrays.asList(directory.listFiles()));
fileList.sort((f1, f2) -> { fileList.sort((f1, f2) -> {
if (f1.isDirectory() && f2.isFile()) if (f1.isDirectory() && f2.isFile())
return -1; return -1;
@ -62,6 +66,8 @@ public class FileManagerAdapter extends RecyclerView.Adapter<FileManagerAdapter.
return String.CASE_INSENSITIVE_ORDER.compare(f1.getName(), f2.getName()); return String.CASE_INSENSITIVE_ORDER.compare(f1.getName(), f2.getName());
}); });
fileFilter = new FileFilter(this, fileList);
} }
@NonNull @NonNull
@ -125,6 +131,10 @@ public class FileManagerAdapter extends RecyclerView.Adapter<FileManagerAdapter.
return fileList.size(); return fileList.size();
} }
public Filter getFilter() {
return fileFilter;
}
public static class FileManagerViewHolder extends RecyclerView.ViewHolder { public static class FileManagerViewHolder extends RecyclerView.ViewHolder {
final ImageView icon; final ImageView icon;
final TextView name; final TextView name;
@ -149,4 +159,48 @@ public class FileManagerAdapter extends RecyclerView.Adapter<FileManagerAdapter.
int digitGroups = (int) (Math.log10(size) / Math.log10(1024)); int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return SIZE_FORMAT.format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups]; return SIZE_FORMAT.format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
} }
private class FileFilter extends Filter {
private final FileManagerAdapter adapter;
private final List<File> originalList;
private final List<File> filteredList;
private FileFilter(final FileManagerAdapter adapter, final List<File> originalList) {
super();
this.originalList = new ArrayList<>(originalList);
this.filteredList = new ArrayList<>();
this.adapter = adapter;
}
@Override
protected FilterResults performFiltering(final CharSequence filter) {
filteredList.clear();
final Filter.FilterResults results = new Filter.FilterResults();
if (filter == null || filter.length() == 0)
filteredList.addAll(originalList);
else {
final String filterPattern = filter.toString().toLowerCase().trim();
for (File f : originalList) {
final CharSequence name = f.getName();
if (name.toString().toLowerCase().contains(filterPattern)) {
filteredList.add(f);
}
}
}
results.values = filteredList;
results.count = filteredList.size();
return results;
}
@Override
protected void publishResults(final CharSequence constraint, final FilterResults filterResults) {
adapter.fileList.clear();
adapter.fileList.addAll((List<File>) filterResults.values);
adapter.notifyDataSetChanged();
}
}
} }

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#7E7E7E"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
</vector>

View File

@ -4,10 +4,19 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".activities.files.FileManagerActivity"> tools:context=".activities.files.FileManagerActivity">
<androidx.appcompat.widget.SearchView
android:id="@+id/fileListSearchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:paddingStart="8dp"
android:paddingEnd="8dp" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/fileListView" android:id="@+id/fileListView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@id/fileListSearchView"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:divider="@null" android:divider="@null"
android:scrollbarSize="5dp" android:scrollbarSize="5dp"

View File

@ -0,0 +1,11 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.files.FileManagerActivity">
<item
android:id="@+id/file_manager_search"
android:icon="@drawable/ic_search"
android:title="@string/search"
app:iconTint="?attr/actionmenu_icon_color"
app:showAsAction="always" />
</menu>

View File

@ -37,6 +37,7 @@
<string name="action_changelog">Changelog</string> <string name="action_changelog">Changelog</string>
<string name="controlcenter_fetch_activity_data">Synchronize</string> <string name="controlcenter_fetch_activity_data">Synchronize</string>
<string name="controlcenter_find_device">Find lost device</string> <string name="controlcenter_find_device">Find lost device</string>
<string name="search">Search</string>
<string name="find_lost_device_message">Search for %1$s?</string> <string name="find_lost_device_message">Search for %1$s?</string>
<string name="controlcenter_take_screenshot">Take Screenshot</string> <string name="controlcenter_take_screenshot">Take Screenshot</string>
<string name="controlcenter_power_off">Power Off</string> <string name="controlcenter_power_off">Power Off</string>