Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2018-01-31 14:25:04 +01:00
commit cc88a52924
8 changed files with 789 additions and 48 deletions

View file

@ -0,0 +1,195 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:orientation="vertical">
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/bottom_sheet_content_padding_small">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title_text_view"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_title_height"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:text="@string/shared_string_export"
android:textAppearance="@style/TextAppearance.ListItemTitle"
osmand:typeface="@string/font_roboto_medium"/>
<TextView
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_descr_height"
android:ellipsize="end"
android:maxLines="2"
android:paddingEnd="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"
android:text="@string/osm_edits_export_desc"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"/>
<LinearLayout
android:id="@+id/poi_row"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_list_item_height"
android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<ImageView
android:id="@+id/poi_icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_action_info_dark"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/poi"
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
<TextView
android:id="@+id/poi_count_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="13"/>
</LinearLayout>
<LinearLayout
android:id="@+id/osm_notes_row"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_list_item_height"
android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<ImageView
android:id="@+id/osm_notes_icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_action_bug_dark"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/osm_notes"
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
<TextView
android:id="@+id/osm_notes_count_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="5"/>
</LinearLayout>
<LinearLayout
android:id="@+id/all_data_row"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_list_item_height"
android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<ImageView
android:id="@+id/all_data_icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_action_folder"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/all_data"
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
<TextView
android:id="@+id/all_data_count_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="18"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider"/>
<FrameLayout
android:id="@+id/cancel_row"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_cancel_button_height"
android:background="?attr/selectableItemBackground">
<TextView
android:id="@+id/cancel_row_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/shared_string_cancel"
android:textAllCaps="true"
android:textColor="?attr/color_dialog_buttons"
android:textSize="@dimen/default_desc_text_size"
android:textStyle="bold"/>
</FrameLayout>
</LinearLayout>

View file

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:orientation="vertical">
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/bottom_sheet_content_padding_small">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title_text_view"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_title_height"
android:gravity="center_vertical"
android:paddingEnd="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"
android:text="@string/choose_file_type"
android:textAppearance="@style/TextAppearance.ListItemTitle"
osmand:typeface="@string/font_roboto_medium"/>
<LinearLayout
android:id="@+id/osc_file_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingEnd="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingStart="@dimen/content_padding">
<ImageView
android:id="@+id/osc_file_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_type_file"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/osc_file"
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/osc_file_desc"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"/>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="@dimen/bottom_sheet_content_padding_small"
android:layout_marginLeft="@dimen/bottom_sheet_divider_margin_start"
android:layout_marginStart="@dimen/bottom_sheet_divider_margin_start"
android:layout_marginTop="@dimen/bottom_sheet_content_padding_small"
android:background="?attr/dashboard_divider"/>
<LinearLayout
android:id="@+id/gpx_file_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingEnd="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingStart="@dimen/content_padding">
<ImageView
android:id="@+id/gpx_file_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_type_file"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/gpx_file"
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/gpx_file_desc"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider"/>
<FrameLayout
android:id="@+id/cancel_row"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_cancel_button_height"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/shared_string_close"
android:textAllCaps="true"
android:textColor="?attr/color_dialog_buttons"
android:textSize="@dimen/default_desc_text_size"
android:textStyle="bold"/>
</FrameLayout>
</LinearLayout>

View file

@ -3728,4 +3728,10 @@
<string name="poi_shop_fireplace">Магазин каминов</string> <string name="poi_shop_fireplace">Магазин каминов</string>
<string name="poi_mountain_area">Горный массив</string>
<string name="poi_couloir">Ущелье</string>
<string name="poi_gorge">Теснина</string>
<string name="poi_shop_boat">Магазин лодок</string>
</resources> </resources>

View file

@ -3704,4 +3704,9 @@
<string name="poi_shop_fireplace">Fireplace store</string> <string name="poi_shop_fireplace">Fireplace store</string>
<string name="poi_shop_boat">Boat store</string>
<string name="poi_cannabis">Cannabis store</string>
</resources> </resources>

View file

@ -9,6 +9,14 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated). 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 PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
--> -->
<string name="gpx_file_desc">GPX - suitable for export to JOSM or other OSM editors.</string>
<string name="osc_file_desc">OSC - suitable for export to OpenStreetMap.</string>
<string name="gpx_file">GPX file</string>
<string name="osc_file">OSC file</string>
<string name="choose_file_type">Choose file type</string>
<string name="osm_edits_export_desc">Select the export type: OSM notes, POI, or both.</string>
<string name="all_data">All data</string>
<string name="osm_notes">OSM Notes</string>
<string name="will_open_tomorrow_at">Will open tomorrow at</string> <string name="will_open_tomorrow_at">Will open tomorrow at</string>
<string name="rendering_attr_hidePOILabels_name">POI labels</string> <string name="rendering_attr_hidePOILabels_name">POI labels</string>
<string name="shared_string_without_name">Without name</string> <string name="shared_string_without_name">Without name</string>
@ -338,9 +346,6 @@
\u2022 OsmAnd Live: bug fixes, fresh data on the server every 30 minutes, updates implemented into the navigation\n\n \u2022 OsmAnd Live: bug fixes, fresh data on the server every 30 minutes, updates implemented into the navigation\n\n
</string> </string>
<string name="release_2_9"> <string name="release_2_9">
\u2022 Detection of stop signs now considers driving direction\n\n
\u2022 New algorithm providing meaningful ascent/descent values for GPX tracks\n\n
\u2022 Terrain (ascent) aware hiking time (Naismith\'s rule)\n\n
\u2022 Updated the context menu: show when the POI opens / closes\n\n \u2022 Updated the context menu: show when the POI opens / closes\n\n
\u2022 Transport menu: all available routes are now at the top\n\n \u2022 Transport menu: all available routes are now at the top\n\n
\u2022 Wikipedia: added the button to open the original article, updated the appearance of articles\n\n \u2022 Wikipedia: added the button to open the original article, updated the appearance of articles\n\n
@ -348,6 +353,9 @@
\u2022 Notes: added sorting by type and date\n\n \u2022 Notes: added sorting by type and date\n\n
\u2022 OSM edits: show an icon and a name of the POI category, display completed actions\n\n \u2022 OSM edits: show an icon and a name of the POI category, display completed actions\n\n
\u2022 New quick coordinate input screen for quick markers creation\n\n \u2022 New quick coordinate input screen for quick markers creation\n\n
\u2022 Detection of stop signs now considers driving direction\n\n
\u2022 New algorithm providing meaningful ascent/descent values for GPX tracks\n\n
\u2022 Terrain (ascent) aware hiking time (Naismith\'s rule)\n\n
</string> </string>
<string name="auto_split_recording_title">Auto-split recordings after gap</string> <string name="auto_split_recording_title">Auto-split recordings after gap</string>
<string name="auto_split_recording_descr">Start new segment after gap of 6 min, new track after gap of 2 h, or new file after a longer gap if the date has changed.</string> <string name="auto_split_recording_descr">Start new segment after gap of 6 min, new track after gap of 2 h, or new file after a longer gap if the date has changed.</string>

View file

@ -0,0 +1,123 @@
package net.osmand.plus.osmedit;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.plus.R;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.osmedit.OsmEditsFragment.ExportTypesDef;
import net.osmand.plus.widgets.TextViewEx;
public class ExportOptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragment {
public static final String TAG = "ExportOptionsBottomSheetDialogFragment";
public static final String POI_COUNT_KEY = "poi_count";
public static final String NOTES_COUNT_KEY = "notes_count";
private ExportOptionsFragmentListener listener;
private int poiCount;
private int osmNotesCount;
public void setListener(ExportOptionsFragmentListener listener) {
this.listener = listener;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
final View mainView = View.inflate(new ContextThemeWrapper(getContext(), themeRes),
R.layout.fragment_osm_export_options_bottom_sheet_dialog, container);
Bundle args = getArguments();
if (args != null) {
poiCount = args.getInt(POI_COUNT_KEY);
osmNotesCount = args.getInt(NOTES_COUNT_KEY);
}
if (nightMode) {
((TextViewEx) mainView.findViewById(R.id.title_text_view)).setTextColor(getResources().getColor(R.color.ctx_menu_info_text_dark));
}
((ImageView) mainView.findViewById(R.id.poi_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_info_dark));
((ImageView) mainView.findViewById(R.id.osm_notes_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_bug_dark));
((ImageView) mainView.findViewById(R.id.all_data_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_folder));
((TextView) mainView.findViewById(R.id.poi_count_text_view)).setText(String.valueOf(poiCount));
((TextView) mainView.findViewById(R.id.osm_notes_count_text_view)).setText(String.valueOf(osmNotesCount));
((TextView) mainView.findViewById(R.id.all_data_count_text_view)).setText(String.valueOf(poiCount + osmNotesCount));
View poiRow = mainView.findViewById(R.id.poi_row);
if (poiCount > 0) {
poiRow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(OsmEditsFragment.EXPORT_TYPE_POI);
}
dismiss();
}
});
} else {
disable(poiRow);
}
View osmNotesRow = mainView.findViewById(R.id.osm_notes_row);
if (osmNotesCount > 0) {
osmNotesRow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(OsmEditsFragment.EXPORT_TYPE_NOTES);
}
dismiss();
}
});
} else {
disable(osmNotesRow);
}
View allDataRow = mainView.findViewById(R.id.all_data_row);
if ((poiCount + osmNotesCount) > 0) {
allDataRow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(OsmEditsFragment.EXPORT_TYPE_ALL);
}
dismiss();
}
});
} else {
disable(allDataRow);
}
mainView.findViewById(R.id.cancel_row).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
setupHeightAndBackground(mainView, R.id.scroll_view);
return mainView;
}
private void disable(View view) {
view.setEnabled(false);
view.setAlpha(.5f);
}
public interface ExportOptionsFragmentListener {
void onClick(@ExportTypesDef int type);
}
}

View file

@ -0,0 +1,78 @@
package net.osmand.plus.osmedit;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import net.osmand.plus.R;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.osmedit.OsmEditsFragment.FileTypesDef;
import net.osmand.plus.widgets.TextViewEx;
public class FileTypeBottomSheetDialogFragment extends MenuBottomSheetDialogFragment {
public static final String TAG = "FileTypeBottomSheetDialogFragment";
private FileTypeFragmentListener listener;
public void setListener(FileTypeFragmentListener listener) {
this.listener = listener;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
final View mainView = View.inflate(new ContextThemeWrapper(getContext(), themeRes),
R.layout.fragment_osm_file_type_bottom_sheet_dialog, container);
if (nightMode) {
((TextViewEx) mainView.findViewById(R.id.title_text_view)).setTextColor(getResources().getColor(R.color.ctx_menu_info_text_dark));
}
Drawable fileIcon = getContentIcon(R.drawable.ic_type_file);
((ImageView) mainView.findViewById(R.id.osc_file_icon)).setImageDrawable(fileIcon);
((ImageView) mainView.findViewById(R.id.gpx_file_icon)).setImageDrawable(fileIcon);
mainView.findViewById(R.id.osc_file_row).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(OsmEditsFragment.FILE_TYPE_OSC);
}
dismiss();
}
});
mainView.findViewById(R.id.gpx_file_row).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(OsmEditsFragment.FILE_TYPE_GPX);
}
dismiss();
}
});
mainView.findViewById(R.id.cancel_row).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
setupHeightAndBackground(mainView, R.id.scroll_view);
return mainView;
}
public interface FileTypeFragmentListener {
void onClick(@FileTypesDef int type);
}
}

View file

@ -7,9 +7,11 @@ import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.view.ActionMode; import android.support.v7.view.ActionMode;
import android.util.Xml; import android.util.Xml;
@ -29,6 +31,9 @@ import android.widget.Toast;
import net.osmand.data.PointDescription; import net.osmand.data.PointDescription;
import net.osmand.osm.edit.Node; import net.osmand.osm.edit.Node;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.GPXUtilities.GPXFile;
import net.osmand.plus.GPXUtilities.WptPt;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.OsmandSettings; import net.osmand.plus.OsmandSettings;
@ -40,9 +45,12 @@ import net.osmand.plus.base.OsmAndListFragment;
import net.osmand.plus.dialogs.ProgressDialogFragment; import net.osmand.plus.dialogs.ProgressDialogFragment;
import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.myplaces.FavoritesActivity; import net.osmand.plus.myplaces.FavoritesActivity;
import net.osmand.plus.osmedit.ExportOptionsBottomSheetDialogFragment.ExportOptionsFragmentListener;
import net.osmand.plus.osmedit.FileTypeBottomSheetDialogFragment.FileTypeFragmentListener;
import net.osmand.plus.osmedit.OsmEditOptionsBottomSheetDialogFragment.OsmEditOptionsFragmentListener;
import net.osmand.plus.osmedit.OsmPoint.Group;
import net.osmand.plus.osmedit.dialogs.SendPoiDialogFragment; import net.osmand.plus.osmedit.dialogs.SendPoiDialogFragment;
import net.osmand.plus.osmedit.dialogs.SendPoiDialogFragment.PoiUploaderType; import net.osmand.plus.osmedit.dialogs.SendPoiDialogFragment.PoiUploaderType;
import net.osmand.plus.osmedit.OsmEditOptionsBottomSheetDialogFragment.OsmEditOptionsFragmentListener;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer;
@ -50,6 +58,8 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -57,6 +67,25 @@ import java.util.Map;
public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialogFragment.ProgressDialogPoiUploader, OpenstreetmapLocalUtil.OnNodeCommittedListener { public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialogFragment.ProgressDialogPoiUploader, OpenstreetmapLocalUtil.OnNodeCommittedListener {
public static final int EXPORT_TYPE_ALL = 0;
public static final int EXPORT_TYPE_POI = 1;
public static final int EXPORT_TYPE_NOTES = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({EXPORT_TYPE_ALL, EXPORT_TYPE_POI, EXPORT_TYPE_NOTES})
@interface ExportTypesDef {
}
public static final int FILE_TYPE_OSC = 0;
public static final int FILE_TYPE_GPX = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({FILE_TYPE_OSC, FILE_TYPE_GPX})
@interface FileTypesDef {
}
private static final String EXPORT_TYPE_KEY = "export_type";
private final static int MODE_DELETE = 100; private final static int MODE_DELETE = 100;
private final static int MODE_UPLOAD = 101; private final static int MODE_UPLOAD = 101;
@ -72,14 +101,16 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
private ActionMode actionMode; private ActionMode actionMode;
private long refreshId; private long refreshId;
private int exportType;
public static void getOsmEditView(View v, OsmPoint child, OsmandApplication app) { public static void getOsmEditView(View v, OsmPoint child, OsmandApplication app) {
TextView viewName = ((TextView) v.findViewById(R.id.name)); TextView viewName = ((TextView) v.findViewById(R.id.name));
ImageView icon = (ImageView) v.findViewById(R.id.icon); ImageView icon = (ImageView) v.findViewById(R.id.icon);
String name = OsmEditingPlugin.getEditName(child); String name = OsmEditingPlugin.getEditName(child);
viewName.setText(name); viewName.setText(name);
if (child.getGroup() == OsmPoint.Group.POI) { if (child.getGroup() == Group.POI) {
icon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.ic_type_info, R.color.color_distance)); icon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.ic_type_info, R.color.color_distance));
} else if (child.getGroup() == OsmPoint.Group.BUG) { } else if (child.getGroup() == Group.BUG) {
icon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.ic_type_bug, R.color.color_distance)); icon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.ic_type_bug, R.color.color_distance));
} }
@ -97,6 +128,10 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null) {
exportType = savedInstanceState.getInt(EXPORT_TYPE_KEY);
}
setHasOptionsMenu(true); setHasOptionsMenu(true);
plugin = OsmandPlugin.getEnabledPlugin(OsmEditingPlugin.class); plugin = OsmandPlugin.getEnabledPlugin(OsmEditingPlugin.class);
@ -111,15 +146,30 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
emptyView.setBackgroundColor(getResources().getColor(getMyApplication().getSettings() emptyView.setBackgroundColor(getResources().getColor(getMyApplication().getSettings()
.isLightContent() ? R.color.ctx_menu_info_view_bg_light : R.color.ctx_menu_info_view_bg_dark)); .isLightContent() ? R.color.ctx_menu_info_view_bg_light : R.color.ctx_menu_info_view_bg_dark));
Fragment optionsFragment = getChildFragmentManager().findFragmentByTag(OsmEditOptionsBottomSheetDialogFragment.TAG); FragmentManager fm = getChildFragmentManager();
Fragment optionsFragment = fm.findFragmentByTag(OsmEditOptionsBottomSheetDialogFragment.TAG);
if (optionsFragment != null) { if (optionsFragment != null) {
((OsmEditOptionsBottomSheetDialogFragment) optionsFragment).setListener(createOsmEditOptionsFragmentListener()); ((OsmEditOptionsBottomSheetDialogFragment) optionsFragment).setListener(createOsmEditOptionsFragmentListener());
} }
Fragment exportOptFragment = fm.findFragmentByTag(ExportOptionsBottomSheetDialogFragment.TAG);
if (exportOptFragment != null) {
((ExportOptionsBottomSheetDialogFragment) exportOptFragment).setListener(createExportOptionsFragmentListener());
}
Fragment fileTypeFragment = fm.findFragmentByTag(FileTypeBottomSheetDialogFragment.TAG);
if (fileTypeFragment != null) {
((FileTypeBottomSheetDialogFragment) fileTypeFragment).setListener(createFileTypeFragmentListener());
}
plugin.getPoiModificationLocalUtil().addNodeCommittedListener(this); plugin.getPoiModificationLocalUtil().addNodeCommittedListener(this);
return view; return view;
} }
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(EXPORT_TYPE_KEY, exportType);
}
@Override @Override
public void onDestroyView() { public void onDestroyView() {
plugin.getPoiModificationLocalUtil().removeNodeCommittedListener(this); plugin.getPoiModificationLocalUtil().removeNodeCommittedListener(this);
@ -152,6 +202,16 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
listAdapter.notifyDataSetChanged(); listAdapter.notifyDataSetChanged();
} }
private List<OsmPoint> getOsmEditsByGroup(Group group) {
List<OsmPoint> res = new ArrayList<>();
for (OsmPoint point : osmEdits) {
if (point.getGroup() == group) {
res.add(point);
}
}
return res;
}
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear(); menu.clear();
@ -173,13 +233,19 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
}); });
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
item = menu.add(R.string.local_osm_changes_backup).setIcon(R.drawable.ic_action_gshare_dark); item = menu.add(R.string.shared_string_export).setIcon(R.drawable.ic_action_gshare_dark);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
new BackupOpenstreetmapPointAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Bundle args = new Bundle();
osmEdits.toArray(new OsmPoint[osmEdits.size()])); args.putInt(ExportOptionsBottomSheetDialogFragment.POI_COUNT_KEY, getOsmEditsByGroup(Group.POI).size());
args.putInt(ExportOptionsBottomSheetDialogFragment.NOTES_COUNT_KEY, getOsmEditsByGroup(Group.BUG).size());
ExportOptionsBottomSheetDialogFragment fragment = new ExportOptionsBottomSheetDialogFragment();
fragment.setArguments(args);
fragment.setUsedOnMap(false);
fragment.setListener(createExportOptionsFragmentListener());
fragment.show(getChildFragmentManager(), ExportOptionsBottomSheetDialogFragment.TAG);
return true; return true;
} }
}); });
@ -485,6 +551,43 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
}; };
} }
private ExportOptionsFragmentListener createExportOptionsFragmentListener() {
return new ExportOptionsFragmentListener() {
@Override
public void onClick(int type) {
exportType = type;
openFileTypeMenu();
}
};
}
private FileTypeFragmentListener createFileTypeFragmentListener() {
return new FileTypeFragmentListener() {
@Override
public void onClick(int type) {
List<OsmPoint> points = getPointsToExport();
new BackupOpenstreetmapPointAsyncTask(type, exportType).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
points.toArray(new OsmPoint[points.size()]));
}
};
}
private void openFileTypeMenu() {
FileTypeBottomSheetDialogFragment fragment = new FileTypeBottomSheetDialogFragment();
fragment.setUsedOnMap(false);
fragment.setListener(createFileTypeFragmentListener());
fragment.show(getChildFragmentManager(), FileTypeBottomSheetDialogFragment.TAG);
}
private List<OsmPoint> getPointsToExport() {
if (exportType == EXPORT_TYPE_POI) {
return getOsmEditsByGroup(Group.POI);
} else if (exportType == EXPORT_TYPE_NOTES) {
return getOsmEditsByGroup(Group.BUG);
}
return osmEdits;
}
protected OsmPoint getPointAfterModify(OsmPoint info) { protected OsmPoint getPointAfterModify(OsmPoint info) {
if (info instanceof OpenstreetmapPoint && info.getId() == refreshId) { if (info instanceof OpenstreetmapPoint && info.getId() == refreshId) {
for (OpenstreetmapPoint p : plugin.getDBPOI().getOpenstreetmapPoints()) { for (OpenstreetmapPoint p : plugin.getDBPOI().getOpenstreetmapPoints()) {
@ -533,7 +636,7 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
private void showOnMap(OsmPoint osmPoint) { private void showOnMap(OsmPoint osmPoint) {
boolean isOsmPoint = osmPoint instanceof OpenstreetmapPoint; boolean isOsmPoint = osmPoint instanceof OpenstreetmapPoint;
String type = osmPoint.getGroup() == OsmPoint.Group.POI ? PointDescription.POINT_TYPE_POI : PointDescription.POINT_TYPE_OSM_BUG; String type = osmPoint.getGroup() == Group.POI ? PointDescription.POINT_TYPE_POI : PointDescription.POINT_TYPE_OSM_BUG;
String name = (isOsmPoint ? ((OpenstreetmapPoint) osmPoint).getName() : ((OsmNotesPoint) osmPoint).getText()); String name = (isOsmPoint ? ((OpenstreetmapPoint) osmPoint).getName() : ((OsmNotesPoint) osmPoint).getText());
getMyApplication().getSettings().setMapLocationToShow(osmPoint.getLatitude(), osmPoint.getLongitude(), 15, getMyApplication().getSettings().setMapLocationToShow(osmPoint.getLatitude(), osmPoint.getLongitude(), 15,
new PointDescription(type, name), true, osmPoint); //$NON-NLS-1$ new PointDescription(type, name), true, osmPoint); //$NON-NLS-1$
@ -580,9 +683,9 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
while (it.hasNext()) { while (it.hasNext()) {
OsmPoint osmPoint = it.next(); OsmPoint osmPoint = it.next();
assert plugin != null; assert plugin != null;
if (osmPoint.getGroup() == OsmPoint.Group.POI) { if (osmPoint.getGroup() == Group.POI) {
plugin.getDBPOI().deletePOI((OpenstreetmapPoint) osmPoint); plugin.getDBPOI().deletePOI((OpenstreetmapPoint) osmPoint);
} else if (osmPoint.getGroup() == OsmPoint.Group.BUG) { } else if (osmPoint.getGroup() == Group.BUG) {
plugin.getDBBug().deleteAllBugModifications((OsmNotesPoint) osmPoint); plugin.getDBBug().deleteAllBugModifications((OsmNotesPoint) osmPoint);
} }
it.remove(); it.remove();
@ -600,21 +703,24 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
public class BackupOpenstreetmapPointAsyncTask extends AsyncTask<OsmPoint, OsmPoint, String> { public class BackupOpenstreetmapPointAsyncTask extends AsyncTask<OsmPoint, OsmPoint, String> {
private File osmchange; private File osmchange;
private boolean oscFile;
public BackupOpenstreetmapPointAsyncTask() { public BackupOpenstreetmapPointAsyncTask(int fileType, int exportType) {
OsmandApplication app = (OsmandApplication) getActivity().getApplication(); OsmandApplication app = (OsmandApplication) getActivity().getApplication();
osmchange = app.getAppPath("poi_modification.osc"); oscFile = fileType == FILE_TYPE_OSC;
osmchange = app.getAppPath(getFileName(exportType));
} }
@Override @Override
protected String doInBackground(OsmPoint... points) { protected String doInBackground(OsmPoint... points) {
if (oscFile) {
FileOutputStream out = null; FileOutputStream out = null;
try { try {
out = new FileOutputStream(osmchange); out = new FileOutputStream(osmchange);
XmlSerializer sz = Xml.newSerializer(); XmlSerializer sz = Xml.newSerializer();
sz.setOutput(out, "UTF-8"); sz.setOutput(out, "UTF-8");
sz.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
sz.startDocument("UTF-8", true); sz.startDocument("UTF-8", true);
sz.startTag("", "osmChange"); sz.startTag("", "osmChange");
sz.attribute("", "generator", "OsmAnd"); sz.attribute("", "generator", "OsmAnd");
@ -641,13 +747,69 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
e.printStackTrace(); e.printStackTrace();
} }
} }
} else {
GPXFile gpx = new GPXFile();
for (OsmPoint point : points) {
if (point.getGroup() == Group.POI) {
OpenstreetmapPoint p = (OpenstreetmapPoint) point;
WptPt wpt = new WptPt();
wpt.name = "node" + " " + OsmPoint.stringAction.get(p.getAction());
wpt.lat = p.getLatitude();
wpt.lon = p.getLongitude();
wpt.desc = "id: " + String.valueOf(p.getId());
wpt.comment = getTagsString(p);
gpx.addPoint(wpt);
} else if (point.getGroup() == Group.BUG) {
OsmNotesPoint p = (OsmNotesPoint) point;
WptPt wpt = new WptPt();
wpt.name = "note" + " " + OsmPoint.stringAction.get(p.getAction());
wpt.lat = p.getLatitude();
wpt.lon = p.getLongitude();
wpt.desc = "id: " + String.valueOf(p.getId());
wpt.comment = p.getText();
gpx.addPoint(wpt);
}
}
GPXUtilities.writeGpxFile(osmchange, gpx, getMyApplication());
}
return null; return null;
} }
private String getFileName(int exportType) {
StringBuilder sb = new StringBuilder();
if (exportType == EXPORT_TYPE_POI) {
sb.append("osm_edits_modification");
} else if (exportType == EXPORT_TYPE_NOTES) {
sb.append("osm_notes_modification");
} else {
sb.append("osm_modification");
}
sb.append(oscFile ? ".osc" : ".gpx");
return sb.toString();
}
private String getTagsString(OpenstreetmapPoint point) {
StringBuilder sb = new StringBuilder();
for (String tag : point.getEntity().getTagKeySet()) {
String val = point.getEntity().getTag(tag);
if (isNotValid(tag, val)) {
continue;
}
sb.append(tag).append(" : ");
sb.append(val).append("; ");
}
return sb.toString();
}
private boolean isNotValid(String tag, String val) {
return val == null || val.length() == 0 || tag.length() == 0
|| tag.startsWith(EditPoiData.REMOVE_TAG_PREFIX) || tag.equals("poi_type_tag");
}
private void writeContent(XmlSerializer sz, OsmPoint[] points, OsmPoint.Action a) throws IllegalArgumentException, IllegalStateException, IOException { private void writeContent(XmlSerializer sz, OsmPoint[] points, OsmPoint.Action a) throws IllegalArgumentException, IllegalStateException, IOException {
for (OsmPoint point : points) { for (OsmPoint point : points) {
if (point.getGroup() == OsmPoint.Group.POI) { if (point.getGroup() == Group.POI) {
OpenstreetmapPoint p = (OpenstreetmapPoint) point; OpenstreetmapPoint p = (OpenstreetmapPoint) point;
if (p.getAction() == a) { if (p.getAction() == a) {
sz.startTag("", "node"); sz.startTag("", "node");
@ -657,7 +819,7 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
sz.attribute("", "version", "1"); sz.attribute("", "version", "1");
for (String tag : p.getEntity().getTagKeySet()) { for (String tag : p.getEntity().getTagKeySet()) {
String val = p.getEntity().getTag(tag); String val = p.getEntity().getTag(tag);
if (val == null || val.length() == 0 || tag.length() == 0 || "poi_type_tag".equals(tag)) { if (isNotValid(tag, val)) {
continue; continue;
} }
sz.startTag("", "tag"); sz.startTag("", "tag");
@ -667,7 +829,7 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
} }
sz.endTag("", "node"); sz.endTag("", "node");
} }
} else if (point.getGroup() == OsmPoint.Group.BUG) { } else if (point.getGroup() == Group.BUG) {
OsmNotesPoint p = (OsmNotesPoint) point; OsmNotesPoint p = (OsmNotesPoint) point;
if (p.getAction() == a) { if (p.getAction() == a) {
sz.startTag("", "note"); sz.startTag("", "note");