Merge branch 'master' of github.com:osmandapp/Osmand
|
@ -29,6 +29,7 @@ public class RenderingRuleStorageProperties {
|
|||
public static final String SHIELD = "shield";
|
||||
public static final String SHADOW_RADIUS = "shadowRadius";
|
||||
public static final String SHADOW_COLOR = "shadowColor";
|
||||
public static final String ONEWAY_ARROWS_COLOR = "onewayArrowsColor";
|
||||
public static final String SHADER = "shader";
|
||||
public static final String CAP_5 = "cap_5";
|
||||
public static final String CAP_4 = "cap_4";
|
||||
|
@ -103,6 +104,7 @@ public class RenderingRuleStorageProperties {
|
|||
public RenderingRuleProperty R_SHADOW_RADIUS;
|
||||
public RenderingRuleProperty R_SHADOW_COLOR;
|
||||
public RenderingRuleProperty R_SHADER;
|
||||
public RenderingRuleProperty R_ONEWAY_ARROWS_COLOR;
|
||||
public RenderingRuleProperty R_CAP_5;
|
||||
public RenderingRuleProperty R_CAP_4;
|
||||
public RenderingRuleProperty R_CAP_3;
|
||||
|
@ -288,6 +290,8 @@ public class RenderingRuleStorageProperties {
|
|||
|
||||
R_SHADOW_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(SHADOW_COLOR));
|
||||
R_SHADOW_RADIUS = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(SHADOW_RADIUS));
|
||||
|
||||
R_ONEWAY_ARROWS_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(ONEWAY_ARROWS_COLOR));
|
||||
}
|
||||
|
||||
public RenderingRuleProperty get(String name) {
|
||||
|
|
|
@ -30,6 +30,19 @@
|
|||
<string name="osm_live_subscription">OSM Live subscription</string>
|
||||
<string name="osm_live_subscribe_btn">Subscribe</string>
|
||||
<string name="osm_live_default_price">€1,49</string>
|
||||
<string name="osm_live_email_desc">We need it to provide you information about contributions</string>
|
||||
<string name="osm_live_user_public_name">Public Name</string>
|
||||
<string name="osm_live_hide_user_name">Don\'t show my name in reports</string>
|
||||
<string name="osm_live_support_region">Support region</string>
|
||||
<string name="osm_live_month_cost">Month cost</string>
|
||||
<string name="osm_live_month_cost_desc">Monthly payment</string>
|
||||
<string name="osm_live_active">Active</string>
|
||||
<string name="osm_live_not_active">Inactive</string>
|
||||
<string name="osm_live_enter_email">Please enter valid E-mail address</string>
|
||||
<string name="osm_live_enter_user_name">Please enter Public Name</string>
|
||||
<string name="osm_live_thanks">Thank you for subscribing to live updates!</string>
|
||||
<string name="osm_live_region_desc">Part your donation will be sent to OSM users who submit changes to the map in that region</string>
|
||||
<string name="osm_live_subscription_settings">Subscription settings</string>
|
||||
|
||||
<string name="osm_live_header">This subscription enables hourly updates for all maps around the world.
|
||||
Major part of the income goes back to OSM community and is paid out per each OSM contribution.
|
||||
|
|
BIN
OsmAnd/res/drawable-hdpi/ic_action_startpoint.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
OsmAnd/res/drawable-hdpi/ic_action_waypoint.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAnd/res/drawable-mdpi/ic_action_startpoint.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
OsmAnd/res/drawable-mdpi/ic_action_waypoint.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAnd/res/drawable-xhdpi/ic_action_startpoint.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAnd/res/drawable-xhdpi/ic_action_waypoint.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
OsmAnd/res/drawable-xxhdpi/ic_action_startpoint.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAnd/res/drawable-xxhdpi/ic_action_waypoint.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
14
OsmAnd/res/drawable/bg_card_orange.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<nine-patch android:src="@drawable/bg_card_shadow" />
|
||||
</item>
|
||||
<item>
|
||||
<shape>
|
||||
<solid
|
||||
android:color="@color/osmand_orange" />
|
||||
<corners
|
||||
android:radius="2dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
13
OsmAnd/res/drawable/btn_round_blue.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="true"><shape android:shape="rectangle">
|
||||
<solid android:color="@color/map_widget_blue_pressed" />
|
||||
<corners android:radius="@dimen/map_button_rect_rad" />
|
||||
</shape></item>
|
||||
<item><shape android:shape="rectangle">
|
||||
<solid android:color="@color/map_widget_blue" />
|
||||
<corners android:radius="@dimen/map_button_rect_rad" />
|
||||
</shape></item>
|
||||
|
||||
</selector>
|
13
OsmAnd/res/drawable/btn_round_shade.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="true"><shape android:shape="rectangle">
|
||||
<solid android:color="@color/map_widget_dark_pressed" />
|
||||
<corners android:radius="@dimen/map_button_rect_rad" />
|
||||
</shape></item>
|
||||
<item><shape android:shape="rectangle">
|
||||
<solid android:color="@color/fab_color_pressed" />
|
||||
<corners android:radius="@dimen/map_button_rect_rad" />
|
||||
</shape></item>
|
||||
|
||||
</selector>
|
|
@ -62,7 +62,7 @@
|
|||
layout="@layout/reports_for_spinner_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_gravity="fill_vertical"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="56dp"/>
|
||||
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:orientation="vertical">
|
||||
android:paddingTop="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/subscription_banner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/osmand_orange"
|
||||
android:background="@drawable/bg_card_orange"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingLeft="24dp"
|
||||
|
@ -22,24 +22,26 @@
|
|||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_action_osm_live"/>
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_action_osm_live"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="@string/osm_live_subscription"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
android:textStyle="bold"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
</LinearLayout>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/osm_live_subscription"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
android:textStyle="bold"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
</LinearLayout>
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -51,27 +53,28 @@
|
|||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:gravity="right"
|
||||
android:layout_marginTop="16dp">
|
||||
<Button
|
||||
android:id="@+id/read_more_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/color_white"
|
||||
android:background="@drawable/btn_round_transparent"
|
||||
android:text="@string/shared_string_read_more"/>
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="right">
|
||||
|
||||
<Button
|
||||
android:id="@+id/subscription_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="32dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:background="@drawable/btn_round_transparent"
|
||||
android:text="@string/osm_live_subscribe_btn"/>
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/read_more_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_round_shade"
|
||||
android:text="@string/shared_string_read_more"
|
||||
android:textColor="@color/color_white"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/subscription_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="32dp"
|
||||
android:background="@drawable/btn_round_shade"
|
||||
android:text="@string/osm_live_subscribe_btn"
|
||||
android:textColor="@color/color_white"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -85,31 +88,54 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minHeight="44dp">
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="64dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="120dp"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="@string/osm_live_subscription"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
android:orientation="vertical">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="@string/shared_string_status"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/statusTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/osm_live_active"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size_large"
|
||||
app:typeface="@string/font_roboto_medium"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Active"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:textAllCapsCompat="true"
|
||||
app:typeface="@string/font_roboto_medium"/>
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="right|center_vertical"
|
||||
android:layout_marginRight="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/statusIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_action_done"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
|
@ -121,7 +147,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minHeight="44dp">
|
||||
android:minHeight="48dp">
|
||||
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
|
@ -129,93 +155,23 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="Support country"
|
||||
android:text="@string/osm_live_support_region"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/regionTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="right"
|
||||
android:text="World"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_medium"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/dashboard_divider"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minHeight="44dp">
|
||||
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="Email"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="my@email.com"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_medium"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/dashboard_divider"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minHeight="44dp">
|
||||
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="Visible Name"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="None"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
app:typeface="@string/font_roboto_medium"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -225,36 +181,23 @@
|
|||
android:layout_height="1dp"
|
||||
android:background="?attr/dashboard_divider"/>
|
||||
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minHeight="44dp">
|
||||
android:gravity="right|center_vertical"
|
||||
android:minHeight="48dp">
|
||||
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="120dp"
|
||||
<Button
|
||||
android:id="@+id/subscribeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="Last pay"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="25 Nov 2015"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_medium"/>
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:text="@string/osm_live_subscribe_btn"
|
||||
android:textColor="?attr/color_dialog_buttons"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
11
OsmAnd/res/layout/osmand_simple_list_item_1.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="@dimen/list_content_padding"
|
||||
android:paddingEnd="@dimen/list_content_padding"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall" />
|
|
@ -5,7 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:background="@android:drawable/list_selector_background">
|
||||
android:background="?attr/expandable_list_item_background">
|
||||
|
||||
<TextView
|
||||
android:text="@string/reports_for"
|
||||
|
|
|
@ -16,15 +16,16 @@
|
|||
<ImageButton
|
||||
android:id="@+id/closeButton"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:src="@drawable/ic_action_remove_dark"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/titleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:text="Subscription form"
|
||||
android:text="@string/osm_live_subscription"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/default_list_text_size_large"
|
||||
android:textStyle="bold"
|
||||
|
@ -34,191 +35,246 @@
|
|||
|
||||
<include layout="@layout/shadow_bottom"/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="56dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/emailIcon"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_action_message"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/emailEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:hint="E-mail address"
|
||||
android:inputType="textEmailAddress"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="72dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="We need it to provide you information about contributions"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
|
||||
|
||||
|
||||
<LinearLayout
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="56dp"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/userNameIcon"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_person"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="56dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/userNameEdit"
|
||||
<ImageView
|
||||
android:id="@+id/emailIcon"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_action_message"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/emailEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:hint="@string/shared_string_email_address"
|
||||
android:inputType="textEmailAddress"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:layout_marginLeft="72dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:hint="Public Name"
|
||||
android:inputType="text"/>
|
||||
android:text="@string/osm_live_email_desc"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
<CheckBox
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_marginLeft="72dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Don't show my name in reports"
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="56dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/countryIcon"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_world_globe_dark"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="56dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.AutoCompleteTextViewEx
|
||||
android:id="@+id/selectCountryEdit"
|
||||
android:layout_width="fill_parent"
|
||||
<ImageView
|
||||
android:id="@+id/userNameIcon"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_person"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/userNameEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:hint="@string/osm_live_user_public_name"
|
||||
android:inputType="text"/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/hideUserNameCheckbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_marginLeft="72dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:text="@string/osm_live_hide_user_name"
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:minHeight="56dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/countryIcon"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_world_globe_dark"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="2dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:text="@string/osm_live_support_region"/>
|
||||
|
||||
<net.osmand.plus.widgets.AutoCompleteTextViewEx
|
||||
android:id="@+id/selectCountryEdit"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="0dp"
|
||||
android:drawableRight="@drawable/ic_action_arrow_drop_down"
|
||||
android:editable="false"
|
||||
android:text="Ukraine"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="2dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:text="@string/osm_live_region_desc"/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/editModeBottomView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/saveChangesButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="72dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:background="@drawable/btn_round_blue"
|
||||
android:text="@string/shared_string_save_changes"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/purchaseCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:background="?attr/bg_card"
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/osm_live_month_cost"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size_large"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/priceTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:gravity="right"
|
||||
android:text="@string/osm_live_default_price"
|
||||
android:textColor="?attr/color_dialog_buttons"
|
||||
android:textSize="@dimen/default_list_text_size_large"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:hint="Support region"
|
||||
android:drawableRight="@drawable/ic_action_arrow_drop_down"
|
||||
android:editable="false"/>
|
||||
android:text="@string/osm_live_month_cost_desc"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="?attr/divider_color"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/subscribeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:text="@string/osm_live_subscribe_btn"
|
||||
android:textColor="?attr/color_dialog_buttons"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:background="?attr/bg_card"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Month cost"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size_large"
|
||||
android:textStyle="bold"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/priceTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:text="@string/osm_live_default_price"
|
||||
android:textColor="?attr/color_dialog_buttons"
|
||||
android:textSize="@dimen/default_list_text_size_large"
|
||||
android:textStyle="bold"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:text="Monthly payment"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
app:typeface="@string/font_roboto_regular"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="?attr/divider_color"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/subscribeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:text="Subscribe"
|
||||
android:textColor="?attr/color_dialog_buttons"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -2057,4 +2057,6 @@
|
|||
<string name="clear_updates_proposition_message">Можете да премахнете свалените актуализации и да възстановите оригиналната карта</string>
|
||||
<string name="add_time_span">Добавете времеви интервал</string>
|
||||
<string name="shared_string_remove">Премахване</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Скрий подземните обекти</string>
|
||||
<string name="shared_string_read_more">Прочети още</string>
|
||||
</resources>
|
||||
|
|
|
@ -2092,4 +2092,7 @@
|
|||
<string name="poi_protected_area">Àrea protegida</string>
|
||||
<string name="poi_fair_trade_no">Comerç just: no</string>
|
||||
<string name="poi_fair_trade_yes">Comerç just: sí</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_earth_moving">Motiu de l\'explosió: aplicació industrial, moviment de terres</string>
|
||||
<string name="poi_nuclear_explosion_time_utc">Hora de la explosió (UTC)</string>
|
||||
<string name="poi_nuclear_explosion_hole">Cràter de l\'explosió</string>
|
||||
</resources>
|
||||
|
|
|
@ -1917,9 +1917,12 @@ Per retornar a l\'estil habitual dels mapes d\'OsmAnd, només cal desactivar aqu
|
|||
<string name="select_month_and_country">Seleccioneu el mes i el país</string>
|
||||
<string name="number_of_contributors">Nombre de col·laboradors</string>
|
||||
<string name="number_of_edits">Nombre d\'edicions</string>
|
||||
<string name="reports_for">Informe per:</string>
|
||||
<string name="reports_for">Informe per</string>
|
||||
<string name="shared_string_select">Selecciona</string>
|
||||
<string name="shared_string_remove">Esborra</string>
|
||||
<string name="clear_updates_proposition_message">Podeu esborrar les actualitzacions baixades i tornar a l\'edició original del mapa</string>
|
||||
<string name="road_blocked">Via tallada</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Amaga elements soterrats</string>
|
||||
<string name="data_is_not_available">No es disposa de dades</string>
|
||||
<string name="shared_string_read_more">Llegeix més</string>
|
||||
</resources>
|
||||
|
|
|
@ -1925,4 +1925,5 @@
|
|||
<string name="number_of_edits">Počet úprav</string>
|
||||
<string name="reports_for">Report za</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Skrýt objekty v pozadí</string>
|
||||
<string name="shared_string_email_address">Email</string>
|
||||
</resources>
|
||||
|
|
|
@ -2678,19 +2678,19 @@
|
|||
<string name="poi_nuclear_explosion_shot_name_en">Shot navnet (en)</string>
|
||||
<string name="poi_nuclear_explosion_series">Eksplosionsserie</string>
|
||||
<string name="poi_nuclear_explosion_purpose_nuclear_weapons_related">Eksplosionsformål: atomvåben relateret</string>
|
||||
<string name="poi_nuclear_explosion_purpose_weapons_effects">Eksplosionsformål: våben effekt</string>
|
||||
<string name="poi_nuclear_explosion_purpose_weapons_effects">Eksplosionsformål: våbeneffekt</string>
|
||||
<string name="poi_nuclear_explosion_purpose_safety_experiment">Eksplosionsformål: sikkerhedseksperiment</string>
|
||||
<string name="poi_nuclear_explosion_purpose_research_for_peaceful_applications">Eksplosionsformål: forskning for fredelige anvendelser</string>
|
||||
<string name="poi_nuclear_explosion_purpose_fundamental_science">Eksplosionsformål: grundlæggende videnskab</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_cavity_excavation">Eksplosionsformål: industriel anvendelse, hulrum udgravning</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_cavity_excavation">Eksplosionsformål: industriel anvendelse, udgravning af hulrum</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_seismic_sounding">Eksplosionsformål: industriel anvendelse, seismiske pejlinger</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_oil_stimulation">Eksplosionsformål: industriel anvendelse, olie stimulation</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_oil_stimulation">Eksplosionsformål: industriel anvendelse, oliestimulering</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application">Eksplosionsformål: industriel anvendelse</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_earth_moving">Eksplosionsformål: industriel anvendelse, jordflytning</string>
|
||||
<string name="poi_nuclear_explosion_time_utc">Eksplosionstidpunkt (UTC)</string>
|
||||
<string name="poi_nuclear_explosion_yield">Eksplosion udbytte</string>
|
||||
<string name="poi_nuclear_explosion_hole">Eksplosion hul</string>
|
||||
<string name="poi_nuclear_explosion_height_of_burst">Højden af eksplosionen</string>
|
||||
<string name="poi_nuclear_explosion_hole">Eksplosionshul</string>
|
||||
<string name="poi_nuclear_explosion_height_of_burst">Eksplosionenshøjde</string>
|
||||
<string name="poi_nuclear_explosion_ground_zero_altitude">Jordoverfladenshøjde</string>
|
||||
<string name="poi_nuclear_explosion_body_wave_magnitude">bølge størrelsesorden</string>
|
||||
<string name="poi_nuclear_explosion_salvo_first_detonation">Eksplosionssalve: første detonation af en salvetest</string>
|
||||
|
@ -2699,4 +2699,8 @@
|
|||
<string name="poi_nuclear_explosion_warhead">Eksplosion: sprænghoved</string>
|
||||
<string name="poi_nuclear_explosion_device">Eksplosion: enhed</string>
|
||||
|
||||
<string name="poi_addr_housename">Huset navn</string>
|
||||
|
||||
<string name="poi_religion">Religiøse varer</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1535,7 +1535,7 @@
|
|||
<string name="rendering_attr_showAccess_name">Vis adgangsbegrænsninger</string>
|
||||
<string name="rendering_attr_showSurfaceGrade_name">Vis vejkvaliteten</string>
|
||||
<string name="rendering_attr_showSurfaces_name">Vis vejbelægning</string>
|
||||
<string name="rendering_attr_showCycleRoutes_name">Vis cykelruter</string>
|
||||
<string name="rendering_attr_showCycleRoutes_name">Cykelruter</string>
|
||||
<string name="local_map_names">Lokale navne</string>
|
||||
<string name="lang_sw">Swahili</string>
|
||||
<string name="lang_he">Hebræisk</string>
|
||||
|
@ -2237,4 +2237,34 @@
|
|||
<string name="shared_string_remove">Fjern</string>
|
||||
<string name="data_is_not_available">Data er ikke tilgængelig</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Skjul underjordiske objekter</string>
|
||||
<string name="shared_string_read_more">Læs mere</string>
|
||||
<string name="osmand_plus_extended_description_4000_chars_v2">" OsmAnd Maps & Navigation - lav ruter og find steder på kortet uden en internetforbindelse. Hent et kort for et land, før du går på en rejse til at finde steder og ruter i et ukendt område.
|
||||
\n\nGrundlæggende indstillinger:
|
||||
\n• Detaljerede kort over 200 lande
|
||||
\n• Offline navigator med stemmevejledning\n• Adressesøgning i offline mode
|
||||
\n• Info om steder på kortet: steder af interesse, caféer, parkeringspladser, butikker
|
||||
\n• Tlføj steder til foretrukne
|
||||
\n• Kørsel-, cykling- og fodgængernavigation
|
||||
\n\nYderligere indstillinger:
|
||||
\n• Mulighed for at vise og optage GPX spor\n• Wikipedia beskrivelse af IP\n• Tilføj foto-, audio-, og videonoter til kort
|
||||
\n• Dag- og natkort tilstand for mere praktisk kørsel
|
||||
\n• Oplysninger om offentlig transport og stoppesteder\n• Cykel- og gangstier
|
||||
\n• Vandreruter for turisme over hele verden
|
||||
\n• Online kort fra adskillige kilder
|
||||
\n• Info om vej- og fortovskvalitet og gadebelysning
|
||||
\n• Tilføj, rediger og sletning af IP (for OpenStreetMap.org brugere)
|
||||
\n• OsMo - live overvågning af andre enheder
|
||||
\n\nFå pålidelig navigation i dit land - enten det er Frankrig, Tyskland, Mexico, Storbritannien, Spanien, Holland, USA, Rusland, Brasilien eller et andet land.
|
||||
\n\nUdvidelser:
|
||||
\n• kontur kort og terræn skygge https://goo.gl/7mojP8 højdekurver data og terræn visualisering tilføjet til grundlæggende OsmAnd kortet.
|
||||
\n• Skikort info om skipister, langrendsløjper, tovbaner og skilifterne-https://goo.gl/pX6DxJ.
|
||||
\n• Søkort https://goo.gl/0hEdxm særlig kortstil til visning af nautiske navigation tegn for arteriel og offshore marine navigation.
|
||||
\n• Parkeringposition https://goo.gl/6JxQXF hjælper dig med at markere placeringen af din parkerede bil og se hvor meget tid tilbage, hvis parkering er tidsbegrænset.
|
||||
\n\nFølg med på!
|
||||
\nTwitter: https://twitter.com/osmandapp
|
||||
\nFacebook: https://www.facebook.com/osmandapp\nHjemmeside: http://osmand.net
|
||||
\n\nEr der brug for hjælp med OsmAnd, kontakt da supportteamet: support@osmand.net. "</string>
|
||||
<string name="shared_string_email_address">Email adresse</string>
|
||||
<string name="shared_string_status">Status</string>
|
||||
<string name="shared_string_save_changes">Gem ændringer</string>
|
||||
</resources>
|
||||
|
|
|
@ -2010,4 +2010,5 @@
|
|||
<string name="clear_updates_proposition_message">Kartenaktualisierungen können gelöscht werden um zur orginal Karte zurückzukehren</string>
|
||||
<string name="data_is_not_available">Daten nicht verfügbar</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Unterirdische Objekt verbergen</string>
|
||||
<string name="shared_string_read_more">Mehr lesen</string>
|
||||
</resources>
|
||||
|
|
|
@ -2671,4 +2671,7 @@
|
|||
<string name="poi_nuclear_explosion_yield">Rendimiento de la explosión</string>
|
||||
<string name="poi_nuclear_explosion_salvo_first_detonation">Explosión de salva: Primera detonación de prueba</string>
|
||||
<string name="poi_nuclear_explosion_salvo_second_or_later_detonation">Explosión de salva: Segunda o posterior detonación de prueba</string>
|
||||
</resources>
|
||||
<string name="poi_addr_housename">Nombre de casa</string>
|
||||
<string name="poi_religion">Artículos religiosos</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -2057,4 +2057,23 @@
|
|||
<string name="shared_string_remove">Quitar</string>
|
||||
<string name="data_is_not_available">Datos no disponibles</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Ocultar objetos subterráneos</string>
|
||||
<string name="shared_string_read_more">Leer más</string>
|
||||
<string name="osmand_plus_extended_description_4000_chars_v2">" OsmAnd Maps & Navigation (mapas y navegación de OsmAnd), crea rutas y encuentra ubicaciones en el mapa sin conectar con Internet. Descarga el mapa de un país antes de viajar para encontrar lugares y rutas en áreas desconocidas.\n\nOpciones básicas:\n• Mapas detallados en 200 países\n• Navegación sin conexión con avisos de voz\n• Búsqueda de direcciones en modo sin conexión\n• Información sobre ubicaciones en el mapa: lugares de interés, cafés, estacionamientos, tiendas\n• Añada sus ubicaciones a los favoritos\n• Navegación en automóvil, bicicleta y caminando\n\nOpciones adicionales:\n• Capacidad para ver y grabar trazas GPX\n• Descripción de Wikipedia en PDI
|
||||
\n• Añada notas de fotos, audios y videos en el mapa
|
||||
\n• Modo de mapa Día y Noche para una conducción más cómoda\n• Información sobre rutas y paradas de transporte público
|
||||
\n• Rutas de ciclovías y senderos
|
||||
\n• Rutas de senderos para el turismo en todo el mundo\n• Mapas en línea de numerosas fuentes
|
||||
\n• Información sobre la calidad del pavimento y el alumbrado público
|
||||
\n• Añada, edite y quite PDI (para usuarios de OpenStreetMap.org)
|
||||
\n• OsMo - monitorice en vivo otros dispositivos.
|
||||
\n• Obtén un navegador confiable en su país - ya sea Francia, Alemania, México, Reino Unido, España, los Países Bajos, EUA, Rusia, Brasil o cualquier otro estado.
|
||||
\n\nComplementos:
|
||||
\n• Mapas de curvas de nivel y sombreado del terreno: https://goo.gl/7mojP8 Datos de curvas de nivel y visualización del terreno se agrega al mapa básico de OsmAnd.
|
||||
\n• Mapa invernal: https://goo.gl/pX6DxJ Información sobre pistas de esquí, pistas de esquí de fondo, teleféricos y telesillas.
|
||||
\n• Mapa náutico: https://goo.gl/0hEdxm Estilo especial del mapa para la visualización de señales de navegación náutica y costera.
|
||||
\n• Estacionamiento: https://goo.gl/6JxQXF Ayuda a marcar la ubicación de su vehículo estacionado y ver cuánto tiempo falta si el estacionamiento es limitado.
|
||||
\n\n¡Manténgase al tanto!\nTwitter: https://twitter.com/osmandapp
|
||||
\nFacebook: https://www.facebook.com/osmandapp
|
||||
\nSitio web: http://osmand.net
|
||||
\nSi necesita ayuda con la aplicación OsmAnd, contacte con nuestro equipo de soporte: support@osmand.net. "</string>
|
||||
</resources>
|
||||
|
|
|
@ -2665,4 +2665,7 @@
|
|||
<string name="poi_nuclear_explosion_warhead">Explosión: ojiva</string>
|
||||
<string name="poi_nuclear_explosion_device">Explosión: dispositivo</string>
|
||||
|
||||
<string name="poi_addr_housename">Nombre de la casa</string>
|
||||
<string name="poi_religion">Artículos religiosos</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -2056,4 +2056,7 @@
|
|||
<string name="reports_for">Informe para</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Ocultar objetos subterráneos</string>
|
||||
<string name="data_is_not_available">No hay datos disponibles</string>
|
||||
<string name="shared_string_read_more">Leer más</string>
|
||||
<string name="osmand_plus_extended_description_4000_chars_v2">" OsmAnd Mapas y Navegación - prepara rutas y encuentra ubicaciones en el mapa sin una conexión a Internet. Descarga un mapa de un país antes de que viajes para encontrar sitios y rutas en un área que no te sea familiar. Opciones básicas: • Mapas detallados de 200 países • Navegador fuera de línea con avisos de voz • Búsqueda de direcciones en modo sin conexión • Información sobre ubicaciones en el mapa: sitios de interés, cafeterías, aparcamientos, tiendas • Añadir ubicaciones a tus favoritos • Opciones adicionales de navegación en modos Conducción, Ciclismo y Pedestre : • Capacidad de ver y grabar trazas GPX • Descripciones de Wikipedia de los PDI • Añadir notas de foto, audio y vídeo al mapa • Modos de mapa Día y Noche para una conducción más conveniente • Información sobre rutas y paradas de transporte público • Vías ciclistas y caminos • Vías de senderismo para hacer turismo en todo el mundo • Mapas en línea de numerosas fuentes • Información sobre calidad del pavimento e iluminación de las y las calles • Añadir, editar y eliminar PDI (para usuarios deOpenstreetmap.org) • OsMo - monitorización de directo de otros dispositivos Consigue un explorador fiable en tu país - ya sea Francia, Alemania, México, Reino Unido, España, Holanda, EE.UU., Rusia, Brasil o cualquiera otro estado. Extras: • Mapas de contorno y sombreado del terreno https://goo.gl/7mojP8 Datos de curvas de nivel y visualización de terreno añadidos al mapa básico OsmAnd . • Mapas de esquí https://goo.gl/pX6DxJ La información sobre pistas de esquí, pistas de esquí de fondo, telecabinas y ascensores de esquí. • Mapa náutico https://goo.gl/0hEdxm Estilo de mapa especial para ver señales de navegación náutica para arteriales y navegación costera. • Posición de aparcamiento https://goo.gl/6jxQXF Te ayuda a marcar la ubicación de tu vehículo aparcado y ver cuánto tiempo queda si el aparcamiento es por tiempo limitado. ¡Mantente informado! Twitter: https://twitter.com/osmandapp Facebook: https://www.facebook.com/osmandapp Sitio: http://osmand.net Si necesitas ayuda con la aplicación OsmAnd, por favor contacta con nuestro equipo de soporte: support@osmand.net. "</string>
|
||||
<string name="shared_string_email_address">Dirección de correo electrónico</string>
|
||||
</resources>
|
||||
|
|
|
@ -2122,4 +2122,9 @@
|
|||
<string name="road_blocked">Route barrée</string>
|
||||
<string name="add_time_span">Ajouter un laps de temps</string>
|
||||
<string name="data_is_not_available">Donnée indisponible</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Cacher les objets souterrains</string>
|
||||
<string name="shared_string_read_more">Lire la suite</string>
|
||||
<string name="shared_string_email_address">Adresse email</string>
|
||||
<string name="shared_string_status">Statut</string>
|
||||
<string name="shared_string_save_changes">Enregistrer les modifications</string>
|
||||
</resources>
|
||||
|
|
|
@ -2143,10 +2143,13 @@
|
|||
<string name="number_of_edits">Numero di modifiche</string>
|
||||
<string name="number_of_contributors">Numero di contributori</string>
|
||||
<string name="shared_string_select">Scegli</string>
|
||||
<string name="reports_for">Rapporto per:</string>
|
||||
<string name="reports_for">Rapporto per</string>
|
||||
<string name="shared_string_remove">Rimuovi</string>
|
||||
<string name="clear_updates_proposition_message">Puoi eliminare gli aggiornamenti scaricati e avere la mappa originale</string>
|
||||
<string name="road_blocked">Strada bloccata</string>
|
||||
<string name="add_time_span">Aggiungi durata</string>
|
||||
<string name="data_is_not_available">Il dato non è disponibile</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Nascondi gli oggetti sotterranei</string>
|
||||
<string name="shared_string_read_more">Approfondisci</string>
|
||||
<string name="shared_string_email_address">Indirizzo email</string>
|
||||
</resources>
|
||||
|
|
|
@ -2175,4 +2175,5 @@
|
|||
<string name="reports_for">Verslag voor:</string>
|
||||
<string name="data_is_not_available">Gegevens niet beschikbaar</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Verberg ondergrondse objecten</string>
|
||||
<string name="shared_string_read_more">Lees meer...</string>
|
||||
</resources>
|
||||
|
|
|
@ -303,7 +303,7 @@
|
|||
|
||||
<string name="error_occurred_loading_gpx">Wystąpił błąd podczas wczytywania GPX</string>
|
||||
<string name="send_report">Wyślij zgłoszenie</string>
|
||||
<string name="none_region_found">Brak danych offline na karcie SD. Pobierz je z Internetu.</string>
|
||||
<string name="none_region_found">Brak danych offline na karcie SD. Proszę pobrać je z sieci.</string>
|
||||
<string name="poi_namefinder_query_empty">Wprowadź zapytanie by znaleźć POI</string>
|
||||
<string name="any_poi">Jakiekolwiek</string>
|
||||
<string name="layer_transport_route">Trasa transportu publicznego</string>
|
||||
|
@ -2069,7 +2069,7 @@
|
|||
<string name="updates_size">Aktualizacje: %s</string>
|
||||
<string name="last_map_change">Ostatnia zmiana mapy: %s</string>
|
||||
<string name="rec_split_clip_length">Długość nagrania</string>
|
||||
<string name="shared_string_not_selected">Nie wybrane</string>
|
||||
<string name="shared_string_not_selected">Nie wybrany</string>
|
||||
<string name="item_removed">Pozycja usunięta</string>
|
||||
<string name="n_items_removed">Pozycje usunięta</string>
|
||||
<string name="shared_string_undo_all">COFNIJ WSZYSTKO</string>
|
||||
|
@ -2090,4 +2090,6 @@
|
|||
<string name="number_of_edits">Liczba edycji</string>
|
||||
<string name="reports_for">Raport dla</string>
|
||||
<string name="number_of_contributors">Liczba współtwórców</string>
|
||||
<string name="shared_string_read_more">Przeczytaj więcej</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Ukrycie podziemnych obiektów</string>
|
||||
</resources>
|
||||
|
|
|
@ -2626,4 +2626,48 @@
|
|||
<string name="poi_protection_object_habitat">Objeto de proteção: habitat</string>
|
||||
<string name="poi_protection_object_water">Objeto de proteção: água</string>
|
||||
|
||||
<string name="poi_nuclear_explosion_country">Explosão: país</string>
|
||||
<string name="poi_nuclear_explosion_site">Explosão: local</string>
|
||||
<string name="poi_nuclear_explosion_type_underground_shaft">Tipo de explosão: subterrânea, escavação</string>
|
||||
<string name="poi_nuclear_explosion_type_underground_tunnel">Tipo de explosão: subterrânea, túnel</string>
|
||||
<string name="poi_nuclear_explosion_type_atmospheric">Tipo de explosão: atmosférica</string>
|
||||
<string name="poi_nuclear_explosion_type_atmospheric_airdrop">Tipo de explosão: atmosférica, lançamento aéreo</string>
|
||||
<string name="poi_nuclear_explosion_type_atmospheric_surface_tower">Tipo de explosão: atmosférica, superfície, torre</string>
|
||||
<string name="poi_nuclear_explosion_type_atmospheric_balloon">Tipo de explosão: atmosférica, balão</string>
|
||||
<string name="poi_nuclear_explosion_type_atmospheric_atmospheric_surface">Tipo de explosão: atmosférica, superfície</string>
|
||||
<string name="poi_nuclear_explosion_type_atmospheric_water_surface_barge">Tipo de explosão: atmosférica, superfície d\'água, barca</string>
|
||||
<string name="poi_nuclear_explosion_type_underground">Tipo de explosão: subterrânea</string>
|
||||
<string name="poi_nuclear_explosion_type_cratering_burst">Tipo de explosão: erupção de cratera (subsolo raso)</string>
|
||||
<string name="poi_nuclear_explosion_type_atmospheric_rocket_or_missile">Tipo de explosão: atmosférica, foguete ou míssil</string>
|
||||
<string name="poi_nuclear_explosion_type_space">Tipo de explosão: espacial (mais de 80 km de altitude)</string>
|
||||
<string name="poi_nuclear_explosion_type_underwater">Tipo de explosão: subaquática</string>
|
||||
<string name="poi_nuclear_explosion_date_utc">Data da explosão (UTC)</string>
|
||||
<string name="poi_nuclear_explosion_shot_name_en">Nome do disparo (en)</string>
|
||||
<string name="poi_nuclear_explosion_series">Série de explosões</string>
|
||||
<string name="poi_nuclear_explosion_purpose_nuclear_weapons_related">Propósito da explosão: relacionado com armas nucleares</string>
|
||||
<string name="poi_nuclear_explosion_purpose_weapons_effects">Propósito da explosão: efeito das armas</string>
|
||||
<string name="poi_nuclear_explosion_purpose_safety_experiment">Propósito da explosão: experimento de segurança</string>
|
||||
<string name="poi_nuclear_explosion_purpose_research_for_peaceful_applications">Propósito da explosão: investigação para aplicações pacíficas</string>
|
||||
<string name="poi_nuclear_explosion_purpose_fundamental_science">Propósito da explosão: ciência básica</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_cavity_excavation">Propósito da explosão: aplicação industrial, escavação de cavidade</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_seismic_sounding">Propósito da explosão: aplicação industrial, sondagem sísmica</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_oil_stimulation">Propósito da explosão: aplicação industrial, estimulação de petróleo</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application">Propósito da explosão: aplicação industrial</string>
|
||||
<string name="poi_nuclear_explosion_purpose_industrial_application_earth_moving">Propósito da explosão: aplicação industrial, movimentação de terra</string>
|
||||
<string name="poi_nuclear_explosion_time_utc">Hora da explosão (UTC)</string>
|
||||
<string name="poi_nuclear_explosion_yield">Produto da explosão</string>
|
||||
<string name="poi_nuclear_explosion_hole">Buraco da explosão</string>
|
||||
<string name="poi_nuclear_explosion_height_of_burst">Altura da erupção</string>
|
||||
<string name="poi_nuclear_explosion_ground_zero_altitude">Altitude do marco zero</string>
|
||||
<string name="poi_nuclear_explosion_body_wave_magnitude">Magnitude da conda do corpo</string>
|
||||
<string name="poi_nuclear_explosion_salvo_first_detonation">Salva de explosão: primeira detonação de um teste de salva</string>
|
||||
<string name="poi_nuclear_explosion_salvo_second_or_later_detonation">Salva de explosão: segunda ou posterior detonação de um teste de salva</string>
|
||||
<string name="poi_nuclear_explosion_crater_diameter">Explosão: diâmetro de cratera</string>
|
||||
<string name="poi_nuclear_explosion_warhead">Explosão: ogiva</string>
|
||||
<string name="poi_nuclear_explosion_device">Explosão: dispositivo</string>
|
||||
|
||||
<string name="poi_addr_housename">Complemento</string>
|
||||
|
||||
<string name="poi_religion">Artigos religiosos</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -2640,4 +2640,7 @@
|
|||
<string name="poi_nuclear_explosion_warhead">Боеголовка</string>
|
||||
<string name="poi_nuclear_explosion_device">Устройство</string>
|
||||
|
||||
<string name="poi_addr_housename">Название дома</string>
|
||||
<string name="poi_religion">Религиозный магазин</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -714,7 +714,7 @@
|
|||
<string name="left_side_navigation">Ghia a manca</string>
|
||||
<string name="left_side_navigation_descr">Abìlita in sos istados in ue si ghiat mantenende sa manca</string>
|
||||
<string name="unknown_from_location">Sa positzione de tzucada no est istada galu determinata</string>
|
||||
<string name="unknown_location">Positzione calu non connota</string>
|
||||
<string name="unknown_location">Positzione galu disconnota</string>
|
||||
<string name="modify_transparency">Muda sa trasparèntzia (0 - trasparente, 255 - annapau)</string>
|
||||
<string name="confirm_interrupt_download">Boles firmare s’isgarrigamentu de sos documentos?</string>
|
||||
<string name="local_indexes_cat_tile">Mapas in lìnia e in cache a tasseddos</string>
|
||||
|
@ -2094,4 +2094,5 @@
|
|||
<string name="road_blocked">Àndala blocada</string>
|
||||
<string name="shared_string_select">Ischerta</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Cua ogetos suta de terra</string>
|
||||
<string name="shared_string_read_more">Leghe àteru</string>
|
||||
</resources>
|
||||
|
|
|
@ -2076,4 +2076,7 @@
|
|||
<string name="road_blocked">Blockerad väg</string>
|
||||
<string name="data_is_not_available">Inga data tillgängliga</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Dölj underjordiska objekt</string>
|
||||
<string name="shared_string_read_more">Läs mer</string>
|
||||
<string name="rec_split_storage_size">Lagringsutrymme</string>
|
||||
<string name="shared_string_email_address">E-postadress</string>
|
||||
</resources>
|
||||
|
|
|
@ -2641,4 +2641,7 @@
|
|||
<string name="poi_nuclear_explosion_warhead">Explosion: warhead</string>
|
||||
<string name="poi_nuclear_explosion_device">Explosion: device</string>
|
||||
|
||||
<string name="poi_addr_housename">House name</string>
|
||||
<string name="poi_religion">Religious goods</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -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
|
||||
-->
|
||||
<string name="shared_string_status">Status</string>
|
||||
<string name="shared_string_save_changes">Save changes</string>
|
||||
<string name="shared_string_email_address">E-mail address</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Hide underground objects</string>
|
||||
<string name="data_is_not_available">Data is not available</string>
|
||||
<string name="shared_string_remove">Remove</string>
|
||||
|
@ -1287,6 +1290,53 @@ Approximate map coverage and quality:
|
|||
List of countries supported (basically world wide!):
|
||||
Afghanistan, Albania, Algeria, Andorra, Angola, Anguilla, Antigua and Barbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, Bolivia, Bonaire, Bosnia and Herzegovina, Botswana, Brazil, British Virgin Islands, Brunei, Bulgaria, Burkina Faso, Burundi, Cambodia, Cameroon, Canada, Cape Verde, Central African Republic, Chad, Chile, China, Colombia, Comoros, Congo, Costa Rica, Ivory Coast, Croatia, Cuba, Curaçao, Cyprus, Czech Republic, Denmark, Djibouti, Dominica, Dominican Republic, Ecuador, Egypt, El Salvador, Equatorial Guinea, Eritrea, Estonia, Ethiopia, Fiji, Finland, France, French Guiana, French Polynesia, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, Guinea-Bissau, Guyana, Haiti, Vatican, Honduras, Hong Kong, Hungary, Iceland, India, Indonesia, Iran, Iraq, Ireland, Isle of Man, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, North Korea and South Korea, Kuwait, Kyrgyzstan, Laos, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, Macedonia, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, Martinique, Mauritania, Mauritius, Mayotte, Mexico, Micronesia, Moldova, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, Netherlands Antilles, New Caledonia, New Zealand, Nicaragua, Niger, Nigeria, Norway, Oman, Pakistan, Palau, Palestinian Territory, Panama, Papua New Guinea, Paraguay, Peru, Philippines, Poland, Portugal, Puerto Rico, Qatar, Romania, Russia, Rwanda, Saint Barthelemy, Saint Helena, Saint Kitts and Nevis, Saint Lucia, Saint Martin, Saint Pierre and Miquelon, Saint Vincent and the Grenadines, Samoa, San Marino, Saudi Arabia, Senegal, Serbia, Seychelles, Sierra Leone, Singapore, Slovakia, Slovenia, Somalia, South Africa, South Georgia, South Sudan, Spain, Sri Lanka, Sudan, Suriname, Swaziland, Sweden, Switzerland, Syria, Taiwan, Tajikistan, Tanzania, Thailand, Timor-Leste, Togo, Tokelau, Tonga, Trinidad and Tobago, Tunisia, Turkey, Turkmenistan, Tuvalu, Uganda, Ukraine, United Arab Emirates, United Kingdom (UK), United States of America (USA), Uruguay, Uzbekistan, Vanuatu, Venezuela, Vietnam, Wallis and Futuna, Western Sahara, Yemen, Zambia, Zimbabwe.
|
||||
</string>
|
||||
<string name="osmand_plus_extended_description_4000_chars_v2">
|
||||
OsmAnd Maps & Navigation - make routes and find locations on the map without an internet connection. Download a map of a country before you go on a trip to find places and routes in an unfamiliar area.
|
||||
|
||||
Basic options:
|
||||
• Detailed maps of 200 countries
|
||||
• Offline navigator with voice prompts
|
||||
• Address search in offline mode
|
||||
• Info about locations on the map: places of interest, cafes, parking lots, shops
|
||||
• Adding locations to favorites
|
||||
• Driving, cycling and pedestrian navigation
|
||||
|
||||
Additional options:
|
||||
• Ability to view and record GPX tracks
|
||||
• Wikipedia description of POI
|
||||
• Adding photo, audio, and video notes to the map
|
||||
• Day and Night map modes for more convenient driving
|
||||
• Information about public transport routes and stops
|
||||
• Bicycle paths and footpaths
|
||||
• Walking trails for tourism all over the world
|
||||
• Online maps from numerous sources
|
||||
• Info about road pavement quality and street lighting
|
||||
• Adding, editing and deleting POI (for OpenStreetMap.org users)
|
||||
• OsMo - live monitoring of other devices
|
||||
|
||||
Get a reliable navigator in your country - be it France, Germany, Mexico, United Kingdom, Spain, the Netherlands, USA, Russia, Brazil or any other state.
|
||||
|
||||
Plugins:
|
||||
• Contour maps and terrain shading https://goo.gl/7mojP8
|
||||
Contour lines data and terrain visualization added to the basic OsmAnd map.
|
||||
|
||||
• Ski maps https://goo.gl/pX6DxJ
|
||||
The info about ski pistes, cross-country skiing tracks, cable railways and ski lifts.
|
||||
|
||||
• Nautical map https://goo.gl/0hEdxm
|
||||
Special map style for viewing nautical navigation signs for arterial and nearshore marine navigation.
|
||||
|
||||
• Parking position https://goo.gl/6JxQXF
|
||||
Helps you mark the location of your parked vehicle and see how much time left if the parking is time-limited.
|
||||
|
||||
Stay tuned!
|
||||
|
||||
Twitter: https://twitter.com/osmandapp
|
||||
Facebook: https://www.facebook.com/osmandapp
|
||||
Site: http://osmand.net
|
||||
|
||||
If you need help with OsmAnd application, please contact our support team: support@osmand.net.
|
||||
</string>
|
||||
<string name="filterpoi_activity">Create POI filter</string>
|
||||
<string name="recalculate_route_to_your_location">Transport mode:</string>
|
||||
<string name="select_navigation_mode">Select transport mode</string>
|
||||
|
|
147
OsmAnd/src/net/osmand/AndroidNetworkUtils.java
Normal file
|
@ -0,0 +1,147 @@
|
|||
package net.osmand;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.Version;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
|
||||
public class AndroidNetworkUtils {
|
||||
|
||||
public interface OnRequestResultListener {
|
||||
void onResult(String result);
|
||||
}
|
||||
|
||||
public static void sendRequestAsync(final OsmandApplication ctx,
|
||||
final String url,
|
||||
final Map<String, String> parameters,
|
||||
final String userOperation,
|
||||
final OnRequestResultListener listener) {
|
||||
|
||||
new AsyncTask<Void, Void, String>() {
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
try {
|
||||
return sendRequest(ctx, url, parameters, userOperation);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String response) {
|
||||
if (listener != null) {
|
||||
listener.onResult(response);
|
||||
}
|
||||
}
|
||||
|
||||
}.execute((Void) null);
|
||||
}
|
||||
|
||||
|
||||
public static String sendRequest(OsmandApplication ctx, String url, Map<String, String> parameters, String userOperation) {
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
connection = NetworkUtils.getHttpURLConnection(url);
|
||||
|
||||
connection.setRequestProperty("Accept-Charset", "UTF-8");
|
||||
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx));
|
||||
connection.setConnectTimeout(15000);
|
||||
|
||||
if (parameters != null && parameters.size() > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
||||
}
|
||||
String params = sb.toString();
|
||||
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
connection.setUseCaches(false);
|
||||
connection.setRequestMethod("POST");
|
||||
|
||||
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
|
||||
connection.setRequestProperty("Content-Length", String.valueOf(params.getBytes("UTF-8").length));
|
||||
connection.setFixedLengthStreamingMode(params.getBytes("UTF-8").length);
|
||||
|
||||
OutputStream output = new BufferedOutputStream(connection.getOutputStream());
|
||||
output.write(params.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
output.close();
|
||||
|
||||
} else {
|
||||
connection.setRequestMethod("GET");
|
||||
connection.connect();
|
||||
}
|
||||
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
String msg = userOperation
|
||||
+ " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage();
|
||||
showToast(ctx, msg);
|
||||
} else {
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
responseBody.setLength(0);
|
||||
InputStream i = connection.getInputStream();
|
||||
if (i != null) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(i, "UTF-8"), 256);
|
||||
String s;
|
||||
boolean f = true;
|
||||
while ((s = in.readLine()) != null) {
|
||||
if (!f) {
|
||||
responseBody.append("\n");
|
||||
} else {
|
||||
f = false;
|
||||
}
|
||||
responseBody.append(s);
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
i.close();
|
||||
} catch (Exception e) {
|
||||
// ignore exception
|
||||
}
|
||||
}
|
||||
return responseBody.toString();
|
||||
}
|
||||
|
||||
} catch (NullPointerException e) {
|
||||
// that's tricky case why NPE is thrown to fix that problem httpClient could be used
|
||||
String msg = ctx.getString(R.string.auth_failed);
|
||||
showToast(ctx, msg);
|
||||
} catch (MalformedURLException e) {
|
||||
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
|
||||
} catch (IOException e) {
|
||||
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation));
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void showToast(OsmandApplication ctx, String message) {
|
||||
ctx.showToastMessage(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -815,6 +815,10 @@ public class OsmandSettings {
|
|||
public final OsmandPreference<String> BILLING_USER_NAME = new StringPreference("billing_user_name", "").makeGlobal();
|
||||
public final OsmandPreference<String> BILLING_USER_EMAIL = new StringPreference("billing_user_email", "").makeGlobal();
|
||||
public final OsmandPreference<String> BILLING_USER_COUNTRY = new StringPreference("billing_user_country", "").makeGlobal();
|
||||
public final OsmandPreference<String> BILLING_USER_COUNTRY_DOWNLOAD_NAME = new StringPreference("billing_user_country_download_name", "").makeGlobal();
|
||||
public final OsmandPreference<Boolean> BILLING_HIDE_USER_NAME = new BooleanPreference("billing_hide_user_name", false).makeGlobal();
|
||||
public final OsmandPreference<Boolean> BILLING_PURCHASE_TOKEN_SENT = new BooleanPreference("billing_purchase_token_sent", false).makeGlobal();
|
||||
public final OsmandPreference<Boolean> LIVE_UPDATES_PURCHASED = new BooleanPreference("billing_live_updates_purchased", false).makeGlobal();
|
||||
|
||||
// this value string is synchronized with settings_pref.xml preference name
|
||||
public final OsmandPreference<String> USER_OSM_BUG_NAME =
|
||||
|
|
|
@ -5,7 +5,8 @@ import android.content.Intent;
|
|||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.Version;
|
||||
|
@ -13,33 +14,28 @@ import net.osmand.plus.inapp.util.IabHelper;
|
|||
import net.osmand.plus.inapp.util.IabResult;
|
||||
import net.osmand.plus.inapp.util.Inventory;
|
||||
import net.osmand.plus.inapp.util.Purchase;
|
||||
import net.osmand.plus.inapp.util.SkuDetails;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class InAppHelper {
|
||||
// Debug tag, for logging
|
||||
static final String TAG = "InAppHelper";
|
||||
boolean mDebugLog = false;
|
||||
|
||||
private static boolean mSubscribedToLiveUpdates = false;
|
||||
private static String mLiveUpdatesPrice;
|
||||
|
||||
public static final String SKU_LIVE_UPDATES = "osm_live_subscription_1";
|
||||
|
||||
// Static test
|
||||
//public static final String SKU_LIVE_UPDATES = "android.test.purchased";
|
||||
//public static final String SKU_LIVE_UPDATES = "android.test.canceled";
|
||||
//public static final String SKU_LIVE_UPDATES = "android.test.refunded";
|
||||
//public static final String SKU_LIVE_UPDATES = "android.test.item_unavailable";
|
||||
|
||||
private static final String SKU_LIVE_UPDATES_FULL = "osm_live_subscription_2";
|
||||
private static final String SKU_LIVE_UPDATES_FREE = "osm_free_live_subscription_2";
|
||||
private static String SKU_LIVE_UPDATES;
|
||||
|
||||
// (arbitrary) request code for the purchase flow
|
||||
private static final int RC_REQUEST = 10001;
|
||||
|
@ -53,25 +49,44 @@ public class InAppHelper {
|
|||
|
||||
public interface InAppCallbacks {
|
||||
void onError(String error);
|
||||
|
||||
void onGetItems();
|
||||
|
||||
void onItemPurchased(String sku);
|
||||
|
||||
void showHideProgress(boolean show);
|
||||
void showProgress();
|
||||
|
||||
void dismissProgress();
|
||||
}
|
||||
|
||||
public static boolean isSubscribedToLiveUpdates() {
|
||||
return mSubscribedToLiveUpdates;
|
||||
}
|
||||
|
||||
public static String getLiveUpdatesPrice() {
|
||||
return mLiveUpdatesPrice;
|
||||
}
|
||||
|
||||
public static String getSkuLiveUpdates() {
|
||||
return SKU_LIVE_UPDATES;
|
||||
}
|
||||
|
||||
public InAppHelper(OsmandApplication ctx, InAppCallbacks callbacks) {
|
||||
this.ctx = ctx;
|
||||
this.callbacks = callbacks;
|
||||
if (SKU_LIVE_UPDATES == null) {
|
||||
if (Version.isFreeVersion(ctx)) {
|
||||
SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FREE;
|
||||
} else {
|
||||
SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start(final boolean stopAfterResult) {
|
||||
this.stopAfterResult = stopAfterResult;
|
||||
/* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
|
||||
* (that you got from the Google Play developer console). This is not your
|
||||
/* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
|
||||
* (that you got from the Google Play developer console). This is not your
|
||||
* developer public key, it's the *app-specific* public key.
|
||||
*
|
||||
* Instead of just storing the entire literal string here embedded in the
|
||||
|
@ -89,18 +104,18 @@ public class InAppHelper {
|
|||
"YTjh1H/ZgqIHy5ZluahINuDE76qdLYMXrDMQIDAQAB";
|
||||
|
||||
// Create the helper, passing it our context and the public key to verify signatures with
|
||||
Log.d(TAG, "Creating InAppHelper.");
|
||||
logDebug("Creating InAppHelper.");
|
||||
mHelper = new IabHelper(ctx, base64EncodedPublicKey);
|
||||
|
||||
// enable debug logging (for a production application, you should set this to false).
|
||||
mHelper.enableDebugLogging(true);
|
||||
mHelper.enableDebugLogging(false);
|
||||
|
||||
// Start setup. This is asynchronous and the specified listener
|
||||
// will be called once setup completes.
|
||||
Log.d(TAG, "Starting setup.");
|
||||
logDebug("Starting setup.");
|
||||
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
|
||||
public void onIabSetupFinished(IabResult result) {
|
||||
Log.d(TAG, "Setup finished.");
|
||||
logDebug("Setup finished.");
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
// Oh noes, there was a problem.
|
||||
|
@ -118,8 +133,10 @@ public class InAppHelper {
|
|||
if (mHelper == null) return;
|
||||
|
||||
// IAB is fully set up. Now, let's get an inventory of stuff we own.
|
||||
Log.d(TAG, "Setup successful. Querying inventory.");
|
||||
mHelper.queryInventoryAsync(mGotInventoryListener);
|
||||
logDebug("Setup successful. Querying inventory.");
|
||||
List<String> skus = new ArrayList<>();
|
||||
skus.add(SKU_LIVE_UPDATES);
|
||||
mHelper.queryInventoryAsync(true, skus, mGotInventoryListener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -127,7 +144,7 @@ public class InAppHelper {
|
|||
// Listener that's called when we finish querying the items and subscriptions we own
|
||||
private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
|
||||
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
|
||||
Log.d(TAG, "Query inventory finished.");
|
||||
logDebug("Query inventory finished.");
|
||||
|
||||
// Have we been disposed of in the meantime? If so, quit.
|
||||
if (mHelper == null) return;
|
||||
|
@ -144,35 +161,46 @@ public class InAppHelper {
|
|||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Query inventory was successful.");
|
||||
logDebug("Query inventory was successful.");
|
||||
|
||||
/*
|
||||
* Check for items we own. Notice that for each purchase, we check
|
||||
* Check for items we own. Notice that for each purchase, we check
|
||||
* the developer payload to see if it's correct! See
|
||||
* verifyDeveloperPayload().
|
||||
*/
|
||||
|
||||
// Do we have the live updates?
|
||||
Purchase liveUpdatesPurchase = inventory.getPurchase(SKU_LIVE_UPDATES);
|
||||
mSubscribedToLiveUpdates = (liveUpdatesPurchase != null &&
|
||||
verifyDeveloperPayload(liveUpdatesPurchase));
|
||||
Log.d(TAG, "User " + (mSubscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
|
||||
mSubscribedToLiveUpdates = (liveUpdatesPurchase != null);
|
||||
if (mSubscribedToLiveUpdates) {
|
||||
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
|
||||
}
|
||||
logDebug("User " + (mSubscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
|
||||
+ " live updates purchased.");
|
||||
|
||||
if (inventory.hasDetails(SKU_LIVE_UPDATES)) {
|
||||
SkuDetails liveUpdatesDetails = inventory.getSkuDetails(SKU_LIVE_UPDATES);
|
||||
mLiveUpdatesPrice = liveUpdatesDetails.getPrice();
|
||||
}
|
||||
|
||||
if (liveUpdatesPurchase != null && !ctx.getSettings().BILLING_PURCHASE_TOKEN_SENT.get()) {
|
||||
sendToken(liveUpdatesPurchase.getToken());
|
||||
}
|
||||
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(false);
|
||||
callbacks.dismissProgress();
|
||||
callbacks.onGetItems();
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
stop();
|
||||
}
|
||||
|
||||
Log.d(TAG, "Initial inapp query finished");
|
||||
logDebug("Initial inapp query finished");
|
||||
}
|
||||
};
|
||||
|
||||
public void purchaseLiveUpdates(final Activity activity, final String email, final String userName,
|
||||
final String country) {
|
||||
final String countryDownloadName, final boolean hideUserName) {
|
||||
if (!mHelper.subscriptionsSupported()) {
|
||||
complain("Subscriptions not supported on your device yet. Sorry!");
|
||||
if (callbacks != null) {
|
||||
|
@ -185,7 +213,7 @@ public class InAppHelper {
|
|||
}
|
||||
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(true);
|
||||
callbacks.showProgress();
|
||||
}
|
||||
|
||||
new AsyncTask<Void, Void, String>() {
|
||||
|
@ -195,57 +223,72 @@ public class InAppHelper {
|
|||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
userId = ctx.getSettings().BILLING_USER_ID.get();
|
||||
if (Algorithms.isEmpty(userId)) {
|
||||
return sendRequest("http://download.osmand.net/subscription/register?email=" + email
|
||||
+ "&visibleName=" + userName + "&preferredCountry=" + country
|
||||
+ (Algorithms.isEmpty(userId) ? "&status=new" : ""),
|
||||
"POST", "Requesting userId...");
|
||||
} else {
|
||||
try {
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
parameters.put("visibleName", hideUserName ? "" : userName);
|
||||
parameters.put("preferredCountry", countryDownloadName);
|
||||
parameters.put("email", email);
|
||||
if (Algorithms.isEmpty(userId)) {
|
||||
parameters.put("status", "new");
|
||||
}
|
||||
|
||||
return AndroidNetworkUtils.sendRequest(ctx,
|
||||
"http://download.osmand.net/subscription/register.php",
|
||||
parameters, "Requesting userId...");
|
||||
|
||||
} catch (Exception e) {
|
||||
logError("sendRequest Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String response) {
|
||||
if (Algorithms.isEmpty(userId)) {
|
||||
Log.d(TAG, "Response=" + response);
|
||||
if (response == null) {
|
||||
logDebug("Response=" + response);
|
||||
if (response == null) {
|
||||
complain("Cannot retrieve userId from server.");
|
||||
if (callbacks != null) {
|
||||
callbacks.dismissProgress();
|
||||
callbacks.onError("Cannot retrieve userId from server.");
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
stop();
|
||||
}
|
||||
return;
|
||||
|
||||
} else {
|
||||
try {
|
||||
JSONObject obj = new JSONObject(response);
|
||||
userId = obj.getString("userid");
|
||||
ctx.getSettings().BILLING_USER_ID.set(userId);
|
||||
logDebug("UserId=" + userId);
|
||||
} catch (JSONException e) {
|
||||
String message = "JSON parsing error: "
|
||||
+ (e.getMessage() == null ? "unknown" : e.getMessage());
|
||||
complain(message);
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(false);
|
||||
callbacks.onError("Cannot retrieve userId from server.");
|
||||
callbacks.dismissProgress();
|
||||
callbacks.onError(message);
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
stop();
|
||||
}
|
||||
return;
|
||||
|
||||
} else {
|
||||
try {
|
||||
JSONObject obj = new JSONObject(response);
|
||||
userId = obj.getString("userid");
|
||||
ctx.getSettings().BILLING_USER_ID.set(userId);
|
||||
Log.d(TAG, "UserId=" + userId);
|
||||
} catch (JSONException e) {
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(false);
|
||||
callbacks.onError("JSON parsing error: " + e.getMessage());
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callbacks != null) {
|
||||
callbacks.dismissProgress();
|
||||
}
|
||||
if (!Algorithms.isEmpty(userId)) {
|
||||
Log.d(TAG, "Launching purchase flow for live updates subscription for userId=" + userId);
|
||||
logDebug("Launching purchase flow for live updates subscription for userId=" + userId);
|
||||
String payload = userId;
|
||||
mHelper.launchPurchaseFlow(activity,
|
||||
SKU_LIVE_UPDATES, IabHelper.ITEM_TYPE_SUBS,
|
||||
RC_REQUEST, mPurchaseFinishedListener, payload);
|
||||
if (mHelper != null) {
|
||||
mHelper.launchPurchaseFlow(activity,
|
||||
SKU_LIVE_UPDATES, IabHelper.ITEM_TYPE_SUBS,
|
||||
RC_REQUEST, mPurchaseFinishedListener, payload);
|
||||
}
|
||||
} else {
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(false);
|
||||
callbacks.onError("Empty userId");
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
|
@ -257,57 +300,31 @@ public class InAppHelper {
|
|||
}
|
||||
|
||||
public boolean onActivityResultHandled(int requestCode, int resultCode, Intent data) {
|
||||
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
|
||||
logDebug("onActivityResult(" + requestCode + "," + resultCode + "," + data);
|
||||
if (mHelper == null) return false;
|
||||
|
||||
// Pass on the activity result to the helper for handling
|
||||
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
|
||||
// not handled, so handle it ourselves (here's where you'd
|
||||
// perform any handling of activity results not related to in-app
|
||||
// billing...
|
||||
//super.onActivityResult(requestCode, resultCode, data);
|
||||
try {
|
||||
// Pass on the activity result to the helper for handling
|
||||
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
|
||||
// not handled, so handle it ourselves (here's where you'd
|
||||
// perform any handling of activity results not related to in-app
|
||||
// billing...
|
||||
//super.onActivityResult(requestCode, resultCode, data);
|
||||
return false;
|
||||
} else {
|
||||
logDebug("onActivityResult handled by IABUtil.");
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logError("onActivityResultHandled", e);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Log.d(TAG, "onActivityResult handled by IABUtil.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies the developer payload of a purchase. */
|
||||
private boolean verifyDeveloperPayload(Purchase p) {
|
||||
String payload = p.getDeveloperPayload();
|
||||
|
||||
/*
|
||||
* TODO: verify that the developer payload of the purchase is correct. It will be
|
||||
* the same one that you sent when initiating the purchase.
|
||||
*
|
||||
* WARNING: Locally generating a random string when starting a purchase and
|
||||
* verifying it here might seem like a good approach, but this will fail in the
|
||||
* case where the user purchases an item on one device and then uses your app on
|
||||
* a different device, because on the other device you will not have access to the
|
||||
* random string you originally generated.
|
||||
*
|
||||
* So a good developer payload has these characteristics:
|
||||
*
|
||||
* 1. If two different users purchase an item, the payload is different between them,
|
||||
* so that one user's purchase can't be replayed to another user.
|
||||
*
|
||||
* 2. The payload must be such that you can verify it even when the app wasn't the
|
||||
* one who initiated the purchase flow (so that items purchased by the user on
|
||||
* one device work on other devices owned by the user).
|
||||
*
|
||||
* Using your own server to store and verify developer payloads across app
|
||||
* installations is recommended.
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback for when a purchase is finished
|
||||
private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
|
||||
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
|
||||
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
|
||||
logDebug("Purchase finished: " + result + ", purchase: " + purchase);
|
||||
|
||||
// if we were disposed of in the meantime, quit.
|
||||
if (mHelper == null) return;
|
||||
|
@ -315,7 +332,7 @@ public class InAppHelper {
|
|||
if (result.isFailure()) {
|
||||
complain("Error purchasing: " + result);
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(false);
|
||||
callbacks.dismissProgress();
|
||||
callbacks.onError("Error purchasing: " + result);
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
|
@ -323,27 +340,20 @@ public class InAppHelper {
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (!verifyDeveloperPayload(purchase)) {
|
||||
complain("Error purchasing. Authenticity verification failed.");
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(false);
|
||||
callbacks.onError("Error purchasing. Authenticity verification failed.");
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Purchase successful.");
|
||||
logDebug("Purchase successful.");
|
||||
|
||||
if (purchase.getSku().equals(SKU_LIVE_UPDATES)) {
|
||||
// bought the infinite gas subscription
|
||||
Log.d(TAG, "Live updates subscription purchased.");
|
||||
showToast("Thank you for subscribing to live updates!");
|
||||
// bought live updates
|
||||
sendToken(purchase.getToken());
|
||||
|
||||
logDebug("Live updates subscription purchased.");
|
||||
showToast(ctx.getString(R.string.osm_live_thanks));
|
||||
mSubscribedToLiveUpdates = true;
|
||||
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
|
||||
|
||||
if (callbacks != null) {
|
||||
callbacks.showHideProgress(false);
|
||||
callbacks.dismissProgress();
|
||||
callbacks.onItemPurchased(SKU_LIVE_UPDATES);
|
||||
}
|
||||
if (stopAfterResult) {
|
||||
|
@ -355,79 +365,67 @@ public class InAppHelper {
|
|||
|
||||
// Do not forget call stop() when helper is not needed anymore
|
||||
public void stop() {
|
||||
Log.d(TAG, "Destroying helper.");
|
||||
logDebug("Destroying helper.");
|
||||
if (mHelper != null) {
|
||||
mHelper.dispose();
|
||||
mHelper = null;
|
||||
}
|
||||
}
|
||||
|
||||
void complain(String message) {
|
||||
Log.e(TAG, "**** InAppHelper Error: " + message);
|
||||
private void sendToken(String token) {
|
||||
String userId = ctx.getSettings().BILLING_USER_ID.get();
|
||||
String email = ctx.getSettings().BILLING_USER_EMAIL.get();
|
||||
try {
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
parameters.put("userid", userId);
|
||||
parameters.put("sku", SKU_LIVE_UPDATES);
|
||||
parameters.put("purchaseToken", token);
|
||||
parameters.put("email", email);
|
||||
|
||||
AndroidNetworkUtils.sendRequestAsync(ctx,
|
||||
"http://download.osmand.net/subscription/purchased.php",
|
||||
parameters, "Sending purchase info...", new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String result) {
|
||||
if (result != null) {
|
||||
try {
|
||||
JSONObject obj = new JSONObject(result);
|
||||
if (!obj.has("error")) {
|
||||
ctx.getSettings().BILLING_PURCHASE_TOKEN_SENT.set(true);
|
||||
} else {
|
||||
complain("SendToken Error: " + obj.getString("error"));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
logError("sendToken", e);
|
||||
complain("SendToken Error: " + (e.getMessage() != null ? e.getMessage() : "JSONException"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logError("sendToken Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void complain(String message) {
|
||||
logError("**** InAppHelper Error: " + message);
|
||||
showToast("Error: " + message);
|
||||
}
|
||||
|
||||
void showToast(final String message) {
|
||||
private void showToast(final String message) {
|
||||
ctx.showToastMessage(message);
|
||||
}
|
||||
|
||||
private String sendRequest(String url, String requestMethod, String userOperation) {
|
||||
Log.d(TAG, "Sending request " + url); //$NON-NLS-1$
|
||||
try {
|
||||
HttpURLConnection connection = NetworkUtils.getHttpURLConnection(url);
|
||||
|
||||
connection.setConnectTimeout(15000);
|
||||
connection.setRequestMethod(requestMethod);
|
||||
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx)); //$NON-NLS-1$
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
connection.connect();
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
String msg = userOperation
|
||||
+ " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage(); //$NON-NLS-1$//$NON-NLS-2$
|
||||
Log.e(TAG, msg);
|
||||
showToast(msg);
|
||||
} else {
|
||||
Log.d(TAG, "Response : " + connection.getResponseMessage()); //$NON-NLS-1$
|
||||
// populate return fields.
|
||||
responseBody.setLength(0);
|
||||
InputStream i = connection.getInputStream();
|
||||
if (i != null) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(i, "UTF-8"), 256); //$NON-NLS-1$
|
||||
String s;
|
||||
boolean f = true;
|
||||
while ((s = in.readLine()) != null) {
|
||||
if (!f) {
|
||||
responseBody.append("\n"); //$NON-NLS-1$
|
||||
} else {
|
||||
f = false;
|
||||
}
|
||||
responseBody.append(s);
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
i.close();
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
return responseBody.toString();
|
||||
}
|
||||
connection.disconnect();
|
||||
} catch (NullPointerException e) {
|
||||
// that's tricky case why NPE is thrown to fix that problem httpClient could be used
|
||||
String msg = ctx.getString(R.string.auth_failed);
|
||||
Log.e(TAG, msg, e);
|
||||
showToast(msg);
|
||||
} catch (MalformedURLException e) {
|
||||
Log.e(TAG, userOperation + " " + ctx.getString(R.string.failed_op), e); //$NON-NLS-1$
|
||||
showToast(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, userOperation + " " + ctx.getString(R.string.failed_op), e); //$NON-NLS-1$
|
||||
showToast(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation));
|
||||
}
|
||||
|
||||
return null;
|
||||
void logDebug(String msg) {
|
||||
if (mDebugLog) Log.d(TAG, msg);
|
||||
}
|
||||
|
||||
void logError(String msg) {
|
||||
Log.e(TAG, "Error: " + msg);
|
||||
}
|
||||
|
||||
void logError(String msg, Throwable e) {
|
||||
Log.e(TAG, "Error: " + msg, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
package net.osmand.plus.liveupdates;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.osmand.map.WorldRegion;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.BaseOsmAndDialogFragment;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class CountrySelectionFragment extends BaseOsmAndDialogFragment {
|
||||
|
||||
private List<CountryItem> countryItems = new ArrayList<>();
|
||||
private OnFragmentInteractionListener mListener;
|
||||
|
||||
public List<CountryItem> getCountryItems() {
|
||||
return countryItems;
|
||||
}
|
||||
|
||||
public CountryItem getCountryItem(String downloadName) {
|
||||
if (!Algorithms.isEmpty(downloadName)) {
|
||||
for (CountryItem item : countryItems) {
|
||||
if (downloadName.equals(item.downloadName)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
if (countryItems.size() == 0) {
|
||||
initCountries(getMyApplication());
|
||||
}
|
||||
|
||||
View view = inflater.inflate(R.layout.fragment_search_list, container, false);
|
||||
ListView listView = (ListView) view.findViewById(android.R.id.list);
|
||||
final ArrayAdapter<CountryItem> adapter = new ListAdapter(getListItemIcon());
|
||||
if (countryItems.size() > 0) {
|
||||
adapter.addAll(countryItems);
|
||||
}
|
||||
listView.setAdapter(adapter);
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
mListener.onSearchResult(adapter.getItem(position));
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
final EditText searchEditText = (EditText) view.findViewById(R.id.searchEditText);
|
||||
searchEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
adapter.getFilter().filter(s);
|
||||
}
|
||||
});
|
||||
ImageButton clearButton = (ImageButton) view.findViewById(R.id.clearButton);
|
||||
setThemedDrawable(clearButton, R.drawable.ic_action_remove_dark);
|
||||
clearButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnFragmentInteractionListener) {
|
||||
mListener = (OnFragmentInteractionListener) context;
|
||||
} else if (getParentFragment() instanceof OnFragmentInteractionListener) {
|
||||
mListener = (OnFragmentInteractionListener) getParentFragment();
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnFragmentInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
protected int getListItemIcon() {
|
||||
return R.drawable.ic_map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
public interface OnFragmentInteractionListener {
|
||||
void onSearchResult(CountryItem name);
|
||||
}
|
||||
|
||||
|
||||
public void initCountries(OsmandApplication app) {
|
||||
final WorldRegion root = app.getRegions().getWorldRegion();
|
||||
ArrayList<WorldRegion> groups = new ArrayList<>();
|
||||
groups.add(root);
|
||||
processGroup(root, groups);
|
||||
Collections.sort(groups, new Comparator<WorldRegion>() {
|
||||
@Override
|
||||
public int compare(WorldRegion lhs, WorldRegion rhs) {
|
||||
if (lhs == root) {
|
||||
return -1;
|
||||
}
|
||||
if (rhs == root) {
|
||||
return 1;
|
||||
}
|
||||
return getHumanReadableName(lhs).compareTo(getHumanReadableName(rhs));
|
||||
}
|
||||
});
|
||||
for (WorldRegion group : groups) {
|
||||
String name = getHumanReadableName(group);
|
||||
if (group == root) {
|
||||
countryItems.add(new CountryItem(name, ""));
|
||||
} else {
|
||||
countryItems.add(new CountryItem(name, group.getRegionDownloadName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processGroup(WorldRegion group,
|
||||
List<WorldRegion> nameList) {
|
||||
if (group.isRegionMapDownload()) {
|
||||
nameList.add(group);
|
||||
}
|
||||
|
||||
if (group.getSubregions() != null) {
|
||||
for (WorldRegion g : group.getSubregions()) {
|
||||
processGroup(g, nameList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getHumanReadableName(WorldRegion group) {
|
||||
String name;
|
||||
if (group.getLevel() > 2 || (group.getLevel() == 2
|
||||
&& group.getSuperregion().getRegionId().equals(WorldRegion.RUSSIA_REGION_ID))) {
|
||||
WorldRegion parent = group.getSuperregion();
|
||||
WorldRegion parentsParent = group.getSuperregion().getSuperregion();
|
||||
if (group.getLevel() == 3) {
|
||||
if (parentsParent.getRegionId().equals(WorldRegion.RUSSIA_REGION_ID)) {
|
||||
name = parentsParent.getLocaleName() + " " + group.getLocaleName();
|
||||
} else if (!parent.getRegionId().equals(WorldRegion.UNITED_KINGDOM_REGION_ID)) {
|
||||
name = parent.getLocaleName() + " " + group.getLocaleName();
|
||||
} else {
|
||||
name = group.getLocaleName();
|
||||
}
|
||||
} else {
|
||||
name = parent.getLocaleName() + " " + group.getLocaleName();
|
||||
}
|
||||
} else {
|
||||
name = group.getLocaleName();
|
||||
}
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static class CountryItem implements Serializable {
|
||||
private String localName;
|
||||
private String downloadName;
|
||||
|
||||
public CountryItem(String localName, String downloadName) {
|
||||
this.localName = localName;
|
||||
this.downloadName = downloadName;
|
||||
}
|
||||
|
||||
public String getLocalName() {
|
||||
return localName;
|
||||
}
|
||||
|
||||
public String getDownloadName() {
|
||||
return downloadName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return localName;
|
||||
}
|
||||
}
|
||||
|
||||
private class ListAdapter extends ArrayAdapter<CountryItem> {
|
||||
private final Drawable drawableLeft;
|
||||
|
||||
public ListAdapter(@DrawableRes int drawableLeftId) {
|
||||
super(getMyActivity(), android.R.layout.simple_list_item_1);
|
||||
this.drawableLeft = drawableLeftId == -1 ? null : getContentIcon(drawableLeftId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
CountryItem item = getItem(position);
|
||||
TextView view = (TextView) super.getView(position, convertView, parent);
|
||||
view.setText(item.localName);
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, null, null, null);
|
||||
view.setCompoundDrawablePadding(getResources().getDimensionPixelSize(R.dimen.list_content_padding));
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,15 +3,23 @@ package net.osmand.plus.liveupdates;
|
|||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.SwitchCompat;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
|
@ -22,6 +30,7 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.osmand.map.WorldRegion;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
|
@ -56,6 +65,7 @@ import static net.osmand.plus.liveupdates.LiveUpdatesHelper.setAlarmForPendingIn
|
|||
|
||||
public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
||||
public static final String TITLE = "Live Updates";
|
||||
private static final int SUBSCRIPTION_SETTINGS = 5;
|
||||
public static final Comparator<LocalIndexInfo> LOCAL_INDEX_INFO_COMPARATOR = new Comparator<LocalIndexInfo>() {
|
||||
@Override
|
||||
public int compare(LocalIndexInfo lhs, LocalIndexInfo rhs) {
|
||||
|
@ -70,6 +80,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
|||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,7 +88,6 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
|||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_live_updates, container, false);
|
||||
listView = (ExpandableListView) view.findViewById(android.R.id.list);
|
||||
// View header = inflater.inflate(R.layout.live_updates_header, listView, false);
|
||||
|
||||
View bottomShadowView = inflater.inflate(R.layout.shadow_bottom, listView, false);
|
||||
listView.addFooterView(bottomShadowView);
|
||||
|
@ -94,37 +104,73 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
|||
}
|
||||
});
|
||||
|
||||
//test
|
||||
//getSettings().LIVE_UPDATES_PURCHASED.set(true);
|
||||
|
||||
subscriptionHeader = inflater.inflate(R.layout.live_updates_header, listView, false);
|
||||
View subscriptionBanner = subscriptionHeader.findViewById(R.id.subscription_banner);
|
||||
View subscriptionInfo = subscriptionHeader.findViewById(R.id.subscription_info);
|
||||
Button subscriptionButton = (Button) subscriptionHeader.findViewById(R.id.subscription_button);
|
||||
subscriptionButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
|
||||
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
|
||||
}
|
||||
});
|
||||
if (InAppHelper.isSubscribedToLiveUpdates()) {
|
||||
subscriptionBanner.setVisibility(View.GONE);
|
||||
subscriptionInfo.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
subscriptionBanner.setVisibility(View.VISIBLE);
|
||||
subscriptionInfo.setVisibility(View.GONE);
|
||||
}
|
||||
updateSubscriptionHeader();
|
||||
|
||||
listView.addHeaderView(subscriptionHeader);
|
||||
|
||||
loadLocalIndexesTask = new LoadLocalIndexTask(adapter, this).execute();
|
||||
return view;
|
||||
}
|
||||
|
||||
public void updateSubscriptionBanner() {
|
||||
public void updateSubscriptionHeader() {
|
||||
View subscriptionBanner = subscriptionHeader.findViewById(R.id.subscription_banner);
|
||||
View subscriptionInfo = subscriptionHeader.findViewById(R.id.subscription_info);
|
||||
if (InAppHelper.isSubscribedToLiveUpdates()) {
|
||||
if (getSettings().LIVE_UPDATES_PURCHASED.get()) {
|
||||
ImageView statusIcon = (ImageView) subscriptionHeader.findViewById(R.id.statusIcon);
|
||||
TextView statusTextView = (TextView) subscriptionHeader.findViewById(R.id.statusTextView);
|
||||
TextView regionNameTextView = (TextView) subscriptionHeader.findViewById(R.id.regionTextView);
|
||||
|
||||
if (InAppHelper.isSubscribedToLiveUpdates()) {
|
||||
statusTextView.setText(getString(R.string.osm_live_active));
|
||||
statusIcon.setImageDrawable(getMyApplication().getIconsCache().getContentIcon(R.drawable.ic_action_done));
|
||||
} else {
|
||||
statusTextView.setText(getString(R.string.osm_live_not_active));
|
||||
statusIcon.setImageDrawable(getMyApplication().getIconsCache().getContentIcon(R.drawable.ic_action_remove_dark));
|
||||
}
|
||||
|
||||
OsmandSettings settings = getMyApplication().getSettings();
|
||||
|
||||
String countryName = settings.BILLING_USER_COUNTRY.get();
|
||||
if (Algorithms.isEmpty(countryName)) {
|
||||
WorldRegion world = getMyApplication().getRegions().getWorldRegion();
|
||||
countryName = world.getLocaleName();
|
||||
}
|
||||
regionNameTextView.setText(countryName);
|
||||
|
||||
Button subscribeButton = (Button) subscriptionHeader.findViewById(R.id.subscribeButton);
|
||||
subscribeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
|
||||
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
|
||||
}
|
||||
});
|
||||
|
||||
subscriptionBanner.setVisibility(View.GONE);
|
||||
subscriptionInfo.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
Button readMoreBtn = (Button) subscriptionHeader.findViewById(R.id.read_more_button);
|
||||
readMoreBtn.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Uri uri = Uri.parse("http://osmand.net/osm_live.php");
|
||||
Intent goToOsmLive = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(goToOsmLive);
|
||||
}
|
||||
});
|
||||
Button subscriptionButton = (Button) subscriptionHeader.findViewById(R.id.subscription_button);
|
||||
subscriptionButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
|
||||
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
|
||||
}
|
||||
});
|
||||
|
||||
subscriptionBanner.setVisibility(View.VISIBLE);
|
||||
subscriptionInfo.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -142,6 +188,34 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
if (getSettings().LIVE_UPDATES_PURCHASED.get()) {
|
||||
ActionBar actionBar = getMyActivity().getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||
}
|
||||
|
||||
SubMenu split = menu.addSubMenu(R.string.shared_string_more_actions);
|
||||
split.setIcon(R.drawable.ic_overflow_menu_white);
|
||||
MenuItemCompat.setShowAsAction(split.getItem(), MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
|
||||
MenuItem item = split.add(0, SUBSCRIPTION_SETTINGS, 0, R.string.osm_live_subscription_settings);
|
||||
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == SUBSCRIPTION_SETTINGS) {
|
||||
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
|
||||
subscriptionFragment.setEditMode(true);
|
||||
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
protected class LocalIndexesAdapter extends OsmandBaseExpandableListAdapter {
|
||||
public static final int SHOULD_UPDATE_GROUP_POSITION = 0;
|
||||
public static final int SHOULD_NOT_UPDATE_GROUP_POSITION = 1;
|
||||
|
@ -359,6 +433,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
|||
divider = view.findViewById(R.id.divider);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void bindLocalIndexInfo(final LocalIndexInfo item, boolean isLastChild) {
|
||||
OsmandApplication context = fragment.getMyActivity().getMyApplication();
|
||||
final OsmandSettings.CommonPreference<Boolean> shouldUpdatePreference =
|
||||
|
@ -425,7 +500,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
|||
extends AsyncTask<Void, LocalIndexInfo, List<LocalIndexInfo>>
|
||||
implements AbstractLoadLocalIndexTask {
|
||||
|
||||
private List<LocalIndexInfo> result;
|
||||
//private List<LocalIndexInfo> result;
|
||||
private LocalIndexesAdapter adapter;
|
||||
private LiveUpdatesFragment fragment;
|
||||
private LocalIndexHelper helper;
|
||||
|
@ -461,7 +536,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
|
|||
|
||||
@Override
|
||||
protected void onPostExecute(List<LocalIndexInfo> result) {
|
||||
this.result = result;
|
||||
//this.result = result;
|
||||
adapter.sort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public class PerformLiveUpdateAsyncTask
|
|||
} else {
|
||||
settings.LIVE_UPDATES_RETRIES.resetToDefault();
|
||||
List<IncrementalChangesManager.IncrementalUpdate> ll = result.getItemsForUpdate();
|
||||
if (!ll.isEmpty()) {
|
||||
if (ll != null && !ll.isEmpty()) {
|
||||
ArrayList<IndexItem> itemsToDownload = new ArrayList<>(ll.size());
|
||||
for (IncrementalChangesManager.IncrementalUpdate iu : ll) {
|
||||
IndexItem indexItem = new IndexItem(iu.fileName, "Incremental update",
|
||||
|
|
|
@ -22,23 +22,19 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.map.WorldRegion;
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.BaseOsmAndFragment;
|
||||
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ReportsFragment extends BaseOsmAndFragment implements SearchSelectionFragment.OnFragmentInteractionListener {
|
||||
public class ReportsFragment extends BaseOsmAndFragment implements CountrySelectionFragment.OnFragmentInteractionListener {
|
||||
public static final String TITLE = "Report";
|
||||
public static final String TOTAL_CHANGES_BY_MONTH_URL_PATTERN = "http://download.osmand.net/" +
|
||||
"reports/query_report.php?report=total_changes_by_month&month=%s®ion=%s";
|
||||
|
@ -50,11 +46,9 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti
|
|||
private Spinner montReportsSpinner;
|
||||
private MonthsForReportsAdapter monthsForReportsAdapter;
|
||||
|
||||
CountrySearchSelectionFragment searchSelectionFragment = new CountrySearchSelectionFragment();
|
||||
private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment();
|
||||
private TextView countryNameTextView;
|
||||
|
||||
HashMap<String, String> queryRegionNames = new HashMap<>();
|
||||
ArrayList<String> regionNames = new ArrayList<>();
|
||||
private CountryItem selectedCountryItem;
|
||||
|
||||
private ImageView numberOfContributorsIcon;
|
||||
private ImageView numberOfEditsIcon;
|
||||
|
@ -69,7 +63,6 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti
|
|||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
initCountries();
|
||||
View view = inflater.inflate(R.layout.fragment_reports, container, false);
|
||||
montReportsSpinner = (Spinner) view.findViewById(R.id.montReportsSpinner);
|
||||
monthsForReportsAdapter = new MonthsForReportsAdapter(getActivity());
|
||||
|
@ -79,15 +72,15 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti
|
|||
regionReportsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SearchSelectionFragment countrySearchSelectionFragment =
|
||||
searchSelectionFragment;
|
||||
countrySearchSelectionFragment
|
||||
.show(getChildFragmentManager(), "CountriesSearchSelectionFragment");
|
||||
countrySelectionFragment.show(getChildFragmentManager(), "CountriesSearchSelectionFragment");
|
||||
}
|
||||
});
|
||||
|
||||
countrySelectionFragment.initCountries(getMyApplication());
|
||||
selectedCountryItem = countrySelectionFragment.getCountryItems().get(0);
|
||||
|
||||
countryNameTextView = (TextView) regionReportsButton.findViewById(android.R.id.text1);
|
||||
countryNameTextView.setText(regionNames.get(0));
|
||||
countryNameTextView.setText(selectedCountryItem.getLocalName());
|
||||
|
||||
setThemedDrawable(view, R.id.calendarImageView, R.drawable.ic_action_data);
|
||||
setThemedDrawable(view, R.id.regionIconImageView, R.drawable.ic_world_globe_dark);
|
||||
|
@ -127,7 +120,7 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti
|
|||
public void requestAndUpdateUi() {
|
||||
int monthItemPosition = montReportsSpinner.getSelectedItemPosition();
|
||||
String monthUrlString = monthsForReportsAdapter.getQueryString(monthItemPosition);
|
||||
String countryUrlString = queryRegionNames.get(countryNameTextView.getText().toString());
|
||||
String countryUrlString = selectedCountryItem.getDownloadName();
|
||||
|
||||
tryUpdateData(monthUrlString, countryUrlString);
|
||||
}
|
||||
|
@ -171,79 +164,12 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSearchResult(String name) {
|
||||
countryNameTextView.setText(name);
|
||||
public void onSearchResult(CountryItem item) {
|
||||
selectedCountryItem = item;
|
||||
countryNameTextView.setText(item.getLocalName());
|
||||
requestAndUpdateUi();
|
||||
}
|
||||
|
||||
private void initCountries() {
|
||||
final WorldRegion root = getMyApplication().getRegions().getWorldRegion();
|
||||
ArrayList<WorldRegion> groups = new ArrayList<>();
|
||||
groups.add(root);
|
||||
processGroup(root, groups, getActivity());
|
||||
Collections.sort(groups, new Comparator<WorldRegion>() {
|
||||
@Override
|
||||
public int compare(WorldRegion lhs, WorldRegion rhs) {
|
||||
if (lhs == root) {
|
||||
return -1;
|
||||
}
|
||||
if (rhs == root) {
|
||||
return 1;
|
||||
}
|
||||
return getHumanReadableName(lhs).compareTo(getHumanReadableName(rhs));
|
||||
}
|
||||
});
|
||||
for (WorldRegion group : groups) {
|
||||
String name = getHumanReadableName(group);
|
||||
regionNames.add(name);
|
||||
queryRegionNames.put(name, group == root ? "" : group.getRegionDownloadName());
|
||||
}
|
||||
}
|
||||
|
||||
private static String getHumanReadableName(WorldRegion group) {
|
||||
String name;
|
||||
if (group.getLevel() > 2 || (group.getLevel() == 2
|
||||
&& group.getSuperregion().getRegionId().equals(WorldRegion.RUSSIA_REGION_ID))) {
|
||||
WorldRegion parent = group.getSuperregion();
|
||||
WorldRegion parentsParent = group.getSuperregion().getSuperregion();
|
||||
if (group.getLevel() == 3) {
|
||||
if (parentsParent.getRegionId().equals(WorldRegion.RUSSIA_REGION_ID)) {
|
||||
name = parentsParent.getLocaleName() + " " + group.getLocaleName();
|
||||
} else if (!parent.getRegionId().equals(WorldRegion.UNITED_KINGDOM_REGION_ID)) {
|
||||
name = parent.getLocaleName() + " " + group.getLocaleName();
|
||||
} else {
|
||||
name = group.getLocaleName();
|
||||
}
|
||||
} else {
|
||||
name = parent.getLocaleName() + " " + group.getLocaleName();
|
||||
}
|
||||
} else {
|
||||
name = group.getLocaleName();
|
||||
}
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getQueryString(int position) {
|
||||
return queryRegionNames.get(position);
|
||||
}
|
||||
|
||||
private static void processGroup(WorldRegion group,
|
||||
List<WorldRegion> nameList,
|
||||
Context context) {
|
||||
if (group.isRegionMapDownload()) {
|
||||
nameList.add(group);
|
||||
}
|
||||
|
||||
if (group.getSubregions() != null) {
|
||||
for (WorldRegion g : group.getSubregions()) {
|
||||
processGroup(g, nameList, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MonthsForReportsAdapter extends ArrayAdapter<String> {
|
||||
private static final SimpleDateFormat queryFormat = new SimpleDateFormat("yyyy-MM", Locale.US);
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
|
@ -325,18 +251,6 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti
|
|||
}
|
||||
}
|
||||
|
||||
public static class CountrySearchSelectionFragment extends SearchSelectionFragment {
|
||||
@Override
|
||||
protected ArrayList<String> getList() {
|
||||
return ((ReportsFragment) getParentFragment()).regionNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getListItemIcon() {
|
||||
return R.drawable.ic_map;
|
||||
}
|
||||
}
|
||||
|
||||
private void enableProgress() {
|
||||
numberOfContributorsIcon.setImageDrawable(getPaintedContentIcon(R.drawable.ic_group, inactiveColor));
|
||||
numberOfEditsIcon.setImageDrawable(getPaintedContentIcon(R.drawable.ic_map, inactiveColor));
|
||||
|
|
|
@ -111,7 +111,7 @@ public abstract class SearchSelectionFragment extends BaseOsmAndDialogFragment {
|
|||
private final Drawable drawableLeft;
|
||||
|
||||
public ListAdapter(Context context, @DrawableRes int drawableLeftId) {
|
||||
super(getMyActivity(), android.R.layout.simple_list_item_1);
|
||||
super(getMyActivity(), R.layout.osmand_simple_list_item_1);
|
||||
this.drawableLeft = drawableLeftId == -1 ? null : getContentIcon(drawableLeftId);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package net.osmand.plus.liveupdates;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -10,61 +9,122 @@ import android.view.MotionEvent;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.map.WorldRegion;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.BaseOsmAndDialogFragment;
|
||||
import net.osmand.plus.inapp.InAppHelper;
|
||||
import net.osmand.plus.inapp.InAppHelper.InAppCallbacks;
|
||||
import net.osmand.plus.liveupdates.SearchSelectionFragment.OnFragmentInteractionListener;
|
||||
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
|
||||
import net.osmand.plus.liveupdates.CountrySelectionFragment.OnFragmentInteractionListener;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppCallbacks, OnFragmentInteractionListener{
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppCallbacks, OnFragmentInteractionListener {
|
||||
|
||||
public static final String TAG = "SubscriptionFragment";
|
||||
private static final String EDIT_MODE_ID = "edit_mode_id";
|
||||
private static final String USER_NAME_ID = "user_name_id";
|
||||
private static final String EMAIL_ID = "email_id";
|
||||
private static final String COUNTRY_ITEM_ID = "country_id";
|
||||
private static final String HIDE_USER_NAME_ID = "hide_user_name_id";
|
||||
|
||||
private InAppHelper inAppHelper;
|
||||
private OsmandSettings settings;
|
||||
private ProgressDialog dlg;
|
||||
private boolean editMode;
|
||||
|
||||
private String userName;
|
||||
private String email;
|
||||
private String country;
|
||||
private String prevEmail;
|
||||
private CountryItem selectedCountryItem;
|
||||
|
||||
ArrayList<String> regionNames = new ArrayList<>();
|
||||
private CountrySearchSelectionFragment searchSelectionFragment
|
||||
= new CountrySearchSelectionFragment();
|
||||
private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment();
|
||||
|
||||
public void setEditMode(boolean editMode) {
|
||||
this.editMode = editMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putBoolean(EDIT_MODE_ID, editMode);
|
||||
|
||||
View view = getView();
|
||||
if (view != null) {
|
||||
EditText userNameEdit = (EditText) view.findViewById(R.id.userNameEdit);
|
||||
outState.putString(USER_NAME_ID, userNameEdit.getText().toString());
|
||||
EditText emailEdit = (EditText) view.findViewById(R.id.emailEdit);
|
||||
outState.putString(EMAIL_ID, emailEdit.getText().toString());
|
||||
CheckBox hideUserNameCheckbox = (CheckBox) view.findViewById(R.id.hideUserNameCheckbox);
|
||||
outState.putBoolean(HIDE_USER_NAME_ID, hideUserNameCheckbox.isChecked());
|
||||
if (selectedCountryItem != null) {
|
||||
outState.putSerializable(COUNTRY_ITEM_ID, selectedCountryItem);
|
||||
}
|
||||
}
|
||||
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
settings = getMyApplication().getSettings();
|
||||
inAppHelper = new InAppHelper(getMyApplication(), this);
|
||||
Activity activity = getActivity();
|
||||
if (activity instanceof OsmLiveActivity) {
|
||||
((OsmLiveActivity) activity).setInAppHelper(inAppHelper);
|
||||
if (savedInstanceState != null) {
|
||||
editMode = savedInstanceState.getBoolean(EDIT_MODE_ID);
|
||||
}
|
||||
|
||||
inAppHelper.start(false);
|
||||
settings = getMyApplication().getSettings();
|
||||
prevEmail = settings.BILLING_USER_EMAIL.get();
|
||||
if (!editMode) {
|
||||
inAppHelper = new InAppHelper(getMyApplication(), this);
|
||||
Activity activity = getActivity();
|
||||
if (activity instanceof OsmLiveActivity) {
|
||||
((OsmLiveActivity) activity).setInAppHelper(inAppHelper);
|
||||
}
|
||||
inAppHelper.start(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
String userName = settings.BILLING_USER_NAME.get();
|
||||
String email = settings.BILLING_USER_EMAIL.get();
|
||||
String countryDownloadName = settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get();
|
||||
boolean hideUserName = settings.BILLING_HIDE_USER_NAME.get();
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
userName = savedInstanceState.getString(USER_NAME_ID);
|
||||
email = savedInstanceState.getString(EMAIL_ID);
|
||||
hideUserName = savedInstanceState.getBoolean(HIDE_USER_NAME_ID);
|
||||
Object obj = savedInstanceState.getSerializable(COUNTRY_ITEM_ID);
|
||||
if (obj instanceof CountryItem) {
|
||||
selectedCountryItem = (CountryItem) obj;
|
||||
countryDownloadName = selectedCountryItem.getDownloadName();
|
||||
} else {
|
||||
countryDownloadName = "";
|
||||
}
|
||||
}
|
||||
|
||||
View view = inflater.inflate(R.layout.subscription_fragment, container, false);
|
||||
ImageButton closeButton = (ImageButton) view.findViewById(R.id.closeButton);
|
||||
if (editMode) {
|
||||
closeButton.setImageDrawable(getMyApplication().getIconsCache().getIcon(R.drawable.ic_action_mode_back));
|
||||
} else {
|
||||
closeButton.setImageDrawable(getMyApplication().getIconsCache().getIcon(R.drawable.ic_action_remove_dark));
|
||||
}
|
||||
closeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -72,67 +132,141 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
|
|||
}
|
||||
});
|
||||
|
||||
initCountries();
|
||||
TextView title = (TextView) view.findViewById(R.id.titleTextView);
|
||||
if (editMode) {
|
||||
title.setText(getString(R.string.osm_live_subscription_settings));
|
||||
} else {
|
||||
title.setText(getString(R.string.osm_live_subscription));
|
||||
}
|
||||
|
||||
userName = settings.BILLING_USER_NAME.get();
|
||||
final EditText userNameEdit = (EditText) view.findViewById(R.id.userNameEdit);
|
||||
if (!Algorithms.isEmpty(userName)) {
|
||||
userNameEdit.setText(userName);
|
||||
}
|
||||
|
||||
email = settings.BILLING_USER_EMAIL.get();
|
||||
final EditText emailEdit = (EditText) view.findViewById(R.id.emailEdit);
|
||||
if (!Algorithms.isEmpty(email)) {
|
||||
emailEdit.setText(email);
|
||||
}
|
||||
|
||||
country = settings.BILLING_USER_COUNTRY.get();
|
||||
countrySelectionFragment.initCountries(getMyApplication());
|
||||
if (Algorithms.isEmpty(countryDownloadName)) {
|
||||
selectedCountryItem = countrySelectionFragment.getCountryItems().get(0);
|
||||
} else {
|
||||
selectedCountryItem = countrySelectionFragment.getCountryItem(countryDownloadName);
|
||||
}
|
||||
|
||||
final EditText selectCountryEdit = (EditText) view.findViewById(R.id.selectCountryEdit);
|
||||
if (!Algorithms.isEmpty(country)) {
|
||||
selectCountryEdit.setText(country);
|
||||
if (selectedCountryItem != null) {
|
||||
selectCountryEdit.setText(selectedCountryItem.getLocalName());
|
||||
}
|
||||
selectCountryEdit.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
SearchSelectionFragment countrySearchSelectionFragment =
|
||||
searchSelectionFragment;
|
||||
countrySearchSelectionFragment
|
||||
CountrySelectionFragment countryCountrySelectionFragment =
|
||||
countrySelectionFragment;
|
||||
countryCountrySelectionFragment
|
||||
.show(getChildFragmentManager(), "CountriesSearchSelectionFragment");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Button subscribeButton = (Button) view.findViewById(R.id.subscribeButton);
|
||||
subscribeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (inAppHelper != null) {
|
||||
userName = userNameEdit.getText().toString().trim();
|
||||
email = emailEdit.getText().toString().trim();
|
||||
country = selectCountryEdit.getText().toString().trim();
|
||||
final CheckBox hideUserNameCheckbox = (CheckBox) view.findViewById(R.id.hideUserNameCheckbox);
|
||||
hideUserNameCheckbox.setChecked(hideUserName);
|
||||
|
||||
if (Algorithms.isEmpty(userName)) {
|
||||
getMyApplication().showToastMessage("Please enter visible name");
|
||||
return;
|
||||
View editModeBottomView = view.findViewById(R.id.editModeBottomView);
|
||||
View purchaseCard = view.findViewById(R.id.purchaseCard);
|
||||
if (editMode) {
|
||||
editModeBottomView.setVisibility(View.VISIBLE);
|
||||
purchaseCard.setVisibility(View.GONE);
|
||||
|
||||
Button saveChangesButton = (Button) view.findViewById(R.id.saveChangesButton);
|
||||
saveChangesButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (applySettings(userNameEdit.getText().toString().trim(),
|
||||
emailEdit.getText().toString().trim(), hideUserNameCheckbox.isChecked())) {
|
||||
|
||||
final Map<String, String> parameters = new HashMap<>();
|
||||
parameters.put("visibleName", settings.BILLING_HIDE_USER_NAME.get() ? "" : settings.BILLING_USER_NAME.get());
|
||||
parameters.put("preferredCountry", settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get());
|
||||
parameters.put("email", settings.BILLING_USER_EMAIL.get());
|
||||
parameters.put("cemail", prevEmail);
|
||||
parameters.put("userid", settings.BILLING_USER_ID.get());
|
||||
|
||||
showProgress();
|
||||
|
||||
AndroidNetworkUtils.sendRequestAsync(getMyApplication(),
|
||||
"http://download.osmand.net/subscription/update.php",
|
||||
parameters, "Sending data...", new AndroidNetworkUtils.OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String result) {
|
||||
dismissProgress();
|
||||
OsmandApplication app = getMyApplication();
|
||||
if (result != null) {
|
||||
try {
|
||||
JSONObject obj = new JSONObject(result);
|
||||
if (!obj.has("error")) {
|
||||
String userId = obj.getString("userid");
|
||||
app.getSettings().BILLING_USER_ID.set(userId);
|
||||
String email = obj.getString("email");
|
||||
app.getSettings().BILLING_USER_EMAIL.set(email);
|
||||
String visibleName = obj.getString("visibleName");
|
||||
if (!Algorithms.isEmpty(visibleName)) {
|
||||
app.getSettings().BILLING_USER_NAME.set(visibleName);
|
||||
app.getSettings().BILLING_HIDE_USER_NAME.set(false);
|
||||
} else {
|
||||
app.getSettings().BILLING_HIDE_USER_NAME.set(true);
|
||||
}
|
||||
String preferredCountry = obj.getString("preferredCountry");
|
||||
app.getSettings().BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(preferredCountry);
|
||||
|
||||
Fragment parent = getParentFragment();
|
||||
if (parent != null && parent instanceof LiveUpdatesFragment) {
|
||||
((LiveUpdatesFragment) parent).updateSubscriptionHeader();
|
||||
}
|
||||
|
||||
dismiss();
|
||||
} else {
|
||||
app.showToastMessage("Error: " + obj.getString("error"));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
app.showToastMessage(getString(R.string.shared_string_io_error));
|
||||
}
|
||||
} else {
|
||||
app.showToastMessage(getString(R.string.shared_string_io_error));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (Algorithms.isEmpty(email) || !AndroidUtils.isValidEmail(email)) {
|
||||
getMyApplication().showToastMessage("Please enter valid E-mail address");
|
||||
return;
|
||||
}
|
||||
|
||||
settings.BILLING_USER_NAME.set(userName);
|
||||
settings.BILLING_USER_EMAIL.set(email);
|
||||
settings.BILLING_USER_COUNTRY.set(country);
|
||||
|
||||
final WorldRegion world = getMyApplication().getRegions().getWorldRegion();
|
||||
String countryParam = country.equals(world.getLocaleName()) ? "" : country;
|
||||
|
||||
inAppHelper.purchaseLiveUpdates(getActivity(), email, userName, countryParam);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
editModeBottomView.setVisibility(View.GONE);
|
||||
purchaseCard.setVisibility(View.VISIBLE);
|
||||
|
||||
updatePrice(view);
|
||||
final Button subscribeButton = (Button) view.findViewById(R.id.subscribeButton);
|
||||
subscribeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (inAppHelper != null) {
|
||||
if (applySettings(userNameEdit.getText().toString().trim(),
|
||||
emailEdit.getText().toString().trim(), hideUserNameCheckbox.isChecked())) {
|
||||
|
||||
inAppHelper.purchaseLiveUpdates(getActivity(),
|
||||
settings.BILLING_USER_EMAIL.get(),
|
||||
settings.BILLING_USER_NAME.get(),
|
||||
settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get(),
|
||||
settings.BILLING_HIDE_USER_NAME.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setThemedDrawable((ImageView) view.findViewById(R.id.userNameIcon), R.drawable.ic_person);
|
||||
setThemedDrawable((ImageView) view.findViewById(R.id.emailIcon), R.drawable.ic_action_message);
|
||||
|
@ -140,17 +274,15 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
|
|||
selectCountryEdit.setCompoundDrawablesWithIntrinsicBounds(
|
||||
null, null, getContentIcon(R.drawable.ic_action_arrow_drop_down), null);
|
||||
|
||||
dlg = new ProgressDialog(getActivity());
|
||||
dlg.setTitle("");
|
||||
dlg.setMessage(getString(R.string.wait_current_task_finished));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
inAppHelper.stop();
|
||||
if (inAppHelper != null) {
|
||||
inAppHelper.stop();
|
||||
}
|
||||
if (dlg != null && dlg.isShowing()) {
|
||||
dlg.hide();
|
||||
}
|
||||
|
@ -160,22 +292,44 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
|
|||
}
|
||||
}
|
||||
|
||||
private boolean applySettings(String userName, String email, boolean hideUserName) {
|
||||
String countryName = selectedCountryItem != null ? selectedCountryItem.getLocalName() : "";
|
||||
String countryDownloadName = selectedCountryItem != null ? selectedCountryItem.getDownloadName() : "";
|
||||
|
||||
if (Algorithms.isEmpty(email) || !AndroidUtils.isValidEmail(email)) {
|
||||
getMyApplication().showToastMessage(getString(R.string.osm_live_enter_email));
|
||||
return false;
|
||||
}
|
||||
if (Algorithms.isEmpty(userName) && !hideUserName) {
|
||||
getMyApplication().showToastMessage(getString(R.string.osm_live_enter_user_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.BILLING_USER_NAME.set(userName);
|
||||
settings.BILLING_USER_EMAIL.set(email);
|
||||
settings.BILLING_USER_COUNTRY.set(countryName);
|
||||
settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(countryDownloadName);
|
||||
settings.BILLING_HIDE_USER_NAME.set(hideUserName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetItems() {
|
||||
|
||||
updatePrice(getView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemPurchased(String sku) {
|
||||
|
||||
if (InAppHelper.SKU_LIVE_UPDATES.equals(sku)) {
|
||||
if (InAppHelper.getSkuLiveUpdates().equals(sku)) {
|
||||
Fragment parentFragment = getParentFragment();
|
||||
if (parentFragment instanceof LiveUpdatesFragment) {
|
||||
((LiveUpdatesFragment) parentFragment).updateSubscriptionBanner();
|
||||
((LiveUpdatesFragment) parentFragment).updateSubscriptionHeader();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,97 +337,46 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
|
|||
}
|
||||
|
||||
@Override
|
||||
public void showHideProgress(boolean show) {
|
||||
if (show) {
|
||||
dlg.show();
|
||||
} else {
|
||||
dlg.hide();
|
||||
public void showProgress() {
|
||||
if (dlg != null) {
|
||||
dlg.dismiss();
|
||||
}
|
||||
dlg = new ProgressDialog(getActivity());
|
||||
dlg.setTitle("");
|
||||
dlg.setMessage(getString(R.string.wait_current_task_finished));
|
||||
dlg.setCancelable(false);
|
||||
dlg.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissProgress() {
|
||||
if (dlg != null) {
|
||||
dlg.dismiss();
|
||||
dlg = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSearchResult(String name) {
|
||||
public void onSearchResult(CountryItem item) {
|
||||
selectedCountryItem = item;
|
||||
View view = getView();
|
||||
if (view != null) {
|
||||
EditText selectCountryEdit = (EditText) view.findViewById(R.id.selectCountryEdit);
|
||||
if (selectCountryEdit != null) {
|
||||
selectCountryEdit.setText(name);
|
||||
selectCountryEdit.setText(item.getLocalName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initCountries() {
|
||||
final WorldRegion root = getMyApplication().getRegions().getWorldRegion();
|
||||
ArrayList<WorldRegion> groups = new ArrayList<>();
|
||||
groups.add(root);
|
||||
processGroup(root, groups, getActivity());
|
||||
Collections.sort(groups, new Comparator<WorldRegion>() {
|
||||
@Override
|
||||
public int compare(WorldRegion lhs, WorldRegion rhs) {
|
||||
if (lhs == root) {
|
||||
return -1;
|
||||
}
|
||||
if (rhs == root) {
|
||||
return 1;
|
||||
}
|
||||
return getHumanReadableName(lhs).compareTo(getHumanReadableName(rhs));
|
||||
private void updatePrice(View view) {
|
||||
if (view == null) {
|
||||
view = getView();
|
||||
}
|
||||
if (view != null) {
|
||||
TextView priceTextView = (TextView) view.findViewById(R.id.priceTextView);
|
||||
if (InAppHelper.getLiveUpdatesPrice() != null) {
|
||||
priceTextView.setText(InAppHelper.getLiveUpdatesPrice());
|
||||
}
|
||||
});
|
||||
for (WorldRegion group : groups) {
|
||||
String name = getHumanReadableName(group);
|
||||
regionNames.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processGroup(WorldRegion group,
|
||||
List<WorldRegion> nameList,
|
||||
Context context) {
|
||||
if (group.isRegionMapDownload()) {
|
||||
nameList.add(group);
|
||||
}
|
||||
|
||||
if (group.getSubregions() != null) {
|
||||
for (WorldRegion g : group.getSubregions()) {
|
||||
processGroup(g, nameList, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getHumanReadableName(WorldRegion group) {
|
||||
String name;
|
||||
if (group.getLevel() > 2 || (group.getLevel() == 2
|
||||
&& group.getSuperregion().getRegionId().equals(WorldRegion.RUSSIA_REGION_ID))) {
|
||||
WorldRegion parent = group.getSuperregion();
|
||||
WorldRegion parentsParent = group.getSuperregion().getSuperregion();
|
||||
if (group.getLevel() == 3) {
|
||||
if (parentsParent.getRegionId().equals(WorldRegion.RUSSIA_REGION_ID)) {
|
||||
name = parentsParent.getLocaleName() + " " + group.getLocaleName();
|
||||
} else if (!parent.getRegionId().equals(WorldRegion.UNITED_KINGDOM_REGION_ID)) {
|
||||
name = parent.getLocaleName() + " " + group.getLocaleName();
|
||||
} else {
|
||||
name = group.getLocaleName();
|
||||
}
|
||||
} else {
|
||||
name = parent.getLocaleName() + " " + group.getLocaleName();
|
||||
}
|
||||
} else {
|
||||
name = group.getLocaleName();
|
||||
}
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static class CountrySearchSelectionFragment extends SearchSelectionFragment {
|
||||
@Override
|
||||
protected ArrayList<String> getList() {
|
||||
return ((SubscriptionFragment) getParentFragment()).regionNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getListItemIcon() {
|
||||
return R.drawable.ic_map;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,8 @@ public class MapContextMenuFragment extends Fragment implements DownloadEvents {
|
|||
private int menuBottomViewHeight;
|
||||
private int menuFullHeight;
|
||||
private int menuFullHeightMax;
|
||||
private int menuTopViewHeightExcludingTitle;
|
||||
private int menuTitleTopBottomPadding;
|
||||
|
||||
private int screenHeight;
|
||||
private int viewHeight;
|
||||
|
@ -717,8 +719,19 @@ public class MapContextMenuFragment extends Fragment implements DownloadEvents {
|
|||
menuFullHeight = view.findViewById(R.id.context_menu_main).getHeight();
|
||||
|
||||
int dy = 0;
|
||||
if (!menu.isLandscapeLayout() && menuTopViewHeight != 0) {
|
||||
dy = Math.max(0, newMenuTopViewHeight - menuTopViewHeight - (newMenuTopShadowAllHeight - menuTopShadowAllHeight));
|
||||
if (!menu.isLandscapeLayout()) {
|
||||
TextView line1 = (TextView) view.findViewById(R.id.context_menu_line1);
|
||||
if (menuTopViewHeight != 0) {
|
||||
int titleHeight = line1.getLineCount() * line1.getLineHeight() + menuTitleTopBottomPadding;
|
||||
if (titleHeight < line1.getMeasuredHeight()) {
|
||||
titleHeight = line1.getMeasuredHeight();
|
||||
}
|
||||
newMenuTopViewHeight = menuTopViewHeightExcludingTitle + titleHeight;
|
||||
dy = Math.max(0, newMenuTopViewHeight - menuTopViewHeight - (newMenuTopShadowAllHeight - menuTopShadowAllHeight));
|
||||
} else {
|
||||
menuTopViewHeightExcludingTitle = newMenuTopViewHeight - line1.getMeasuredHeight();
|
||||
menuTitleTopBottomPadding = line1.getMeasuredHeight() - line1.getLineCount() * line1.getLineHeight();
|
||||
}
|
||||
}
|
||||
menuTopViewHeight = newMenuTopViewHeight;
|
||||
menuTopShadowAllHeight = newMenuTopShadowAllHeight;
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
package net.osmand.plus.osmo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.plus.GPXUtilities.WptPt;
|
||||
|
@ -24,6 +17,15 @@ import org.json.JSONArray;
|
|||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
||||
|
||||
private static final String GROUP_NAME = "name";
|
||||
|
@ -48,6 +50,8 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
private OsMoPlugin plugin;
|
||||
private OsmandApplication app;
|
||||
|
||||
private Gson gson = new Gson();
|
||||
|
||||
public interface OsMoGroupsUIListener {
|
||||
|
||||
public void groupsListChange(String operation, OsMoGroup group);
|
||||
|
@ -69,7 +73,7 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
}
|
||||
|
||||
public void addUiListeners(OsMoGroupsUIListener uiListener) {
|
||||
if (!uiListeners.contains(uiListener)){
|
||||
if (!uiListeners.contains(uiListener)) {
|
||||
uiListeners.add(uiListener);
|
||||
}
|
||||
}
|
||||
|
@ -79,12 +83,12 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
}
|
||||
|
||||
private void connectDeviceImpl(OsMoDevice d) {
|
||||
d.enabled = true;
|
||||
d.enabled = true;
|
||||
d.active = true;
|
||||
String mid = service.getMyTrackerId();
|
||||
String mgid = service.getMyGroupTrackerId();
|
||||
if ((mid == null || !mid.equals(d.getTrackerId()))
|
||||
&& (mgid == null || !mgid.equals(d.getTrackerId()))) {
|
||||
&& (mgid == null || !mgid.equals(d.getTrackerId()))) {
|
||||
tracker.startTrackingId(d);
|
||||
}
|
||||
}
|
||||
|
@ -115,9 +119,9 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
|
||||
public String disconnectGroup(OsMoGroup model) {
|
||||
model.enabled = false;
|
||||
String operation = "GROUP_DISCONNECT:"+model.groupId;
|
||||
String operation = "GROUP_DISCONNECT:" + model.groupId;
|
||||
service.pushCommand(operation);
|
||||
for(OsMoDevice d : model.getGroupUsers(null)) {
|
||||
for (OsMoDevice d : model.getGroupUsers(null)) {
|
||||
tracker.stopTrackingId(d);
|
||||
}
|
||||
storage.save();
|
||||
|
@ -144,7 +148,7 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
for (OsMoGroup g : getGroups()) {
|
||||
OsMoDevice d = g.updateLastLocation(trackerId, location);
|
||||
if (d != null && uiListeners != null) {
|
||||
for(OsMoGroupsUIListener listener : uiListeners) {
|
||||
for (OsMoGroupsUIListener listener : uiListeners) {
|
||||
listener.deviceLocationChanged(d);
|
||||
}
|
||||
}
|
||||
|
@ -157,47 +161,47 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
boolean processed = false;
|
||||
String operation = command + ":" + gid;
|
||||
OsMoGroup group = null;
|
||||
if(command.equalsIgnoreCase("GP")) {
|
||||
if (command.equalsIgnoreCase("GP")) {
|
||||
group = storage.getGroup(gid);
|
||||
if(group != null && gid.length() > 0) {
|
||||
if (group != null && gid.length() > 0) {
|
||||
List<OsMoDevice> delta = mergeGroup(group, obj, false);
|
||||
String mygid = service.getMyGroupTrackerId();
|
||||
StringBuilder b = new StringBuilder();
|
||||
for(OsMoDevice d : delta) {
|
||||
if(d.getDeletedTimestamp() != 0 && d.isEnabled()) {
|
||||
if(group.name != null && !d.getTrackerId().equals(mygid)) {
|
||||
for (OsMoDevice d : delta) {
|
||||
if (d.getDeletedTimestamp() != 0 && d.isEnabled()) {
|
||||
if (group.name != null && !d.getTrackerId().equals(mygid)) {
|
||||
b.append(app.getString(R.string.osmo_user_left, d.getVisibleName(), group.getVisibleName(app))).append("\n");
|
||||
}
|
||||
disconnectImpl(d);
|
||||
} else if(!d.isActive()) {
|
||||
if(group.name != null && !d.getTrackerId().equals(mygid)) {
|
||||
} else if (!d.isActive()) {
|
||||
if (group.name != null && !d.getTrackerId().equals(mygid)) {
|
||||
b.append(app.getString(R.string.osmo_user_joined, d.getVisibleName(), group.getVisibleName(app))).append("\n");
|
||||
}
|
||||
connectDeviceImpl(d);
|
||||
}
|
||||
}
|
||||
if(b.length() > 0 && app.getSettings().OSMO_SHOW_GROUP_NOTIFICATIONS.get()){
|
||||
if (b.length() > 0 && app.getSettings().OSMO_SHOW_GROUP_NOTIFICATIONS.get()) {
|
||||
app.showToastMessage(b.toString().trim());
|
||||
}
|
||||
storage.save();
|
||||
}
|
||||
processed = true;
|
||||
} else if(command.equalsIgnoreCase("GROUP_DISCONNECT")) {
|
||||
} else if (command.equalsIgnoreCase("GROUP_DISCONNECT")) {
|
||||
group = storage.getGroup(gid);
|
||||
if(group != null) {
|
||||
if (group != null) {
|
||||
disconnectAllGroupUsers(group);
|
||||
disableGroupTracks(group, group.groupTracks);
|
||||
disableGroupTracks(group, Collections.singleton(group.name + " points.gpx"));
|
||||
}
|
||||
processed = true;
|
||||
} else if(command.equalsIgnoreCase("GROUP_CONNECT")) {
|
||||
} else if (command.equalsIgnoreCase("GROUP_CONNECT")) {
|
||||
group = storage.getGroup(gid);
|
||||
if(group != null) {
|
||||
if (group != null) {
|
||||
mergeGroup(group, obj, true);
|
||||
group.active = true;
|
||||
// connect to enabled devices in group
|
||||
for(OsMoDevice d : group.getGroupUsers(null)) {
|
||||
if(d.isEnabled()) {
|
||||
for (OsMoDevice d : group.getGroupUsers(null)) {
|
||||
if (d.isEnabled()) {
|
||||
d.active = false;
|
||||
connectDeviceImpl(d);
|
||||
}
|
||||
|
@ -205,8 +209,8 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
storage.save();
|
||||
}
|
||||
processed = true;
|
||||
} else if(command.equalsIgnoreCase("GROUP_CREATE") || command.equalsIgnoreCase("GROUP_JOIN") ) {
|
||||
if(command.equalsIgnoreCase("GROUP_CREATE")) {
|
||||
} else if (command.equalsIgnoreCase("GROUP_CREATE") || command.equalsIgnoreCase("GROUP_JOIN")) {
|
||||
if (command.equalsIgnoreCase("GROUP_CREATE")) {
|
||||
operation = command;
|
||||
try {
|
||||
gid = obj.getString(GROUP_ID);
|
||||
|
@ -217,7 +221,7 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
}
|
||||
}
|
||||
group = storage.getGroup(gid);
|
||||
if(group == null) {
|
||||
if (group == null) {
|
||||
group = new OsMoGroup();
|
||||
group.groupId = gid;
|
||||
storage.addGroup(group);
|
||||
|
@ -225,9 +229,9 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
connectGroupImpl(group);
|
||||
storage.save();
|
||||
processed = true;
|
||||
} else if(command.equals("GROUP_LEAVE")) {
|
||||
} else if (command.equals("GROUP_LEAVE")) {
|
||||
group = storage.getGroup(gid);
|
||||
if(group != null) {
|
||||
if (group != null) {
|
||||
storage.deleteGroup(group);
|
||||
}
|
||||
storage.save();
|
||||
|
@ -248,8 +252,8 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
storage.save();
|
||||
}
|
||||
processed = true;
|
||||
for(OsMoGroup g : storage.getGroups()) {
|
||||
if(!g.isMainGroup() && g.isEnabled()) {
|
||||
for (OsMoGroup g : storage.getGroups()) {
|
||||
if (!g.isMainGroup() && g.isEnabled()) {
|
||||
connectGroupImpl(g);
|
||||
}
|
||||
}
|
||||
|
@ -259,8 +263,8 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
return processed;
|
||||
}
|
||||
}
|
||||
if(processed && uiListeners != null) {
|
||||
for(OsMoGroupsUIListener listener : uiListeners){
|
||||
if (processed && uiListeners != null) {
|
||||
for (OsMoGroupsUIListener listener : uiListeners) {
|
||||
listener.groupsListChange(operation, group);
|
||||
}
|
||||
|
||||
|
@ -269,11 +273,11 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
}
|
||||
|
||||
private void disableGroupTracks(OsMoGroup group, Collection<String> tracks) {
|
||||
if(!tracks.isEmpty()) {
|
||||
if (!tracks.isEmpty()) {
|
||||
GpxSelectionHelper helper = app.getSelectedGpxHelper();
|
||||
for(String t : tracks) {
|
||||
SelectedGpxFile sg = helper.getSelectedFileByName("osmo/"+t);
|
||||
if(sg != null && sg.getGpxFile() != null) {
|
||||
for (String t : tracks) {
|
||||
SelectedGpxFile sg = helper.getSelectedFileByName("osmo/" + t);
|
||||
if (sg != null && sg.getGpxFile() != null) {
|
||||
helper.selectGpxFile(sg.getGpxFile(), false, false);
|
||||
}
|
||||
}
|
||||
|
@ -295,16 +299,16 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
|
||||
private void parseGroup(JSONObject obj, OsMoGroup gr) {
|
||||
try {
|
||||
if(obj.has(GROUP_NAME)) {
|
||||
if (obj.has(GROUP_NAME)) {
|
||||
gr.name = obj.getString(GROUP_NAME);
|
||||
}
|
||||
if(obj.has(DESCRIPTION)) {
|
||||
if (obj.has(DESCRIPTION)) {
|
||||
gr.description = obj.getString(DESCRIPTION);
|
||||
}
|
||||
if(obj.has(POLICY)) {
|
||||
if (obj.has(POLICY)) {
|
||||
gr.policy = obj.getString(POLICY);
|
||||
}
|
||||
if(obj.has(EXPIRE_TIME)) {
|
||||
if (obj.has(EXPIRE_TIME)) {
|
||||
gr.expireTime = obj.getLong(EXPIRE_TIME);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
|
@ -316,7 +320,7 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
|
||||
private void disconnectAllGroupUsers(OsMoGroup gr) {
|
||||
gr.active = false;
|
||||
for(OsMoDevice d : gr.getGroupUsers(null)) {
|
||||
for (OsMoDevice d : gr.getGroupUsers(null)) {
|
||||
disconnectImpl(d);
|
||||
}
|
||||
}
|
||||
|
@ -325,7 +329,7 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
private List<OsMoDevice> mergeGroup(OsMoGroup gr, JSONObject obj, boolean deleteUsers) {
|
||||
List<OsMoDevice> delta = new ArrayList<OsMoDevice>();
|
||||
try {
|
||||
if(obj.has("group")) {
|
||||
if (obj.has("group")) {
|
||||
parseGroup(obj.getJSONObject("group"), gr);
|
||||
}
|
||||
Map<String, OsMoDevice> toDelete = new HashMap<String, OsMoDevice>(gr.users);
|
||||
|
@ -404,12 +408,12 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
}
|
||||
points.add(pt);
|
||||
}
|
||||
if(points.size() > 0) {
|
||||
if (points.size() > 0) {
|
||||
plugin.getSaveGpxTask(gr.name + " points", modify, false).execute(points.toArray(new WptPt[points.size()]));
|
||||
}
|
||||
}
|
||||
if(deleteUsers) {
|
||||
for(OsMoDevice s : toDelete.values()) {
|
||||
if (deleteUsers) {
|
||||
for (OsMoDevice s : toDelete.values()) {
|
||||
s.deleted = System.currentTimeMillis();
|
||||
delta.add(s);
|
||||
}
|
||||
|
@ -423,17 +427,10 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
|
||||
|
||||
public String createGroup(String groupName, boolean onlyByInvite, String description, String policy) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
obj.put("name", groupName);
|
||||
obj.put("onlyByInvite", onlyByInvite);
|
||||
obj.put("description", description);
|
||||
obj.put("policy", policy);
|
||||
service.pushCommand("GROUP_CREATE|" + obj.toString());
|
||||
return "GROUP_CREATE";
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Protocol.CreateGroupData obj = new Protocol.CreateGroupData(groupName,
|
||||
onlyByInvite, description, policy);
|
||||
service.pushCommand("GROUP_CREATE|" + gson.toJson(obj));
|
||||
return "GROUP_CREATE";
|
||||
}
|
||||
|
||||
|
||||
|
@ -443,24 +440,24 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
}
|
||||
|
||||
public String joinGroup(String groupId, String userName, String nick) {
|
||||
final String op = "GROUP_JOIN:"+groupId+"|"+nick;
|
||||
final String op = "GROUP_JOIN:" + groupId + "|" + nick;
|
||||
OsMoGroup g = storage.getGroup(groupId);
|
||||
if(g == null){
|
||||
if (g == null) {
|
||||
g = new OsMoGroup();
|
||||
g.groupId = groupId;
|
||||
storage.addGroup(g);
|
||||
}
|
||||
g.userName = userName;
|
||||
service.pushCommand(op);
|
||||
return "GROUP_JOIN:"+groupId;
|
||||
return "GROUP_JOIN:" + groupId;
|
||||
}
|
||||
|
||||
public String leaveGroup(OsMoGroup group) {
|
||||
final String op = "GROUP_LEAVE:"+group.groupId;
|
||||
final String op = "GROUP_LEAVE:" + group.groupId;
|
||||
storage.deleteGroup(group);
|
||||
storage.save();
|
||||
service.pushCommand(op);
|
||||
if(group.isEnabled()) {
|
||||
if (group.isEnabled()) {
|
||||
group.enabled = false;
|
||||
disconnectAllGroupUsers(group);
|
||||
}
|
||||
|
@ -483,5 +480,4 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
|
|||
storage.clearGroups();
|
||||
storage.save();
|
||||
}
|
||||
|
||||
}
|
|
@ -617,9 +617,9 @@ public class OsMoGroupsActivity extends OsmandExpandableListActivity implements
|
|||
if (!checkOperationIsNotRunning()) {
|
||||
return;
|
||||
}
|
||||
String operation = osMoPlugin.getGroups().leaveGroup((OsMoGroup) selectedObject);
|
||||
String operation = osMoPlugin.getGroups().leaveGroup(selectedObject);
|
||||
startLongRunningOperation(operation);
|
||||
adapter.update((OsMoGroup) selectedObject);
|
||||
adapter.update(selectedObject);
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
}
|
||||
|
@ -1037,7 +1037,7 @@ public class OsMoGroupsActivity extends OsmandExpandableListActivity implements
|
|||
}
|
||||
|
||||
public void hideProgressBar() {
|
||||
OsMoGroupsActivity.this.operation = null;
|
||||
this.operation = null;
|
||||
setSupportProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
|
||||
|
@ -1210,7 +1210,7 @@ public class OsMoGroupsActivity extends OsmandExpandableListActivity implements
|
|||
} else {
|
||||
label.setTypeface(Typeface.DEFAULT, Typeface.ITALIC);
|
||||
}
|
||||
View v = (View) row.findViewById(R.id.settings);
|
||||
View v = row.findViewById(R.id.settings);
|
||||
if(model.isMainGroup()) {
|
||||
v.setVisibility(View.GONE);
|
||||
} else {
|
||||
|
@ -1383,7 +1383,7 @@ public class OsMoGroupsActivity extends OsmandExpandableListActivity implements
|
|||
Message msg = Message.obtain(uiHandler, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.notifyDataSetInvalidated();
|
||||
adapter.notifyDataSetChanged();
|
||||
updateStatus();
|
||||
}
|
||||
});
|
||||
|
|
17
OsmAnd/src/net/osmand/plus/osmo/Protocol.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package net.osmand.plus.osmo;
|
||||
|
||||
public class Protocol {
|
||||
public static class CreateGroupData {
|
||||
public final String name;
|
||||
public final boolean onlyByInvite;
|
||||
public final String description;
|
||||
public final String policy;
|
||||
|
||||
public CreateGroupData(String name, boolean onlyByInvite, String description, String policy) {
|
||||
this.name = name;
|
||||
this.onlyByInvite = onlyByInvite;
|
||||
this.description = description;
|
||||
this.policy = policy;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ public class DoubleTapScaleDetector {
|
|||
secondDown = null;
|
||||
if (isDoubleTapping) {
|
||||
isDoubleTapping = false;
|
||||
listener.onZoomEnded(scale, 0);
|
||||
listener.onZoomEnded(scale);
|
||||
return true;
|
||||
} else {
|
||||
firstUp = MotionEvent.obtain(event);
|
||||
|
@ -77,7 +77,7 @@ public class DoubleTapScaleDetector {
|
|||
float delta = convertPxToDp((int) (firstDown.getY() - event.getY()));
|
||||
float scaleDelta = delta / (displayHeightPx / SCALE_PER_SCREEN);
|
||||
scale = 1 - scaleDelta;
|
||||
listener.onZoomingOrRotating(scale, 0);
|
||||
listener.onZooming(scale);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +130,9 @@ public class DoubleTapScaleDetector {
|
|||
public interface DoubleTapZoomListener {
|
||||
public void onZoomStarted(PointF centerPoint);
|
||||
|
||||
public void onZoomingOrRotating(double relativeToStart, float angle);
|
||||
public void onZooming(double relativeToStart);
|
||||
|
||||
public void onZoomEnded(double relativeToStart, float angleRelative);
|
||||
public void onZoomEnded(double relativeToStart);
|
||||
|
||||
public void onGestureInit(float x1, float y1, float x2, float y2);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package net.osmand.plus.views;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
|
||||
import net.osmand.util.MapUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
public class MultiTouchSupport {
|
||||
|
||||
|
@ -29,7 +29,7 @@ public class MultiTouchSupport {
|
|||
|
||||
public void onZoomingOrRotating(double relativeToStart, float angle);
|
||||
|
||||
public void onZoomEnded(double relativeToStart, float angleRelative);
|
||||
public void onZoomOrRotationEnded(double relativeToStart, float angleRelative);
|
||||
|
||||
public void onGestureInit(float x1, float y1, float x2, float y2);
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class MultiTouchSupport {
|
|||
Integer pointCount = (Integer) getPointerCount.invoke(event);
|
||||
if(pointCount < 2){
|
||||
if(inZoomMode){
|
||||
listener.onZoomEnded(zoomRelative, angleRelative);
|
||||
listener.onZoomOrRotationEnded(zoomRelative, angleRelative);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public class MultiTouchSupport {
|
|||
return true;
|
||||
} else if(actionCode == ACTION_POINTER_UP){
|
||||
if(inZoomMode){
|
||||
listener.onZoomEnded(zoomRelative, angleRelative);
|
||||
listener.onZoomOrRotationEnded(zoomRelative, angleRelative);
|
||||
inZoomMode = false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -73,6 +73,9 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
private OsmandApplication application;
|
||||
protected OsmandSettings settings = null;
|
||||
|
||||
private int maxZoom;
|
||||
private int minZoom;
|
||||
|
||||
private class FPSMeasurement {
|
||||
int fpsMeasureCount = 0;
|
||||
int fpsMeasureMs = 0;
|
||||
|
@ -167,7 +170,9 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
@Override
|
||||
public void onTwoFingerTap() {
|
||||
afterTwoFingerTap = true;
|
||||
getAnimatedDraggingThread().startZooming(getZoom() - 1, currentViewport.getZoomFloatPart(), true);
|
||||
if (isZoomingAllowed(getZoom(), -1)) {
|
||||
getAnimatedDraggingThread().startZooming(getZoom() - 1, currentViewport.getZoomFloatPart(), true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -301,7 +306,9 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
|
||||
// ///////////////////////// NON UI PART (could be extracted in common) /////////////////////////////
|
||||
public void setIntZoom(int zoom) {
|
||||
if (mainLayer != null && zoom <= mainLayer.getMaximumShownMapZoom() && zoom >= mainLayer.getMinimumShownMapZoom()) {
|
||||
zoom = zoom > maxZoom ? maxZoom : zoom;
|
||||
zoom = zoom < minZoom ? minZoom : zoom;
|
||||
if (mainLayer != null) {
|
||||
animatedDraggingThread.stopAnimating();
|
||||
currentViewport.setZoomAndAnimation(zoom, 0, 0);
|
||||
currentViewport.setRotate(zoom > LOWEST_ZOOM_TO_ROTATE ? rotate : 0);
|
||||
|
@ -310,7 +317,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
}
|
||||
|
||||
public void setComplexZoom(int zoom, double mapDensity) {
|
||||
if (mainLayer != null && zoom <= mainLayer.getMaximumShownMapZoom() && zoom >= mainLayer.getMinimumShownMapZoom()) {
|
||||
if (mainLayer != null && zoom <= maxZoom && zoom >= minZoom) {
|
||||
animatedDraggingThread.stopAnimating();
|
||||
currentViewport.setZoomAndAnimation(zoom, 0);
|
||||
currentViewport.setMapDensity(mapDensity);
|
||||
|
@ -396,11 +403,13 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
public void setMainLayer(BaseMapLayer mainLayer) {
|
||||
this.mainLayer = mainLayer;
|
||||
int zoom = currentViewport.getZoom();
|
||||
if (mainLayer.getMaximumShownMapZoom() < zoom) {
|
||||
zoom = mainLayer.getMaximumShownMapZoom();
|
||||
maxZoom = mainLayer.getMaximumShownMapZoom() - 1;
|
||||
minZoom = mainLayer.getMinimumShownMapZoom() + 1;
|
||||
if (maxZoom < zoom) {
|
||||
zoom = maxZoom;
|
||||
}
|
||||
if (mainLayer.getMinimumShownMapZoom() > zoom) {
|
||||
zoom = mainLayer.getMinimumShownMapZoom();
|
||||
if (minZoom > zoom) {
|
||||
zoom = minZoom;
|
||||
}
|
||||
currentViewport.setZoomAndAnimation(zoom, 0, 0);
|
||||
refreshMap();
|
||||
|
@ -736,7 +745,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
|
||||
// for internal usage
|
||||
protected void zoomToAnimate(int zoom, double zoomToAnimate, boolean notify) {
|
||||
if (mainLayer != null && mainLayer.getMaximumShownMapZoom() >= zoom && mainLayer.getMinimumShownMapZoom() <= zoom) {
|
||||
if (mainLayer != null && maxZoom >= zoom && minZoom <= zoom) {
|
||||
currentViewport.setZoomAndAnimation(zoom, zoomToAnimate);
|
||||
currentViewport.setRotate(zoom > LOWEST_ZOOM_TO_ROTATE ? rotate : 0);
|
||||
refreshMap();
|
||||
|
@ -859,7 +868,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
private static final float ANGLE_THRESHOLD = 15;
|
||||
|
||||
@Override
|
||||
public void onZoomEnded(double relativeToStart, float angleRelative) {
|
||||
public void onZoomOrRotationEnded(double relativeToStart, float angleRelative) {
|
||||
// 1.5 works better even on dm.density=1 devices
|
||||
float dz = (float) (Math.log(relativeToStart) / Math.log(2)) * 1.5f;
|
||||
setIntZoom(Math.round(dz) + initialViewport.getZoom());
|
||||
|
@ -880,6 +889,24 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onZoomEnded(double relativeToStart) {
|
||||
// 1.5 works better even on dm.density=1 devices
|
||||
float dz = (float) ((relativeToStart - 1) * DoubleTapScaleDetector.SCALE_PER_SCREEN);
|
||||
setIntZoom(Math.round(dz) + initialViewport.getZoom());
|
||||
final int newZoom = getZoom();
|
||||
if (application.accessibilityEnabled()) {
|
||||
if (newZoom != initialViewport.getZoom()) {
|
||||
showMessage(application.getString(R.string.zoomIs) + " " + newZoom); //$NON-NLS-1$
|
||||
} else {
|
||||
final LatLon p1 = initialViewport.getLatLonFromPixel(x1, y1);
|
||||
final LatLon p2 = initialViewport.getLatLonFromPixel(x2, y2);
|
||||
showMessage(OsmAndFormatter.getFormattedDistance((float) MapUtils.getDistance(p1.getLatitude(), p1.getLongitude(), p2.getLatitude(), p2.getLongitude()), application));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onGestureInit(float x1, float y1, float x2, float y2) {
|
||||
this.x1 = x1;
|
||||
|
@ -912,7 +939,12 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
if (dz != 0 || relAngle != 0) {
|
||||
changeZoomPosition((float) dz, relAngle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onZooming(double relativeToStart) {
|
||||
double dz = (relativeToStart - 1) * DoubleTapScaleDetector.SCALE_PER_SCREEN;
|
||||
changeZoomPosition((float) dz, 0);
|
||||
}
|
||||
|
||||
private void changeZoomPosition(float dz, float angle) {
|
||||
|
@ -929,26 +961,39 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
final LatLon r = calc.getLatLonFromPixel(cp.x + dx, cp.y + dy);
|
||||
setLatLon(r.getLatitude(), r.getLongitude());
|
||||
int baseZoom = initialViewport.getZoom();
|
||||
LOG.debug("baseZoom=" + baseZoom);
|
||||
while (initialViewport.getZoomFloatPart() + dz > 1) {
|
||||
while (initialViewport.getZoomFloatPart() + dz > 1 && isZoomingAllowed(baseZoom, dz)) {
|
||||
dz--;
|
||||
if (baseZoom < mainLayer.getMaximumShownMapZoom()) {
|
||||
baseZoom++;
|
||||
}
|
||||
baseZoom++;
|
||||
}
|
||||
while (initialViewport.getZoomFloatPart() + dz < 0) {
|
||||
while (initialViewport.getZoomFloatPart() + dz < 0 && isZoomingAllowed(baseZoom, dz)) {
|
||||
dz++;
|
||||
if (baseZoom > mainLayer.getMinimumShownMapZoom()) {
|
||||
baseZoom--;
|
||||
}
|
||||
baseZoom--;
|
||||
}
|
||||
if (!isZoomingAllowed(baseZoom, dz)) {
|
||||
dz = 0;
|
||||
}
|
||||
LOG.debug("baseZoom=" + baseZoom);
|
||||
zoomToAnimate(baseZoom, dz, true);
|
||||
rotateToAnimate(calcRotate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isZoomingAllowed(int baseZoom, float dz) {
|
||||
if (baseZoom > maxZoom) {
|
||||
return false;
|
||||
}
|
||||
if (baseZoom == maxZoom - 2 && dz > 1) {
|
||||
return false;
|
||||
}
|
||||
if (baseZoom < minZoom) {
|
||||
return false;
|
||||
}
|
||||
if (baseZoom == minZoom + 2 && dz < -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private class MapTileViewOnGestureListener extends SimpleOnGestureListener {
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
|
@ -1019,10 +1064,12 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
|||
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent e) {
|
||||
final RotatedTileBox tb = getCurrentRotatedTileBox();
|
||||
final double lat = tb.getLatFromPixel(e.getX(), e.getY());
|
||||
final double lon = tb.getLonFromPixel(e.getX(), e.getY());
|
||||
getAnimatedDraggingThread().startMoving(lat, lon, getZoom() + 1, true);
|
||||
if (isZoomingAllowed(getZoom(), 1)) {
|
||||
final RotatedTileBox tb = getCurrentRotatedTileBox();
|
||||
final double lat = tb.getLatFromPixel(e.getX(), e.getY());
|
||||
final double lon = tb.getLonFromPixel(e.getX(), e.getY());
|
||||
getAnimatedDraggingThread().startMoving(lat, lon, getZoom() + 1, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|