Merge pull request #10187 from osmandapp/SearchHistoryBackup

Import / Export Search History
This commit is contained in:
Vitaliy 2020-11-16 07:11:13 +00:00 committed by GitHub
commit 38699980ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 276 additions and 16 deletions

View file

@ -11,6 +11,7 @@
Thx - Hardy
-->
<string name="shared_string_search_history">Search history</string>
<string name="register_opr_have_account">I already have an account</string>
<string name="register_opr_create_new_account">Create new account</string>
<string name="register_on_openplacereviews_desc">Photos are provided by open data project OpenPlaceReviews.org. In order to upload your photos you need to sign up on website.</string>

View file

@ -121,26 +121,50 @@ public class SearchHistoryHelper {
return helper;
}
public void addItemsToHistory(List<HistoryEntry> 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));

View file

@ -18,5 +18,6 @@ public enum ExportSettingsType {
TTS_VOICE,
VOICE,
ACTIVE_MARKERS,
HISTORY_MARKERS
HISTORY_MARKERS,
SEARCH_HISTORY
}

View file

@ -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<HistoryEntry> {
private SearchHistoryHelper searchHistoryHelper;
public SearchHistorySettingsItem(@NonNull OsmandApplication app, @NonNull List<HistoryEntry> items) {
super(app, null, items);
}
public SearchHistorySettingsItem(@NonNull OsmandApplication app, @Nullable SearchHistorySettingsItem baseItem, @NonNull List<HistoryEntry> 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<HistoryEntry> 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<? extends SettingsItem> getReader() {
return getJsonReader();
}
@Nullable
@Override
SettingsItemWriter<? extends SettingsItem> getWriter() {
return getJsonWriter();
}
}

View file

@ -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<HistoryEntry> 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<OpenstreetmapPoint> osmEditsPointList = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> 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<FavoriteGroup> favoriteGroups = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> 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;
}

View file

@ -17,5 +17,6 @@ public enum SettingsItemType {
OSM_EDITS,
FAVOURITES,
ACTIVE_MARKERS,
HISTORY_MARKERS
HISTORY_MARKERS,
SEARCH_HISTORY
}

View file

@ -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;
}

View file

@ -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<RecyclerView
MapMarkersGroup markersGroup = (MapMarkersGroup) currentItem;
itemHolder.title.setText(markersGroup.getName());
itemHolder.icon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_action_flag, activeColorRes));
} else if (currentItem instanceof HistoryEntry) {
itemHolder.title.setText(((HistoryEntry) currentItem).getName().getName());
}
itemHolder.divider.setVisibility(shouldShowDivider(position) ? View.VISIBLE : View.GONE);
}

View file

@ -25,6 +25,7 @@ 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.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.osmedit.OsmNotesPoint;
@ -310,6 +311,10 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
title.setText(R.string.markers_history);
setupIcon(icon, R.drawable.ic_action_flag, itemSelected);
break;
case SEARCH_HISTORY:
HistoryEntry historyEntry = (HistoryEntry) currentItem;
title.setText(historyEntry.getName().getName());
break;
default:
return child;
}
@ -414,6 +419,8 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
return R.string.map_markers;
case HISTORY_MARKERS:
return R.string.markers_history;
case SEARCH_HISTORY:
return R.string.shared_string_search_history;
default:
return R.string.access_empty_list;
}

View file

@ -10,7 +10,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.activity.OnBackPressedCallback;
@ -205,6 +204,18 @@ public class ImportCompleteFragment extends BaseOsmAndFragment {
app.getSettings().FAVORITES_TAB.set(FavoritesActivity.FAV_TAB);
startActivity(favoritesActivity);
break;
case SEARCH_HISTORY:
if (activity instanceof MapActivity) {
QuickSearchDialogFragment.showInstance(
(MapActivity) activity,
"",
null,
QuickSearchDialogFragment.QuickSearchType.REGULAR,
QuickSearchDialogFragment.QuickSearchTab.HISTORY,
null
);
}
break;
default:
break;
}

View file

@ -32,6 +32,7 @@ import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
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.MapMarkersGroup;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
import net.osmand.plus.osmedit.OsmNotesPoint;
@ -204,6 +205,7 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment {
List<File> mapFilesList = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> 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;
}

View file

@ -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<FavoriteGroup> favoriteGroups = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> 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;
}

View file

@ -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, activeColorRes));
holder.title.setText(R.string.shared_string_search_history);
break;
}
}