Compare commits

..

7 Commits

Author SHA1 Message Date
Jean-Baptiste
ffea67a2b3 [android] Rework socials networks on the place page
Signed-off-by: Jean-Baptiste <jeanbaptiste.charron@outlook.fr>
2025-11-14 23:32:48 +01:00
map-per
9bfebc2046 Add "Business is vacant"/'disused' option to editor (#526)
Signed-off-by: map-per <map-per@gmx.de>
Co-authored-by: map-per <map-per@gmx.de>
Co-committed-by: map-per <map-per@gmx.de>
2025-11-14 22:10:02 +01:00
Jean-Baptiste
24b498e386 [android] Fix FAB styles not apply
Signed-off-by: Jean-Baptiste <jeanbaptiste.charron@outlook.fr>
2025-11-14 19:34:23 +01:00
Jean-Baptiste
0a0bb61942 [android] Improve opening_hours layout in the editor
Signed-off-by: Jean-Baptiste <jeanbaptiste.charron@outlook.fr>
2025-11-14 19:26:33 +01:00
x7z4w
d78fe108ad [tools][styles] Suppress drules diffs output
Signed-off-by: x7z4w <x7z4w@noreply.codeberg.org>
2025-11-14 14:08:02 +01:00
x7z4w
4aa441101c [tools] Cache python bytecode
Signed-off-by: x7z4w <x7z4w@noreply.codeberg.org>
2025-11-14 14:08:02 +01:00
Konstantin Pastbin
2d275d9148 [generator] Use more threads to Index Taiwan_*
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-11-14 13:59:25 +01:00
38 changed files with 563 additions and 257 deletions

View File

@@ -153,6 +153,7 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
private final Map<Metadata.MetadataType, View> mDetailsBlocks = new HashMap<>();
private final Map<Metadata.MetadataType, View> mSocialMediaBlocks = new HashMap<>();
private MaterialButton mReset;
private MaterialButton mDisused;
private EditorHostFragment mParent;
@@ -827,6 +828,8 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
osmInfo.setMovementMethod(LinkMovementMethod.getInstance());
mReset = view.findViewById(R.id.reset);
mReset.setOnClickListener(this);
mDisused = view.findViewById(R.id.disused);
mDisused.setOnClickListener(this);
mDetailsBlocks.put(Metadata.MetadataType.FMD_OPEN_HOURS, blockOpeningHours);
mDetailsBlocks.put(Metadata.MetadataType.FMD_PHONE_NUMBER, blockPhone);
@@ -894,6 +897,8 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
mParent.addLanguage();
else if (id == R.id.reset)
reset();
else if (id == R.id.disused)
placeDisused();
else if (id == R.id.block_outdoor_seating)
mOutdoorSeating.toggle();
}
@@ -939,9 +944,12 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
if (mParent.addingNewObject())
{
UiUtils.hide(mReset);
UiUtils.hide(mDisused);
return;
}
mDisused.setVisibility(Editor.nativeCanMarkPlaceAsDisused() ? View.VISIBLE : View.GONE);
if (Editor.nativeIsMapObjectUploaded())
{
mReset.setText(R.string.editor_place_doesnt_exist);
@@ -1014,6 +1022,19 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
dialogFragment.setTextSaveListener(this::commitPlaceDoesntExists);
}
private void placeDisused()
{
new MaterialAlertDialogBuilder(requireActivity(), R.style.MwmTheme_AlertDialog)
.setTitle(R.string.editor_mark_business_vacant_title)
.setMessage(R.string.editor_mark_business_vacant_description)
.setPositiveButton(R.string.editor_submit, (dlg, which) -> {
Editor.nativeMarkPlaceAsDisused();
mParent.processEditedFeatures();
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
private void commitPlaceDoesntExists(@NonNull String text)
{
Editor.nativePlaceDoesNotExist(text);

View File

@@ -358,7 +358,7 @@ public class EditorHostFragment
.show();
}
private void processEditedFeatures()
public void processEditedFeatures()
{
if (OsmOAuth.isAuthorized())
{

View File

@@ -20,6 +20,8 @@ import app.organicmaps.sdk.bookmarks.data.Metadata;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.placepage.PlacePageUtils;
import app.organicmaps.widget.placepage.PlacePageViewModel;
import com.google.android.material.imageview.ShapeableImageView;
import com.google.android.material.textview.MaterialTextView;
import java.util.ArrayList;
import java.util.List;
@@ -29,21 +31,15 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
private static final String TAG = PlacePageLinksFragment.class.getSimpleName();
private View mFrame;
private View mFacebookPage;
private MaterialTextView mTvFacebookPage;
private View mInstagramPage;
private MaterialTextView mTvInstagramPage;
private View mTwitterPage;
private MaterialTextView mTvTwitterPage;
private View mFediversePage;
private MaterialTextView mTvFediversePage;
private View mBlueskyPage;
private MaterialTextView mTvBlueskyPage;
private View mVkPage;
private MaterialTextView mTvVkPage;
private View mLinePage;
private MaterialTextView mTvLinePage;
private View mSocial;
private ShapeableImageView mFacebookIv;
private ShapeableImageView mInstagramIv;
private ShapeableImageView mTwitterIv;
private ShapeableImageView mFediverseIv;
private ShapeableImageView mBlueskyIv;
private ShapeableImageView mVkIv;
private ShapeableImageView mLineIv;
private View mWebsite;
private MaterialTextView mTvWebsite;
private View mWebsiteMenu;
@@ -71,6 +67,16 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
metaLayout.setVisibility(GONE);
}
private static void refreshMetadataOrHideSocial(@Nullable String metadata, @NonNull ShapeableImageView metaIv)
{
if (!TextUtils.isEmpty(metadata))
{
metaIv.setVisibility(VISIBLE);
}
else
metaIv.setVisibility(GONE);
}
@NonNull
private String getLink(@NonNull Metadata.MetadataType type)
{
@@ -128,40 +134,35 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
mWikimedia.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_WIKIMEDIA_COMMONS));
mWikimedia.setOnLongClickListener((v) -> copyUrl(mWikimedia, Metadata.MetadataType.FMD_WIKIMEDIA_COMMONS));
mFacebookPage = mFrame.findViewById(R.id.ll__place_facebook);
mTvFacebookPage = mFrame.findViewById(R.id.tv__place_facebook_page);
mFacebookPage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_FACEBOOK));
mFacebookPage.setOnLongClickListener((v) -> copyUrl(mFacebookPage, Metadata.MetadataType.FMD_CONTACT_FACEBOOK));
mSocial = mFrame.findViewById(R.id.ll__place_social);
mInstagramPage = mFrame.findViewById(R.id.ll__place_instagram);
mTvInstagramPage = mFrame.findViewById(R.id.tv__place_instagram_page);
mInstagramPage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_INSTAGRAM));
mInstagramPage.setOnLongClickListener((v) -> copyUrl(mInstagramPage, Metadata.MetadataType.FMD_CONTACT_INSTAGRAM));
mFacebookIv = mSocial.findViewById(R.id.iv__place_facebook);
mFacebookIv.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_FACEBOOK));
mFacebookIv.setOnLongClickListener((v) -> copyUrl(mFacebookIv, Metadata.MetadataType.FMD_CONTACT_FACEBOOK));
mFediversePage = mFrame.findViewById(R.id.ll__place_fediverse);
mTvFediversePage = mFrame.findViewById(R.id.tv__place_fediverse_page);
mFediversePage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_FEDIVERSE));
mFediversePage.setOnLongClickListener((v) -> copyUrl(mFediversePage, Metadata.MetadataType.FMD_CONTACT_FEDIVERSE));
mInstagramIv = mSocial.findViewById(R.id.iv__place_instagram);
mInstagramIv.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_INSTAGRAM));
mInstagramIv.setOnLongClickListener((v) -> copyUrl(mInstagramIv, Metadata.MetadataType.FMD_CONTACT_INSTAGRAM));
mBlueskyPage = mFrame.findViewById(R.id.ll__place_bluesky);
mTvBlueskyPage = mFrame.findViewById(R.id.tv__place_bluesky_page);
mBlueskyPage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_BLUESKY));
mBlueskyPage.setOnLongClickListener((v) -> copyUrl(mBlueskyPage, Metadata.MetadataType.FMD_CONTACT_BLUESKY));
mFediverseIv = mSocial.findViewById(R.id.iv__place_fediverse);
mFediverseIv.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_FEDIVERSE));
mFediverseIv.setOnLongClickListener((v) -> copyUrl(mFediverseIv, Metadata.MetadataType.FMD_CONTACT_FEDIVERSE));
mTwitterPage = mFrame.findViewById(R.id.ll__place_twitter);
mTvTwitterPage = mFrame.findViewById(R.id.tv__place_twitter_page);
mTwitterPage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_TWITTER));
mTwitterPage.setOnLongClickListener((v) -> copyUrl(mTwitterPage, Metadata.MetadataType.FMD_CONTACT_TWITTER));
mBlueskyIv = mSocial.findViewById(R.id.iv__place_bluesky);
mBlueskyIv.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_BLUESKY));
mBlueskyIv.setOnLongClickListener((v) -> copyUrl(mBlueskyIv, Metadata.MetadataType.FMD_CONTACT_BLUESKY));
mVkPage = mFrame.findViewById(R.id.ll__place_vk);
mTvVkPage = mFrame.findViewById(R.id.tv__place_vk_page);
mVkPage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_VK));
mVkPage.setOnLongClickListener((v) -> copyUrl(mVkPage, Metadata.MetadataType.FMD_CONTACT_VK));
mTwitterIv = mSocial.findViewById(R.id.iv__place_twitter);
mTwitterIv.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_TWITTER));
mTwitterIv.setOnLongClickListener((v) -> copyUrl(mTwitterIv, Metadata.MetadataType.FMD_CONTACT_TWITTER));
mLinePage = mFrame.findViewById(R.id.ll__place_line);
mTvLinePage = mFrame.findViewById(R.id.tv__place_line_page);
mLinePage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_LINE));
mLinePage.setOnLongClickListener((v) -> copyUrl(mLinePage, Metadata.MetadataType.FMD_CONTACT_LINE));
mVkIv = mSocial.findViewById(R.id.iv__place_vk);
mVkIv.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_VK));
mVkIv.setOnLongClickListener((v) -> copyUrl(mVkIv, Metadata.MetadataType.FMD_CONTACT_VK));
mLineIv = mSocial.findViewById(R.id.iv__place_line);
mLineIv.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_LINE));
mLineIv.setOnLongClickListener((v) -> copyUrl(mLineIv, Metadata.MetadataType.FMD_CONTACT_LINE));
mPanoramax = mFrame.findViewById(R.id.ll__place_panoramax);
mTvPanoramax = mFrame.findViewById(R.id.tv__place_panoramax);
@@ -215,25 +216,25 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_EMAIL), mEmail, mTvEmail);
final String facebook = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_FACEBOOK);
refreshMetadataOrHide(facebook, mFacebookPage, mTvFacebookPage);
refreshMetadataOrHideSocial(facebook, mFacebookIv);
final String instagram = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_INSTAGRAM);
refreshMetadataOrHide(instagram, mInstagramPage, mTvInstagramPage);
refreshMetadataOrHideSocial(instagram, mInstagramIv);
final String fediverse = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_FEDIVERSE);
refreshMetadataOrHide(fediverse, mFediversePage, mTvFediversePage);
refreshMetadataOrHideSocial(fediverse, mFediverseIv);
final String bluesky = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_BLUESKY);
refreshMetadataOrHide(bluesky, mBlueskyPage, mTvBlueskyPage);
refreshMetadataOrHideSocial(bluesky, mBlueskyIv);
final String twitter = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_TWITTER);
refreshMetadataOrHide(twitter, mTwitterPage, mTvTwitterPage);
refreshMetadataOrHideSocial(twitter, mTwitterIv);
final String vk = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_VK);
refreshMetadataOrHide(vk, mVkPage, mTvVkPage);
refreshMetadataOrHideSocial(vk, mVkIv);
final String line = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_LINE);
refreshMetadataOrHide(line, mLinePage, mTvLinePage);
refreshMetadataOrHideSocial(line, mLineIv);
final String panoramax = mMapObject.getMetadata(Metadata.MetadataType.FMD_PANORAMAX);
final String panoramaxTitle = TextUtils.isEmpty(panoramax) ? "" : getResources().getString(R.string.panoramax);

View File

@@ -3,8 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/feedback_fab"
style="MwmWidget.M3.FAB.Primary"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Material3.FloatingActionButton"
style="@style/MwmWidget.M3.FAB.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/feedback"

View File

@@ -394,7 +394,8 @@
<com.google.android.material.card.MaterialCardView
android:id="@+id/cv__more"
style="@style/MwmWidget.Editor.CardView">
style="@style/MwmWidget.Editor.CardView"
android:layout_marginBottom="@dimen/margin_base">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -421,6 +422,17 @@
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.button.MaterialButton
android:id="@+id/disused"
style="@style/MwmWidget.M3.Button.Secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginBottom="@dimen/margin_quarter"
app:backgroundTint="?cardBackground"
android:textColor="@color/base_red"
app:strokeColor="@color/base_red"
android:text="@string/editor_business_vacant_button"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/reset"
style="@style/MwmWidget.M3.Button.Secondary"

View File

@@ -22,7 +22,7 @@
android:id="@+id/empty_opening_hours"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginStart="@dimen/editor_margin_timetable_left"
android:orientation="vertical"
tools:visibility="gone">
@@ -57,10 +57,8 @@
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.TextButton"
android:layout_below="@id/opening_hours"
android:layout_marginStart="@dimen/editor_margin_timetable_left"
android:layout_marginTop="@dimen/margin_base_plus"
android:gravity="center_vertical"
android:minHeight="@dimen/height_block_base"
android:layout_marginTop="@dimen/margin_base"
android:gravity="center_horizontal"
android:text="@string/edit_opening_hours"
android:textColor="?colorSecondary"
android:textAppearance="@style/MwmTextAppearance.Body1" />

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_bluesky"
style="@style/PlacePageItemFrame"
android:tag="website"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_bluesky"
style="@style/PlacePageMetadataIcon"
app:srcCompat="@drawable/ic_bluesky"
app:tint="?colorSecondary"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__place_bluesky_page"
android:textAlignment="viewStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
tools:text="@string/bluesky"/>
</LinearLayout>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_facebook"
style="@style/PlacePageItemFrame"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_facebook"
style="@style/PlacePageMetadataIcon"
app:srcCompat="@drawable/ic_facebook_white"
app:tint="?colorSecondary"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__place_facebook_page"
android:textAlignment="viewStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
tools:text="@string/facebook"/>
</LinearLayout>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_fediverse"
style="@style/PlacePageItemFrame"
android:tag="website"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_fediverse"
style="@style/PlacePageMetadataIcon"
app:srcCompat="@drawable/ic_mastodon"
app:tint="?colorSecondary"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__place_fediverse_page"
android:textAlignment="viewStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
tools:text="@string/mastodon"/>
</LinearLayout>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_instagram"
style="@style/PlacePageItemFrame"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_instagram"
style="@style/PlacePageMetadataIcon"
app:srcCompat="@drawable/ic_instagram_white"
app:tint="?colorSecondary"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__place_instagram_page"
android:textAlignment="viewStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
tools:text="@string/instagram"/>
</LinearLayout>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_line"
style="@style/PlacePageItemFrame"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_line"
style="@style/PlacePageMetadataIcon"
app:srcCompat="@drawable/ic_line_white"
app:tint="?colorSecondary"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__place_line_page"
android:textAlignment="viewStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
tools:text="@string/editor_line_social_network"/>
</LinearLayout>

View File

@@ -13,13 +13,7 @@
android:layout_height="wrap_content"
tools:layout="@layout/place_page_phone_fragment" />
<include layout="@layout/place_page_email" />
<include layout="@layout/place_page_fediverse" />
<include layout="@layout/place_page_facebook" />
<include layout="@layout/place_page_instagram" />
<include layout="@layout/place_page_twitter" />
<include layout="@layout/place_page_vk" />
<include layout="@layout/place_page_line" />
<include layout="@layout/place_page_bluesky" />
<include layout="@layout/place_page_social" />
<include layout="@layout/place_page_wikimedia" />
<include layout="@layout/place_page_panoramax" />
</LinearLayout>

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_social"
style="@style/PlacePageItemFrame"
android:tag="website"
android:gravity="center"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_fediverse"
style="@style/PlacePageMetadataIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_mastodon"
app:tint="?colorSecondary"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_facebook"
style="@style/PlacePageMetadataIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_facebook_white"
app:tint="?colorSecondary"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_instagram"
style="@style/PlacePageMetadataIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_instagram_white"
app:tint="?colorSecondary"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_twitter"
style="@style/PlacePageMetadataIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_twitterx_white"
app:tint="?colorSecondary"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_vk"
style="@style/PlacePageMetadataIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_vk_white"
app:tint="?colorSecondary"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_line"
style="@style/PlacePageMetadataIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_line_white"
app:tint="?colorSecondary"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_bluesky"
style="@style/PlacePageMetadataIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_bluesky"
app:tint="?colorSecondary"/>
</LinearLayout>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_twitter"
style="@style/PlacePageItemFrame"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_twitter"
style="@style/PlacePageMetadataIcon"
app:srcCompat="@drawable/ic_twitterx_white"
app:tint="?colorSecondary"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__place_twitter_page"
android:textAlignment="viewStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
tools:text="@string/twitter"/>
</LinearLayout>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_vk"
style="@style/PlacePageItemFrame"
tools:background="#20FF0000"
tools:visibility="visible">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iv__place_vk"
style="@style/PlacePageMetadataIcon"
app:srcCompat="@drawable/ic_vk_white"
app:tint="?colorSecondary"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__place_vk_page"
android:textAlignment="viewStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
tools:text="@string/vk"/>
</LinearLayout>

View File

@@ -38,8 +38,7 @@
android:id="@+id/done"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="MwmWidget.M3.FAB.Primary"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Material3.FloatingActionButton"
style="@style/MwmWidget.M3.FAB.Primary"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:contentDescription="@string/save"

View File

@@ -551,6 +551,14 @@
<string name="editor_place_doesnt_exist_description">Describe what the place looks like now to send an error note to the OpenStreetMap community</string>
<!-- Error message for "Place doesn't exist" dialog when comment is empty -->
<string name="delete_place_empty_comment_error">Please indicate the reason for deleting the place</string>
<!-- Button in the editor to mark business as vacant -->
<string name="editor_business_vacant_button">Business is vacant</string>
<!-- Title of confirmation dialog before marking business as vacant -->
<string name="editor_mark_business_vacant_title">Mark business as vacant</string>
<!-- Description in confirmation dialog before marking business as vacant -->
<string name="editor_mark_business_vacant_description">Use this if the business has moved out and the space is empty and ready for a new tenant.</string>
<!-- Submit change to OSM in the editor -->
<string name="editor_submit">Submit</string>
<!-- Phone number error message -->
<string name="error_enter_correct_phone">Enter a valid phone number</string>
<string name="error_enter_correct_web">Enter a valid web address</string>

View File

@@ -277,6 +277,12 @@ JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeIsNameEd
return g_editableMapObject.IsNameEditable();
}
JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeCanMarkPlaceAsDisused(JNIEnv * env,
jclass clazz)
{
return g_editableMapObject.CanMarkPlaceAsDisused();
}
JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeIsPointType(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.IsPointType();
@@ -434,6 +440,11 @@ JNIEXPORT void JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeRollbackMapO
g_framework->NativeFramework()->RollBackChanges(g_editableMapObject.GetID());
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeMarkPlaceAsDisused(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->MarkPlaceAsDisused(g_editableMapObject);
}
JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeGetAllCreatableFeatureTypes(JNIEnv * env,
jclass clazz,
jstring jLang)

View File

@@ -99,6 +99,7 @@ public final class Editor
public static native boolean nativeIsAddressEditable();
public static native boolean nativeIsNameEditable();
public static native boolean nativeCanMarkPlaceAsDisused();
public static native boolean nativeIsPointType();
public static native boolean nativeIsBuilding();
@@ -164,6 +165,7 @@ public final class Editor
public static native void nativeCreateNote(String text);
public static native void nativePlaceDoesNotExist(@NonNull String comment);
public static native void nativeRollbackMapObject();
public static native void nativeMarkPlaceAsDisused();
public static native void nativeCreateStandaloneNote(double lat, double lon, String text);
/**

View File

@@ -33,6 +33,7 @@ set(SRC
xml_feature.cpp
xml_feature.hpp
yes_no_unknown.hpp
keys_to_remove.hpp
)
omim_add_library(${PROJECT_NAME} ${SRC})

View File

@@ -57,6 +57,9 @@ std::string GetTypeForFeature(editor::XMLFeature const & node)
}
}
if (node.HasTag("disused:shop") || node.HasTag("disused:amenity"))
return "vacant business";
if (node.HasTag("addr:housenumber") || node.HasTag("addr:street") || node.HasTag("addr:postcode"))
return "address";

View File

@@ -0,0 +1,135 @@
#pragma once
#include <string_view>
// Keys that should be removed when a place in OSM is replaced, copied from
// https://github.com/mnalis/StreetComplete-taginfo-categorize/blob/master/sc_to_remove.txt
// Changes to the list: don't remove 'wheelchair' and addresses in the 'contact:' style
inline constexpr std::string_view kKeysToRemove[] = {
"shop_?[1-9]?(:.*)?", "craft_?[1-9]?", "amenity_?[1-9]?", "club_?[1-9]?", "old_amenity",
"old_shop", "information", "leisure", "office_?[1-9]?", "tourism",
// popular shop=* / craft=* subkeys
"marketplace", "household", "swimming_pool", "laundry", "golf", "sports", "ice_cream",
"scooter", "music", "retail", "yes", "ticket", "newsagent", "lighting", "truck", "car_repair",
"car_parts", "video", "fuel", "farm", "car", "tractor", "hgv", "ski", "sculptor",
"hearing_aids", "surf", "photo", "boat", "gas", "kitchen", "anime", "builder", "hairdresser",
"security", "bakery", "bakehouse", "fishing", "doors", "kiosk", "market", "bathroom", "lamps",
"vacant", "insurance(:.*)?", "caravan", "gift", "bicycle", "bicycle_rental", "insulation",
"communication", "mall", "model", "empty", "wood", "hunting", "motorcycle", "trailer",
"camera", "water", "fireplace", "outdoor", "blacksmith", "electronics", "fan", "piercing",
"stationery", "sensory_friendly(:.*)?", "street_vendor", "sells(:.*)?", "safety_equipment",
// obsoleted information
"(demolished|abandoned|disused)(:(?!bui).+)?", "was:.*", "not:.*", "damage", "created_by",
"check_date", "opening_date", "last_checked", "checked_exists:date", "pharmacy_survey",
"old_ref", "update", "import_uuid", "review", "fixme:atp",
// classifications / links to external databases
"fhrs:.*", "old_fhrs:.*", "fvst:.*", "ncat", "nat_ref", "gnis:.*", "winkelnummer",
"type:FR:FINESS", "type:FR:APE", "kvl_hro:amenity", "ref:DK:cvr(:.*)?", "certifications?",
"transiscope", "opendata:type", "local_ref", "official_ref",
// names and identifications
"name_?[1-9]?(:.*)?", ".*_name_?[1-9]?(:.*)?", "noname", "branch(:.*)?", "brand(:.*)?",
"not:brand(:.*)?", "network(:.*)?", "operator(:.*)?", "operator_type", "ref", "ref:vatin",
"designation", "SEP:CLAVEESC", "identifier", "ref:FR:SIRET", "ref:FR:SIREN", "ref:FR:NAF",
"(old_)?ref:FR:prix-carburants",
// contacts
"contact_person", "phone(:.*)?", "phone_?[1-9]?", "emergency:phone", "emergency_telephone_code",
"contact:(?!housenumber$|street$|place$|postcode$|city$|country$|pobox$|unit$).*",
"mobile", "fax", "facebook", "instagram", "twitter", "youtube", "telegram", "tiktok", "email",
"website_?[1-9]?(:.*)?", "app:.*", "ownership",
"url", "url:official", "source_ref:url", "owner",
// payments
"payment(:.*)?", "payment_multi_fee", "currency(:.*)?", "cash_withdrawal(:.*)?", "fee",
"charge", "charge_fee", "money_transfer", "donation:compensation", "paypoint",
// generic shop/craft attributes
"seasonal", "time", "opening_hours(:.*)?", "check_(in|out)", "wifi", "internet",
"internet_access(:.*)?", "second_hand", "self_service", "automated", "license:.*",
"bulk_purchase", ".*:covid19", "language:.*", "baby_feeding", "description(:.*)?",
"description[0-9]", "min_age", "max_age", "supermarket(:.*)?", "social_facility(:.*)?",
"functional", "trade", "wholesale", "sale", "smoking(:outside)?", "zero_waste", "origin",
"attraction", "strapline", "dog", "showroom", "toilets?(:.*)?", "sanitary_dump_station",
"changing_table(:.*)?", "blind", "company(:.*)?", "stroller", "walk-in",
"webshop", "operational_status.*", "status", "drive_through", "surveillance(:.*)?",
"outdoor_seating", "indoor_seating", "colour", "access_simple", "floor", "product_category",
"guide", "source_url", "category", "kids_area", "kids_area:indoor", "resort", "since", "state",
"temporary", "self_checkout", "audio_loop", "related_law(:.*)?", "official_status(:.*)?",
// food and drink details
"bar", "cafe", "coffee", "microroasting", "microbrewery", "brewery", "real_ale", "taproom",
"training", "distillery", "drink(:.*)?", "cocktails", "alcohol", "wine([:_].*)?",
"happy_hours", "diet:.*", "cuisine", "ethnic", "tasting", "breakfast", "lunch", "organic",
"produced_on_site", "restaurant", "food", "pastry", "pastry_shop", "product", "produce",
"chocolate", "fair_trade", "butcher", "reservation(:.*)?", "takeaway(:.*)?", "delivery(:.*)?",
"caterer", "real_fire", "flour_fortified", "highchair", "fast_food", "pub", "snack",
"confectionery", "drinking_water:refill",
// related to repair shops/crafts
"service(:.*)?", "motorcycle:.*", "repair", ".*:repair", "electronics_repair(:.*)?",
"workshop",
// shop=hairdresser, shop=clothes
"unisex", "male", "female", "gender", "gender_simple", "lgbtq(:.*)?", "gay", "female:signed",
"male:signed",
// healthcare
"healthcare(:.*)?", "healthcare_.*", "health", "health_.*", "speciality", "medical_.*",
"emergency_ward", "facility(:.*)?", "activities", "healthcare_facility(:.*)?",
"laboratory(:.*)?", "blood(:.*)?", "blood_components", "infection(:.*)?", "disease(:.*)?",
"covid19(:.*)?", "COVID_.*", "CovidVaccineCenterId", "coronaquarantine", "hospital(:.*)?",
"hospital_type_id", "emergency_room", "sample_collection(:.*)?", "bed_count", "capacity:beds",
"part_time_beds", "personnel:count", "staff_count(:.*)?", "admin_staff", "doctors",
"doctors_num", "nurses_num", "counselling_type", "testing_centres", "toilets_number",
"urgent_care", "vaccination", "clinic", "hospital", "pharmacy", "alternative", "laboratory",
"sample_collection", "provided_for(:.*)?", "social_facility_for", "ambulance", "ward",
"HSE_(code|hgid|hgroup|region)", "collection_centre", "design", "AUTORIZATIE", "reg_id",
"post_addr", "scope", "ESTADO", "NIVSOCIO", "NO", "EMP_EST", "COD_HAB", "CLA_PERS", "CLA_PRES",
"snis_code:.*", "hfac_bed", "hfac_type", "nature", "moph_code", "IJSN:.*", "massgis:id",
"OGD-Stmk:.*", "paho:.*", "panchayath", "pbf_contract", "pcode", "pe:minsa:.*", "who:.*",
"pharmacy:category", "tactile_paving", "HF_(ID|TYPE|N_EN)", "RoadConn", "bin", "hiv(:.*)?",
// accommodation & layout
"rooms", "stars", "accommodation", "beds", "capacity(:persons)?", "laundry_service",
"guest_house",
// amenity=place_of_worship
"deanery", "subject:(wikidata|wikipedia|wikimedia_commons)", "church", "church:type",
// schools
"capacity:(pupils|teachers)", "grades", "population:pupils(:.*)?",
"school:(FR|gender|trust|type|type_idn|group:type)", "primary",
// clubs
"animal(_breeding|_training)?", "billiards(:.*)?", "board_game", "sport_1", "sport:boating",
"boat:type", "canoe(_rental|:service)?", "kayak(_rental|:service)?",
"sailboat(_rental|:service)?", "horse_riding", "rugby", "boules", "callsign", "card_games",
"car_service", "catastro:ref", "chess(:.*)?", "children", "climbing(:.*)?", "club(:.*)?",
"communication(:amateur_radio.*)", "community_centre:for", "dffr:network", "dormitory",
"education_for:ages", "electrified", "esperanto", "events_venue", "family", "federation",
"free_flying(:.*)?", "freemasonry(:.*)?", "free_refill", "gaelic_games(:.*)?", "membership",
"military_service", "model_aerodrome(:.*)?", "mode_of_organisation(:.*)?", "snowmobile",
"social_centre(:for)?", "source_dat", "tennis", "old_website", "organisation", "school_type",
"scout(:type)?", "fraternity", "live_music", "lockable", "playground(:theme)?", "nudism",
"music_genre", "length", "fire_station:type:FR", "cadet", "observatory:type", "tower:type",
"zoo", "shooting", "commons", "groomer", "group_only", "hazard", "identity", "interaction",
"logo", "maxheight", "provides", "regional", "scale", "site", "plots", "allotments",
"local_food", "monitoring:pedestrian", "recording:automated", "yacht", "background_music",
"url:spaceapi", "openfire", "fraternity(:.*)?",
// misc specific attributes
"clothes", "shoes", "tailor", "beauty", "tobacco", "carpenter", "furniture", "lottery",
"sport", "dispensing", "tailor:.*", "gambling", "material", "raw_material", "stonemason",
"studio", "scuba_diving(:.*)?", "polling_station", "collector", "books", "agrarian",
"musical_instrument", "massage", "parts", "post_office(:.*)?", "religion", "denomination",
"rental", ".*:rental", "tickets:.*", "public_transport", "goods_supply", "pet", "appliance",
"artwork_type", "charity", "company", "crop", "dry_cleaning", "factory", "feature",
"air_conditioning", "atm", "vending", "vending_machine", "recycling_type", "museum",
"license_classes", "dance:.*", "isced:level", "school", "preschool", "university",
"research_institution", "research", "member_of", "topic", "townhall:type", "parish", "police",
"government", "thw:(lv|rb|ltg)", "office", "administration", "administrative", "association",
"transport", "utility", "consulting", "Commercial", "commercial", "private", "taxi",
"admin_level", "official_status", "target", "liaison", "diplomatic(:.*)?", "embassy",
"consulate", "aeroway", "department", "faculty", "aerospace:product", "boundary", "population",
"diocese", "depot", "cargo", "function", "game", "party", "political_party.*",
"telecom(munication)?", "service_times", "kitchen:facilities", "it:(type|sales)",
"cannabis:cbd", "bath:type", "bath:(open_air|sand_bath)", "animal_boarding", "animal_shelter",
"mattress", "screen", "monitoring:weather", "public", "theatre", "culture", "library",
"cooperative(:.*)?", "winery", "curtain", "lawyer(:.*)?", "local_authority(:.*)?", "equipment",
"hackerspace",
"camp_site", "camping", "bbq", "static_caravans", "emergency(:.*)?", "evacuation_cent(er|re)",
"education", "engineering", "forestry", "foundation", "lawyer", "logistics", "military",
"community_centre", "bank", "operational", "users_(PLWD|boy|elderly|female|girl|men)",
"Comments?", "comments?", "entrance:(width|step_count|kerb:height)", "fenced", "motor_vehicle",
"shelter",
};

View File

@@ -668,7 +668,7 @@ void Editor::UploadChanges(string const & oauthToken, ChangesetTags tags, Finish
{}
// Add tags to XMLFeature
UpdateXMLFeatureTags(feature, journal);
UpdateXMLFeatureTags(feature, journal, changeset);
// Upload XMLFeature to OSM
LOG(LDEBUG, ("CREATE Feature (newEditor)", feature));
@@ -686,7 +686,7 @@ void Editor::UploadChanges(string const & oauthToken, ChangesetTags tags, Finish
XMLFeature feature = GetMatchingFeatureFromOSM(changeset, fti.m_object);
// Update tags of XMLFeature
UpdateXMLFeatureTags(feature, journal);
UpdateXMLFeatureTags(feature, journal, changeset);
// Upload XMLFeature to OSM
LOG(LDEBUG, ("MODIFIED Feature (newEditor)", feature));
@@ -1321,7 +1321,8 @@ bool Editor::IsFeatureUploadedImpl(FeaturesContainer const & features, MwmId con
return info && info->m_uploadStatus == kUploaded;
}
void Editor::UpdateXMLFeatureTags(editor::XMLFeature & feature, std::list<JournalEntry> const & journal)
void Editor::UpdateXMLFeatureTags(editor::XMLFeature & feature, std::list<JournalEntry> const & journal,
ChangesetWrapper & changeset)
{
for (JournalEntry const & entry : journal)
{
@@ -1335,6 +1336,13 @@ void Editor::UpdateXMLFeatureTags(editor::XMLFeature & feature, std::list<Journa
}
case JournalEntryType::ObjectCreated: break;
case JournalEntryType::LegacyObject: ASSERT_FAIL(("Legacy Objects can not be edited with the new editor")); break;
case JournalEntryType::BusinessReplacement:
{
BusinessReplacementData const & businessReplacementData = std::get<BusinessReplacementData>(entry.data);
feature.OSMBusinessReplacement(businessReplacementData.old_type, businessReplacementData.new_type);
changeset.AddChangesetTag("info:place_marked_as_disused", "yes");
break;
}
}
}
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include "editor/changeset_wrapper.hpp"
#include "editor/config_loader.hpp"
#include "editor/editor_config.hpp"
#include "editor/editor_notes.hpp"
@@ -241,7 +242,8 @@ private:
static bool IsFeatureUploadedImpl(FeaturesContainer const & features, MwmId const & mwmId, uint32_t index);
void UpdateXMLFeatureTags(editor::XMLFeature & feature, std::list<JournalEntry> const & journal);
static void UpdateXMLFeatureTags(editor::XMLFeature & feature, std::list<JournalEntry> const & journal,
ChangesetWrapper & changeset);
/// Deleted, edited and created features.
base::AtomicSharedPtr<FeaturesContainer> m_features;

View File

@@ -1,4 +1,5 @@
#include "editor/xml_feature.hpp"
#include "editor/keys_to_remove.hpp"
#include "indexer/classificator.hpp"
#include "indexer/editable_map_object.hpp"
@@ -15,6 +16,7 @@
#include "base/timer.hpp"
#include <array>
#include <boost/regex.hpp>
#include <sstream>
#include <string>
@@ -502,6 +504,29 @@ osm::EditJournal XMLFeature::GetEditJournal() const
entry.data = legacyObjData;
break;
}
case osm::JournalEntryType::BusinessReplacement:
{
osm::BusinessReplacementData businessReplacementData;
// Old Feature Type
std::string old_strType = getAttribute(xmlData, "old_type");
if (old_strType.empty())
MYTHROW(editor::InvalidJournalEntry, ("Old Feature type is empty"));
businessReplacementData.old_type = classif().GetTypeByReadableObjectName(old_strType);
if (businessReplacementData.old_type == IndexAndTypeMapping::INVALID_TYPE)
MYTHROW(editor::InvalidJournalEntry, ("Invalid old Feature Type:", old_strType));
// New Feature Type
std::string new_strType = getAttribute(xmlData, "new_type");
if (new_strType.empty())
MYTHROW(editor::InvalidJournalEntry, ("New Feature type is empty"));
businessReplacementData.new_type = classif().GetTypeByReadableObjectName(new_strType);
if (businessReplacementData.new_type == IndexAndTypeMapping::INVALID_TYPE)
MYTHROW(editor::InvalidJournalEntry, ("Invalid new Feature Type:", new_strType));
entry.data = businessReplacementData;
break;
}
}
if (isHistory)
journal.AddJournalHistoryEntry(entry);
@@ -572,6 +597,14 @@ void XMLFeature::SetEditJournal(osm::EditJournal const & journal)
xmlData.append_attribute("version") = legacyObjData.version.data();
break;
}
case osm::JournalEntryType::BusinessReplacement:
{
osm::BusinessReplacementData const & businessReplacementData =
std::get<osm::BusinessReplacementData>(entry.data);
xmlData.append_attribute("old_type") = classif().GetReadableObjectName(businessReplacementData.old_type).data();
xmlData.append_attribute("new_type") = classif().GetReadableObjectName(businessReplacementData.new_type).data();
break;
}
}
}
};
@@ -675,6 +708,52 @@ void XMLFeature::UpdateOSMTag(std::string_view key, std::string_view value)
}
}
void XMLFeature::OSMBusinessReplacement(uint32_t old_type, uint32_t new_type)
{
std::string name = GetTagValue("name");
// Remove OSM tags using the list from keys_to_remove.hpp
static boost::regex const regex([]
{
std::string regexPattern;
for (auto const & key : kKeysToRemove)
{
if (!regexPattern.empty())
regexPattern.append("|");
regexPattern.append(key);
}
return regexPattern;
}());
ForEachTag([this](std::string_view key, std::string_view /*value*/)
{
if (boost::regex_match(key.begin(), key.end(), regex))
RemoveTag(key);
});
if (classif().GetReadableObjectName(new_type) == "disusedbusiness")
{
// Mark as 'disused'
string const strOldType = classif().GetReadableObjectName(old_type);
strings::SimpleTokenizer iter(strOldType, "-");
string_view const key = *iter;
if (++iter)
SetTagValue("disused:" + std::string(key), *iter);
else
SetTagValue("disused:" + std::string(key), "yes");
if (!name.empty())
SetTagValue("old_name", name);
}
else
{
// Add new category tag
ASSERT_FAIL("Only marking places as 'disused' is implemented yet. Wrong new_type: " +
classif().GetReadableObjectName(new_type));
}
}
string XMLFeature::GetAttribute(string const & key) const
{
return GetRootNode().attribute(key.data()).value();

View File

@@ -187,6 +187,8 @@ public:
/// Wrapper for SetTagValue and RemoveTag, avoids duplication for similar alternative osm tags
void UpdateOSMTag(std::string_view key, std::string_view value);
/// Replace an old business with a new business
void OSMBusinessReplacement(uint32_t old_type, uint32_t new_type);
std::string GetAttribute(std::string const & key) const;
void SetAttribute(std::string const & key, std::string const & value);

View File

@@ -41,6 +41,14 @@ void EditJournal::MarkAsCreated(uint32_t type, feature::GeomType geomType, m2::P
AddJournalEntry({JournalEntryType::ObjectCreated, time(nullptr), osm::ObjCreateData{type, geomType, mercator}});
}
void EditJournal::AddBusinessReplacement(uint32_t old_type, uint32_t new_type)
{
LOG(LDEBUG, ("Business of type ", classif().GetReadableObjectName(old_type), " was replaced by a ",
classif().GetReadableObjectName(new_type)));
AddJournalEntry(
{JournalEntryType::BusinessReplacement, time(nullptr), osm::BusinessReplacementData{old_type, new_type}});
}
void EditJournal::AddJournalEntry(JournalEntry entry)
{
m_journal.push_back(std::move(entry));
@@ -103,6 +111,15 @@ std::string EditJournal::ToString(osm::JournalEntry const & journalEntry)
LegacyObjData const & legacyObjData = std::get<LegacyObjData>(journalEntry.data);
return ToString(journalEntry.journalEntryType).append(": version=\"").append(legacyObjData.version).append("\"");
}
case osm::JournalEntryType::BusinessReplacement:
{
BusinessReplacementData const & businessReplacementData = std::get<BusinessReplacementData>(journalEntry.data);
return ToString(journalEntry.journalEntryType)
.append(": Category changed from ")
.append(classif().GetReadableObjectName(businessReplacementData.old_type))
.append(" to ")
.append(classif().GetReadableObjectName(businessReplacementData.new_type));
}
default: UNREACHABLE();
}
}
@@ -114,6 +131,7 @@ std::string EditJournal::ToString(osm::JournalEntryType journalEntryType)
case osm::JournalEntryType::TagModification: return "TagModification";
case osm::JournalEntryType::ObjectCreated: return "ObjectCreated";
case osm::JournalEntryType::LegacyObject: return "LegacyObject";
case osm::JournalEntryType::BusinessReplacement: return "BusinessReplacement";
default: UNREACHABLE();
}
}
@@ -126,6 +144,8 @@ std::optional<JournalEntryType> EditJournal::TypeFromString(std::string const &
return JournalEntryType::ObjectCreated;
else if (entryType == "LegacyObject")
return JournalEntryType::LegacyObject;
else if (entryType == "BusinessReplacement")
return JournalEntryType::BusinessReplacement;
else
return {};
}

View File

@@ -16,6 +16,7 @@ enum class JournalEntryType
TagModification,
ObjectCreated,
LegacyObject, // object without full journal history, used for transition to new editor
BusinessReplacement,
// Possible future values: ObjectDeleted, ObjectDisused, ObjectNotDisused, LocationChanged, FeatureTypeChanged
};
@@ -38,11 +39,17 @@ struct LegacyObjData
std::string version;
};
struct BusinessReplacementData
{
uint32_t old_type;
uint32_t new_type;
};
struct JournalEntry
{
JournalEntryType journalEntryType = JournalEntryType::TagModification;
time_t timestamp;
std::variant<TagModData, ObjCreateData, LegacyObjData> data;
std::variant<TagModData, ObjCreateData, LegacyObjData, BusinessReplacementData> data;
};
/// Used to determine whether existing OSM object should be updated or new one created
@@ -69,6 +76,9 @@ public:
/// Log object creation in the journal
void MarkAsCreated(uint32_t type, feature::GeomType geomType, m2::PointD mercator);
/// Log business replacement in the journal
void AddBusinessReplacement(uint32_t old_type, uint32_t new_type);
void AddJournalEntry(JournalEntry entry);
/// Clear Journal and move content to journalHistory, used after upload to OSM

View File

@@ -87,6 +87,32 @@ vector<MapObject::MetadataID> EditableMapObject::GetEditableProperties() const
return props;
}
bool EditableMapObject::CanMarkPlaceAsDisused() const
{
if (GetEditingLifecycle() == EditingLifecycle::CREATED)
return false;
auto types = GetTypes();
types.SortBySpec();
uint32_t mainType = *types.begin();
std::string mainTypeStr = classif().GetReadableObjectName(mainType);
constexpr string_view typePrefixes[] = {
"shop",
"amenity-restaurant",
"amenity-fast_food",
"amenity-cafe",
"amenity-pub",
"amenity-bar",
};
for (auto const & typePrefix : typePrefixes)
if (mainTypeStr.starts_with(typePrefix))
return true;
return false;
}
NamesDataSource EditableMapObject::GetNamesDataSource()
{
auto const mwmInfo = GetID().m_mwmId.GetInfo();
@@ -656,6 +682,16 @@ void EditableMapObject::MarkAsCreated(uint32_t type, feature::GeomType geomType,
m_journal.MarkAsCreated(type, geomType, std::move(mercator));
}
void EditableMapObject::MarkAsDisused()
{
auto types = GetTypes();
types.SortBySpec();
uint32_t old_type = *types.begin();
uint32_t new_type = classif().GetTypeByReadableObjectName("disusedbusiness");
ApplyBusinessReplacement(new_type);
m_journal.AddBusinessReplacement(old_type, new_type);
}
void EditableMapObject::ClearJournal()
{
m_journal.Clear();
@@ -673,7 +709,7 @@ void EditableMapObject::ApplyEditsFromJournal(EditJournal const & editJournal)
void EditableMapObject::ApplyJournalEntry(JournalEntry const & entry)
{
LOG(LDEBUG, ("Applying Journal Entry: ", osm::EditJournal::ToString(entry)));
// Todo
switch (entry.journalEntryType)
{
case JournalEntryType::TagModification:
@@ -760,6 +796,12 @@ void EditableMapObject::ApplyJournalEntry(JournalEntry const & entry)
ASSERT_FAIL(("Legacy Objects can not be loaded from Journal"));
break;
}
case JournalEntryType::BusinessReplacement:
{
BusinessReplacementData const & businessReplacementData = std::get<BusinessReplacementData>(entry.data);
ApplyBusinessReplacement(businessReplacementData.new_type);
break;
}
}
}
@@ -859,6 +901,47 @@ void EditableMapObject::LogDiffInJournal(EditableMapObject const & unedited_emo)
}
}
void EditableMapObject::ApplyBusinessReplacement(uint32_t new_type)
{
// Types
feature::TypesHolder new_feature_types;
new_feature_types.Add(new_type); // Update feature type
std::string wheelchairType = feature::GetReadableWheelchairType(m_types);
if (!wheelchairType.empty())
new_feature_types.SafeAdd(classif().GetTypeByReadableObjectName(wheelchairType));
std::vector<uint32_t> const buildingTypes = ftypes::IsBuildingChecker::Instance().GetTypes();
for (uint32_t const & type : buildingTypes)
if (m_types.Has(type))
new_feature_types.SafeAdd(type);
m_types = new_feature_types;
// Names
m_name.Clear();
// Metadata
feature::Metadata new_metadata;
constexpr MetadataID metadataToKeep[] = {
MetadataID::FMD_WHEELCHAIR,
MetadataID::FMD_POSTCODE,
MetadataID::FMD_LEVEL,
MetadataID::FMD_ELE,
MetadataID::FMD_HEIGHT,
MetadataID::FMD_MIN_HEIGHT,
MetadataID::FMD_BUILDING_LEVELS,
MetadataID::FMD_BUILDING_MIN_LEVEL
};
for (MetadataID const & metadataID : metadataToKeep)
new_metadata.Set(metadataID, std::string(m_metadata.Get(metadataID)));
m_metadata = new_metadata;
}
bool AreObjectsEqualIgnoringStreet(EditableMapObject const & lhs, EditableMapObject const & rhs)
{
feature::TypesHolder const & lhsTypes = lhs.GetTypes();

View File

@@ -78,6 +78,8 @@ public:
/// All store/load/valid operations will be via MetadataEntryIFace interface instead of switch-case.
std::vector<MetadataID> GetEditableProperties() const;
bool CanMarkPlaceAsDisused() const;
/// See comment for NamesDataSource class.
NamesDataSource GetNamesDataSource();
LocalizedStreet const & GetStreet() const;
@@ -141,11 +143,16 @@ public:
void SetJournal(EditJournal && editJournal);
EditingLifecycle GetEditingLifecycle() const;
void MarkAsCreated(uint32_t type, feature::GeomType geomType, m2::PointD mercator);
void MarkAsDisused();
void ClearJournal();
void ApplyEditsFromJournal(EditJournal const & journal);
void ApplyJournalEntry(JournalEntry const & entry);
void LogDiffInJournal(EditableMapObject const & unedited_emo);
private:
void ApplyBusinessReplacement(uint32_t new_type);
public:
/// Check whether langCode can be used as default name.
static bool CanUseAsDefaultName(int8_t const langCode, std::vector<int8_t> const & nativeMwmLanguages);

View File

@@ -3091,6 +3091,13 @@ void Framework::DeleteFeature(FeatureID const & fid)
UpdatePlacePageInfoForCurrentSelection();
}
void Framework::MarkPlaceAsDisused(osm::EditableMapObject emo)
{
emo.MarkAsDisused();
osm::Editor::Instance().SaveEditedFeature(emo);
UpdatePlacePageInfoForCurrentSelection();
}
osm::NewFeatureCategories Framework::GetEditorCategories() const
{
return osm::Editor::Instance().GetNewFeatureCategories();

View File

@@ -755,6 +755,7 @@ public:
bool GetEditableMapObject(FeatureID const & fid, osm::EditableMapObject & emo) const;
osm::Editor::SaveResult SaveEditedMapObject(osm::EditableMapObject emo);
void DeleteFeature(FeatureID const & fid);
void MarkPlaceAsDisused(osm::EditableMapObject emo);
osm::NewFeatureCategories GetEditorCategories() const;
bool RollBackChanges(FeatureID const & fid);
void CreateNote(osm::MapObject const & mapObject, osm::Editor::NoteProblemType const type, std::string const & note);

View File

@@ -36,8 +36,11 @@ def multithread_run_if_one_country(func):
def wrap(env, country, **kwargs):
if len(env.countries) == 1:
kwargs.update({"threads_count": settings.THREADS_COUNT})
# Otherwise index stage of Taiwan_* mwms continues to run after all other mwms have finished:
elif country == 'Taiwan_North':
kwargs.update({"threads_count": 4})
kwargs.update({"threads_count": 6})
elif country == 'Taiwan_South':
kwargs.update({"threads_count": 2})
func(env, country, **kwargs)
return wrap

View File

@@ -1,9 +1,6 @@
#!/usr/bin/env bash
set -e -u
# Prevent python from generating compiled *.pyc files
export PYTHONDONTWRITEBYTECODE=1
OMIM_PATH="${OMIM_PATH:-$(dirname "$0")/../..}"
DATA_PATH="${DATA_PATH:-$OMIM_PATH/data}"
@@ -23,7 +20,7 @@ function BuildDrawingRules() {
-p "$DATA_PATH/styles/$styleType/include/"
# Output diff and store to a file
if [ -f "$DATA_PATH/drules_proto$suffix.txt.prev" ]; then
diff -u "$DATA_PATH/drules_proto$suffix.txt.prev" "$DATA_PATH/drules_proto$suffix.txt" | tee "$DATA_PATH/drules_proto$suffix.txt.diff" || true
diff -u "$DATA_PATH/drules_proto$suffix.txt.prev" "$DATA_PATH/drules_proto$suffix.txt" > "$DATA_PATH/drules_proto$suffix.txt.diff" || true
fi
}
@@ -68,10 +65,10 @@ python3 "$OMIM_PATH/tools/python/stylesheet/drules_merge.py" \
for item in ${outputs[*]}
do
if [ -f "$DATA_PATH/$item.prev" ] && [ -f "$DATA_PATH/$item" ]; then
diff -u "$DATA_PATH/$item.prev" "$DATA_PATH/$item" | tee "$DATA_PATH/$item.diff" || true
diff -u "$DATA_PATH/$item.prev" "$DATA_PATH/$item" > "$DATA_PATH/$item.diff" || true
else
echo "Skipping diff for $item (first run or file missing)"
fi
done
echo "Diffs for all changes are stored in $DATA_PATH/*.txt.diff"
echo "Diffs for all changes are stored in $DATA_PATH/*.txt.diff"

View File

@@ -14,9 +14,6 @@ then
exit
fi
# Prevent python from generating compiled *.pyc files
export PYTHONDONTWRITEBYTECODE=1
# Add env var to disable renderer on a display (renderer not working into a Github container)
export QT_QPA_PLATFORM=offscreen

View File

@@ -1,9 +1,6 @@
#!/usr/bin/env bash
set -e -u
# Prevent python from generating compiled *.pyc files
export PYTHONDONTWRITEBYTECODE=1
DEBUG="${1:-empty}"
MY_PATH="`dirname \"$0\"`" # relative

View File

@@ -13,9 +13,6 @@ if ! command -v scour &> /dev/null; then
exit
fi
# Prevent python from generating compiled *.pyc files
export PYTHONDONTWRITEBYTECODE=1
OMIM_PATH="${OMIM_PATH:-$(cd "$(dirname "$0")/../.."; pwd)}"
echo "Started processing"

View File

@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
271DC2172EC60C0C00442D94 /* keys_to_remove.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 271DC2162EC60C0C00442D94 /* keys_to_remove.hpp */; };
340C20DE1C3E4DFD00111D22 /* osm_auth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 340C20DC1C3E4DFD00111D22 /* osm_auth.cpp */; };
340C20DF1C3E4DFD00111D22 /* osm_auth.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 340C20DD1C3E4DFD00111D22 /* osm_auth.hpp */; };
340DC8291C4E71E500EAA2CC /* changeset_wrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 340DC8271C4E71E500EAA2CC /* changeset_wrapper.cpp */; };
@@ -75,6 +76,7 @@
/* Begin PBXFileReference section */
270C9C212E16AABF00ABA688 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = ../../libs/editor/module.modulemap; sourceTree = SOURCE_ROOT; };
271DC2162EC60C0C00442D94 /* keys_to_remove.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = keys_to_remove.hpp; sourceTree = "<group>"; };
340C20DC1C3E4DFD00111D22 /* osm_auth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = osm_auth.cpp; sourceTree = "<group>"; };
340C20DD1C3E4DFD00111D22 /* osm_auth.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = osm_auth.hpp; sourceTree = "<group>"; };
340DC8271C4E71E500EAA2CC /* changeset_wrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = changeset_wrapper.cpp; sourceTree = "<group>"; };
@@ -240,6 +242,7 @@
6715560420BEC331002BA3B4 /* edits_migration.hpp */,
3D052486200F62ED00F24998 /* feature_matcher.cpp */,
3D052485200F62ED00F24998 /* feature_matcher.hpp */,
271DC2162EC60C0C00442D94 /* keys_to_remove.hpp */,
6715565220BF0F86002BA3B4 /* new_feature_categories.cpp */,
6715565320BF0F87002BA3B4 /* new_feature_categories.hpp */,
341138741C15AE42002E3B3E /* opening_hours_ui.cpp */,
@@ -337,6 +340,7 @@
6715565520BF0F87002BA3B4 /* new_feature_categories.hpp in Headers */,
6715560820BEC332002BA3B4 /* edits_migration.hpp in Headers */,
3D052487200F62EE00F24998 /* feature_matcher.hpp in Headers */,
271DC2172EC60C0C00442D94 /* keys_to_remove.hpp in Headers */,
3411387B1C15AE42002E3B3E /* ui2oh.hpp in Headers */,
341138791C15AE42002E3B3E /* opening_hours_ui.hpp in Headers */,
);