Compare commits

..

26 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
Konstantin Pastbin
0814b574a9 [core] Add mapgen to default CDNs list
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-11-14 10:04:40 +01:00
patepelo
b4abce822e [search] Improve search terms and synonyms
Signed-off-by: patepelo <developing.anton@gmail.com>
Co-authored-by: patepelo <developing.anton@gmail.com>
Co-committed-by: patepelo <developing.anton@gmail.com>
2025-11-14 10:04:10 +01:00
gekeleda
2e0443097a [android] Improve map language settings
Signed-off-by: gekeleda <git@davidgekeler.eu>
Co-authored-by: gekeleda <git@davidgekeler.eu>
Co-committed-by: gekeleda <git@davidgekeler.eu>
2025-11-14 07:58:47 +01:00
Jean-Baptiste
f6426fe689 [android] Update Add schedule button to M3
Signed-off-by: Jean-Baptiste <jeanbaptiste.charron@outlook.fr>
2025-11-13 22:26:42 +01:00
Yannik Bloscheck
6296de6ce9 [types] Add day spas
Signed-off-by: Yannik Bloscheck <git@yannikbloscheck.com>
2025-11-13 17:59:17 +01:00
NoelClick
4f63c5fdcf [android] Hide offline explanation after two downloads
Signed-off-by: NoelClick <dev@noel.click>
Co-authored-by: NoelClick <dev@noel.click>
Co-committed-by: NoelClick <dev@noel.click>
2025-11-13 13:32:01 +01:00
x7z4w
e4648fbc1f Revert "[core][drape] Making arrows smooth again"
Signed-off-by: x7z4w <x7z4w@noreply.codeberg.org>
2025-11-13 11:36:21 +01:00
NoelClick
1de35bb5f8 [android] Adjust phrasing to "Opens on ... / Closes on ..." for clarity
- Update i18n strings following review suggestion.

Signed-off-by: NoelClick <dev@noel.click>
2025-11-12 23:07:53 +01:00
NoelClick
7b7df6ff2e [android] Remove unused full "minutes" plural resource
- Keep only `minutes_short` (`%d min`) for compact display.
- Ensures consistency with search UI and avoids redundant i18n strings.

Signed-off-by: NoelClick <dev@noel.click>
2025-11-12 23:07:53 +01:00
NoelClick
33e2f4854e [android] Use 60/15 min short-horizon windows (yellow) for closes/opens
- Closes: Yellow when <= 60 min
- Opens: Yellow when <= 15 min
- Keep compact unit via `plurals/minutes_short`
- Long-horizon cases continue to show "Open / Closed now • Opens / Closes ... at ..."
- Use full weekday names for clarity

Signed-off-by: NoelClick <dev@noel.click>
2025-11-12 23:07:53 +01:00
NoelClick
5b4fa55e83 [android] Use compact min unit for short opening-hours label
* Replace "minutes" plural with new "minutes_short" (`%d min`) for concise
  display on the place page.

Signed-off-by: NoelClick <dev@noel.click>
(cherry picked from commit 5468927a285466a5c5614328a4400abb5182d302)
Signed-off-by: NoelClick <dev@noel.click>
2025-11-12 23:07:53 +01:00
NoelClick
83256c4895 [android] Show "Opens / Closes X at Y" using formatter + add i18n strings
- Wire `PlacePageView.refreshOpenState()` to `OpenStateTextFormatter`.
- Keep <= 60 min branch with plurals (“Closes in %d minutes • at HH:mm”).
- Add day hint when next change is not today (“Opens Sat at 09:00”).
- Add localized strings with positional placeholders:
  - `opens_at` / `closes_at` (... `%s`).
  - `opens_day_at` / `closes_day_at` (`%1$s=%day`, `%2$s=%time`).

Refs: #2303

Signed-off-by: NoelClick <dev@noel.click>
(cherry picked from commit be80c7486882ab64a64efc30d0979d3674bbcc29)
Signed-off-by: NoelClick <dev@noel.click>
2025-11-12 23:07:53 +01:00
NoelClick
94542456a2 [android] Add OpenStateTextFormatter and JVM tests
- Introduce a tiny, pure formatter for opening-hours labels:
	- `formatHoursMinutes(12/24h)`, `isSameLocalDate()`, `dayShort()`
	- `buildAtLabel(...)` that accepts already-localized templates
- Add JVM unit tests for hour formatting and label selection.

Signed-off-by: NoelClick <dev@noel.click>
(cherry picked from commit df4b5f2281607e5a35b98b1007fb34eabd4aa657)
Signed-off-by: NoelClick <dev@noel.click>
2025-11-12 23:07:53 +01:00
patepelo
dd620c3f0c Add wiki debug command to docs
Signed-off-by: patepelo <developing.anton@gmail.com>
2025-11-13 02:01:27 +07:00
Jean-Baptiste
a42db17858 [android] Add icon before some settings
Signed-off-by: Jean-Baptiste <jeanbaptiste.charron@outlook.fr>
2025-11-12 19:13:37 +01:00
patepelo
738d0641ca Add Myanmar Burma synonyms
Signed-off-by: patepelo <developing.anton@gmail.com>
2025-11-12 21:16:34 +07:00
Yannik Bloscheck
4f5f8782fe [types] Adding lifebuoy
Signed-off-by: Yannik Bloscheck <git@yannikbloscheck.com>
2025-11-12 12:25:57 +01:00
Yannik Bloscheck
a886270dda [types] Add emergency access points
Signed-off-by: Yannik Bloscheck <git@yannikbloscheck.com>
2025-11-12 12:25:32 +01:00
x7z4w
66609ff08b [styles] Fix winery label
Signed-off-by: x7z4w <x7z4w@noreply.codeberg.org>
2025-11-12 10:49:38 +01:00
111 changed files with 1410 additions and 898 deletions

View File

@@ -4,6 +4,7 @@ import android.location.Location;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import app.organicmaps.MwmActivity;
@@ -26,6 +27,10 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
{
private static boolean sAutodownloadLocked;
private static final int HIDE_THRESHOLD = 2;
// Default bundles (e.g., world/coasts). Used to approximate “user-downloaded” count.
private static final int DEFAULT_MAP_BASELINE = 2;
private final MwmActivity mActivity;
private final View mFrame;
private final MaterialTextView mParent;
@@ -33,6 +38,7 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
private final MaterialTextView mSize;
private final WheelProgressView mProgress;
private final MaterialButton mButton;
private final View mOfflineExplanation;
private int mStorageSubscriptionSlot;
@@ -43,8 +49,10 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
@Override
public void onStatusChanged(List<MapManager.StorageCallbackData> data)
{
if (mCurrentCountry == null)
if (mCurrentCountry == null) {
updateOfflineExplanationVisibility();
return;
}
for (MapManager.StorageCallbackData item : data)
{
@@ -58,7 +66,7 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
{
mCurrentCountry.update();
updateProgressState(false);
updateOfflineExplanationVisibility();
return;
}
}
@@ -101,6 +109,12 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
return enqueued || progress || applying;
}
private void updateOfflineExplanationVisibility() {
if (mOfflineExplanation == null) return;
// hide once threshold reached; safe to call repeatedly.
app.organicmaps.util.UiUtils.showIf(MapManager.nativeGetDownloadedCount() < (DEFAULT_MAP_BASELINE + HIDE_THRESHOLD), mOfflineExplanation);
}
private void updateProgressState(boolean shouldAutoDownload)
{
updateStateInternal(shouldAutoDownload);
@@ -108,6 +122,8 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
private void updateStateInternal(boolean shouldAutoDownload)
{
updateOfflineExplanationVisibility();
boolean showFrame =
(mCurrentCountry != null && !mCurrentCountry.present && !RoutingController.get().isNavigating());
if (showFrame)
@@ -191,6 +207,9 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
mProgress = controls.findViewById(R.id.wheel_downloader_progress);
mButton = controls.findViewById(R.id.downloader_button);
mOfflineExplanation = mFrame.findViewById(R.id.offline_explanation);
updateOfflineExplanationVisibility();
mProgress.setOnClickListener(v -> {
if (mCurrentCountry == null)
return;
@@ -247,6 +266,7 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
public void onResume()
{
updateOfflineExplanationVisibility();
if (mStorageSubscriptionSlot == 0)
{
mStorageSubscriptionSlot = MapManager.nativeSubscribe(mStorageCallback);

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

@@ -1,7 +1,10 @@
package app.organicmaps.editor;
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.core.os.ConfigurationCompat;
import androidx.core.os.LocaleListCompat;
import androidx.fragment.app.Fragment;
import app.organicmaps.base.BaseMwmRecyclerFragment;
import app.organicmaps.sdk.editor.Editor;
@@ -11,6 +14,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class LanguagesFragment extends BaseMwmRecyclerFragment<LanguagesAdapter>
@@ -32,10 +36,23 @@ public class LanguagesFragment extends BaseMwmRecyclerFragment<LanguagesAdapter>
Set<String> existingLanguages =
args != null ? new HashSet<>(args.getStringArrayList(EXISTING_LOCALIZED_NAMES)) : new HashSet<>();
Configuration config = requireContext().getResources().getConfiguration();
LocaleListCompat systemLocales = ConfigurationCompat.getLocales(config);
List<Language> languages = new ArrayList<>();
List<Language> systemLanguages = new ArrayList<>();
for (Language lang : Editor.nativeGetSupportedLanguages(false))
{
if (existingLanguages.contains(lang.code))
// Separately extract system languages
for (int i = 0; i < systemLocales.size(); i++)
{
Locale locale = systemLocales.get(i);
if (locale != null && locale.getLanguage().equals(lang.code))
systemLanguages.add(lang);
}
if (existingLanguages.contains(lang.code) || systemLanguages.contains(lang))
continue;
languages.add(lang);
@@ -43,6 +60,8 @@ public class LanguagesFragment extends BaseMwmRecyclerFragment<LanguagesAdapter>
Collections.sort(languages, Comparator.comparing(lhs -> lhs.name));
languages.addAll(0, systemLanguages);
return new LanguagesAdapter(this, languages.toArray(new Language[languages.size()]));
}

View File

@@ -1,5 +1,6 @@
package app.organicmaps.editor;
import android.content.res.ColorStateList;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -11,6 +12,7 @@ import androidx.annotation.IdRes;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.R;
@@ -381,6 +383,29 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter
final boolean enable = mComplementItem != null && mComplementItem.weekdays.length != 0;
final String text = mFragment.getString(R.string.editor_time_add);
mAdd.setEnabled(enable);
final ColorStateList bgButtonColor = new ColorStateList(
new int[][]{
new int[]{android.R.attr.state_enabled}, // enabled
new int[]{-android.R.attr.state_enabled} // disabled
},
new int[]{
ContextCompat.getColor(
mAdd.getContext(), R.color.base_accent),
ContextCompat.getColor(mAdd.getContext(), R.color.button_accent_disabled)
});
final ColorStateList textButtonColor = new ColorStateList(
new int[][]{
new int[]{android.R.attr.state_enabled}, // enabled
new int[]{-android.R.attr.state_enabled} // disabled
},
new int[]{
ContextCompat.getColor(
mAdd.getContext(),
UiUtils.getStyledResourceId(mAdd.getContext(), android.R.attr.textColorPrimaryInverse)),
ContextCompat.getColor(mAdd.getContext(), R.color.button_accent_text_disabled)
});
mAdd.setBackgroundTintList(bgButtonColor);
mAdd.setTextColor(textButtonColor);
mAdd.setText(enable ? text + " (" + TimeFormatUtils.formatWeekdays(mComplementItem) + ")" : text);
}
}

View File

@@ -0,0 +1,49 @@
package app.organicmaps.widget.placepage;
import java.time.ZonedDateTime;
import java.time.format.TextStyle;
import java.util.Locale;
public class OpenStateTextFormatter
{
private OpenStateTextFormatter() {}
static String formatHoursMinutes(int hour, int minute, boolean use24h)
{
if (use24h)
return String.format(Locale.ROOT, "%02d:%02d", hour, minute);
int h = hour % 12;
if (h == 0) h = 12;
String ampm = (hour < 12) ? "AM" : "PM";
return String.format(Locale.ROOT, "%d:%02d %s", h, minute, ampm);
}
static boolean isSameLocalDate(ZonedDateTime a, ZonedDateTime b)
{
return a.toLocalDate().isEqual(b.toLocalDate());
}
static String dayShort(ZonedDateTime t, Locale locale)
{
return t.getDayOfWeek().getDisplayName(TextStyle.SHORT, locale);
}
static String buildAtLabel(
boolean opens,
boolean isToday,
String dayShort,
String time,
String opensAtLocalized,
String closesAtLocalized,
String opensDayAtLocalized,
String closesDayAtLocalized
)
{
if (isToday)
return opens ? String.format(Locale.ROOT, opensAtLocalized, time) // Opens at %s
: String.format(Locale.ROOT, closesAtLocalized, time); // Closes at %s
return opens ? String.format(Locale.ROOT, opensDayAtLocalized, dayShort, time) // Opens %s at %s
: String.format(Locale.ROOT, closesDayAtLocalized, dayShort, time); // Closes %s at %s
}
}

View File

@@ -85,9 +85,11 @@ import com.google.android.material.textview.MaterialTextView;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class PlacePageView extends Fragment
implements View.OnClickListener, View.OnLongClickListener, LocationListener, SensorListener, Observer<MapObject>,
@@ -105,6 +107,10 @@ public class PlacePageView extends Fragment
private static final String LINKS_FRAGMENT_TAG = "LINKS_FRAGMENT_TAG";
private static final String TRACK_SHARE_MENU_ID = "TRACK_SHARE_MENU_ID";
private static final int SHORT_HORIZON_CLOSE_MIN = 60;
private static final int SHORT_HORIZON_OPEN_MIN = 15;
private static final List<CoordinatesFormat> visibleCoordsFormat =
Arrays.asList(CoordinatesFormat.LatLonDMS, CoordinatesFormat.LatLonDecimal, CoordinatesFormat.OLCFull,
CoordinatesFormat.UTM, CoordinatesFormat.MGRS, CoordinatesFormat.OSMLink);
@@ -797,57 +803,95 @@ public class PlacePageView extends Fragment
final String ohStr = mMapObject.getMetadata(Metadata.MetadataType.FMD_OPEN_HOURS);
final Timetable[] timetables = OpeningHours.nativeTimetablesFromString(ohStr);
if (timetables != null && timetables.length != 0)
// No valid timetable
if (timetables == null || timetables.length == 0)
{
final Context context = requireContext();
final OhState poiState = OpeningHours.nativeCurrentState(timetables);
// Ignore unknown rule state
if (poiState.state == OhState.State.Unknown)
{
UiUtils.hide(mTvOpenState);
return;
}
// Get colours
final ForegroundColorSpan colorGreen =
new ForegroundColorSpan(ContextCompat.getColor(context, R.color.base_green));
final ForegroundColorSpan colorYellow =
new ForegroundColorSpan(ContextCompat.getColor(context, R.color.base_yellow));
final ForegroundColorSpan colorRed = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.base_red));
// Get next state info
final SpannableStringBuilder openStateString = new SpannableStringBuilder();
final boolean isOpen = (poiState.state == OhState.State.Open); // False == Closed due to early exit for Unknown
final long nextStateTime = isOpen ? poiState.nextTimeClosed : poiState.nextTimeOpen; // Unix time (seconds)
final int minsToNextState = (int) ((nextStateTime - (System.currentTimeMillis() / 1000)) / 60);
if (minsToNextState <= 60) // POI opens/closes in 60 mins
{
final String minsToChangeStr = minsToNextState + " " + getString(R.string.minute);
final String nextChangeFormatted = getString(isOpen ? R.string.closes_in : R.string.opens_in, minsToChangeStr);
final ForegroundColorSpan nextChangeColor = isOpen ? colorYellow : colorRed;
// TODO: We should check closed/open time for specific feature's timezone.
ZonedDateTime time = ZonedDateTime.ofInstant(Instant.ofEpochSecond(nextStateTime), ZoneId.systemDefault());
String localizedTime =
new HoursMinutes(time.getHour(), time.getMinute(), DateUtils.is24HourFormat(context)).toString();
openStateString.append(nextChangeFormatted, nextChangeColor, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
.append("") // Add spacer
.append(getString(R.string.at, localizedTime));
}
else if (isOpen)
openStateString.append(getString(R.string.open_now), colorGreen, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// TODO: Add "Closes at 18:00" etc
else // Closed
openStateString.append(getString(R.string.closed_now), colorRed, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// TODO: Add "Opens at 18:00" etc
UiUtils.setTextAndHideIfEmpty(mTvOpenState, openStateString);
UiUtils.hide(mTvOpenState);
return;
}
// No valid timetable
UiUtils.hide(mTvOpenState);
final Context context = requireContext();
final OhState poiState = OpeningHours.nativeCurrentState(timetables);
// Ignore unknown rule state
if (poiState.state == OhState.State.Unknown)
{
UiUtils.hide(mTvOpenState);
return;
}
// Get colours
final ForegroundColorSpan colorGreen =
new ForegroundColorSpan(ContextCompat.getColor(context, R.color.base_green));
final ForegroundColorSpan colorYellow =
new ForegroundColorSpan(ContextCompat.getColor(context, R.color.base_yellow));
final ForegroundColorSpan colorRed = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.base_red));
// Get next state info
final SpannableStringBuilder openStateString = new SpannableStringBuilder();
final boolean isOpen = (poiState.state == OhState.State.Open); // False == Closed due to early exit for Unknown
final long nextStateTime = isOpen ? poiState.nextTimeClosed : poiState.nextTimeOpen; // Unix time (seconds)
final long nowSec = System.currentTimeMillis() / 1000;
final int minsToNextState = (int) ((nextStateTime - nowSec) / 60);
// NOTE: Timezone is currently device timezone. TODO: use feature-specific timezone.
final ZonedDateTime nextChangeLocal =
ZonedDateTime.ofInstant(Instant.ofEpochSecond(nextStateTime), ZoneId.systemDefault());
String localizedTimeString = OpenStateTextFormatter.formatHoursMinutes(
nextChangeLocal.getHour(), nextChangeLocal.getMinute(), DateUtils.is24HourFormat(context));
final boolean shortHorizonClosing = isOpen && minsToNextState >= 0 && minsToNextState <= SHORT_HORIZON_CLOSE_MIN;
final boolean shortHorizonOpening = !isOpen && minsToNextState >= 0 && minsToNextState <= SHORT_HORIZON_OPEN_MIN;
if (shortHorizonClosing || shortHorizonOpening) // POI Opens/Closes in 60 mins • at 18:00
{
final String minsToChangeStr = getResources().getQuantityString(
R.plurals.minutes_short, Math.max(minsToNextState, 1), Math.max(minsToNextState, 1));
final String nextChangeFormatted = getString(isOpen ? R.string.closes_in : R.string.opens_in, minsToChangeStr);
openStateString.append(nextChangeFormatted, colorYellow, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
.append("") // Add spacer
.append(getString(R.string.at, localizedTimeString));
}
else
{
final String opensAtStr = getString(R.string.opens_at); // "Opens at %s"
final String closesAtStr = getString(R.string.closes_at); // "Closes at %s"
final String opensDayAtStr = getString(R.string.opens_day_at); // "Opens %1$s at %2$s"
final String closesDayAtStr = getString(R.string.closes_day_at); // "Closes %1$s at %2$s"
final boolean isToday =
OpenStateTextFormatter.isSameLocalDate(nextChangeLocal, ZonedDateTime.now(nextChangeLocal.getZone()));
// Full weekday name per design feedback.
final String dayName =
nextChangeLocal.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault());
if (isOpen) // > 60 minutes OR negative (safety). Show “Open now • Closes at 18:00”
{
openStateString.append(getString(R.string.open_now), colorGreen, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
final String atLabel =
OpenStateTextFormatter.buildAtLabel(false, isToday, dayName, localizedTimeString,
opensAtStr, closesAtStr, opensDayAtStr, closesDayAtStr);
if (!TextUtils.isEmpty(atLabel))
openStateString.append("").append(atLabel);
}
else // Closed
{
openStateString.append(getString(R.string.closed_now), colorRed, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
final String atLabel =
OpenStateTextFormatter.buildAtLabel(true, isToday, dayName, localizedTimeString,
opensAtStr, closesAtStr, opensDayAtStr, closesDayAtStr);
if (!TextUtils.isEmpty(atLabel))
openStateString.append("").append(atLabel);
}
}
UiUtils.setTextAndHideIfEmpty(mTvOpenState, openStateString);
}
private void addPlace()

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

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M80,360v-160q0,-33 23.5,-56.5T160,120h640q33,0 56.5,23.5T880,200v160h-80v-160L160,200v160L80,360ZM160,720q-33,0 -56.5,-23.5T80,640v-200h80v200h640v-200h80v200q0,33 -23.5,56.5T800,720L160,720ZM40,840v-80h880v80L40,840ZM480,420ZM80,440v-80h240q11,0 21,6t15,16l47,93 123,-215q5,-9 14,-14.5t20,-5.5q11,0 21,5.5t15,16.5l49,98h235v80L620,440q-11,0 -21,-5.5T584,418l-26,-53 -123,215q-5,10 -15,15t-21,5q-11,0 -20.5,-6T364,578l-69,-138L80,440Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M480,840q-150,0 -255,-105T120,480q0,-150 105,-255t255,-105q14,0 27.5,1t26.5,3q-41,29 -65.5,75.5T444,300q0,90 63,153t153,63q55,0 101,-24.5t75,-65.5q2,13 3,26.5t1,27.5q0,150 -105,255T480,840ZM480,760q88,0 158,-48.5T740,585q-20,5 -40,8t-40,3q-123,0 -209.5,-86.5T364,300q0,-20 3,-40t8,-40q-78,32 -126.5,102T200,480q0,116 82,198t198,82ZM470,490Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?colorControlNormal">
<path
android:pathData="M19,9h-4v-6h-6v6h-4l7,7 7,-7ZM5,18v2h14v-2h-14Z"
android:fillColor="#FFF"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M216,784q-45,-45 -70.5,-104T120,558q0,-63 24,-124.5T222,318q35,-35 86.5,-60t122,-39.5Q501,204 591.5,201t202.5,7q8,106 5,195t-16.5,160.5q-13.5,71.5 -38,125T684,778q-53,53 -112.5,77.5T450,880q-65,0 -127,-25.5T216,784ZM328,768q29,17 59.5,24.5T450,800q46,0 91,-18.5t86,-59.5q18,-18 36.5,-50.5t32,-85Q709,534 716,459.5t2,-177.5q-49,-2 -110.5,-1.5T485,290q-61,9 -116,29t-90,55q-45,45 -62,89t-17,85q0,59 22.5,103.5T262,714q42,-80 111,-153.5T534,440q-72,63 -125.5,142.5T328,768ZM328,768ZM328,768Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M200,800v-280h-80v-80h240v80h-80v280h-80ZM200,360v-200h80v200h-80ZM360,360v-80h80v-120h80v120h80v80L360,360ZM440,800v-360h80v360h-80ZM680,800v-120h-80v-80h240v80h-80v120h-80ZM680,520v-360h80v360h-80Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M280,920q-33,0 -56.5,-23.5T200,840v-720q0,-33 23.5,-56.5T280,40h400q33,0 56.5,23.5T760,120v124q18,7 29,22t11,34v80q0,19 -11,34t-29,22v404q0,33 -23.5,56.5T680,920L280,920ZM280,840h400v-720L280,120v720ZM280,840v-720,720ZM394,640h172q14,0 24,-10t10,-24v-132q0,-14 -10,-24t-24,-10h-6v-40q0,-33 -23.5,-56.5T480,320q-33,0 -56.5,23.5T400,400v40h-6q-14,0 -24,10t-10,24v132q0,14 10,24t24,10ZM440,440v-40q0,-17 11.5,-28.5T480,360q17,0 28.5,11.5T520,400v40h-80Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M339,698q22,-22 49.5,-36t58.5,-19q-5,19 -8,38t-3,39q0,24 3.5,47t11.5,44L339,698ZM254,614 L170,528q62,-62 142,-95t168,-33q49,0 96,10.5t90,30.5q-44,8 -81.5,29T517,522q-9,-1 -18.5,-1.5T480,520q-64,0 -122.5,24.5T254,614ZM84,444 L0,360q95,-97 219.5,-148.5T480,160q136,0 260.5,51.5T960,360l-84,84q-79,-79 -181.5,-121.5T480,280q-112,0 -214.5,42.5T84,444ZM760,520 L772,580q12,5 22.5,10.5T816,604l58,-18 40,68 -46,40q2,12 2,26t-2,26l46,40 -40,68 -58,-18q-11,8 -21.5,13.5T772,860l-12,60h-80l-12,-60q-12,-5 -22.5,-10.5T624,836l-58,18 -40,-68 46,-40q-2,-12 -2,-26t2,-26l-46,-40 40,-68 58,18q11,-8 21.5,-13.5T668,580l12,-60h80ZM720,640q-33,0 -56.5,23.5T640,720q0,33 23.5,56.5T720,800q33,0 56.5,-23.5T800,720q0,-33 -23.5,-56.5T720,640Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M480,480q-66,0 -113,-47t-47,-113q0,-66 47,-113t113,-47q66,0 113,47t47,113q0,66 -47,113t-113,47ZM160,800v-112q0,-34 17.5,-62.5T224,582q62,-31 126,-46.5T480,520q66,0 130,15.5T736,582q29,15 46.5,43.5T800,688v112L160,800ZM240,720h480v-32q0,-11 -5.5,-20T700,654q-54,-27 -109,-40.5T480,600q-56,0 -111,13.5T260,654q-9,5 -14.5,14t-5.5,20v32ZM480,400q33,0 56.5,-23.5T560,320q0,-33 -23.5,-56.5T480,240q-33,0 -56.5,23.5T400,320q0,33 23.5,56.5T480,400ZM480,320ZM480,720Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="m798,638 l-62,-62q44,-41 69,-97t25,-119q0,-63 -25,-118t-69,-96l62,-64q56,53 89,125t33,153q0,81 -33,153t-89,125ZM670,510l-64,-64q18,-17 29,-38.5t11,-47.5q0,-26 -11,-47.5T606,274l64,-64q32,29 50,67.5t18,82.5q0,44 -18,82.5T670,510ZM360,520q-66,0 -113,-47t-47,-113q0,-66 47,-113t113,-47q66,0 113,47t47,113q0,66 -47,113t-113,47ZM40,840v-112q0,-33 17,-62t47,-44q51,-26 115,-44t141,-18q77,0 141,18t115,44q30,15 47,44t17,62v112L40,840ZM120,760h480v-32q0,-11 -5.5,-20T580,694q-36,-18 -92.5,-36T360,640q-71,0 -127.5,18T140,694q-9,5 -14.5,14t-5.5,20v32ZM360,440q33,0 56.5,-23.5T440,360q0,-33 -23.5,-56.5T360,280q-33,0 -56.5,23.5T280,360q0,33 23.5,56.5T360,440ZM360,360ZM360,760Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M360,440h80v-160h-80v160ZM480,440h80v-160h-80v160ZM600,440h80v-160h-80v160ZM240,880q-33,0 -56.5,-23.5T160,800v-480l240,-240h320q33,0 56.5,23.5T800,160v640q0,33 -23.5,56.5T720,880L240,880ZM240,800h480v-640L434,160L240,354v446ZM240,800h480,-480Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M13.26,3C8.17,2.86 4,6.95 4,12L2.21,12c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.8c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.8c0.31,-0.31 0.09,-0.85 -0.36,-0.85L6,12c0,-3.9 3.18,-7.05 7.1,-7 3.72,0.05 6.85,3.18 6.9,6.9 0.05,3.91 -3.1,7.1 -7,7.1 -1.61,0 -3.1,-0.55 -4.28,-1.48 -0.4,-0.31 -0.96,-0.28 -1.32,0.08 -0.42,0.42 -0.39,1.13 0.08,1.49C9,20.29 10.91,21 13,21c5.05,0 9.14,-4.17 9,-9.26 -0.13,-4.69 -4.05,-8.61 -8.74,-8.74zM12.75,8c-0.41,0 -0.75,0.34 -0.75,0.75v3.68c0,0.35 0.19,0.68 0.49,0.86l3.12,1.85c0.36,0.21 0.82,0.09 1.03,-0.26 0.21,-0.36 0.09,-0.82 -0.26,-1.03l-2.88,-1.71v-3.4c0,-0.4 -0.34,-0.74 -0.75,-0.74z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M480,560q-33,0 -56.5,-23.5T400,480q0,-33 23.5,-56.5T480,400q33,0 56.5,23.5T560,480q0,33 -23.5,56.5T480,560ZM480,840q-139,0 -241,-91.5T122,520h82q14,104 92.5,172T480,760q117,0 198.5,-81.5T760,480q0,-117 -81.5,-198.5T480,200q-69,0 -129,32t-101,88h110v80L120,400v-240h80v94q51,-64 124.5,-99T480,120q75,0 140.5,28.5t114,77q48.5,48.5 77,114T840,480q0,75 -28.5,140.5t-77,114q-48.5,48.5 -114,77T480,840Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M2,20h20v-4h-20v4ZM4,17h2v2h-2v-2ZM2,4v4h20v-4h-20ZM6,7h-2v-2h2v2ZM2,14h20v-4h-20v4ZM4,11h2v2h-2v-2Z"
android:fillColor="#FFF"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M160,720q-33,0 -56.5,-23.5T80,640v-320q0,-33 23.5,-56.5T160,240h640q33,0 56.5,23.5T880,320v320q0,33 -23.5,56.5T800,720L160,720ZM160,640h640v-320L680,320v160h-80v-160h-80v160h-80v-160h-80v160h-80v-160L160,320v320ZM280,480h80,-80ZM440,480h80,-80ZM600,480h80,-80ZM480,480Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M280,800v-520L80,280v-120h520v120L400,280v520L280,800ZM640,800v-320L520,480v-120h360v120L760,480v320L640,800Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480h80q0,115 72.5,203T418,794l-58,-58 56,-56L598,862q-29,10 -58.5,14T480,880ZM500,600v-240h120q17,0 28.5,11.5T660,400v160q0,17 -11.5,28.5T620,600L500,600ZM300,600v-60h100v-40h-60v-40h60v-40L300,420v-60h120q17,0 28.5,11.5T460,400v160q0,17 -11.5,28.5T420,600L300,600ZM560,540h40v-120h-40v120ZM800,480q0,-115 -72.5,-203T542,166l58,58 -56,56 -182,-182q29,-10 58.5,-14t59.5,-4q83,0 156,31.5T763,197q54,54 85.5,127T880,480h-80Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="m476,880 l182,-480h84L924,880h-84l-43,-122L603,758L560,880h-84ZM160,760l-56,-56 202,-202q-35,-35 -63.5,-80T190,320h84q20,39 40,68t48,58q33,-33 68.5,-92.5T484,240L40,240v-80h280v-80h80v80h280v80L564,240q-21,72 -63,148t-83,116l96,98 -30,82 -122,-125 -202,201ZM628,688h144l-72,-204 -72,204Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="m476,880 l182,-480h84L924,880h-84l-43,-122L603,758L560,880h-84ZM628,688h144l-72,-204 -72,204ZM254,640q-66,0 -123.5,-38.5T44,498l72,-36q21,42 58,70t79,28q38,0 62.5,-23.5T340,480q0,-33 -23.5,-56.5T260,400h-60v-80h60q25,0 42.5,-17.5T320,260q0,-25 -17,-42.5T261,200q-23,0 -41,15t-32,33l-63,-49q26,-32 60,-55.5t77,-23.5q57,0 97.5,40.5T400,259q0,27 -10,52.5T361,357q10,10 18.5,20.5T396,400h124v-200h-80v-80h240v80h-80v116l-61,164L420,480v4q0,63 -46,109.5T254,640Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?colorControlNormal">
<path
android:pathData="M480,840 L0,359q93,-93 215.5,-146T480,160q142,0 264.5,53T960,359l-56,57q-81,-81 -190,-128.5T480,240q-103,0 -195,32.5T117,363l419,420 -56,57ZM864,800L761,698q-18,11 -38,16.5t-43,5.5q-68,0 -114,-46t-46,-114q0,-68 46,-114t114,-46q68,0 114,46t46,114q0,23 -5.5,43T818,641l102,103 -56,56ZM680,640q34,0 57,-23t23,-57q0,-34 -23,-57t-57,-23q-34,0 -57,23t-23,57q0,34 23,57t57,23ZM480,783Z"
android:fillColor="#fff"/>
</vector>

View File

@@ -26,27 +26,33 @@
android:clipChildren="false"
android:gravity="center"
tools:ignore="UselessParent">
<com.google.android.material.textview.MaterialTextView
<LinearLayout
android:id="@+id/offline_explanation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="bold"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/offline_explanation_title"/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="normal"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:text="@string/offline_explanation_text"/>
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="@dimen/margin_quarter"
android:layout_marginBottom="@dimen/margin_quarter"/>
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="bold"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/offline_explanation_title"/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="normal"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:text="@string/offline_explanation_text"/>
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="@dimen/margin_quarter"
android:layout_marginBottom="@dimen/margin_quarter"/>
</LinearLayout>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/downloader_parent"
android:layout_width="wrap_content"

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,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/margin_base_plus"
@@ -12,9 +11,7 @@
style="@style/MwmWidget.M3.Button.Primary"
android:layout_gravity="center"
android:enabled="false"
android:background="?accentButtonBackground"
android:padding="@dimen/margin_base"
android:text="@string/editor_time_add"
app:backgroundTint="@null"/>
android:textColor="?android:textColorPrimaryInverse"
android:text="@string/editor_time_add" />
</FrameLayout>

View File

@@ -17,29 +17,34 @@
android:layout_gravity="center"
android:gravity="center_horizontal"
android:background="@drawable/onmap_downloader_background">
<com.google.android.material.textview.MaterialTextView
android:layout_width="@dimen/square_block_size"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="bold"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/offline_explanation_title"/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="212dp"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="normal"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:text="@string/offline_explanation_text"/>
<com.google.android.material.divider.MaterialDivider
<LinearLayout
android:id="@+id/offline_explanation"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="@dimen/margin_quarter"
android:layout_marginBottom="@dimen/margin_quarter"/>
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="bold"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/offline_explanation_title"/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="212dp"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center_horizontal"
android:textStyle="normal"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:text="@string/offline_explanation_text"/>
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="@dimen/margin_quarter"
android:layout_marginBottom="@dimen/margin_quarter"/>
</LinearLayout>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/downloader_parent"
android:layout_width="@dimen/square_block_size"

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

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Items in the Preferences can have space reserved for an icon. As none of the
settings currently have associated icons, this leads to items that seem indented
without purpose. This wastes space and can lead to truncation of the item names
and descriptions. See https://github.com/organicmaps/organicmaps/issues/1872
To rectify this, the iconSpaceReserved property needs to be set to false.
According to https://developer.android.com/reference/android/preference/Preference#attr_android:iconSpaceReserved
false should be the default. However, according to
https://material.io/design/platform-guidance/android-settings.html this goes
against the material design guidelines and the default was overridden to true in
https://cs.android.com/android/platform/superproject/+/android-9.0.0_r1:prebuilts/sdk/current/support/v7/preference/res/values-sw360dp-v13/values-sw360dp-v13.xml
This file sets the default value back to false (i.e. no space reserved for icons).
See also the discussion at https://github.com/organicmaps/organicmaps/pull/1924
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<bool name="config_materialPreferenceIconSpaceReserved" tools:ignore="MissingDefaultResource">false</bool>
</resources>

View File

@@ -441,6 +441,14 @@
<string name="opens_in">Opens in %s</string>
<string name="closes_in">Closes in %s</string>
<string name="closed">Closed</string>
<string name="opens_at">Opens at %s</string>
<string name="closes_at">Closes at %s</string>
<string name="opens_day_at">Opens on %1$s at %2$s</string>
<string name="closes_day_at">Closes on %1$s at %2$s</string>
<plurals name="minutes_short">
<item quantity="one">%d min</item>
<item quantity="other">%d min</item>
</plurals>
<!-- Used in the opening_hours fragment for the last checked date, eg. "Confirmed two weeks ago" -->
<string name="hours_confirmed_time_ago">Confirmed %s</string>
<!-- Used on the place page for the last checked date, eg. "Existence confirmed two weeks ago" -->
@@ -543,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

@@ -1,24 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
android:key="backup_location"
android:summary="@string/pref_backup_location_summary_initial"
android:title="@string/pref_backup_location_title" />
android:title="@string/pref_backup_location_title"
app:iconSpaceReserved="false" />
<Preference
android:key="backup_now"
android:summary="@string/pref_backup_now_summary"
android:title="@string/pref_backup_now_title" />
android:title="@string/pref_backup_now_title"
app:iconSpaceReserved="false" />
<ListPreference
android:defaultValue="86400000"
android:entries="@array/backup_interval_entries"
android:entryValues="@array/backup_interval_values"
android:key="backup_history_interval"
android:title="@string/pref_backup_interval_title" />
android:title="@string/pref_backup_interval_title"
app:iconSpaceReserved="false" />
<ListPreference
android:defaultValue="10"
android:entries="@array/backup_history_entries"
android:entryValues="@array/backup_history_values"
android:key="backup_history_count"
android:title="@string/pref_backup_history_title" />
android:title="@string/pref_backup_history_title"
app:iconSpaceReserved="false" />
</PreferenceScreen>

View File

@@ -7,6 +7,7 @@
<Preference
android:key="@string/pref_osm_profile"
android:title="@string/profile"
app:icon="@drawable/ic_profile"
tools:summary="LongLongUsernameHere"
app:singleLineTitle="false"
android:order="1"/>
@@ -17,6 +18,7 @@
<ListPreference
android:key="@string/pref_munits"
android:title="@string/measurement_units"
app:icon="@drawable/ic_straighten"
app:singleLineTitle="false"
android:summary="@string/measurement_units_summary"
android:entries="@array/measument_units"
@@ -42,6 +44,7 @@
<SwitchPreferenceCompat
android:key="@string/pref_autodownload"
android:title="@string/autodownload"
app:icon="@drawable/ic_download_st"
app:singleLineTitle="false"
android:order="5"/>
<SwitchPreferenceCompat
@@ -49,22 +52,26 @@
android:title="@string/big_font"
app:singleLineTitle="false"
android:defaultValue="false"
app:icon="@drawable/ic_text_fields"
android:order="6"/>
<SwitchPreferenceCompat
android:key="@string/pref_transliteration"
android:title="@string/transliteration_title"
app:singleLineTitle="false"
app:icon="@drawable/ic_translate_indic"
android:defaultValue="false"
android:order="7"/>
<Preference
android:key="@string/pref_storage"
android:title="@string/maps_storage"
app:icon="@drawable/ic_sd_card"
app:singleLineTitle="false"
android:summary="@string/maps_storage_summary"
android:order="8"/>
<SwitchPreferenceCompat
android:key="@string/pref_enable_logging"
android:title="@string/enable_logging"
app:icon="@drawable/ic_browse_activity"
app:singleLineTitle="false"
android:summary="@string/enable_logging_warning_message"
android:defaultValue="false"
@@ -80,6 +87,7 @@
android:key="@string/pref_use_mobile_data"
android:title="@string/mobile_data"
app:singleLineTitle="false"
app:icon="@drawable/ic_network_manage"
android:summary="@string/mobile_data_description"
android:entries="@array/mobile_data_options"
android:entryValues="@array/mobile_data_options_values"
@@ -91,6 +99,7 @@
android:summary="@string/power_managment_description"
android:entries="@array/power_management_scheme"
android:entryValues="@array/power_management_scheme_values"
app:icon="@drawable/ic_eco"
android:order="15"/>
<SwitchPreferenceCompat
android:key="@string/pref_keep_screen_on"
@@ -102,6 +111,7 @@
<SwitchPreferenceCompat
android:key="@string/pref_show_on_lock_screen"
android:title="@string/enable_show_on_lock_screen"
app:icon="@drawable/ic_mobile_lock_portrait"
app:singleLineTitle="false"
android:summary="@string/enable_show_on_lock_screen_description"
android:defaultValue="true"
@@ -109,6 +119,7 @@
<Preference
android:key="@string/pref_map_locale"
android:title="@string/change_map_locale"
app:icon="@drawable/ic_translate"
app:singleLineTitle="false"
android:persistent="false"
android:order="18"/>
@@ -116,6 +127,7 @@
android:key="@string/pref_backup"
android:title="@string/pref_backup_title"
android:summary="@string/pref_backup_summary"
app:icon="@drawable/ic_settings_backup_restore"
app:singleLineTitle="false"
android:persistent="false"
android:order="19"/>
@@ -128,12 +140,14 @@
<ListPreference
android:key="@string/pref_map_style"
android:title="@string/pref_map_style_title"
app:icon="@drawable/ic_dark_mode"
app:singleLineTitle="false"
android:entries="@array/map_style"
android:order="1"/>
<SwitchPreferenceCompat
android:key="@string/pref_3d"
android:title="@string/pref_map_3d_title"
app:icon="@drawable/ic_three_d_rotation"
app:singleLineTitle="false"
android:order="2"/>
<SwitchPreferenceCompat
@@ -146,12 +160,14 @@
android:title="@string/pref_tts_enable_title"
app:singleLineTitle="false"
android:persistent="false"
app:icon="@drawable/ic_record_voice_over"
android:order="4">
</Preference>
<PreferenceScreen
android:key="@string/prefs_routing"
android:order="5"
android:title="@string/driving_options_title">
android:title="@string/driving_options_title"
app:icon="@drawable/ic_instant_mix">
<intent
android:targetClass="app.organicmaps.settings.DrivingOptionsActivity"
android:targetPackage="@string/app_id">
@@ -167,12 +183,14 @@
android:key="@string/pref_play_services"
android:title="@string/google_play_services"
app:singleLineTitle="false"
app:icon="@drawable/ic_wifi_find"
android:summary="@string/pref_use_google_play"
android:defaultValue="true"
android:order="1"/>
<SwitchPreferenceCompat
android:key="@string/pref_search_history"
android:title="@string/search_history_title"
app:icon="@drawable/ic_search_recent_st"
app:singleLineTitle="false"
android:defaultValue="true"
android:order="2"/>

View File

@@ -5,45 +5,54 @@
<SwitchPreferenceCompat
android:key="@string/pref_tts_enabled"
android:title="@string/pref_tts_enable_title" />
android:title="@string/pref_tts_enable_title"
app:iconSpaceReserved="false"/>
<SwitchPreferenceCompat
android:key="@string/pref_tts_street_names"
android:title="@string/pref_tts_street_names_title"
app:isPreferenceVisible="false"
android:summary="@string/pref_tts_street_names_description"
android:defaultValue="false" />
android:defaultValue="false"
app:iconSpaceReserved="false"/>
<ListPreference
android:key="@string/pref_tts_language"
app:isPreferenceVisible="false"
android:title="@string/pref_tts_language_title" />
android:title="@string/pref_tts_language_title"
app:iconSpaceReserved="false"/>
<SeekBarPreference
android:key="@string/pref_tts_volume"
app:isPreferenceVisible="false"
android:title="@string/volume" />
android:title="@string/volume"
app:iconSpaceReserved="false"/>
<Preference
android:key="@string/pref_tts_test_voice"
app:isPreferenceVisible="false"
android:title="@string/pref_tts_test_voice_title" />
android:title="@string/pref_tts_test_voice_title"
app:iconSpaceReserved="false"/>
<Preference
android:key="@string/pref_tts_open_system_settings"
android:title="@string/pref_tts_open_system_settings" />
android:title="@string/pref_tts_open_system_settings"
app:iconSpaceReserved="false"/>
<Preference
android:enabled="false"
android:key="@string/pref_tts_info"
android:persistent="false"
android:selectable="false"
android:summary="@string/prefs_languages_information" />
android:summary="@string/prefs_languages_information"
app:iconSpaceReserved="false" />
<Preference
android:enabled="true"
android:key="@string/pref_tts_info_link"
android:persistent="false"
android:selectable="true"
android:summary="@string/prefs_languages_information_off_link" />
android:summary="@string/prefs_languages_information_off_link"
app:iconSpaceReserved="false" />
<ListPreference
android:key="@string/pref_tts_speed_cameras"
android:title="@string/speedcams_alert_title"
app:singleLineTitle="false"
android:entries="@array/speed_cameras"
android:entryValues="@array/speed_cameras_values"
android:defaultValue="@string/auto_enum_value" />
android:defaultValue="@string/auto_enum_value"
app:iconSpaceReserved="false" />
</androidx.preference.PreferenceScreen>

View File

@@ -0,0 +1,72 @@
package app.organicmaps.widget.placepage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Locale;
public class OpenStateTextFormatterTest
{
private static final String OPENS_AT = "Opens at %s";
private static final String CLOSES_AT = "Closes at %s";
private static final String OPENS_DAY_AT = "Opens %1$s at %2$s";
private static final String CLOSES_DAY_AT = "Closes %1$s at %2$s";
@Test
public void formatHoursMinutes_24h()
{
assertEquals("09:00", OpenStateTextFormatter.formatHoursMinutes(9, 0, true));
assertEquals("18:05", OpenStateTextFormatter.formatHoursMinutes(18, 5, true));
}
@Test
public void formatHoursMinutes_12h()
{
assertEquals("9:00 AM", OpenStateTextFormatter.formatHoursMinutes(9, 0, false));
assertEquals("6:05 PM", OpenStateTextFormatter.formatHoursMinutes(18, 5, false));
assertEquals("12:00 PM", OpenStateTextFormatter.formatHoursMinutes(12, 0, false));
assertEquals("12:00 AM", OpenStateTextFormatter.formatHoursMinutes(0, 0, false));
}
@Test
public void buildAtLabel_today_open_close()
{
String open = OpenStateTextFormatter.buildAtLabel(true, true, "Sat", "09:00",
OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT);
String close = OpenStateTextFormatter.buildAtLabel(false, true, "Sat", "18:00",
OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT);
assertEquals("Opens at 09:00", open);
assertEquals("Closes at 18:00", close);
}
@Test
public void buildAtLabel_other_day()
{
String open = OpenStateTextFormatter.buildAtLabel(true, false, "Sat", "09:00",
OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT);
String close = OpenStateTextFormatter.buildAtLabel(false, false, "Tue", "18:00",
OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT);
assertEquals("Opens Sat at 09:00", open);
assertEquals("Closes Tue at 18:00", close);
}
@Test
public void isSameLocalDate_and_dayShort_helpers()
{
ZonedDateTime a = ZonedDateTime.of(2025, 3, 1, 10, 0, 0, 0, ZoneId.of("Europe/Paris"));
ZonedDateTime b = ZonedDateTime.of(2025, 3, 1, 22, 0, 0, 0, ZoneId.of("Europe/Paris"));
ZonedDateTime c = a.plusDays(1);
assertTrue(OpenStateTextFormatter.isSameLocalDate(a, b));
assertFalse(OpenStateTextFormatter.isSameLocalDate(a, c));
String day = OpenStateTextFormatter.dayShort(c, Locale.US);
// March 2, 2025 is a Sunday; "Sun" in US locale
assertEquals("Sun", day);
}
}

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

@@ -337,7 +337,9 @@
<string name="type.cuisine.vegetarian">Vegetarisch</string>
<string name="type.cuisine.vietnamese">Vietnamesisch</string>
<string name="type.emergency">Notfall</string>
<string name="type.emergency.access_point">Rettungspunkt</string>
<string name="type.emergency.assembly_point">Notfall-Sammelpunkt</string>
<string name="type.emergency.life_ring">Rettungsring</string>
<string name="type.emergency.defibrillator">Defibrillator</string>
<string name="type.emergency.fire_hydrant">Hydrant</string>
<string name="type.emergency.phone">Notruftelefon</string>

View File

@@ -371,7 +371,9 @@
<string name="type.cuisine.vegetarian">Vegetarian</string>
<string name="type.cuisine.vietnamese">Vietnamese</string>
<string name="type.emergency">Emergency</string>
<string name="type.emergency.access_point">Emergency Rescue Point</string>
<string name="type.emergency.assembly_point">Emergency Assembly Point</string>
<string name="type.emergency.life_ring">Lifebuoy</string>
<string name="type.emergency.defibrillator">Defibrillator</string>
<string name="type.emergency.fire_hydrant">Fire Hydrant</string>
<string name="type.emergency.phone">Emergency Phone</string>
@@ -1234,6 +1236,7 @@
<string name="type.shop.kitchen">Kitchen Store</string>
<string name="type.shop.laundry">Laundry</string>
<string name="type.shop.mall">Mall</string>
<string name="type.shop.beauty.day_spa">Day Spa</string>
<string name="type.shop.massage">Massage Salon</string>
<string name="type.shop.mobile_phone">Mobile Phone Store</string>
<string name="type.shop.money_lender">Money Lender</string>

View File

@@ -397,7 +397,9 @@
"amenity-payment_terminal": "Bezahlterminal",
"amenity-public_bath": "Öffentliches Bad",
"amenity-shower": "Dusche",
"emergency-access_point": "4Rettungspunkt|Notfallpunkt|Notfall-Rettungspunkt|Notfall-Treffpunkt",
"emergency-assembly_point": "Notfall-Sammelpunkt",
"emergency-life_ring": "4Rettungsring",
"emergency-defibrillator": "4Defibrillator",
"emergency-fire_hydrant": "4Hydrant",
"emergency-lifeguard": "Notfall-Rettungsschwimmer|Rettungsschwimmer",

View File

@@ -2,28 +2,28 @@
"@category_eat": "Where to eat|eat|Food",
"@category_food": "4Groceries|Grocery|Food",
"@category_transport": "5Transport",
"@category_fuel": "2Gas|Gasoline|3Petrol|4Diesel|3Fuel",
"@category_fuel": "2Gas|4Gasoline|3Petrol|4Diesel|3Fuel",
"@category_parking": "4Parking",
"@category_shopping": "4Shopping",
"@category_hotel": "Hotel|hotels",
"@category_shopping": "4Shopping|shops",
"@category_hotel": "3Hotel|hotels|4Accomodations|accommodation|sleep",
"@category_tourism": "3Sights|3Attractions|3Tourism",
"@category_entertainment": "Entertainment",
"@category_nightlife": "Nightlife",
"@category_children": "Family holiday",
"@category_entertainment": "4Entertainment",
"@category_nightlife": "4Nightlife",
"@category_children": "4Family holiday|children|kid|kids|babies|family|family friendly",
"@category_atm": "ATM|Cash machine",
"@category_rv": "2RV Facilities|4Caravan|Vanlife|5Campervan|5Motorhome",
"amenity-atm|@category_atm": "money|U+1F3E7|U+1F4B2|U+1F4B3|U+1F4B4|U+1F4B5|U+1F4B6|U+1F4B7",
"@category_rv": "2RV Facilities|RV|4Caravan|Vanlife|5Campervan|5Motorhome|camper",
"amenity-atm|@category_atm": "money|cash|U+1F3E7|U+1F4B2|U+1F4B3|U+1F4B4|U+1F4B5|U+1F4B6|U+1F4B7",
"@category_bank": "3Bank",
"@category_secondhand": "4Second Hand",
"@category_secondhand": "4Second Hand|second-hand|vintage|5Vintage shop|4Thrift store|5Resale shop|6Opportunity shop|4Used-goods|thrift|thrifting",
"amenity-bank|@category_bank": "money|U+1F3E6|U+1F4B0|U+1F4B2|U+1F4B3|U+1F4B4|U+1F4B5|U+1F4B6|U+1F4B7",
"@category_recycling": "4Recycling|Waste utilization|Waste disposal|Recyclables|Separate garbage collection|Waste sorting|Reuse",
"amenity-bureau_de_change": "3Currency Exchange|3exchange|money|U+1F4B1|U+1F4B2|U+1F4B4|U+1F4B5|U+1F4B6|U+1F4B7",
"amenity-studio": "Media Studio|Studio",
"amenity-studio": "5Media studio|studio",
"amenity-bar|amenity-pub|@category_eat|@category_nightlife": "2Bar|2pub|beer|drink|U+1F37A|U+1F37B|U+1F376|tavern|bars and pubs|brew pub|cocktail lounge",
"amenity-cafe|@category_eat": "3Cafe|U+2615|U+1F356|U+1F357|U+1F35A|U+1F35B|U+1F35C|U+1F35D|U+1F363|U+1F366|U+1F367|U+1F368|U+1F369|U+1F370|U+1F372|U+1F374|U+1F377|U+1F60B|U+1F375|coffee|cafeteria",
"amenity-fast_food|@category_eat": "4Fast Food|takeaway|U+1F354|U+1F355|U+1F35F|U+1F363|U+1F366|U+1F367|U+1F368|U+1F369|U+1F370|U+1F372|U+1F374|food to go|junk food",
"amenity-restaurant|@category_eat": "3Restaurant|U+1F356|U+1F357|U+1F35A|U+1F35B|U+1F35C|U+1F35D|U+1F363|U+1F366|U+1F367|U+1F368|U+1F369|U+1F370|U+1F372|U+1F374|U+1F377|U+1F60B",
"amenity-fuel|@category_fuel": "Gas Station|Petrol Station|3Filling Station|U+26FD",
"amenity-fuel|@category_fuel": "3Gas station|4Petrol station|3Filling station|fill up|U+26FD",
"@shop": "Shop|Store|U+1F3EA|U+1F3EC",
"shop-bakery|shop-pastry|@category_eat|@category_food|@shop": "3Bakery|3Pastry|Cake|3Cakes|U+1F35E",
"shop|@shop": "",
@@ -34,13 +34,13 @@
"shop-farm|@category_food|@shop": "Farm food",
"shop-garden_centre|@shop": "4Garden Centre|U+1F3E1",
"shop-grocery|@category_food|@shop": "Grocery",
"shop-health_food|@category_food|@shop": "Health food",
"shop-hearing_aids|@shop": "Hearing Aids",
"shop-health_food|@category_food|@shop": "7Health food|7Healthy food|healthfood|organic|vegan|vegetarian",
"shop-hearing_aids|@shop": "7Hearing Aids",
"shop-mobile_phone|@shop": "4Cell Phones|4Mobile Phones|6smartphones|electronics store|U+1F4F1|U+1F4F2",
"shop-florist|@shop": "4Florist|U+1F337|U+1F338|U+1F339|U+1F33A|U+1F33B|U+1F33C|U+1F490|U+1F33E|4flowers|flower shop|floral shop|floral arrangements|same day flowers|bouquet",
"shop-butcher|@category_food|@shop": "4Butcher|U+1F356|U+1F357",
"shop-butcher|@category_food|@shop": "4Butcher|meat|U+1F356|U+1F357",
"shop-furniture|@shop": "4Furniture",
"shop-kitchen|@shop": "Kitchen|Kitchen Studio",
"shop-kitchen|@shop": "4Kitchen|Kitchen Studio|kitchenware",
"shop-alcohol|@category_food|@shop": "4liquor|4alcohol|U+1F377",
"shop-books|@shop": "Bookstore|bookshop|3books|U+1F4D6|U+1F4DA|U+1F4D9|U+1F4D8|U+1F4D7|U+1F4D5",
"shop-shoes|@category_shopping|@shop": "Shoe|U+1F461|U+1F460|U+1F462|U+1F45E|U+1F45F|3shoes|4footwear",
@@ -48,95 +48,95 @@
"shop-hardware|shop-doityourself|@shop": "4Hardware|4Home Improvement|DIY|U+1F529|U+1F528|do it yourself|do-it-yourself",
"shop-houseware|@shop": "4Housewares",
"shop-jewelry|@category_shopping|@shop": "4Jewelry|U+1F48D",
"shop-optician|@shop": "4Optician|U+1F453",
"shop-gift|@category_shopping|@shop": "Gift|U+1F381|souvenir|4souvenirs|3gifts|presents",
"shop-beauty": "4Beauty Shop|barber|beautician|hairdresser|hairdressing|haircut|U+1F484|beauty salon|hair salon|beauty parlor|hair and nail salon|nail salon|coloring",
"shop-optician|@shop": "4Optician|glasses|sunglasses|U+1F453",
"shop-gift|@category_shopping|@shop": "Gift|U+1F381|souvenir|souvenirs|3gifts|presents|4Souvenir shop|gift shop|giftshop",
"shop-beauty": "4Beauty Shop|beautician|U+1F484|beauty salon|beauty parlor|nail salon|coloring",
"shop-greengrocer|@category_food|@shop": "4Greengrocer|U+1F345|U+1F346|U+1F33D|U+1F360|U+1F348|U+1F347|U+1F349|U+1F34A|U+1F34C|U+1F34D|U+1F34E|U+1F34F|U+1F350|U+1F351|U+1F353",
"shop-sports|@category_shopping|@shop": "4Sports Goods|U+1F3BF|U+1F3A3|U+1F3C2|U+1F6B4|U+26BD|U+1F3C0|U+1F3C8|U+26BE|U+1F3BE|U+1F3C9|U+26F3",
"shop-supermarket|@category_food|@shop": "3Supermarket",
"shop-mall|@category_shopping|@shop": "Mall|Gallery|shopping arcade|entertainment center|retail",
"shop-department_store|@category_shopping|@shop": "4Department",
"shop-mall|@category_shopping|@shop": "3Mall|Gallery|shopping arcade|entertainment center|retail",
"shop-department_store|@category_shopping|@shop": "4Department|department store",
"shop-beverages|@category_food|@shop": "4Beverages|4drinks|U+1F379",
"shop-computer|@shop": "4Computer|U+1F4BB",
"shop-computer|@shop": "4Computer shop|computer|computers|U+1F4BB",
"shop-confectionery|craft-confectionery|@category_food|@shop": "4Sweets|4confectionery|candies|candy|U+1F36C|U+1F36D|sweetshop|tuck|Confectioner",
"shop-laundry": "4Laundry|Laundrette|laundromat",
"shop-toys|@category_children|@shop": "Toy|toyshop|kids|toys|kids toys",
"amenity-marketplace|@category_food": "3Marketplace|market",
"amenity-mobile_money_agent": "Mobile Money Agent|mobile money",
"amenity-money_transfer": "Money Transfer",
"shop-clothes|@category_shopping|@shop": "3Clothes|U+1F45A|U+1F457|U+1F456|U+1F455|clothing|wear",
"shop-caravan|@category_rv|@shop": "2RV dealership|4Caravan dealership|Motorhome dealership",
"shop-car|@shop": "3Car Dealership|Auto Dealer|U+1F697|U+1F698|U+1F699",
"shop-bicycle|@shop": "4Bicycle|Bike|cycles|bikes|U+1F6B2|U+1F6B4|U+1F6B5",
"amenity-mobile_money_agent": "6Mobile Money Agent|mobile money",
"amenity-money_transfer": "5Money Transfer",
"shop-clothes|@category_shopping|@shop": "3Clothes|U+1F45A|U+1F457|U+1F456|U+1F455|clothing|apparel|wear|fashion|garments ",
"shop-caravan|@category_rv|@shop": "2RV dealership|4Caravan dealership|5Motorhome dealership",
"shop-car|@shop": "3Car Dealership|4Auto Dealer|U+1F697|U+1F698|U+1F699",
"shop-bicycle|@shop": "4Bicycle|Bike|7Cycling shop|cycles|bikes|U+1F6B2|U+1F6B4|U+1F6B5",
"shop-kiosk": "3Kiosk|U+1F4F0",
"highway-bus_stop|@category_transport": "2Bus Stop|bus|stop|U+1F68C|U+1F68F|U+1F68E|U+1F690",
"railway-tram_stop|@category_transport": "3Tram Stop|tram|stop|U+1F683",
"amenity-bus_station|@category_transport": "2Bus Station|bus|U+1F68C|U+1F68F|U+1F68D",
"railway-station|railway-halt|building-train_station|@category_transport": "3Train Station|trainstation|4railway|railroad|4station|U+1F684|U+1F685|U+1F689|U+1F682|U+1F686|U+1F688|U+1F68A|U+1F68B|Rail Halt",
"railway-station-funicular": "Funicular",
"railway-station-subway|@category_transport": "3Subway Station|3tube|3metro|3underground|U+1F687",
"railway-station-funicular": "4Funicular",
"railway-station-subway|@category_transport": "3Subway Station|subway|3tube|3metro|3underground|U+1F687",
"amenity-ferry_terminal|@category_transport": "3Ferry|terminal|U+1F6A2|U+1F6A4|U+2693",
"amenity-taxi|@category_transport": "3Taxi|Taxi Stand|Taxi Rank|U+1F695|U+1F696",
"amenity-taxi|@category_transport": "Taxi|3Taxi Stand|Taxi Rank|U+1F695|U+1F696",
"amenity-townhall": "3Town Hall|townhall|city hall|guildhall|village hall|4municipal hall|civic centre",
"tourism-attraction|@category_tourism": "4Attraction|U+1F3A0|U+1F3A1|U+1F3A2|U+1F3AA",
"tourism-artwork": "3Artwork|U+1F3A8",
"tourism-viewpoint|@category_tourism": "4Viewpoint|Vista",
"tourism-information": "4Tourist Information|4information|U+1F481",
"tourism-picnic_site|amenity-bbq|leisure-picnic_table": "3Picnic Site|Barbecue Grill|Picnic Table",
"amenity-place_of_worship": "Place of Worship|3temple|U+1F64F",
"amenity-place_of_worship-christian": "4Church|place of worship|temple|4cathedral|basilica|U+1F64F|U+26EA|U+271D|U+2626",
"amenity-place_of_worship-muslim": "4Mosque|tekke|place of worship|temple|U+1F64F|U+262A|U+1F54B|U+1F54C|U+262A",
"amenity-place_of_worship-buddhist": "3Temple|place of worship|U+1F64F|U+26EA|U+2638",
"amenity-place_of_worship-hindu": "3Temple|place of worship|U+1F64F|U+1F549",
"amenity-place_of_worship-shinto": "Shrine|place of worship|3temple|U+1F64F|U+26E9",
"amenity-place_of_worship-jewish": "4Synagogue|place of worship|temple|U+1F64F|U+1F54D|U+2721",
"amenity-place_of_worship-taoist": "3Temple|place of worship|U+1F64F|U+262F",
"tourism-picnic_site|amenity-bbq|leisure-picnic_table": "3Picnic Site|picnic|Barbecue Grill|Picnic Table|bbq|Barbec",
"amenity-place_of_worship": "5Place of Worship|3temple|U+1F64F",
"amenity-place_of_worship-christian": "4Church|place of worship|temple|4cathedral|basilica|christianity|U+1F64F|U+26EA|U+271D|U+2626",
"amenity-place_of_worship-muslim": "4Mosque|tekke|place of worship|temple|islam|U+1F64F|U+262A|U+1F54B|U+1F54C|U+262A",
"amenity-place_of_worship-buddhist": "3Temple|place of worship|4buddist temple|4buddhism|U+1F64F|U+26EA|U+2638",
"amenity-place_of_worship-hindu": "3Temple|place of worship|4hindu temple|4hinduism|U+1F64F|U+1F549",
"amenity-place_of_worship-shinto": "Shrine|place of worship|3temple|4shinto temple|4shinto|U+1F64F|U+26E9",
"amenity-place_of_worship-jewish": "4Synagogue|place of worship|3temple|judaism|U+1F64F|U+1F54D|U+2721",
"amenity-place_of_worship-taoist": "3Temple|place of worship|4taoism|4taoist temple|U+1F64F|U+262F",
"tourism-museum|@category_tourism": "2Museum|U+1F3A8|3exhibition|3gallery",
"waterway-waterfall|@category_tourism": "2Waterfall",
"historic-archaeological_site|@category_tourism": "4Archaeological Site",
"historic-battlefield": "Battlefield",
"historic-stone": "Historic Stone",
"historic-boundary_stone": "Boundary Stone",
"historic-stone": "Historic stone",
"historic-boundary_stone": "Boundary stone",
"historic-castle|@category_tourism": "4Castle|4Palace|4Fortress|U+1F3EF|U+1F3F0|U+1F451|U+1F478|Hillfort|Kremlin|Manor house",
"historic-city_gate|@category_tourism": "City gate",
"historic-citywalls|@category_tourism": "City Wall",
"historic-city_gate|@category_tourism": "4City gate",
"historic-citywalls|@category_tourism": "4City wall",
"historic-fort|@category_tourism": "Fort",
"historic-gallows|@category_tourism": "Gallows",
"historic-memorial|@category_tourism": "4Memorial|monument|U+1F5FC|U+1F5FD|U+1F5FF",
"historic-memorial-cross": "Memorial cross",
"historic-memorial-plaque": "Commemorative plaque",
"historic-memorial-sculpture|@category_tourism": "Sculpture",
"historic-memorial-statue|@category_tourism": "Statue",
"historic-memorial-sculpture|@category_tourism": "5Sculpture",
"historic-memorial-statue|@category_tourism": "3Statue",
"historic-memorial-stolperstein": "Stolperstein",
"historic-memorial-war_memorial|@category_tourism": "War memorial",
"historic-monument|@category_tourism": "4Monument|U+1F5FD|U+1F5FF",
"historic-pillory|@category_tourism": "Pillory",
"historic-cannon": "Cannon",
"historic-anchor": "Historic Anchor",
"historic-ruins|@category_tourism": "4Historic Ruins|3Ruins|U+1F5FF",
"historic-mine": "Historic Mine",
"historic-anchor": "4Historic anchor",
"historic-ruins|@category_tourism": "4Historic ruins|3Ruins|U+1F5FF",
"historic-mine": "4Historic mine",
"historic-ship|@category_tourism": "Ship|boat",
"historic-wreck": "Shipwreck",
"historic-locomotive|@category_tourism": "Historic Locomotive",
"historic-tank|@category_tourism": "Historic Tank",
"historic-aircraft|@category_tourism": "Historic Aircraft",
"historic-locomotive|@category_tourism": "4Historic locomotive",
"historic-tank|@category_tourism": "4Historic tank",
"historic-aircraft|@category_tourism": "4Historic aircraft",
"historic-tomb|@category_tourism": "Tomb|grave|memorial",
"man_made-cross": "Cross",
"historic-wayside_cross": "Wayside cross",
"historic-wayside_shrine": "Wayside shrine",
"leisure-dog_park": "3Dog area|Dog park",
"leisure-dog_park": "Dog area|3Dog park",
"leisure-dance|@category_entertainment": "4Dance|Dancing school",
"leisure-garden": "3Garden",
"leisure-firepit": "5Firepit",
"amenity-bench|amenity-bench-backless": "Bench",
"amenity-boat_rental": "4Boat Rental|boat|3rental",
"amenity-bicycle_rental": "4Bicycle Rental|cycle|bike|3rental|U+1F6B2|U+1F6B4|U+1F6B5|bicycle hire|bike rental",
"amenity-bicycle_repair_station": "4Bicycle Repair Station|cycle|bike|4repair of bicycles",
"amenity-car_sharing": "Car Share|3carsharing|car|sharing|U+1F697|U+1F698|U+1F699|carpool|carsharing services|car sharing|4rideshare",
"amenity-car_rental": "3Car Rental|car|rental|U+1F697|U+1F698|U+1F699|car hire|rent a car|auto rental|vehicle rent",
"amenity-motorcycle_rental": "4Motorcycle Rental|bike|hire|4scooter",
"amenity-cinema|@category_entertainment": "3Cinema|3Movie Theatre|Film|Movies|U+1F3A6|U+1F3AC",
"leisure-bowling_alley|@category_entertainment": "4Bowling Alley",
"amenity-boat_rental": "4Boat rental|boat|boats|3Rental",
"amenity-bicycle_rental": "4Bicycle rental|cycling|cycle|bike|3Rental|U+1F6B2|U+1F6B4|U+1F6B5|bicycle hire|bike rental",
"amenity-bicycle_repair_station": "4Bicycle repair station|cycle|bike|4repair of bicycles",
"amenity-car_sharing": "Car Share|3carsharing|car|sharing|U+1F697|U+1F698|U+1F699|carsharing services|car sharing|4rideshare",
"amenity-car_rental": "3Car rental|car|rental|U+1F697|U+1F698|U+1F699|car hire|rent a car|auto rental|vehicle rent",
"amenity-motorcycle_rental": "4Motorcycle rental|bike|hire|4scooter|4Rental motorcycles|motorcycles",
"amenity-cinema|@category_entertainment": "3Cinema|3Movie theatre|Film|4Movies|U+1F3A6|U+1F3AC",
"leisure-bowling_alley|@category_entertainment": "4Bowling alley",
"amenity-theatre|@category_entertainment": "4Theatre|U+1F3AD",
"amenity-nightclub|@category_entertainment|@category_nightlife": "3Nightclub|night club|4disco|dance|U+1F378|U+1F379|U+1F46F|U+1F483|club|nightspot|night bar",
"amenity-brothel": "Brothel|whorehouse|bordello|U+1F3E9",
@@ -166,10 +166,10 @@
"healthcare-psychotherapist": "Psychotherapist",
"healthcare-sample_collection": "Sample collection",
"healthcare-speech_therapist": "Logopedics|Speech therapist|Speech therapy",
"amenity-hunting_stand": "Hunting Stand",
"amenity-hunting_stand": "4Hunting stand",
"amenity-kindergarten": "5Kindergarten|U+1F476|U+1F37C|U+1F6BC|nursery|4Child Care|childcare",
"amenity-library": "3Library|U+1F4D6",
"amenity-parking|amenity-parking_entrance|@category_parking": "U+1F697|U+1F17F|U+1F698|U+1F699",
"amenity-library": "3Library|3books|book|U+1F4D6",
"amenity-parking|amenity-parking_entrance|@category_parking": "car parking|U+1F697|U+1F17F|U+1F698|U+1F699",
"@category_pharmacy": "3Pharmacy",
"amenity-pharmacy|@category_pharmacy": "4Drugstore|apothecary|4dispensary|U+1F489|U+1F48A",
"@category_post": "3Post",
@@ -192,15 +192,15 @@
"recycling-shoes|@category_recycling": "4Recycling of Shoes|Shoes Recycling|Donate Shoes|Shoes",
"recycling-green_waste|@category_recycling": "4Recycling of Green Waste|5Organic Waste Recycling|5Green Waste Recycling|Food Waste|Garden Waste",
"recycling-cartons|@category_recycling": "4Recycling of Bewerage Cartons|5Cartons Recycling|5Bewerage Cartons Recycling|Cartons",
"amenity-sanitary_dump_station|@category_rv": "2RV Dump Station|5Holding Tank Dump Station|4Dump Station|sanitary dump station|sewage|RV waste|5motorhome dump station|5camper dump station|4caravan dump station",
"amenity-sanitary_dump_station|@category_rv": "2RV Dump Station|5Holding Tank Dump Station|4Dump station|sanitary dump station|sewage|RV waste|5motorhome dump station|5camper dump station|4caravan dump station",
"amenity-school": "3School|U+1F392|U+1F3EB",
"amenity-shelter": "4Shelter|refuge",
"amenity-shelter-basic_hut": "3Bivouac Hut|Bivvy|Bothy|Hut",
"amenity-shelter-lean_to": "3Lean-to Shelter|4Shelter|Refuge",
"amenity-stripclub": "Stripclub",
"amenity-shelter-basic_hut": "basic hut|3Bivouac Hut|Bivvy|Bothy|Hut",
"amenity-shelter-lean_to": "3Lean-to Shelter|4Shelter|Refuge|lean shelter|shelter",
"amenity-stripclub": "Stripclub|strip club",
"amenity-telephone": "2Phone|U+260E|U+1F4DE|5Telephone",
"@category_toilet": "3Toilet",
"amenity-toilets|toilets-yes|@category_toilet": "wc|5restroom|4bathroom|loo|lavatory|U+1F6BD|U+1F6BE|U+1F4A9|U+1F6BB|U+1F6B9|U+1F6BA",
"@category_toilet": "3Toilet|toilets|4Restroom|potty|WC|water closet",
"amenity-toilets|toilets-yes|@category_toilet": "wc|4Bathroom|loo|lavatory|U+1F6BD|U+1F6BE|U+1F4A9|U+1F6BB|U+1F6B9|U+1F6BA",
"amenity-university": "4University|U+1F393|Uni",
"place-continent": "Continent|U+1F30D|U+1F30E|U+1F30F",
"place-country": "Country",
@@ -212,8 +212,8 @@
"place-region": "Region",
"place-island|place-islet": "Island|islet",
"place-suburb|place-quarter|place-neighbourhood|landuse-residential": "Suburb|district|quarter|neighbourhood|neighborhood|Residential Area",
"place-hamlet": "Hamlet|village",
"place-village": "Village|hamlet",
"place-hamlet": "Hamlet|village|settlement|civilization",
"place-village": "Village|hamlet|settlement|civilization",
"place-locality": "Locality",
"place-farm": "Farm|U+1F411|U+1F414|U+1F417|U+1F42E|U+1F404|U+1F430|U+1F407|U+1F40F|U+1F410|U+1F413|U+1F424|U+1F437|U+1F43D|U+1F69C",
"highway-raceway": "Racetrack|U+1F3C1",
@@ -233,18 +233,18 @@
"tourism-guest_house|@category_hotel": "4Guest House|hostel|U+1F3E8",
"tourism-motel|@category_hotel": "3Motel|hostel|U+1F3E8",
"tourism-alpine_hut|@category_hotel": "5Mountain Lodge|5backcountry hut|hut|lodge|alpine hut",
"shop-hairdresser": "3Hairdresser|U+2702|U+1F488|hair salon|hairdressing saloon|barbershop|hair cuttery|haircut|beauty parlor|coloring",
"aeroway-aerodrome": "3Airport|3plane|U+2708",
"leisure-stadium": "4Stadium|4sport|U+26BD|U+26BE|U+1F3BE|U+1F3C0|U+1F3C8|U+1F4AA|U+1F3C9|olympic stadium|sports stadium|sports complex|arena",
"shop-hairdresser": "3Hairdresser|U+2702|U+1F488|hair salon|hairdressing saloon|4barbershop|barber|hair cuttery|haircut|beauty parlor|coloring",
"aeroway-aerodrome": "4Aerodrome|3Airport|3plane|U+2708",
"leisure-stadium": "4Stadium|4sport|U+26BD|U+26BE|U+1F3BE|U+1F3C0|U+1F3C8|U+1F4AA|U+1F3C9|olympic stadium|sports stadium|sports complex|arena|sports arena",
"leisure-playground|@category_children": "4Playground",
"leisure-sports_centre|leisure-sports_centre-sport-american_football|leisure-sports_centre-sport-archery|leisure-sports_centre-sport-athletics|leisure-sports_centre-sport-australian_football|leisure-sports_centre-sport-badminton|leisure-sports_centre-sport-baseball|leisure-sports_centre-sport-basketball|leisure-sports_centre-sport-beachvolleyball|leisure-sports_centre-sport-bowls|leisure-sports_centre-sport-climbing|leisure-sports_centre-sport-cricket|leisure-sports_centre-sport-curling|leisure-sports_centre-sport-equestrian|leisure-sports_centre-sport-field_hockey|leisure-sports_centre-sport-futsal|leisure-sports_centre-sport-golf|leisure-sports_centre-sport-gymnastics|leisure-sports_centre-sport-handball|leisure-sports_centre-sport-ice_hockey|leisure-sports_centre-sport-multi|leisure-sports_centre-sport-padel|leisure-sports_centre-sport-pelota|leisure-sports_centre-sport-scuba_diving|leisure-sports_centre-sport-shooting|leisure-sports_centre-sport-skateboard|leisure-sports_centre-sport-skiing|leisure-sports_centre-sport-soccer|leisure-sports_centre-sport-table_tennis|leisure-sports_centre-sport-tennis|leisure-sports_centre-sport-volleyball|leisure-sports_centre-sport-yoga": "4Sports Center|sport|U+26BD|U+26BE|U+1F3BE|U+1F4AA|U+1F3C8|U+1F3C0|U+1F3C9|sports complex|sports forum",
"leisure-sports_centre|leisure-sports_centre-sport-american_football|leisure-sports_centre-sport-archery|leisure-sports_centre-sport-athletics|leisure-sports_centre-sport-australian_football|leisure-sports_centre-sport-badminton|leisure-sports_centre-sport-baseball|leisure-sports_centre-sport-basketball|leisure-sports_centre-sport-beachvolleyball|leisure-sports_centre-sport-bowls|leisure-sports_centre-sport-climbing|leisure-sports_centre-sport-cricket|leisure-sports_centre-sport-curling|leisure-sports_centre-sport-equestrian|leisure-sports_centre-sport-field_hockey|leisure-sports_centre-sport-futsal|leisure-sports_centre-sport-golf|leisure-sports_centre-sport-gymnastics|leisure-sports_centre-sport-handball|leisure-sports_centre-sport-ice_hockey|leisure-sports_centre-sport-multi|leisure-sports_centre-sport-padel|leisure-sports_centre-sport-pelota|leisure-sports_centre-sport-scuba_diving|leisure-sports_centre-sport-shooting|leisure-sports_centre-sport-skateboard|leisure-sports_centre-sport-skiing|leisure-sports_centre-sport-soccer|leisure-sports_centre-sport-table_tennis|leisure-sports_centre-sport-tennis|leisure-sports_centre-sport-volleyball|leisure-sports_centre-sport-yoga": "4Sports Center|sport|sports|U+26BD|U+26BE|U+1F3BE|U+1F4AA|U+1F3C8|U+1F3C0|U+1F3C9|sports complex|sports forum",
"leisure-sports_centre-sport-swimming": "4Swimmming Centre",
"leisure-golf_course": "Golf Course|U+26F3",
"leisure-golf_course": "4Golf Course|golf|U+26F3",
"leisure-miniature_golf": "4Minigolf|Miniature Golf|Putt Putt|mini golf|mini-golf",
"leisure-escape_game": "4Escape Room|Escape Game|quest",
"leisure-hackerspace": "Hackerspace",
"leisure-pitch": "4Sports Ground|sport|U+26BD|U+26BE|U+1F3BE|U+1F3C0|U+1F3C8|U+1F3C9|U+1F3C3",
"leisure-swimming_pool": "4Swimming Pool|sport|U+1F3CA",
"leisure-hackerspace": "6Hackerspace|hacker space|hacklab|hackspace|5makerspace",
"leisure-pitch": "4Sports Ground|sport|sports|U+26BD|U+26BE|U+1F3BE|U+1F3C0|U+1F3C8|U+1F3C9|U+1F3C3",
"leisure-swimming_pool": "4Swimming Pool|sport|sports|U+1F3CA",
"leisure-swimming_pool-private": "DoNotMatchThisType_OneLanguageDefinitionIsEnoughHere",
"sport-american_football": "American Football",
"sport-archery": "Archery",
@@ -276,16 +276,16 @@
"building": "Building|U+1F3E0|U+1F3E1|U+1F3E2",
"building-address": "Address",
"@category_police": "4Police|cops",
"amenity-police|@category_police": "U+1F693|U+1F46E|U+1F694|U+1F482|U+1F6A8",
"office-diplomatic": "4Embassy",
"amenity-police|@category_police": "Police station|U+1F693|U+1F46E|U+1F694|U+1F482|U+1F6A8",
"office-diplomatic": "4Embassy|5Consulate",
"natural-bay": "Bay",
"@category_water": "3Water|water source",
"amenity-drinking_water|drinking_water-yes|@category_water": "4Drinking Water|3Potable Water|U+1F6B0",
"natural-hot_spring|@category_water": "3Hot Spring",
"natural-spring|@category_water": "3Spring|4Natural Spring",
"man_made-water_well|@category_water": "Water Well",
"amenity-water_point|@category_water|@category_rv": "Water Tank Refill Point|2RV Water Point|water for rv|water for campervan|water for caravan",
"man_made-water_tap|@category_water": "Water Tap",
"amenity-water_point|@category_water|@category_rv": "5Water tank refill point|2RV water roint|water for rv|water for campervan|water for caravan",
"man_made-water_tap|@category_water": "5Water tap",
"@waterbody": "Water body|water surface",
"natural-water|@waterbody": "",
"natural-water-basin|landuse-basin|@waterbody": "Basin",
@@ -294,18 +294,18 @@
"natural-water-reservoir|landuse-reservoir|@waterbody": "5Reservoir",
"waterway-river|waterway-stream|natural-water-river": "River|stream|creek|brook",
"waterway-canal": "Canal",
"shop-car_repair": "3Car Repair Workshop|4service station|auto|garage|4mechanic|U+1F527",
"tourism-camp_site|@category_hotel": "4Camping|campsite|campground|4tent spot|U+26FA",
"shop-car_repair": "3Car Repair Workshop|4service station|auto|garage|4mechanic|4Repair car|U+1F527",
"tourism-camp_site|@category_hotel": "4Camping|campsite|campground|4Tent spot|U+26FA",
"tourism-caravan_site|@category_rv||@category_hotel": "2RV Park|4Caravan Site|RV site|U+1F69A|U+26FA|U+1F69B",
"office": "Office|company|U+1F454|U+1F4BC|U+1F3E2|bureau|administrative office|firm|business|corporation",
"office-company": "Company Office",
"office-government": "Government Office",
"office-lawyer": "3Lawyer|advocate|attorney|4barrister|counsel|councellor|4solicitor",
"office-telecommunication": "Telecom Company|telecommunications",
"office-government": "6Government office",
"office-lawyer": "3Lawyer|advocate|attorney|4Barrister|counsel|councellor|4Solicitor",
"office-telecommunication": "Telecom Company|6Telecommunication office",
"craft-beekeeper": "Beekeeper",
"craft-blacksmith": "Blacksmith",
"craft-brewery": "Craft brewery|4Brewery|brew house|beer|beer bar|craft beer",
"craft-caterer": "Caterer",
"craft-caterer": "4Caterer",
"craft-carpenter": "4Carpenter",
"craft-confectionery": "Confectionery|Confectioner",
"craft-electrician": "4Electrician",
@@ -313,69 +313,69 @@
"craft-gardener": "Gardener",
"craft-grinding_mill": "Grinding Mill|Mill",
"craft-handicraft": "Handicraft",
"craft-hvac": "HVAC",
"craft-hvac": "3HVAC|AC|aircon|heating|air conditioner|ventilation|climate|climatization",
"craft-metal_construction": "5Metal Worker",
"craft-key_cutter": "4Key Cutting|Key Duplication|Key Copying",
"craft-key_cutter": "4Key cutting|Key duplication|Key copying",
"craft-locksmith": "Locksmith",
"craft-painter": "House Painter|painter|decorator",
"craft-photographer": "4Photographer|photography Studio",
"craft-plumber": "Plumber",
"craft-plumber": "4Plumber",
"craft-sawmill": "Sawmill",
"craft-shoemaker": "4Shoe Repair|shoe maker",
"craft-winery": "4Winery|Wine",
"craft-winery": "Winery|Wine",
"craft-tailor": "4Tailor|clothes alteration|alterations",
"area:highway-footway|area:highway-pedestrian|area:highway-steps|place-square": "Square",
"place-sea": "Sea|U+1F30A",
"place-ocean": "Ocean|U+1F30A",
"@category_wifi": "WiFi|Wi-Fi",
"@category_wifi": "WiFi|Wi-Fi|WLAN",
"internet_access|internet_access-wlan|@category_wifi": "3Internet|U+1F4F6",
"natural-beach|natural-beach-sand|natural-beach-gravel|leisure-beach_resort": "Beach|U+1F459",
"man_made-lighthouse": "Lighthouse",
"man_made-lighthouse": "5Lighthouse",
"man_made-survey_point": "4Survey Point|survey marker|survey benchmark|4geodetic mark|geodetic vertex|4triangulation station|4trigonometrical point|trig point|trig pillar|4trig station|trig beacon|trig",
"man_made-flagpole": "Flagpole",
"man_made-flagpole": "4Flagpole",
"man_made-mast": "Mast|pole",
"man_made-communications_tower|man_made-tower-communication": "Communications Tower|cell tower|cellular tower|mast",
"man_made-petroleum_well": "Petroleum Well|Oil Well|Boring",
"man_made-petroleum_well": "7Petroleum Well|Oil Well|Boring",
"organic-only|organic-yes": "4organic|bio|biological|eco|ecological|healthy",
"shop-copyshop": "4Copyshop|copy shop|4printing|4photocopy",
"shop-photo|@shop": "4Photo|frames",
"shop-camera|@shop": "3Camera",
"shop-camera|@shop": "3Camera|cameras|photography",
"shop-travel_agency": "4Travel Agency|tours|4tour agency|trips|journeys|travel bureau|holidays|travel agent|tourist office|last minute tour",
"shop-outdoor|@shop": "4Outdoor Equipment|trekking|hiking|climbing|camping",
"shop-dry_cleaning": "3Dry Cleaner|cleaning",
"shop-tyres|@shop": "3Tyre|tyres",
"shop-tyres|@shop": "3Tyre|tyres|tyre shop|3Tires|tire|tire shop",
"amenity-car_wash": "3Car Wash",
"man_made-telescope|man_made-telescope-optical|man_made-telescope-radio|man_made-telescope-gamma": "5Telescope",
"man_made-telescope|man_made-telescope-optical|man_made-telescope-radio|man_made-telescope-gamma": "4Telescope",
"man_made-observatory": "4Observatory",
"amenity-veterinary": "Veterinary Doctor|4veterinary",
"amenity-animal_shelter": "Animal Shelter",
"amenity-veterinary": "4Veterinary Doctor|3Veterinary|vet|veterinarian",
"amenity-animal_shelter": "6Animal Shelter",
"@charging_station": "4Charging Station|charging",
"amenity-charging_station|@charging_station": "",
"amenity-charging_station-bicycle|@charging_station": "4Bicycle Charging|4Bike Charging",
"amenity-charging_station-motorcar|amenity-charging_station-motorcar-small|@charging_station": "4Motorcar Charging|3Car Charging|Charger",
"amenity-childcare": "Nursery|4Child Care|childcare",
"amenity-bicycle_parking": "4Bicycle Parking|4Bike Parking",
"amenity-waste_basket": "4Trash Bin|4litter bin|waste basket",
"amenity-waste_basket": "4Trash Bin|4litter bin|5waste basket|bin",
"emergency-phone": "4Emergency Phone",
"leisure-fitness_centre": "3Fitness Centre|gym|U+1F4AA|fitness|workout|fitness gym|fitness club|health club|fitness studio|workout studio",
"leisure-fitness_centre": "3Fitness Centre|gym|U+1F4AA|fitness|workout|fitness gym|fitness club|health club|fitness studio|workout studio|sport|sports",
"leisure-sauna": "3Sauna|sweatbath|sweat lodge|steam room|steam sauna|sauna room",
"shop-car_repair-tyres|shop-car_repair": "3Tyre Repair|tyres|4puncture repair|tyre puncture repair|flat tyre repair|tyre replacement",
"shop-chemist|@shop": "4Chemist|Pharmacist",
"shop-pet|@shop": "3Pet",
"tourism-zoo|@category_tourism|@category_children": "2Zoo",
"attraction-animal": "Animal Enclosure",
"tourism-information-office|amenity-ranger_station|@category_tourism": "4Tourist Office",
"tourism-information-visitor_centre|amenity-ranger_station|@category_tourism": "3Visitor Centre",
"amenity-community_centre": "4Community Centre",
"amenity-compressed_air": "Compressed Air",
"tourism-information-office|amenity-ranger_station|@category_tourism": "4Tourism office|6Ranger station",
"tourism-information-visitor_centre|amenity-ranger_station|@category_tourism": "3Visitor centre|6Ranger station",
"amenity-community_centre": "4Community centre",
"amenity-compressed_air": "6Compressed air",
"amenity-courthouse": "4Courthouse",
"amenity-vending_machine-cigarettes": "4Cigarette Dispenser",
"amenity-vending_machine-coffee": "4Coffee Dispenser|Coffee",
"amenity-vending_machine-condoms": "4Condoms Dispenser|Condoms|Condomat",
"amenity-vending_machine-drinks": "4Drinks Dispenser|4Beverages",
"amenity-vending_machine-food|@category_food": "4Food Dispenser|Food|Snacks",
"amenity-vending_machine-parking_tickets|@category_parking": "4Parking Tickets|3Pay and Display|Parkomat|Parking Meter",
"amenity-vending_machine-public_transport_tickets|@category_transport": "Ticket Machine|Transport Tickets|Tickets",
"amenity-vending_machine-cigarettes": "4Cigarette dispenser",
"amenity-vending_machine-coffee": "4Coffee dispenser|Coffee",
"amenity-vending_machine-condoms": "4Condoms dispenser|Condoms|Condomat",
"amenity-vending_machine-drinks": "4Drinks dispenser|4Beverages",
"amenity-vending_machine-food|@category_food": "4Food dispenser|Food|Snacks",
"amenity-vending_machine-parking_tickets|@category_parking": "4Parking tickets|3Pay and Display|Parkomat|Parking Meter",
"amenity-vending_machine-public_transport_tickets|@category_transport": "6Ticket machine|Transport Tickets|Tickets|4Fare machine|Bus tickets|Train tickets|Ticketing",
"amenity-vending_machine-newspapers": "4Newspaper Dispenser|Newspapers",
"amenity-vending_machine-sweets": "4Sweets Dispenser|Sweets|4Candies|Lollies",
"amenity-vending_machine-excrement_bags": "5Excrement Bags Dispenser|4Poop Bags|3Dog Poop Bags|Animal Waste",
@@ -383,59 +383,62 @@
"shop-outpost": "4Pickup Point|4Parcel Pickup",
"amenity-vending_machine-fuel|@category_fuel": "Fuel Dispenser|Gas Pump",
"building-garage": "Garage",
"highway-rest_area|highway-services": "4Rest Area|4Service Area|station",
"highway-rest_area|highway-services": "4Rest area|4Service area|station",
"man_made-chimney": "Chimney",
"man_made-crane": "Crane",
"man_made-tower|man_made-flare": "Tower",
"shop-bookmaker|@gambling": "Bookmaker",
"shop-bookmaker|@gambling": "4Bookmaker",
"shop-seafood|@category_food|@shop": "4Fishmonger|4Seafood|fish market|fish|shellfish|marine",
"shop-second_hand|@category_shopping|@shop|@category_secondhand": "Thrift|Flea market",
"shop-charity|@shop|@category_secondhand": "4Charity",
"shop-ticket": "4Ticket Shop|tickets|booking",
"shop-wine|@category_food|@shop": "4Wine|Winery",
"shop-second_hand|@category_shopping|@shop|@category_secondhand": "Thrift|4Thrift store|Flea market",
"shop-charity|@shop|@category_secondhand": "4Charity|charity shop",
"shop-ticket": "4Ticket Shop|tickets|ticket|booking",
"shop-wine|@category_food|@shop": "Wine|Winery",
"shop-car_parts|@shop": "3Car Parts|4Auto Parts",
"tourism-chalet|@category_hotel": "5Holiday Cottage|5vacation home",
"tourism-chalet|@category_hotel": "5Holiday Cottage|5vacation home|4Chalet",
"tourism-information-board": "Information Board",
"tourism-information-map": "Tourist Map",
"aerialway-station": "Aerialway Station|Cable Car Station",
"aeroway-helipad": "Helipad",
"tourism-information-map": "Tourist map|map|4Information",
"aerialway-station": "Aerialway Station|5Cable car station",
"aeroway-helipad": "4Helipad",
"barrier-border_control": "4Border Control",
"leisure-water_park|@category_tourism|@category_children": "Water Park|3aqua park",
"man_made-water_tower": "Water Tower",
"man_made-windmill": "Windmill",
"man_made-windmill": "4Windmill",
"natural-cave_entrance": "Cave",
"natural-volcano|@mountain": "4Volcano",
"office-estate_agent": "4Estate Agent|Realtor|4Real Estate",
"waterway-lock_gate": "Lock Gate",
"amenity-public_bookcase": "4Book Exchange|Book swap",
"sport-climbing": "4Climbing Centre",
"amenity-public_bookcase": "4Book Exchange|Book swap|book|books|public bookcase|bookcase|free library|street library|sidewalk library",
"sport-climbing": "4Climbing Centre|climbing",
"sport-yoga": "Yoga",
"leisure-fitness_centre-sport-yoga": "Yoga Studio",
"tourism-apartment|@category_hotel": "4Holiday Apartment",
"leisure-resort|@category_hotel": "Resort",
"amenity-biergarten|@category_eat|@category_nightlife": "5Biergarten",
"amenity-driving_school": "4Driving School",
"amenity-music_school": "Music School",
"amenity-language_school": "Language School",
"amenity-ice_cream": "3Ice Cream|Gelato",
"amenity-internet_cafe": "3Internet Cafe",
"amenity-driving_school": "4Driving school",
"amenity-music_school": "4Music school",
"amenity-language_school": "4Language school",
"amenity-ice_cream": "3Ice cream|Gelato",
"amenity-internet_cafe": "3Internet Cafe|5Cybercafé",
"amenity-motorcycle_parking": "4Motorcycle Parking",
"amenity-parking_space-disabled|@category_parking": "Disabled Parking Space",
"amenity-car_pooling|@category_parking": "Car Pooling",
"amenity-parking_space-disabled|@category_parking": "4Disabled parking space",
"amenity-car_pooling|@category_parking": "4Carpooling|car pooling",
"amenity-nursing_home": "4Nursing Home",
"amenity-payment_terminal": "Payment Terminal",
"amenity-payment_centre": "Payment Centre",
"amenity-public_bath": "Public Bath",
"amenity-payment_terminal": "3Payment Terminal",
"amenity-payment_centre": "3Payment Centre",
"amenity-public_bath": "6Public bath",
"amenity-shower": "Shower",
"emergency-assembly_point": "Emergency Assembly Point",
"emergency-access_point": "5Emergency Rescue Point|Emergency Location|Emergency Marker|Emergency Access Point",
"emergency-assembly_point": "5Emergency assembly point",
"emergency-life_ring": "5Lifebuoy|6Life Ring|life-ring|lifering|flotation device|floatation device",
"emergency-defibrillator": "4Defibrillator|AED",
"emergency-fire_hydrant": "4Fire Hydrant|Fire Plug",
"emergency-lifeguard": "Lifeguard|Lifesaver",
"emergency-mountain_rescue": "Mountain Rescue Station|Search and Rescue",
"leisure-fitness_station": "3Fitness Station|street workout",
"emergency-mountain_rescue": "Mountain Rescue Station|Search and Rescue|rescue",
"leisure-fitness_station": "3Fitness Station|street workout|fitness|workout|4Exercise station|Exercise bench|outdoor gym|5Calisthenics park|trim trail",
"office-insurance": "4Insurance Office",
"office-ngo": "4Non-Governmental Organization|NGO",
"shop-erotic|@shop": "4Erotic|4Adult|3Sex",
"shop-beauty-day_spa": "4Day Spa|spa|wellness",
"shop-massage": "Massage salon|Massage Parlour|4massage|spa|massage center|massage therapy|massage services|spa treatment|spa services",
"shop-motorcycle|@shop": "4Motorcycle",
"shop-motorcycle_repair": "4Motorcycle Repair",
@@ -443,14 +446,14 @@
"shop-pawnbroker": "4Pawnbroker",
"shop-stationery|@shop": "5Stationery",
"shop-tattoo": "Tattoo Parlour|4tattoos",
"shop-variety_store|@category_shopping|@shop": "Variety",
"shop-video|@shop": "4Video|3DVD",
"shop-video_games|@shop": "Video games|4videogames|video games|videogames|U+1F47E|U+1F579|U+1F3AE",
"shop-variety_store|@category_shopping|@shop": "4Variety|6Dollar store|5Pound shop|5Five and dime",
"shop-video|@shop": "4Video|3DVD|videoshop|5video shop|video rental|video rental shop|video rental store",
"shop-video_games|@shop": "Video games|4videogames|video games|videogames|gaming|games|U+1F47E|U+1F579|U+1F3AE",
"tourism-wilderness_hut|@category_hotel": "4Wilderness Hut|5backcountry hut|hut|mountain hut|bothy|bivvy",
"tourism-gallery|@category_tourism": "3Art Gallery|3Gallery|museum",
"tourism-theme_park|@category_tourism|@category_children": "Theme park|Amusement park",
"boundary-national_park|@category_tourism": "National Park",
"leisure-nature_reserve|@category_tourism": "Nature reserve",
"tourism-theme_park|@category_tourism|@category_children": "5Theme park|Amusement park",
"boundary-national_park|@category_tourism": "5National Park",
"leisure-nature_reserve|@category_tourism": "4Nature reserve",
"natural-cape": "Cape",
"natural-geyser": "3Geyser",
"natural-glacier|@category_tourism": "Glacier",
@@ -459,31 +462,31 @@
"leisure-indoor_play": "3Indoor Play Centre|indoor play|indoor playground",
"piste:type-downhill|piste:type-nordic": "Skiing|3Ski run|4Piste",
"amenity-events_venue": "Events Venue",
"shop-chocolate|@category_food|@shop": "Chocolate",
"shop-chocolate|@category_food|@shop": "5Chocolate",
"shop-coffee|@category_food|@shop": "Coffee Retailer|Coffee",
"shop-fabric|@shop": "Fabric",
"shop-money_lender": "Money lender",
"shop-music|@shop": "Record|vinyl|Music",
"shop-musical_instrument|@shop": "Musical instruments",
"shop-money_lender": "5Money lender",
"shop-music|@shop": "Record|4vinyl|Music|6Record store",
"shop-musical_instrument|@shop": "7Musical instruments|instruments|guitar|guitars",
"shop-tea|@shop": "Tea",
"shop-telecommunication|@shop": "Telecommunication",
"shop-antiques|@category_shopping|@shop|@category_secondhand": "Antiques",
"shop-telecommunication|@shop": "6Telecommunications shop|Telecommunications|telecom",
"shop-antiques|@category_shopping|@shop|@category_secondhand": "5Antiques",
"shop-art|@category_shopping|@shop": "3Artwork|Arts",
"shop-baby_goods|@category_children|@shop": "Baby Goods",
"shop-baby_goods|@category_children|@shop": "4Baby Goods",
"shop-bag|@category_shopping|@shop": "Bags",
"shop-cheese|@category_food|@shop": "Cheese",
"shop-dairy|@category_food|@shop": "Dairy Products",
"shop-electrical|@shop": "Electrical Supplies|Electrical|U+1F50B|U+1F50C|U+1F4A1|U+1F526",
"shop-fishing|@shop": "Fishing",
"shop-interior_decoration|@shop": "Interior Decorations",
"shop-interior_decoration|@shop": "6Interior decorations|interior design",
"shop-lighting|@shop": "4Lighting|Lighting fixtures|4Lamps",
"shop-lottery|@gambling": "Lottery Tickets",
"shop-medical_supply|@shop": "Medical Supplies",
"shop-nutrition_supplements|@shop": "Nutrition Supplements",
"shop-medical_supply|@shop": "7Medical supplies",
"shop-nutrition_supplements|@shop": "9Nutrition supplements",
"shop-paint|@shop": "Paints",
"shop-perfumery|@category_shopping|@shop": "Perfumery",
"shop-sewing|@shop": "3Sewing Supplies|4Haberdashery",
"shop-storage_rental": "Storage Rental",
"shop-perfumery|@category_shopping|@shop": "5Perfumery|perfume|perfumes",
"shop-sewing|@shop": "3Sewing supplies|4Haberdashery",
"shop-storage_rental": "5Storage rental|4Rent storage",
"shop-tobacco|@shop": "Smoke|Tobacco",
"shop-trade|@shop": "Trades Supplies|Trade Supplies",
"shop-watches|@category_shopping|@shop": "Watches",
@@ -494,35 +497,35 @@
"shop-auction|@category_secondhand": "4Auction|Auctioneer|Auction House",
"shop-collector|@category_shopping|@category_secondhand": "Collectables|Collector",
"man_made-cairn": "4Cairn",
"wheelchair-yes": "5Wheelchair",
"amenity-social_facility": "Social Facility",
"wheelchair-yes": "5Wheelchair|accessible|accessibility|5Handicap accessible",
"amenity-social_facility": "Social Facility|social|group home|nursing home|assisted living|drug clinic|halfway house|disabled workshop|job center|homeless shelter",
"social_facility-soup_kitchen": "4Soup Kitchen|Food",
"social_facility-food_bank": "4Food Bank|foodbank|Food",
"amenity-food_sharing": "Food Sharing|Food",
"amenity-give_box": "Give Box",
"social_facility-food_bank": "4Food Bank|foodbank|Food|donate|Free pantry|Free fridge",
"amenity-food_sharing": "Food Sharing|Food|donate",
"amenity-give_box": "Give Box|donate",
"leisure-sports_hall": "Sports hall",
"amenity-arts_centre|@category_tourism": "Arts Center",
"amenity-prison": "prison",
"amenity-exhibition_centre": "Exhibition Center",
"shop-bathroom_furnishing|@shop": "Bathroom Furnishings",
"shop-bed|@shop": "Bed Shop",
"shop-boutique|@shop": "Boutique",
"amenity-food_court": "Food Court",
"shop-curtain|@shop": "Curtain Shop",
"shop-gas|@shop": "Gas Store",
"shop-pet_grooming": "Pet Grooming",
"shop-hifi|@shop": "HiFi Audio Shop",
"amenity-conference_centre": "Conference Center",
"shop-herbalist|@shop": "Herbalist",
"shop-appliance|@shop": "Appliance Shop",
"shop-agrarian|@shop": "Agricultural Shop",
"shop-fashion_accessories|@shop": "Fashion Accessories",
"amenity-prison": "prison|jail|penitentiary|detention centre|detention center",
"amenity-exhibition_centre": "5Exhibition Center",
"shop-bathroom_furnishing|@shop": "9Bathroom Furnishings",
"shop-bed|@shop": "3Bed Shop",
"shop-boutique|@shop": "4Boutique",
"amenity-food_court": "5Food Court",
"shop-curtain|@shop": "5Curtain Shop",
"shop-gas|@shop": "4Gas Store|gas shop|propane|butane|cooking gas|LNG|CNG|gas bottles",
"shop-pet_grooming": "4Pet Grooming|groomer|dog grooming",
"shop-hifi|@shop": "4HiFi Audio Shop",
"amenity-conference_centre": "5Conference Center",
"shop-herbalist|@shop": "4Herbalist",
"shop-appliance|@shop": "4Appliance Shop|Kitchen appliances|Kitchen gallery",
"shop-agrarian|@shop": "4Agricultural Shop|Feed store|Feed and seed|Farm supply",
"shop-fashion_accessories|@shop": "4Fashion Accessories",
"amenity-waste_transfer_station": "Waste Transfer Station",
"shop-carpet|@shop": "Carpet Shop",
"shop-craft|@shop": "Craft",
"shop-carpet|@shop": "4Carpet Shop",
"shop-craft|@shop": "3Craft",
"shop-pasta|@shop": "Pasta",
"attraction-amusement_ride|attraction-carousel|attraction-roller_coaster|attraction-maze|attraction-historic|attraction-big_wheel|attraction-bumper_car|@category_children": "Attraction|Maze",
"amenity-luggage_locker": "Luggage|locker|storage",
"attraction-amusement_ride|attraction-carousel|attraction-roller_coaster|attraction-maze|attraction-historic|attraction-big_wheel|attraction-bumper_car|@category_children": "Attraction|Maze|Amusement|attractions",
"amenity-luggage_locker": "5Luggage locker|Luggage|locker|4Lockers|storage|5Coin lockers",
"office-security": "4Security Office",
"building-guardhouse": "4Guard"
}

View File

@@ -24,3 +24,4 @@ China_Guangdong Hong Kong
US_Guam Guam
Macedonia North Macedonia
Czech Republic Czechia
Myanmar Burma
1 Samoa American Samoa
24 US_Guam Guam
25 Macedonia North Macedonia
26 Czech Republic Czechia
27 Myanmar Burma

View File

@@ -169,7 +169,7 @@ highway|residential|bridge;[highway=residential][bridge?];;name;int_name;81;
# railway|rail|service|bridge;[railway=rail][service?][service!=spur][bridge?];...
railway|rail|bridge;[railway=rail][bridge?][dont=match];;name;int_name;82;
deprecated:boundary|administrative|10:04.2024;[boundary=administrative][admin_level=10];x;name;int_name;83;
deprecated:boundary|administrative|6:04.2024;[boundary=administrative][admin_level=6];x;name;int_name;84;
emergency|access_point;[emergency=access_point];;name;;84;
highway|secondary|bridge;[highway=secondary][bridge?];;name;int_name;85;
highway|tertiary|bridge;[highway=tertiary][bridge?];;name;int_name;86;
barrier|bollard;87;
@@ -225,7 +225,7 @@ place|suburb;128;
landuse|allotments;129;
landuse|forest|coniferous;[landuse=forest][wood=coniferous],[landuse=forest][leaf_type=coniferous],[natural=wood][wood=coniferous],[natural=wood][leaf_type=coniferous];;name;int_name;130;
landuse|forest|mixed;[landuse=forest][wood=mixed],[landuse=forest][leaf_type=mixed],[landuse=forest][leaf_cycle=mixed],[natural=wood][wood=mixed],[natural=wood][leaf_type=mixed],[natural=wood][leaf_cycle=mixed];;name;int_name;131;
deprecated:natural|wood|mixed:01.2020;[natural=wood][wood=mixed],[natural=wood][leaf_type=mixed],[natural=wood][leaf_cycle=mixed];x;name;int_name;132;landuse|forest|mixed
emergency|life_ring;132;
sport|tennis;133;
# ~730k usages.
landuse|vineyard;134;
@@ -987,7 +987,7 @@ highway|busway|tunnel;[highway=busway][tunnel?];;name;int_name;860;
natural|salt_pond;861;landuse|salt_pond
amenity|conference_centre;862;
amenity|exhibition_centre;863;
deprecated:railway|siding|tunnel:06.2023;864;x
shop|beauty|day_spa;[shop=beauty][beauty=spa];;name;int_name;864;
amenity|boat_rental;865;
area:highway|footway;866;
junction|circular;867;
Can't render this file because it contains an unexpected character in line 7 and column 16.

View File

@@ -77,6 +77,8 @@ vending=water : vending=drinks
vending=milk : vending=drinks
vending=bread : vending=food
highway=emergency_access_point : emergency=access_point
building=entrance : entrance=yes
ice_road=yes : highway=ice_road

View File

@@ -242,6 +242,7 @@
@neutral_label: #51585E;
@healthcare_label: #983E44;
@public_transport_label: #2F6499;
@emergency_label: #247F52;
/* 6.4 Road labels */

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1 @@
<svg height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="none"><circle cx="9" cy="9" fill="#000" opacity=".6" r="9"/><circle cx="9" cy="9" fill="#6b425c" r="8.25"/><path d="m6.30055657 9.36465433.00689805.0737763c.14582844 1.17941477.67189526 2.27631057 1.56061293 3.27868287l-.00113465.0761216c-1.22761107.0592649-2.19488995-.2708693-2.90183667-.9904025-.70694671-.7195332-1.02550703-1.6981313-.95568097-2.93579437.9045588-.05286646 1.66827257.11300557 2.29114131.4976161zm7.46682273-.50627566.2232054.00865956c.0698261 1.23766307-.2487342 2.21626117-.9556809 2.93579437s-1.6742256 1.0496674-2.9018367.9904025l-.0011346-.0761216c.8887176-1.0023723 1.4147844-2.0992681 1.5606129-3.27868287l.006898-.0737763c.570963-.35255965 1.260275-.5213182 2.0679359-.50627566zm-4.7673793-4.05837867.19024281.17805949c1.17397699 1.13425665 1.76096549 2.39289765 1.76096549 3.77592299 0 1.45581612-.6504028 2.78575212-1.9512083 3.98980792-1.30080552-1.2040558-1.95120828-2.5339918-1.95120828-3.98980792 0-1.45581615.65040276-2.77381031 1.95120828-3.95398248zm-3.64250524 1.23453276c.52429331.11064075.98164792.28211324 1.37206381.51441745-.26807889.60635877-.42055963 1.24178775-.45592669 1.90388473-.3404372-.15607091-.70942568-.26527279-1.10368332-.32818887-.12186067-.63450512-.05872551-1.33159631.1875462-2.09011331zm7.28501044 0c.2462718.758517.3094069 1.45560819.1875462 2.09011331-.3942576.06291608-.7632461.17211796-1.1036833.32818887-.035367-.66209698-.1878478-1.29752596-.4559267-1.90388473.3904159-.23230421.8477705-.4037767 1.3720638-.51441745z" fill="#000" fill-rule="evenodd"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m6 0c3.23839694 0 5.8775718 2.56557489 5.9958615 5.77506174l.0041385.22493826c0 3.23839694-2.56557489 5.8775718-5.77506174 5.9958615l-.22493826.0041385c-3.3137085 0-6-2.6862915-6-6s2.6862915-6 6-6zm-3 6h-2.4c0 2.98233765 2.41766235 5.4 5.4 5.4v-2.4c-1.65685425 0-3-1.34314575-3-3zm3-2.4c-1.3254834 0-2.4 1.0745166-2.4 2.4s1.0745166 2.4 2.4 2.4 2.4-1.0745166 2.4-2.4-1.0745166-2.4-2.4-2.4zm0-3v2.4c1.59768088 0 2.90366088 1.24891996 2.99490731 2.82372721l.00509269.17627279h2.4c0-2.98233765-2.41766235-5.4-5.4-5.4z" fill="#983E44" opacity=".6"/></svg>

After

Width:  |  Height:  |  Size: 642 B

View File

@@ -927,7 +927,9 @@ node|z16-[man_made=observatory],
node|z17-[amenity=fire_station],
node|z18-[amenity=internet_cafe],
node|z18-[emergency=defibrillator],
node|z18-[emergency=access_point],
node|z18-[emergency=assembly_point],
node|z19-[emergency=life_ring],
node|z18-[emergency=lifeguard],
node|z18-[amenity=toilets],
node|z18-[amenity=atm],
@@ -1525,9 +1527,15 @@ node|z19-[emergency=fire_hydrant],
node|z18-[emergency=defibrillator],
{icon-image: defibrillator-m.svg;font-size: 11;}
node|z18-[emergency=access_point],
{icon-image: access_point-m.svg;font-size: 11;}
node|z18-[emergency=assembly_point],
{icon-image: assembly_point-m.svg;font-size: 11;}
node|z19-[emergency=life_ring],
{icon-image: lifebuoy-m.svg; font-size: 11;}
node|z17-[emergency=lifeguard],
{icon-image: lifeguard-m.svg; font-size: 11;}
@@ -2099,6 +2107,8 @@ node|z17-[shop=variety_store],
{icon-image: shop-m.svg;}
node|z17-[shop=massage],
{icon-image: massage_salon-m.svg;icon-min-distance: 24;}
node|z17-[shop=beauty][beauty=spa],
{icon-image: day-spa-m.svg;icon-min-distance: 24;}
node|z17-[shop=money_lender],
{icon-image: bank-m.svg;icon-min-distance: 24;}
node|z17-[shop=pawnbroker],

View File

@@ -34,6 +34,7 @@ node[shop=wholesale],
node[craft=photographer],
node[craft=tailor],
node[craft=winery],
{text-color: @shop_label}
node[amenity=bar],
@@ -157,3 +158,6 @@ node[healthcare],
node[amenity=bicycle_rental],
node[amenity=taxi],
{text-color: @public_transport_label;text-halo-radius: 0.1;text-halo-opacity: 0.7;text-halo-color: @label_halo_light;}
node[emergency=access_point],
{text-color: @emergency_label;text-halo-radius: 0.1;text-halo-opacity: 0.7;text-halo-color: @label_halo_light;}

View File

@@ -844,6 +844,7 @@ shop-antiques # icon z16- (also has captio
shop-appliance # icon z18- (also has caption(optional) z18-)
shop-baby_goods # icon z18- (also has caption(optional) z18-)
shop-beauty # icon z16- (also has caption(optional) z16-)
shop-beauty-day_spa # icon z16- (also has caption(optional) z16-)
shop-beverages # icon z16- (also has caption(optional) z16-)
shop-boutique # icon z18- (also has caption(optional) z18-)
shop-car_repair # icon z16- (also has caption(optional) z16-)
@@ -1890,6 +1891,7 @@ leisure-swimming_pool-private # icon z17- (also has captio
# shop-appliance # caption(optional) z18- (also has icon z18-)
# shop-baby_goods # caption(optional) z18- (also has icon z18-)
# shop-beauty # caption(optional) z16- (also has icon z16-)
# shop-beauty-day_spa # caption(optional) z16- (also has icon z16-)
# shop-beverages # caption(optional) z16- (also has icon z16-)
# shop-boutique # caption(optional) z18- (also has icon z18-)
# shop-car_repair # caption(optional) z16- (also has icon z16-)
@@ -2360,6 +2362,7 @@ amenity-bench # icon z18- (also has captio
amenity-bench-backless # icon z18- (also has caption(optional) z19-)
amenity-lounger # icon z18- (also has caption(optional) z19-)
amenity-waste_disposal # icon z18- (also has caption(optional) z18-)
emergency-access_point # icon z18- (also has caption(optional) z18-)
emergency-assembly_point # icon z18- (also has caption(optional) z18-)
emergency-defibrillator # icon z18- (also has caption(optional) z18-)
emergency-phone # icon z17-
@@ -2368,6 +2371,7 @@ man_made-telescope # icon z18- (also has captio
amenity-waste_basket # icon z18- (also has caption(optional) z19-)
emergency-fire_hydrant # icon z19- (also has caption(optional) z19-)
emergency-life_ring # icon z19- (also has caption(optional) z19-)
power-substation # icon z17- (also has caption(optional) z18-, area z13-)
=== -9990
@@ -2391,9 +2395,11 @@ amenity-loading_dock # icon z18- (also has captio
# amenity-vending_machine-sweets # caption(optional) z18- (also has icon z18-)
# amenity-waste_basket # caption(optional) z19- (also has icon z18-)
# amenity-waste_disposal # caption(optional) z18- (also has icon z18-)
# emergency-access_point # caption(optional) z18- (also has icon z18-)
# emergency-assembly_point # caption(optional) z18- (also has icon z18-)
# emergency-defibrillator # caption(optional) z18- (also has icon z18-)
# emergency-fire_hydrant # caption(optional) z19- (also has icon z19-)
# emergency-life_ring # caption(optional) z19- (also has icon z19-)
# entrance # caption(optional) z19- (also has icon z17-)
entrance-exit # icon z17- (also has caption(optional) z19-)
# entrance-exit # caption(optional) z19- (also has icon z17-)

View File

@@ -240,6 +240,7 @@
@neutral_label: #494F54;
@healthcare_label: #A6454B;
@public_transport_label: #234B73;
@emergency_label: #247F52;
/* 6.4 Road labels */

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1 @@
<svg height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="none"><circle cx="9" cy="9" fill="#fff" opacity=".6" r="9"/><circle cx="9" cy="9" fill="#be75a3" r="8.25"/><path d="m6.30055657 9.36465433.00689805.0737763c.14582844 1.17941477.67189526 2.27631057 1.56061293 3.27868287l-.00113465.0761216c-1.22761107.0592649-2.19488995-.2708693-2.90183667-.9904025-.70694671-.7195332-1.02550703-1.6981313-.95568097-2.93579437.9045588-.05286646 1.66827257.11300557 2.29114131.4976161zm7.46682273-.50627566.2232054.00865956c.0698261 1.23766307-.2487342 2.21626117-.9556809 2.93579437s-1.6742256 1.0496674-2.9018367.9904025l-.0011346-.0761216c.8887176-1.0023723 1.4147844-2.0992681 1.5606129-3.27868287l.006898-.0737763c.570963-.35255965 1.260275-.5213182 2.0679359-.50627566zm-4.7673793-4.05837867.19024281.17805949c1.17397699 1.13425665 1.76096549 2.39289765 1.76096549 3.77592299 0 1.45581612-.6504028 2.78575212-1.9512083 3.98980792-1.30080552-1.2040558-1.95120828-2.5339918-1.95120828-3.98980792 0-1.45581615.65040276-2.77381031 1.95120828-3.95398248zm-3.64250524 1.23453276c.52429331.11064075.98164792.28211324 1.37206381.51441745-.26807889.60635877-.42055963 1.24178775-.45592669 1.90388473-.3404372-.15607091-.70942568-.26527279-1.10368332-.32818887-.12186067-.63450512-.05872551-1.33159631.1875462-2.09011331zm7.28501044 0c.2462718.758517.3094069 1.45560819.1875462 2.09011331-.3942576.06291608-.7632461.17211796-1.1036833.32818887-.035367-.66209698-.1878478-1.29752596-.4559267-1.90388473.3904159-.23230421.8477705-.4037767 1.3720638-.51441745z" fill="#fff" fill-rule="evenodd"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m6 0c3.23839694 0 5.8775718 2.56557489 5.9958615 5.77506174l.0041385.22493826c0 3.23839694-2.56557489 5.8775718-5.77506174 5.9958615l-.22493826.0041385c-3.3137085 0-6-2.6862915-6-6s2.6862915-6 6-6zm-3 6h-2.4c0 2.98233765 2.41766235 5.4 5.4 5.4v-2.4c-1.65685425 0-3-1.34314575-3-3zm3-2.4c-1.3254834 0-2.4 1.0745166-2.4 2.4s1.0745166 2.4 2.4 2.4 2.4-1.0745166 2.4-2.4-1.0745166-2.4-2.4-2.4zm0-3v2.4c1.59768088 0 2.90366088 1.24891996 2.99490731 2.82372721l.00509269.17627279h2.4c0-2.98233765-2.41766235-5.4-5.4-5.4z" fill="#d85961"/></svg>

After

Width:  |  Height:  |  Size: 629 B

View File

@@ -844,6 +844,7 @@ shop-antiques # icon z16- (also has captio
shop-appliance # icon z18- (also has caption(optional) z18-)
shop-baby_goods # icon z18- (also has caption(optional) z18-)
shop-beauty # icon z16- (also has caption(optional) z16-)
shop-beauty-day_spa # icon z16- (also has caption(optional) z16-)
shop-beverages # icon z16- (also has caption(optional) z16-)
shop-boutique # icon z18- (also has caption(optional) z18-)
shop-car_repair # icon z16- (also has caption(optional) z16-)
@@ -1893,6 +1894,7 @@ leisure-swimming_pool-private # icon z17- (also has captio
# shop-appliance # caption(optional) z18- (also has icon z18-)
# shop-baby_goods # caption(optional) z18- (also has icon z18-)
# shop-beauty # caption(optional) z16- (also has icon z16-)
# shop-beauty-day_spa # caption(optional) z16- (also has icon z16-)
# shop-beverages # caption(optional) z16- (also has icon z16-)
# shop-boutique # caption(optional) z18- (also has icon z18-)
# shop-car_repair # caption(optional) z16- (also has icon z16-)
@@ -2366,6 +2368,7 @@ amenity-bench # icon z18- (also has captio
amenity-bench-backless # icon z18- (also has caption(optional) z19-)
amenity-lounger # icon z18- (also has caption(optional) z19-)
amenity-waste_disposal # icon z18- (also has caption(optional) z18-)
emergency-access_point # icon z18- (also has caption(optional) z18-)
emergency-assembly_point # icon z18- (also has caption(optional) z18-)
emergency-defibrillator # icon z18- (also has caption(optional) z18-)
emergency-phone # icon z17-
@@ -2374,6 +2377,7 @@ man_made-telescope # icon z18- (also has captio
amenity-waste_basket # icon z18- (also has caption(optional) z19-)
emergency-fire_hydrant # icon z19- (also has caption(optional) z19-)
emergency-life_ring # icon z19- (also has caption(optional) z19-)
power-substation # icon z17- (also has caption(optional) z18-, area z13-)
=== -9990
@@ -2397,9 +2401,11 @@ amenity-loading_dock # icon z18- (also has captio
# amenity-vending_machine-sweets # caption(optional) z18- (also has icon z18-)
# amenity-waste_basket # caption(optional) z19- (also has icon z18-)
# amenity-waste_disposal # caption(optional) z18- (also has icon z18-)
# emergency-access_point # caption(optional) z18- (also has icon z18-)
# emergency-assembly_point # caption(optional) z18- (also has icon z18-)
# emergency-defibrillator # caption(optional) z18- (also has icon z18-)
# emergency-fire_hydrant # caption(optional) z19- (also has icon z19-)
# emergency-life_ring # caption(optional) z19- (also has icon z19-)
# entrance # caption(optional) z19- (also has icon z17-)
entrance-exit # icon z17- (also has caption(optional) z19-)
# entrance-exit # caption(optional) z19- (also has icon z17-)

View File

@@ -180,6 +180,7 @@
@neutral_label: #51585E;
@healthcare_label: #983E44;
@public_transport_label: #2F6499;
@emergency_label: #247F52;
/* 6.4 Road labels */

View File

@@ -151,6 +151,7 @@
@neutral_label: #494F54;
@healthcare_label: #A6454B;
@public_transport_label: #234B73;
@emergency_label: #247F52;
/* ROADS LABELS */
@shield_text: #000000;

View File

@@ -70,3 +70,7 @@ All the following commands require an app restart:
- `?all-types`: Shows all internal types in place page
- `?no-all-types`: Disables showing all internal types in place page
## Search
- `?wiki`: Search results for all elements with Wikipedia links

View File

@@ -147,8 +147,6 @@ set(SRC
osm_o5m_source.hpp
osm_source.cpp
osm_xml_source.hpp
panoramax_collector.cpp
panoramax_collector.hpp
place_processor.cpp
place_processor.hpp
platform_helpers.cpp

View File

@@ -225,6 +225,11 @@ bool FeatureBuilder::PreSerialize()
});
m_params.name = std::move(nameWithRef);
}
else if (ftypes::IsEmergencyAccessPointChecker::Instance()(types))
{
m_params.name.Clear();
m_params.name.AddString(StringUtf8Multilang::kDefaultCode, m_params.ref);
}
m_params.ref.clear();
}

View File

@@ -10,7 +10,6 @@
#include "generator/mini_roundabout_transformer.hpp"
#include "generator/node_mixer.hpp"
#include "generator/osm2type.hpp"
#include "generator/panoramax_collector.hpp"
#include "generator/region_meta.hpp"
#include "routing/speed_camera_prohibition.hpp"
@@ -69,9 +68,6 @@ void CountryFinalProcessor::Process()
if (!m_isolinesPath.empty())
AddIsolines();
LOG(LINFO, ("Enriching with Panoramax data..."));
EnrichPanoramax();
// DropProhibitedSpeedCameras();
LOG(LINFO, ("Processing building parts..."));
ProcessBuildingParts();
@@ -297,50 +293,6 @@ void CountryFinalProcessor::AddAddresses()
LOG(LINFO, ("Total addresses:", totalStats));
}
void CountryFinalProcessor::EnrichPanoramax()
{
if (m_panoramaxFilename.empty() || !Platform::IsFileExistsByFullPath(m_panoramaxFilename))
{
LOG(LINFO, ("Panoramax data not available, skipping enrichment"));
return;
}
LOG(LINFO, ("Enriching roads with Panoramax imagery data from:", m_panoramaxFilename));
// Load Panoramax imagery data
PanoramaxCollector collector;
if (!collector.LoadImageryData(m_panoramaxFilename, ""))
{
LOG(LWARNING, ("Failed to load Panoramax data"));
return;
}
// Enrich roads in each MWM
ForEachMwmTmp(m_temporaryMwmPath, [&](auto const & name, auto const & path)
{
if (!IsCountry(name))
return;
LOG(LINFO, ("Enriching Panoramax for:", name));
std::vector<FeatureBuilder> features;
ForEachFeatureRawFormat<serialization_policy::MaxAccuracy>(
path, [&](FeatureBuilder && fb, uint64_t) {
collector.EnrichRoad(fb);
features.emplace_back(std::move(fb));
});
// Rewrite the file with enriched features
FeatureBuilderWriter<serialization_policy::MaxAccuracy> writer(path, FileWriter::Op::OP_WRITE_TRUNCATE);
for (auto & fb : features)
writer.Write(fb);
LOG(LINFO, (name, "done"));
});
LOG(LINFO, ("Panoramax enrichment complete:", DebugPrint(collector.GetStats())));
}
void CountryFinalProcessor::ProcessCoastline()
{
/// @todo We can remove MinSize at all.

View File

@@ -26,7 +26,6 @@ public:
void SetAddressesDir(std::string const & dir) { m_addressPath = dir; }
void SetCityBoundariesFiles(std::string const & collectorFile) { m_boundariesCollectorFile = collectorFile; }
void SetPanoramaxFile(std::string const & filename) { m_panoramaxFilename = filename; }
// FinalProcessorIntermediateMwmInterface overrides:
void Process() override;
@@ -40,7 +39,6 @@ private:
void AddFakeNodes();
void AddIsolines();
void AddAddresses();
void EnrichPanoramax();
void DropProhibitedSpeedCameras();
// void Finish();
@@ -56,7 +54,6 @@ private:
std::string m_fakeNodesFilename;
std::string m_miniRoundaboutsFilename;
std::string m_addrInterpolFilename;
std::string m_panoramaxFilename;
std::string m_hierarchySrcFilename;

View File

@@ -42,9 +42,6 @@ struct GenerateInfo
// External folders with additional preprocessed data (isolines, addresses).
std::string m_isolinesDir, m_addressesDir;
// Panoramax imagery data file
std::string m_panoramaxFilename;
// Current generated file name if --output option is defined.
std::string m_fileName;

View File

@@ -107,7 +107,6 @@ DEFINE_string(nodes_list_path, "",
DEFINE_bool(generate_isolines_info, false, "Generate the isolines info section");
DEFINE_string(isolines_path, "", "Path to isolines directory. If set, adds isolines linear features.");
DEFINE_string(addresses_path, "", "Path to addresses directory. If set, adds addr:interpolation features.");
DEFINE_string(panoramax_file, "", "Path to Panoramax imagery coords file. If set, enriches roads with street-level imagery availability.");
// Routing.
DEFINE_bool(make_routing_index, false, "Make sections with the routing information.");
@@ -244,7 +243,6 @@ MAIN_WITH_ERROR_HANDLING([](int argc, char ** argv)
genInfo.m_complexHierarchyFilename = FLAGS_complex_hierarchy_data;
genInfo.m_isolinesDir = FLAGS_isolines_path;
genInfo.m_addressesDir = FLAGS_addresses_path;
genInfo.m_panoramaxFilename = FLAGS_panoramax_file;
// Use merged style.
GetStyleReader().SetCurrentStyle(MapStyleMerged);

View File

@@ -1,157 +0,0 @@
#include "generator/panoramax_collector.hpp"
#include "indexer/feature_meta.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "geometry/mercator.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include <cstdint>
#include <fstream>
#include <sstream>
namespace generator
{
PanoramaxCollector::PanoramaxCollector() = default;
bool PanoramaxCollector::LoadImageryData(std::string const & coordsFilePath, std::string const & /* tilesDir */)
{
LOG(LINFO, ("Loading Panoramax imagery from:", coordsFilePath));
std::ifstream file(coordsFilePath, std::ios::binary);
if (!file.is_open())
{
LOG(LWARNING, ("Failed to open Panoramax coords file:", coordsFilePath));
return false;
}
// Read header
uint32_t version;
uint64_t count;
file.read(reinterpret_cast<char*>(&version), sizeof(version));
file.read(reinterpret_cast<char*>(&count), sizeof(count));
if (version != 1)
{
LOG(LWARNING, ("Unsupported Panoramax coords file version:", version));
return false;
}
LOG(LINFO, ("Loading", count, "Panoramax imagery points..."));
// Read coordinates and build spatial index
std::vector<ImageryPoint> points;
points.reserve(count);
for (uint64_t i = 0; i < count; ++i)
{
double lat, lon;
file.read(reinterpret_cast<char*>(&lat), sizeof(lat));
file.read(reinterpret_cast<char*>(&lon), sizeof(lon));
// Convert to Mercator coordinates
m2::PointD mercPt = mercator::FromLatLon(lat, lon);
points.emplace_back(mercPt);
if ((i + 1) % 500000 == 0)
LOG(LINFO, ("Loaded", i + 1, "/", count, "points"));
}
if (!file)
{
LOG(LWARNING, ("Error reading Panoramax coords file"));
return false;
}
file.close();
LOG(LINFO, ("Building spatial index for", points.size(), "points..."));
// Build spatial index
for (auto const & pt : points)
m_imageryTree.Add(pt);
m_stats.m_totalImageryPoints = static_cast<uint32_t>(points.size());
LOG(LINFO, ("Panoramax data loaded:", m_stats.m_totalImageryPoints, "imagery points"));
return true;
}
bool PanoramaxCollector::EnrichRoad(feature::FeatureBuilder & fb)
{
// Only process roads
static auto const & isRoad = ftypes::IsWayChecker::Instance();
if (!isRoad(fb.GetTypes()))
return false;
m_stats.m_totalRoads++;
// Check if road already has Panoramax flag
if (fb.GetMetadata().Has(feature::Metadata::FMD_PANORAMAX))
return false;
// Get road geometry
std::vector<m2::PointD> roadPoints;
fb.ForEachPoint([&roadPoints](m2::PointD const & pt) {
roadPoints.push_back(pt);
});
if (roadPoints.empty())
return false;
// Calculate road bounding box
m2::RectD roadBBox;
for (auto const & pt : roadPoints)
roadBBox.Add(pt);
// Expand bounding box by threshold distance in Mercator units
auto const center = roadBBox.Center();
auto const inflateRect = mercator::RectByCenterXYAndSizeInMeters(center, kDistanceThresholdM);
roadBBox.Inflate(inflateRect.SizeX() / 2.0, inflateRect.SizeY() / 2.0);
// Query imagery tree for nearby points
bool hasImagery = false;
m_imageryTree.ForEachInRect(roadBBox, [&](ImageryPoint const & imgPt) {
if (hasImagery)
return; // Already found, early exit
// Check distance to each road point
for (auto const & roadPt : roadPoints)
{
double const distM = mercator::DistanceOnEarth(roadPt, imgPt.m_point);
if (distM <= kDistanceThresholdM)
{
hasImagery = true;
return;
}
}
});
if (hasImagery)
{
fb.GetMetadata().Set(feature::Metadata::FMD_PANORAMAX, "yes");
m_stats.m_roadsWithImagery++;
return true;
}
return false;
}
std::string DebugPrint(PanoramaxCollector::Stats const & s)
{
std::ostringstream out;
out << "PanoramaxCollector::Stats {"
<< " totalRoads: " << s.m_totalRoads
<< ", roadsWithImagery: " << s.m_roadsWithImagery
<< " (" << (s.m_totalRoads > 0 ? (s.m_roadsWithImagery * 100.0 / s.m_totalRoads) : 0) << "%)"
<< ", totalImageryPoints: " << s.m_totalImageryPoints
<< " }";
return out.str();
}
} // namespace generator

View File

@@ -1,72 +0,0 @@
#pragma once
#include "generator/feature_builder.hpp"
#include "geometry/point2d.hpp"
#include "geometry/tree4d.hpp"
#include "base/geo_object_id.hpp"
#include <string>
#include <vector>
namespace generator
{
/// Enriches road features with Panoramax street-level imagery availability flag.
/// Loads Panoramax imagery coordinates from tile index and marks roads within threshold distance.
class PanoramaxCollector
{
public:
// Distance threshold for matching roads to imagery (meters)
static double constexpr kDistanceThresholdM = 20.0;
/// ImageryPoint represents a single point where street-level imagery exists
struct ImageryPoint
{
m2::PointD m_point; // Mercator coordinates
ImageryPoint() = default;
explicit ImageryPoint(m2::PointD const & pt) : m_point(pt) {}
m2::RectD GetLimitRect() const { return m2::RectD(m_point, m_point); }
};
/// Statistics for debugging/logging
struct Stats
{
uint32_t m_totalRoads = 0;
uint32_t m_roadsWithImagery = 0;
uint32_t m_totalImageryPoints = 0;
uint32_t m_tilesProcessed = 0;
friend std::string DebugPrint(Stats const & s);
};
PanoramaxCollector();
/// Load Panoramax imagery data from tile directory
/// @param tileIndexPath Path to tile_index.json
/// @param tilesDir Directory containing .mvt tiles
/// @return true if data loaded successfully
bool LoadImageryData(std::string const & tileIndexPath, std::string const & tilesDir);
/// Check if a road has nearby imagery and enrich it
/// @param fb FeatureBuilder for a road segment
/// @return true if imagery was found within threshold
bool EnrichRoad(feature::FeatureBuilder & fb);
Stats const & GetStats() const { return m_stats; }
private:
/// Spatial index of imagery points
m4::Tree<ImageryPoint> m_imageryTree;
/// Statistics
Stats m_stats;
/// Decode an MVT tile and extract imagery coordinates
std::vector<m2::PointD> DecodeMVTTile(std::string const & tilePath,
int tileX, int tileY, int zoom);
};
} // namespace generator

View File

@@ -182,7 +182,6 @@ RawGenerator::FinalProcessorPtr RawGenerator::CreateCountryFinalProcessor(Affili
auto finalProcessor = std::make_shared<CountryFinalProcessor>(affiliations, m_genInfo.m_tmpDir, m_threadsCount);
finalProcessor->SetIsolinesDir(m_genInfo.m_isolinesDir);
finalProcessor->SetAddressesDir(m_genInfo.m_addressesDir);
finalProcessor->SetPanoramaxFile(m_genInfo.m_panoramaxFilename);
finalProcessor->SetMiniRoundabouts(m_genInfo.GetIntermediateFileName(MINI_ROUNDABOUTS_FILENAME));
finalProcessor->SetAddrInterpolation(m_genInfo.GetIntermediateFileName(ADDR_INTERPOL_FILENAME));
if (addAds)

View File

@@ -359,7 +359,9 @@
"type.cuisine.vegetarian" = "Vegetarisch";
"type.cuisine.vietnamese" = "Vietnamesisch";
"type.emergency" = "Notfall";
"type.emergency.access_point" = "Rettungspunkt";
"type.emergency.assembly_point" = "Notfall-Sammelpunkt";
"type.emergency.life_ring" = "Rettungsring";
"type.emergency.defibrillator" = "Defibrillator";
"type.emergency.fire_hydrant" = "Hydrant";
"type.emergency.phone" = "Notruftelefon";

View File

@@ -367,7 +367,9 @@
"type.cuisine.vegetarian" = "Vegetarian";
"type.cuisine.vietnamese" = "Vietnamese";
"type.emergency" = "Emergency";
"type.emergency.access_point" = "Emergency Rescue Point";
"type.emergency.assembly_point" = "Emergency Assembly Point";
"type.emergency.life_ring" = "Lifebuoy";
"type.emergency.defibrillator" = "Defibrillator";
"type.emergency.fire_hydrant" = "Fire Hydrant";
"type.emergency.phone" = "Emergency Phone";
@@ -1289,6 +1291,7 @@
"type.shop.kitchen" = "Kitchen Shop";
"type.shop.laundry" = "Launderette";
"type.shop.mall" = "Shopping Centre";
"type.shop.beauty.day_spa" = "Day Spa";
"type.shop.massage" = "Massage Salon";
"type.shop.mobile_phone" = "Mobile Phone Shop";
"type.shop.money_lender" = "Money Lender";

View File

@@ -386,7 +386,9 @@
"type.cuisine.vegetarian" = "Vegetarian";
"type.cuisine.vietnamese" = "Vietnamese";
"type.emergency" = "Emergency";
"type.emergency.access_point" = "Emergency Rescue Point";
"type.emergency.assembly_point" = "Emergency Assembly Point";
"type.emergency.life_ring" = "Lifebuoy";
"type.emergency.defibrillator" = "Defibrillator";
"type.emergency.fire_hydrant" = "Fire Hydrant";
"type.emergency.phone" = "Emergency Phone";
@@ -1329,6 +1331,7 @@
"type.shop.kitchen" = "Kitchen Store";
"type.shop.laundry" = "Laundry";
"type.shop.mall" = "Mall";
"type.shop.beauty.day_spa" = "Day Spa";
"type.shop.massage" = "Massage Salon";
"type.shop.mobile_phone" = "Mobile Phone Store";
"type.shop.money_lender" = "Money Lender";

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

@@ -854,6 +854,12 @@ IsPlatformChecker::IsPlatformChecker()
m_types.push_back(c.GetTypeByPath({"public_transport", "platform"}));
}
IsEmergencyAccessPointChecker::IsEmergencyAccessPointChecker()
{
Classificator const & c = classif();
m_types.push_back(c.GetTypeByPath({"emergency", "access_point"}));
}
IsAddressInterpolChecker::IsAddressInterpolChecker() : BaseChecker(1 /* level */)
{
Classificator const & c = classif();

View File

@@ -629,6 +629,14 @@ public:
DECLARE_CHECKER_INSTANCE(IsPlatformChecker);
};
class IsEmergencyAccessPointChecker : public BaseChecker
{
IsEmergencyAccessPointChecker();
public:
DECLARE_CHECKER_INSTANCE(IsEmergencyAccessPointChecker);
};
class IsAddressInterpolChecker : public BaseChecker
{
IsAddressInterpolChecker();

Some files were not shown because too many files have changed in this diff Show More