feat(list): sort tracked items by last seen with reverse toggle
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package com.wytehat.btlogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Ordering for the tracked item list.
|
||||
*
|
||||
* Default order is newest sighting first. Items that have not been seen for
|
||||
* a long time - or that carry no sighting timestamp at all - are pushed to
|
||||
* the bottom and stay there in both sort directions, so the reverse toggle
|
||||
* never buries a live item under a pile of stale ones.
|
||||
*/
|
||||
final class DeviceSort {
|
||||
|
||||
/** A device unseen for longer than this sinks to the bottom. */
|
||||
static final long STALE_AFTER_MS = 24L * 60L * 60L * 1000L;
|
||||
|
||||
private DeviceSort() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Last moment the device was actually observed. Deliberately ignores
|
||||
* updatedAt, which also moves when the user edits a name or colour.
|
||||
*/
|
||||
static long lastSeen(DeviceRecord record) {
|
||||
|
||||
if (record == null) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
long seen = record.lastRssiAt;
|
||||
|
||||
if (record.connectedAt > seen) {
|
||||
seen = record.connectedAt;
|
||||
}
|
||||
|
||||
if (record.disconnectedAt > seen) {
|
||||
seen = record.disconnectedAt;
|
||||
}
|
||||
|
||||
return seen;
|
||||
}
|
||||
|
||||
static boolean isStale(DeviceRecord record, long now) {
|
||||
|
||||
long seen = lastSeen(record);
|
||||
|
||||
return seen <= 0L ||
|
||||
now - seen > STALE_AFTER_MS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reverse false = newest first (default), true = oldest first.
|
||||
*/
|
||||
static List<DeviceRecord> sorted(List<DeviceRecord> rows, boolean reverse) {
|
||||
|
||||
ArrayList<DeviceRecord> fresh = new ArrayList<DeviceRecord>();
|
||||
ArrayList<DeviceRecord> stale = new ArrayList<DeviceRecord>();
|
||||
|
||||
if (rows == null) {
|
||||
return fresh;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
|
||||
DeviceRecord record = rows.get(i);
|
||||
|
||||
if (record == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isStale(record, now)) {
|
||||
stale.add(record);
|
||||
} else {
|
||||
fresh.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
Comparator<DeviceRecord> newestFirst =
|
||||
new Comparator<DeviceRecord>() {
|
||||
|
||||
public int compare(DeviceRecord left, DeviceRecord right) {
|
||||
|
||||
long a = lastSeen(left);
|
||||
long b = lastSeen(right);
|
||||
|
||||
if (a == b) {
|
||||
return left.displayName()
|
||||
.compareToIgnoreCase(right.displayName());
|
||||
}
|
||||
|
||||
return a > b ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
Collections.sort(fresh, newestFirst);
|
||||
Collections.sort(stale, newestFirst);
|
||||
|
||||
if (reverse) {
|
||||
Collections.reverse(fresh);
|
||||
Collections.reverse(stale);
|
||||
}
|
||||
|
||||
ArrayList<DeviceRecord> result =
|
||||
new ArrayList<DeviceRecord>(fresh.size() + stale.size());
|
||||
|
||||
result.addAll(fresh);
|
||||
|
||||
/*
|
||||
* Stale entries are appended last in both directions.
|
||||
*/
|
||||
result.addAll(stale);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ public class MainActivity extends Activity implements ItemActionListener {
|
||||
private static final int CAMERA = 200;
|
||||
private TrackerDatabase db;
|
||||
private DeviceListAdapter adapter;
|
||||
private boolean reverseSort;
|
||||
private boolean registered;
|
||||
private DeviceRecord editing;
|
||||
private final Handler refreshHandler = new Handler();
|
||||
@@ -46,6 +47,18 @@ public class MainActivity extends Activity implements ItemActionListener {
|
||||
public void onClick(View v) { startActivity(new Intent(MainActivity.this,
|
||||
MapActivity.class)); }
|
||||
});
|
||||
reverseSort = getSharedPreferences("list_settings", 0)
|
||||
.getBoolean("reverse_sort", false);
|
||||
updateSortButton();
|
||||
findViewById(R.id.sort_button).setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
reverseSort = !reverseSort;
|
||||
getSharedPreferences("list_settings", 0).edit()
|
||||
.putBoolean("reverse_sort", reverseSort).apply();
|
||||
updateSortButton();
|
||||
reload();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.settings_button).setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) { showSettings(); }
|
||||
});
|
||||
@@ -347,7 +360,21 @@ public class MainActivity extends Activity implements ItemActionListener {
|
||||
PackageManager.PERMISSION_GRANTED) list.add(permission);
|
||||
}
|
||||
|
||||
private void reload() { if (adapter != null) adapter.setRows(db.tracked()); }
|
||||
private void reload() {
|
||||
if (adapter == null) return;
|
||||
adapter.setRows(DeviceSort.sorted(db.tracked(), reverseSort));
|
||||
}
|
||||
|
||||
/*
|
||||
* Stale items stay pinned to the bottom in both directions, so the
|
||||
* label only describes how the recently seen items are ordered.
|
||||
*/
|
||||
private void updateSortButton() {
|
||||
android.widget.Button button =
|
||||
(android.widget.Button) findViewById(R.id.sort_button);
|
||||
if (button == null) return;
|
||||
button.setText(reverseSort ? "Oldest first" : "Newest first");
|
||||
}
|
||||
|
||||
private void startTracker() {
|
||||
Intent intent = new Intent(this, BluetoothTrackingService.class);
|
||||
|
||||
Reference in New Issue
Block a user