From 14400d0355601687fa82c8edaedb878550784b52 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Sat, 14 Nov 2020 14:28:43 +0200 Subject: [PATCH 1/2] Import / Export Search History --- OsmAnd/res/values/strings.xml | 1 + .../plus/helpers/SearchHistoryHelper.java | 39 +++- .../settings/backend/ExportSettingsType.java | 3 +- .../backup/SearchHistorySettingsItem.java | 168 ++++++++++++++++++ .../backend/backup/SettingsHelper.java | 20 +++ .../backend/backup/SettingsItemType.java | 3 +- .../backend/backup/SettingsItemsFactory.java | 3 + .../fragments/DuplicatesSettingsAdapter.java | 13 +- .../ExportImportSettingsAdapter.java | 7 + .../fragments/ImportCompleteFragment.java | 13 +- .../fragments/ImportDuplicatesFragment.java | 8 + .../fragments/ImportSettingsFragment.java | 10 +- .../ImportedSettingsItemsAdapter.java | 4 + 13 files changed, 276 insertions(+), 16 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/settings/backend/backup/SearchHistorySettingsItem.java diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index d3f4d05618..07a55e3d92 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,7 @@ Thx - Hardy --> + Search history I already have an account Create new account Photos are provided by open data project OpenPlaceReviews.org. In order to upload your photos you need to sign up on website. diff --git a/OsmAnd/src/net/osmand/plus/helpers/SearchHistoryHelper.java b/OsmAnd/src/net/osmand/plus/helpers/SearchHistoryHelper.java index af16333cb2..243663b04e 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/SearchHistoryHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/SearchHistoryHelper.java @@ -121,26 +121,50 @@ public class SearchHistoryHelper { return helper; } + public void addItemsToHistory(List entries) { + for (HistoryEntry model : entries) { + addNewItemToHistory(model, false); + } + updateEntriesList(); + } + private void addNewItemToHistory(HistoryEntry model) { + addNewItemToHistory(model, true); + updateEntriesList(); + } + + private void addNewItemToHistory(HistoryEntry model, boolean markAsAccessed) { HistoryItemDBHelper helper = checkLoadedEntries(); if (mp.containsKey(model.getName())) { model = mp.get(model.getName()); - model.markAsAccessed(System.currentTimeMillis()); + if (markAsAccessed && model != null) { + model.markAsAccessed(System.currentTimeMillis()); + } helper.update(model); } else { loadedEntries.add(model); mp.put(model.getName(), model); - model.markAsAccessed(System.currentTimeMillis()); + if (markAsAccessed) { + model.markAsAccessed(System.currentTimeMillis()); + } helper.add(model); } + } + + public void updateEntriesList() { + HistoryItemDBHelper helper = checkLoadedEntries(); Collections.sort(loadedEntries, new HistoryEntryComparator()); - if (loadedEntries.size() > HISTORY_LIMIT) { + while (loadedEntries.size() > HISTORY_LIMIT) { if (helper.remove(loadedEntries.get(loadedEntries.size() - 1))) { loadedEntries.remove(loadedEntries.size() - 1); } } } + public HistoryEntry getEntryByName(PointDescription pd) { + return mp != null && pd != null ? mp.get(pd) : null; + } + public static class HistoryEntry { double lat; double lon; @@ -149,7 +173,7 @@ public class SearchHistoryHelper { private int[] intervals = new int[0]; private double[] intervalValues = new double[0]; - HistoryEntry(double lat, double lon, PointDescription name) { + public HistoryEntry(double lat, double lon, PointDescription name) { this.lat = lat; this.lon = lon; this.name = name; @@ -427,12 +451,13 @@ public class SearchHistoryHelper { boolean reinsert = false; do { String name = query.getString(0); - PointDescription p = PointDescription.deserializeFromString(name, new LatLon(query.getDouble(1), query.getDouble(2))); + double lat = query.getDouble(1); + double lon = query.getDouble(2); + PointDescription p = PointDescription.deserializeFromString(name, new LatLon(lat, lon)); if (context.getPoiTypes().isTypeForbidden(p.getName())){ query.moveToNext(); } - HistoryEntry e = new HistoryEntry(query.getDouble(1), query.getDouble(2), - p); + HistoryEntry e = new HistoryEntry(lat, lon, p); long time = query.getLong(3); e.setLastAccessTime(time); e.setFrequency(query.getString(4), query.getString(5)); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/ExportSettingsType.java b/OsmAnd/src/net/osmand/plus/settings/backend/ExportSettingsType.java index 3dcb680b06..bed2092bf6 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/ExportSettingsType.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/ExportSettingsType.java @@ -18,5 +18,6 @@ public enum ExportSettingsType { TTS_VOICE, VOICE, ACTIVE_MARKERS, - HISTORY_MARKERS + HISTORY_MARKERS, + SEARCH_HISTORY } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SearchHistorySettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SearchHistorySettingsItem.java new file mode 100644 index 0000000000..a4af84f7ca --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SearchHistorySettingsItem.java @@ -0,0 +1,168 @@ +package net.osmand.plus.settings.backend.backup; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.data.LatLon; +import net.osmand.data.PointDescription; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.helpers.SearchHistoryHelper; +import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry; +import net.osmand.util.Algorithms; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class SearchHistorySettingsItem extends CollectionSettingsItem { + + private SearchHistoryHelper searchHistoryHelper; + + public SearchHistorySettingsItem(@NonNull OsmandApplication app, @NonNull List items) { + super(app, null, items); + } + + public SearchHistorySettingsItem(@NonNull OsmandApplication app, @Nullable SearchHistorySettingsItem baseItem, @NonNull List items) { + super(app, baseItem, items); + } + + SearchHistorySettingsItem(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException { + super(app, json); + } + + @Override + protected void init() { + super.init(); + searchHistoryHelper = SearchHistoryHelper.getInstance(app); + existingItems = searchHistoryHelper.getHistoryEntries(false); + } + + @NonNull + @Override + public SettingsItemType getType() { + return SettingsItemType.SEARCH_HISTORY; + } + + @NonNull + @Override + public String getName() { + return "search_history"; + } + + @NonNull + @Override + public String getPublicName(@NonNull Context ctx) { + return ctx.getString(R.string.shared_string_search_history); + } + + @Override + public void apply() { + List newItems = getNewItems(); + if (!newItems.isEmpty() || !duplicateItems.isEmpty()) { + appliedItems = new ArrayList<>(newItems); + + // leave the last accessed history entry between the duplicate and the original + for (HistoryEntry duplicate : duplicateItems) { + PointDescription name = duplicate.getName(); + HistoryEntry original = searchHistoryHelper.getEntryByName(name); + if (original.getLastAccessTime() < duplicate.getLastAccessTime()) { + appliedItems.remove(original); + appliedItems.add(duplicate); + } + } + searchHistoryHelper.addItemsToHistory(appliedItems); + } + } + + @Override + void readItemsFromJson(@NonNull JSONObject json) throws IllegalArgumentException { + try { + if (!json.has("items")) { + return; + } + JSONArray jsonArray = json.getJSONArray("items"); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + double lat = object.optDouble("latitude"); + double lon = object.optDouble("longitude"); + String serializedPointDescription = object.optString("pointDescription"); + long lastAccessed = object.optLong("lastAccessedTime"); + String intervals = object.optString("intervals"); + String intervalValues = object.optString("intervalValues"); + + HistoryEntry historyEntry = new HistoryEntry(lat, lon, + PointDescription.deserializeFromString(serializedPointDescription, new LatLon(lat, lon))); + historyEntry.setLastAccessTime(lastAccessed); + historyEntry.setFrequency(intervals, intervalValues); + items.add(historyEntry); + } + } catch (JSONException e) { + warnings.add(app.getString(R.string.settings_item_read_error, String.valueOf(getType()))); + throw new IllegalArgumentException("Json parse error", e); + } + } + + @Override + void writeItemsToJson(@NonNull JSONObject json) { + JSONArray jsonArray = new JSONArray(); + if (!items.isEmpty()) { + try { + for (HistoryEntry historyEntry : items) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("latitude", historyEntry.getLat()); + jsonObject.put("longitude", historyEntry.getLon()); + jsonObject.put("pointDescription", + PointDescription.serializeToString(historyEntry.getName())); + jsonObject.put("lastAccessedTime", historyEntry.getLastAccessTime()); + jsonObject.put("intervals", historyEntry.getIntervals()); + jsonObject.put("intervalValues", historyEntry.getIntervalsValues()); + jsonArray.put(jsonObject); + } + json.put("items", jsonArray); + } catch (JSONException e) { + warnings.add(app.getString(R.string.settings_item_write_error, String.valueOf(getType()))); + SettingsHelper.LOG.error("Failed write to json", e); + } + } + } + + @Override + public boolean isDuplicate(@NonNull HistoryEntry historyEntry) { + PointDescription pointDescription = historyEntry.getName(); + for (HistoryEntry entry : existingItems) { + if (Algorithms.objectEquals(pointDescription, entry.getName())) { + return true; + } + } + return false; + } + + @Override + public boolean shouldReadOnCollecting() { + return true; + } + + @NonNull + @Override + public HistoryEntry renameItem(@NonNull HistoryEntry item) { + return item; + } + + @Nullable + @Override + SettingsItemReader getReader() { + return getJsonReader(); + } + + @Nullable + @Override + SettingsItemWriter getWriter() { + return getJsonWriter(); + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java index c974e72686..25f8da10b5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -31,6 +31,8 @@ import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper.GPXInfo; import net.osmand.plus.mapmarkers.MapMarker; import net.osmand.plus.mapmarkers.MapMarkersGroup; +import net.osmand.plus.helpers.SearchHistoryHelper; +import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry; import net.osmand.plus.osmedit.OpenstreetmapPoint; import net.osmand.plus.osmedit.OsmEditingPlugin; import net.osmand.plus.osmedit.OsmNotesPoint; @@ -613,6 +615,10 @@ public class SettingsHelper { markersGroup.setMarkers(markersHistory); dataList.put(ExportSettingsType.HISTORY_MARKERS, Collections.singletonList(markersGroup)); } + List historyEntries = SearchHistoryHelper.getInstance(app).getHistoryEntries(false); + if (!historyEntries.isEmpty()) { + dataList.put(ExportSettingsType.SEARCH_HISTORY, historyEntries); + } return dataList; } @@ -654,6 +660,7 @@ public class SettingsHelper { List osmEditsPointList = new ArrayList<>(); List markersGroups = new ArrayList<>(); List markersHistoryGroups = new ArrayList<>(); + List historyEntries = new ArrayList<>(); for (Object object : data) { if (object instanceof QuickAction) { @@ -685,6 +692,8 @@ public class SettingsHelper { } else if (ExportSettingsType.HISTORY_MARKERS.name().equals(markersGroup.getId())) { markersHistoryGroups.add((MapMarkersGroup) object); } + } else if (object instanceof HistoryEntry) { + historyEntries.add((HistoryEntry) object); } } if (!quickActions.isEmpty()) { @@ -730,6 +739,9 @@ public class SettingsHelper { } settingsItems.add(new HistoryMarkersSettingsItem(app, mapMarkers)); } + if (!historyEntries.isEmpty()) { + settingsItems.add(new SearchHistorySettingsItem(app, historyEntries)); + } return settingsItems; } @@ -753,6 +765,7 @@ public class SettingsHelper { List favoriteGroups = new ArrayList<>(); List markersGroups = new ArrayList<>(); List markersHistoryGroups = new ArrayList<>(); + List historyEntries = new ArrayList<>(); for (SettingsItem item : settingsItems) { switch (item.getType()) { @@ -840,6 +853,10 @@ public class SettingsHelper { HistoryMarkersSettingsItem historyMarkersSettingsItem = (HistoryMarkersSettingsItem) item; markersHistoryGroups.add(historyMarkersSettingsItem.getMarkersGroup()); break; + case SEARCH_HISTORY: + SearchHistorySettingsItem searchHistorySettingsItem = (SearchHistorySettingsItem) item; + historyEntries.addAll(searchHistorySettingsItem.getItems()); + break; default: break; } @@ -899,6 +916,9 @@ public class SettingsHelper { if (!markersGroups.isEmpty()) { settingsToOperate.put(ExportSettingsType.HISTORY_MARKERS, markersHistoryGroups); } + if (!historyEntries.isEmpty()) { + settingsToOperate.put(ExportSettingsType.SEARCH_HISTORY, historyEntries); + } return settingsToOperate; } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemType.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemType.java index 2fed0b2645..6664da22cc 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemType.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemType.java @@ -17,5 +17,6 @@ public enum SettingsItemType { OSM_EDITS, FAVOURITES, ACTIVE_MARKERS, - HISTORY_MARKERS + HISTORY_MARKERS, + SEARCH_HISTORY } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemsFactory.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemsFactory.java index 5160000d0c..b19e95388c 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemsFactory.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemsFactory.java @@ -140,6 +140,9 @@ class SettingsItemsFactory { case HISTORY_MARKERS: item = new HistoryMarkersSettingsItem(app, json); break; + case SEARCH_HISTORY: + item = new SearchHistorySettingsItem(app, json); + break; } return item; } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java index 798b29a476..252b685bfc 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java @@ -14,21 +14,22 @@ import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.map.ITileSource; import net.osmand.plus.FavouritesDbHelper.FavoriteGroup; +import net.osmand.plus.audionotes.AudioVideoNotesPlugin; +import net.osmand.plus.helpers.FileNameTranslationHelper; +import net.osmand.plus.helpers.GpxUiHelper; +import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry; +import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; -import net.osmand.plus.audionotes.AudioVideoNotesPlugin; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; -import net.osmand.plus.helpers.FileNameTranslationHelper; -import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.mapmarkers.MapMarkersGroup; import net.osmand.plus.poi.PoiUIFilter; import net.osmand.plus.profiles.ProfileIconColors; import net.osmand.plus.profiles.RoutingProfileDataObject.RoutingProfilesResources; import net.osmand.plus.quickaction.QuickAction; import net.osmand.plus.render.RenderingIcons; -import net.osmand.plus.settings.backend.ApplicationMode; -import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -160,6 +161,8 @@ public class DuplicatesSettingsAdapter extends RecyclerView.Adapter mapFilesList = new ArrayList<>(); List markersGroups = new ArrayList<>(); List markersHistoryGroups = new ArrayList<>(); + List historyEntries = new ArrayList<>(); for (Object object : duplicatesList) { if (object instanceof ApplicationMode.ApplicationModeBean) { @@ -247,6 +249,8 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment { } else if (ExportSettingsType.HISTORY_MARKERS.name().equals(markersGroup.getId())) { markersHistoryGroups.add(markersGroup); } + } else if (object instanceof HistoryEntry) { + historyEntries.add((HistoryEntry) object); } } if (!profiles.isEmpty()) { @@ -317,6 +321,10 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment { duplicates.add(getString(R.string.markers_history)); duplicates.addAll(markersHistoryGroups); } + if (!historyEntries.isEmpty()) { + duplicates.add(getString(R.string.shared_string_search_history)); + duplicates.addAll(historyEntries); + } return duplicates; } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportSettingsFragment.java index 443cd583f0..7ec65d6bf4 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportSettingsFragment.java @@ -41,6 +41,7 @@ import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; +import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry; import net.osmand.plus.mapmarkers.MapMarker; import net.osmand.plus.mapmarkers.MapMarkersGroup; import net.osmand.plus.osmedit.OpenstreetmapPoint; @@ -53,6 +54,7 @@ import net.osmand.plus.settings.backend.backup.AvoidRoadsSettingsItem; import net.osmand.plus.settings.backend.backup.FavoritesSettingsItem; import net.osmand.plus.settings.backend.backup.FileSettingsItem; import net.osmand.plus.settings.backend.backup.GlobalSettingsItem; +import net.osmand.plus.settings.backend.backup.SearchHistorySettingsItem; import net.osmand.plus.settings.backend.backup.HistoryMarkersSettingsItem; import net.osmand.plus.settings.backend.backup.MapSourcesSettingsItem; import net.osmand.plus.settings.backend.backup.MarkersSettingsItem; @@ -442,6 +444,7 @@ public class ImportSettingsFragment extends BaseOsmAndFragment { List favoriteGroups = new ArrayList<>(); List markersGroups = new ArrayList<>(); List markersHistoryGroups = new ArrayList<>(); + List historyEntries = new ArrayList<>(); for (Object object : data) { if (object instanceof ApplicationModeBean) { appModeBeans.add((ApplicationModeBean) object); @@ -472,6 +475,8 @@ public class ImportSettingsFragment extends BaseOsmAndFragment { } else if (ExportSettingsType.HISTORY_MARKERS.name().equals(markersGroup.getId())) { markersHistoryGroups.add((MapMarkersGroup) object); } + } else if (object instanceof HistoryEntry) { + historyEntries.add((HistoryEntry) object); } } if (!appModeBeans.isEmpty()) { @@ -519,7 +524,10 @@ public class ImportSettingsFragment extends BaseOsmAndFragment { HistoryMarkersSettingsItem baseItem = getBaseItem(SettingsItemType.HISTORY_MARKERS, HistoryMarkersSettingsItem.class); settingsItems.add(new HistoryMarkersSettingsItem(app, baseItem, mapMarkers)); } - + if (!historyEntries.isEmpty()) { + SearchHistorySettingsItem baseItem = getBaseItem(SettingsItemType.SEARCH_HISTORY, SearchHistorySettingsItem.class); + settingsItems.add(new SearchHistorySettingsItem(app, baseItem, historyEntries)); + } return settingsItems; } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java index 9114c430b9..3a978a3a63 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java @@ -150,6 +150,10 @@ public class ImportedSettingsItemsAdapter extends holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_flag, activeColorRes)); holder.title.setText(R.string.markers_history); break; + case SEARCH_HISTORY: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_history)); + holder.title.setText(R.string.shared_string_search_history); + break; } } From 302425ee4246d2b718203f710fe23566b3cdfe74 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Sun, 15 Nov 2020 13:34:19 +0200 Subject: [PATCH 2/2] fix icon color --- .../plus/settings/fragments/ImportedSettingsItemsAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java index 3a978a3a63..b2132c3b3c 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportedSettingsItemsAdapter.java @@ -151,7 +151,7 @@ public class ImportedSettingsItemsAdapter extends holder.title.setText(R.string.markers_history); break; case SEARCH_HISTORY: - holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_history)); + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_history, activeColorRes)); holder.title.setText(R.string.shared_string_search_history); break; }