diff --git a/OsmAnd-java/src/net/osmand/util/Algorithms.java b/OsmAnd-java/src/net/osmand/util/Algorithms.java
index 97dd1bdd16..4d3637bf98 100644
--- a/OsmAnd-java/src/net/osmand/util/Algorithms.java
+++ b/OsmAnd-java/src/net/osmand/util/Algorithms.java
@@ -225,6 +225,13 @@ public class Algorithms {
}
}
+ public static String capitalizeFirstLetter(String s) {
+ if (s != null && s.length() > 0) {
+ return Character.toUpperCase(s.charAt(0)) + (s.length() > 1 ? s.substring(1) : "");
+ } else {
+ return s;
+ }
+ }
public static boolean objectEquals(Object a, Object b) {
if (a == null) {
diff --git a/OsmAnd/res/layout/current_gpx_item.xml b/OsmAnd/res/layout/current_gpx_item.xml
index 4927254a26..9e13ded31b 100644
--- a/OsmAnd/res/layout/current_gpx_item.xml
+++ b/OsmAnd/res/layout/current_gpx_item.xml
@@ -7,200 +7,178 @@
android:minHeight="@dimen/list_item_height"
android:orientation="vertical">
-
-
-
-
-
-
-
-
-
+ android:orientation="horizontal">
+
+
+
+
+
-
-
-
-
-
+ android:paddingTop="12dp"
+ android:layout_marginLeft="@dimen/subHeaderMarginLeft"
+ android:layout_marginRight="@dimen/showAllButtonMarginRight"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:orientation="horizontal">
+
+
+ android:textSize="@dimen/default_list_text_size"
+ android:text=" • "/>
+
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+ android:textColor="?android:textColorPrimary"
+ android:textSize="@dimen/default_sub_text_size"
+ android:visibility="gone"/>
-
+
+
+
+
+
+
+
+
+
diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml
index dc718999c8..c6ece9a82b 100644
--- a/OsmAnd/res/values/strings.xml
+++ b/OsmAnd/res/values/strings.xml
@@ -9,6 +9,9 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
+ Select GPX folder
+ File can not be moved.
+ Move
Tracks
Driving style
Safe, fast or balanced driving
diff --git a/OsmAnd/src/net/osmand/plus/ContextMenuItem.java b/OsmAnd/src/net/osmand/plus/ContextMenuItem.java
index 9990faedda..d821ca946f 100644
--- a/OsmAnd/src/net/osmand/plus/ContextMenuItem.java
+++ b/OsmAnd/src/net/osmand/plus/ContextMenuItem.java
@@ -34,6 +34,7 @@ public class ContextMenuItem {
private final ContextMenuAdapter.OnIntegerValueChangedListener integerListener;
private final boolean hideDivider;
private final int minHeight;
+ private final int tag;
private ContextMenuItem(@StringRes int titleId,
String title,
@@ -50,7 +51,8 @@ public class ContextMenuItem {
ContextMenuAdapter.ItemClickListener itemClickListener,
ContextMenuAdapter.OnIntegerValueChangedListener integerListener,
boolean hideDivider,
- int minHeight) {
+ int minHeight,
+ int tag) {
this.titleId = titleId;
this.title = title;
this.mIcon = icon;
@@ -68,6 +70,7 @@ public class ContextMenuItem {
this.integerListener = integerListener;
this.hideDivider = hideDivider;
this.minHeight = minHeight;
+ this.tag = tag;
}
@StringRes
@@ -185,6 +188,10 @@ public class ContextMenuItem {
return minHeight;
}
+ public int getTag() {
+ return tag;
+ }
+
public static ItemBuilder createBuilder(String title) {
return new ItemBuilder().setTitle(title);
}
@@ -212,6 +219,7 @@ public class ContextMenuItem {
private boolean mSkipPaintingWithoutColor;
private boolean mHideDivider;
private int mMinHeight;
+ private int mTag;
public ItemBuilder setTitleId(@StringRes int titleId, @Nullable Context context) {
this.mTitleId = titleId;
@@ -302,10 +310,20 @@ public class ContextMenuItem {
return this;
}
+ public int getTag() {
+ return mTag;
+ }
+
+ public ItemBuilder setTag(int tag) {
+ this.mTag = tag;
+ return this;
+ }
+
public ContextMenuItem createItem() {
return new ContextMenuItem(mTitleId, mTitle, mIcon, mColorRes, mSecondaryIcon,
mSelected, mProgress, mLayout, mLoading, mIsCategory, mSkipPaintingWithoutColor,
- mPosition, mDescription, mItemClickListener, mIntegerListener, mHideDivider, mMinHeight);
+ mPosition, mDescription, mItemClickListener, mIntegerListener, mHideDivider,
+ mMinHeight, mTag);
}
}
}
diff --git a/OsmAnd/src/net/osmand/plus/GPXDatabase.java b/OsmAnd/src/net/osmand/plus/GPXDatabase.java
new file mode 100644
index 0000000000..78ece2e3f6
--- /dev/null
+++ b/OsmAnd/src/net/osmand/plus/GPXDatabase.java
@@ -0,0 +1,226 @@
+package net.osmand.plus;
+
+import net.osmand.IndexConstants;
+import net.osmand.plus.GPXUtilities.GPXTrackAnalysis;
+import net.osmand.plus.api.SQLiteAPI;
+import net.osmand.util.Algorithms;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class GPXDatabase {
+
+ private static final String DB_NAME = "gpx_database";
+ private static final int DB_VERSION = 1;
+ private static final String GPX_TABLE_NAME = "gpxTable";
+ private static final String GPX_COL_NAME = "fileName";
+ private static final String GPX_COL_DIR = "fileDir";
+ private static final String GPX_COL_TOTAL_DISTANCE = "totalDistance";
+ private static final String GPX_COL_TOTAL_TRACKS = "totalTracks";
+ private static final String GPX_COL_START_TIME = "startTime";
+ private static final String GPX_COL_END_TIME = "endTime";
+ private static final String GPX_COL_TIME_SPAN = "timeSpan";
+ private static final String GPX_COL_TIME_MOVING = "timeMoving";
+ private static final String GPX_COL_TOTAL_DISTANCE_MOVING = "totalDistanceMoving";
+
+ private static final String GPX_COL_DIFF_ELEVATION_UP = "diffElevationUp";
+ private static final String GPX_COL_DIFF_ELEVATION_DOWN = "diffElevationDown";
+ private static final String GPX_COL_AVG_ELEVATION = "avgElevation";
+ private static final String GPX_COL_MIN_ELEVATION = "minElevation";
+ private static final String GPX_COL_MAX_ELEVATION = "maxElevation";
+
+ private static final String GPX_COL_MAX_SPEED = "maxSpeed";
+ private static final String GPX_COL_AVG_SPEED = "avgSpeed";
+
+ private static final String GPX_COL_POINTS = "points";
+ private static final String GPX_COL_WPT_POINTS = "wptPoints";
+
+ private static final String GPX_TABLE_CREATE = "CREATE TABLE IF NOT EXISTS " + GPX_TABLE_NAME + " (" +
+ GPX_COL_NAME + " TEXT, " +
+ GPX_COL_DIR + " TEXT, " +
+ GPX_COL_TOTAL_DISTANCE + " double, " +
+ GPX_COL_TOTAL_TRACKS + " int, " +
+ GPX_COL_START_TIME + " long, " +
+ GPX_COL_END_TIME + " long, " +
+ GPX_COL_TIME_SPAN + " long, " +
+ GPX_COL_TIME_MOVING + " long, " +
+ GPX_COL_TOTAL_DISTANCE_MOVING + " double, " +
+
+ GPX_COL_DIFF_ELEVATION_UP + " double, " +
+ GPX_COL_DIFF_ELEVATION_DOWN + " double, " +
+ GPX_COL_AVG_ELEVATION + " double, " +
+ GPX_COL_MIN_ELEVATION + " double, " +
+ GPX_COL_MAX_ELEVATION + " double, " +
+
+ GPX_COL_MAX_SPEED + " double, " +
+ GPX_COL_AVG_SPEED + " double, " +
+
+ GPX_COL_POINTS + " int, " +
+ GPX_COL_WPT_POINTS + " int);";
+
+ private OsmandApplication context;
+
+ public static class GpxDataItem {
+ private File file;
+ private GPXTrackAnalysis analysis;
+
+ public GpxDataItem(File file, GPXTrackAnalysis analysis) {
+ this.file = file;
+ this.analysis = analysis;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public GPXTrackAnalysis getAnalysis() {
+ return analysis;
+ }
+ }
+
+ public GPXDatabase(OsmandApplication app) {
+ context = app;
+ }
+
+ private SQLiteAPI.SQLiteConnection openConnection(boolean readonly) {
+ SQLiteAPI.SQLiteConnection conn = context.getSQLiteAPI().getOrCreateDatabase(DB_NAME, readonly);
+ if (conn.getVersion() == 0 || DB_VERSION != conn.getVersion()) {
+ if (readonly) {
+ conn.close();
+ conn = context.getSQLiteAPI().getOrCreateDatabase(DB_NAME, readonly);
+ }
+ if (conn.getVersion() == 0) {
+ onCreate(conn);
+ } else {
+ onUpgrade(conn, conn.getVersion(), DB_VERSION);
+ }
+ conn.setVersion(DB_VERSION);
+
+ }
+ return conn;
+ }
+
+ public void onCreate(SQLiteAPI.SQLiteConnection db) {
+ db.execSQL(GPX_TABLE_CREATE);
+ }
+
+ public void onUpgrade(SQLiteAPI.SQLiteConnection db, int oldVersion, int newVersion) {
+ /*
+ if (newVersion == 2) {
+ db.execSQL(GPX_TABLE_CREATE);
+ //...
+ }
+ */
+ }
+
+ public boolean remove(GpxDataItem item) {
+ SQLiteAPI.SQLiteConnection db = openConnection(false);
+ if(db != null){
+ try {
+ db.execSQL("DELETE FROM " + GPX_TABLE_NAME + " WHERE " + GPX_COL_NAME + " = ?, " + GPX_COL_DIR + " = ?",
+ new Object[] { item.file.getName(), item.file.getParentFile().getName() });
+ } finally {
+ db.close();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public boolean add(GpxDataItem item) {
+ SQLiteAPI.SQLiteConnection db = openConnection(false);
+ if(db != null){
+ try {
+ insert(item, db);
+ } finally {
+ db.close();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void insert(GpxDataItem item, SQLiteAPI.SQLiteConnection db) {
+ String fileName = item.file.getName();
+ String fileDir = item.file.getParentFile().getName();
+ GPXTrackAnalysis a = item.getAnalysis();
+ db.execSQL(
+ "INSERT INTO " + GPX_TABLE_NAME + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ new Object[] { fileName, fileDir, a.totalDistance, a.totalTracks, a.startTime, a.endTime,
+ a.timeSpan, a.timeMoving, a.totalDistanceMoving, a.diffElevationUp, a.diffElevationDown,
+ a.avgElevation, a.minElevation, a.maxElevation, a.maxSpeed, a.avgSpeed, a.points, a.wptPoints });
+ }
+
+ public List getItems() {
+ List items = new ArrayList<>();
+ SQLiteAPI.SQLiteConnection db = openConnection(true);
+ if(db != null){
+ try {
+ SQLiteAPI.SQLiteCursor query = db.rawQuery(
+ "SELECT " + GPX_COL_NAME + ", " + GPX_COL_DIR + "," + GPX_COL_TOTAL_DISTANCE + ", " +
+ GPX_COL_TOTAL_TRACKS + ", " + GPX_COL_START_TIME + ", " + GPX_COL_END_TIME + ", " +
+ GPX_COL_TIME_SPAN + ", " + GPX_COL_TIME_MOVING + ", " + GPX_COL_TOTAL_DISTANCE_MOVING + ", " +
+ GPX_COL_DIFF_ELEVATION_UP + ", " + GPX_COL_DIFF_ELEVATION_DOWN + ", " + GPX_COL_AVG_ELEVATION + ", " +
+ GPX_COL_MIN_ELEVATION + ", " + GPX_COL_MAX_ELEVATION + ", " + GPX_COL_MAX_SPEED + ", " +
+ GPX_COL_AVG_SPEED + ", " + GPX_COL_POINTS + ", " + GPX_COL_WPT_POINTS +
+ " FROM " + GPX_TABLE_NAME , null);
+
+ if (query.moveToFirst()) {
+ do {
+ String fileName = query.getString(0);
+ String fileDir = query.getString(1);
+ float totalDistance = (float)query.getDouble(2);
+ int totalTracks = (int)query.getInt(3);
+ long startTime = query.getLong(4);
+ long endTime = query.getLong(5);
+ long timeSpan = query.getLong(6);
+ long timeMoving = query.getLong(7);
+ float totalDistanceMoving = (float)query.getDouble(8);
+ double diffElevationUp = query.getDouble(9);
+ double diffElevationDown = query.getDouble(10);
+ double avgElevation = query.getDouble(11);
+ double minElevation = query.getDouble(12);
+ double maxElevation = query.getDouble(13);
+ float maxSpeed = (float)query.getDouble(14);
+ float avgSpeed = (float)query.getDouble(15);
+ int points = (int)query.getInt(16);
+ int wptPoints = (int)query.getInt(17);
+
+ GPXTrackAnalysis a = new GPXTrackAnalysis();
+ a.totalDistance = totalDistance;
+ a.totalTracks = totalTracks;
+ a.startTime = startTime;
+ a.endTime = endTime;
+ a.timeSpan = timeSpan;
+ a.timeMoving = timeMoving;
+ a.totalDistanceMoving = totalDistanceMoving;
+ a.diffElevationUp = diffElevationUp;
+ a.diffElevationDown = diffElevationDown;
+ a.avgElevation = avgElevation;
+ a.minElevation = minElevation;
+ a.maxElevation = maxElevation;
+ a.maxSpeed = maxSpeed;
+ a.avgSpeed = avgSpeed;
+ a.points = points;
+ a.wptPoints = wptPoints;
+
+ File dir;
+ if (!Algorithms.isEmpty(fileDir)) {
+ dir = new File(context.getAppPath(IndexConstants.GPX_INDEX_DIR), fileDir);
+ } else {
+ dir = context.getAppPath(IndexConstants.GPX_INDEX_DIR);
+ }
+ GpxDataItem item = new GpxDataItem(new File(dir, fileName), a);
+ items.add(item);
+ } while (query.moveToNext());
+
+ }
+ query.close();
+ } finally {
+ db.close();
+ }
+ }
+ return items;
+ }
+}
diff --git a/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java
index 531a1f0a3c..6fc6584320 100644
--- a/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java
+++ b/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java
@@ -166,6 +166,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment {
ImageView icon = (ImageView) currentGpxView.findViewById(R.id.icon);
icon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.monitoring_rec_big));
+ icon.setVisibility(selectionMode && showOnMapMode ? View.GONE : View.VISIBLE);
final boolean light = app.getSettings().isLightContent();
SavingTrackHelper sth = app.getSavingTrackHelper();
@@ -583,6 +584,59 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment {
}
}
+ private void moveGpx(final GpxInfo info) {
+
+ final ContextMenuAdapter menuAdapter = new ContextMenuAdapter();
+ ContextMenuItem.ItemBuilder itemBuilder = new ContextMenuItem.ItemBuilder();
+
+ File[] listFiles = app.getAppPath(IndexConstants.GPX_INDEX_DIR).listFiles();
+ final List dirs = new ArrayList<>();
+ if (listFiles != null) {
+ Arrays.sort(listFiles);
+ for (File f : listFiles) {
+ if (f.isDirectory() && !info.file.getParentFile().equals(f)) {
+ dirs.add(f);
+ }
+ }
+ if (!info.file.getParentFile().equals(app.getAppPath(IndexConstants.GPX_INDEX_DIR))) {
+ dirs.add(0, app.getAppPath(IndexConstants.GPX_INDEX_DIR));
+ }
+ int i = 0;
+ for (File dir: dirs) {
+ menuAdapter.addItem(itemBuilder.setTitle(Algorithms.capitalizeFirstLetter(dir.getName()))
+ .setIcon(R.drawable.ic_action_folder_stroke).setTag(i).createItem());
+ i++;
+ }
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ final ArrayAdapter listAdapter =
+ menuAdapter.createListAdapter(getActivity(), app.getSettings().isLightContent());
+ builder.setTitle(R.string.select_gpx_folder);
+ builder.setAdapter(listAdapter, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ContextMenuItem item = menuAdapter.getItem(which);
+ int index = item.getTag();
+ File dir = dirs.get(index);
+ File dest = new File(dir, info.file.getName());
+ if (dest.exists()) {
+ Toast.makeText(app, R.string.file_with_name_already_exists, Toast.LENGTH_LONG).show();
+ } else {
+ if (info.file.renameTo(dest)) {
+ asyncLoader = new LoadGpxTask();
+ asyncLoader.execute(getActivity());
+ } else {
+ Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ }
+ });
+ builder.setNegativeButton(R.string.shared_string_cancel, null);
+ builder.create().show();
+ }
+ }
+
public class LoadGpxTask extends AsyncTask> {
private List result;
@@ -872,10 +926,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment {
if (groupName.length() == 0) {
groupName = getString(R.string.shared_string_tracks);
}
- t.append(Character.toUpperCase(groupName.charAt(0)));
- if (groupName.length() > 1) {
- t.append(groupName.substring(1));
- }
+ t.append(Algorithms.capitalizeFirstLetter(groupName));
boolean light = app.getSettings().isLightContent();
if (selectionMode) {
@@ -1021,6 +1072,15 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment {
}
});
+ item = optionsMenu.getMenu().add(R.string.shared_string_move).setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_folder_stroke));
+ item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ moveGpx(gpxInfo);
+ return true;
+ }
+ });
+
item = optionsMenu.getMenu().add(R.string.shared_string_rename)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_edit_dark));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {