Compare commits

..

30 Commits

Author SHA1 Message Date
map-per
c09831caaa Use list form SC
Signed-off-by: map-per <map-per@gmx.de>
2025-11-14 21:58:42 +01:00
map-per
005f731faa clang-format
Signed-off-by: map-per <map-per@gmx.de>
2025-11-13 17:46:05 +01:00
map-per
237894cd45 switch to boost::regex and only construct regex once
Signed-off-by: map-per <map-per@gmx.de>
2025-11-13 17:27:21 +01:00
Yannik Bloscheck
323b49388d [ios] Added file to Xcode
Signed-off-by: Yannik Bloscheck <git@yannikbloscheck.com>
2025-11-13 14:02:28 +01:00
map-per
da9f2af963 use full regex match
Signed-off-by: map-per <map-per@gmx.de>
2025-11-13 11:53:15 +01:00
map-per
f292298c4e use own kes_to_remove list
Signed-off-by: map-per <map-per@gmx.de>
2025-11-13 11:16:07 +01:00
map-per
be15215b83 fixes
Signed-off-by: map-per <map-per@gmx.de>
2025-11-13 10:25:35 +01:00
map-per
4ae64791ff [editor] Mark businesse as disused/vacant
Signed-off-by: map-per <map-per@gmx.de>
2025-11-13 10:13:59 +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
zyphlar
c8bfeb8e96 Don't error when a temp file doesn't exist
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-11-11 19:46:22 -08:00
zyphlar
7fc5ed494b [tools] Handle not-yet-generated drules files
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-11-12 02:26:27 +01:00
zyphlar
d9850f506a [docs] Add CDN_SETUP_INSTRUCTIONS.md
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-11-12 02:26:27 +01:00
zyphlar
f16d14e07f [generator] Automate maps generation with Docker and CI/CD
Co-authored-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-11-12 02:26:27 +01:00
Codeberg Translate
7852cdb5a5 [strings] Update from Codeberg Translate
Co-authored-by: Codeberg Translate <translate@codeberg.org>
Co-authored-by: JanezPavelZebovec <janezpavelzebovec@noreply.codeberg.org>
Co-authored-by: Linus_W_Frische <linus_w_frische@noreply.codeberg.org>
Co-authored-by: Prefill add-on <noreply-addon-prefill@weblate.org>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: dobridabar <dobridabar@noreply.codeberg.org>
Co-authored-by: javnik <javnik@noreply.codeberg.org>
Co-authored-by: ovl-005 <ovl-005@noreply.codeberg.org>
Translation: CoMaps/Android - Map Feature Types
Translation: CoMaps/Android UI Strings
Translation: CoMaps/iOS - Map Feature Types
Translation: CoMaps/iOS UI Strings
2025-11-12 00:09:38 +00:00
x7z4w
9a96096066 [android] Remove routing options item divider
Signed-off-by: x7z4w <x7z4w@noreply.codeberg.org>
2025-11-11 19:18:25 +01:00
Wojciech Sipak
f72c4a28d9 fix openlr helpers build
See the commit e0f8e043bb
apparently the code was never tested

Signed-off-by: Wojciech Sipak <wsipak@protonmail.com>
2025-11-11 18:46:49 +01:00
Wojciech Sipak
68bb78b00d fix levenshtein dfa test build
The constuctor argument type was modified without
any adjustments to the callers.

See the commit
a0a5459b15

Signed-off-by: Wojciech Sipak <wsipak@protonmail.com>
2025-11-11 18:46:49 +01:00
Jean-Baptiste
b9d4f082de [android] Rework clear and close icon on Android
Signed-off-by: Jean-Baptiste <jeanbaptiste.charron@outlook.fr>
2025-11-11 17:55:28 +01:00
Jean-Baptiste
7e40a0e642 [android] Fix drawable used in floating marker view
Signed-off-by: Jean-Baptiste <jeanbaptiste.charron@outlook.fr>
2025-11-11 17:51:53 +01:00
112 changed files with 1983 additions and 474 deletions

View File

@@ -5,10 +5,10 @@ on:
jobs:
description: 'Which job(s) to run right now?'
required: true
default: 'all'
default: 'all-except-upload'
type: choice
options:
- all
- all-except-upload
- copy-coasts
- planet
- wiki
@@ -16,30 +16,82 @@ on:
- subways
- tiger
- maps
- upload
map-generator-continue:
description: 'Continue previous map generation?'
required: false
default: false
type: boolean
map-generator-countries:
description: 'Generate specific MWMs? (i.e. "US_New York_*, foo")'
required: false
type: string
reset:
description: 'Reset part of the system?'
required: false
default: 'no'
type: choice
options:
- 'no'
- wiki-ratelimit
## RCLONE_CONF is multi-line text containing keys and credentials for us2,ru1,fi1,de1 servers
env:
RCLONE_CONF: ${{ secrets.RCLONE_CONF }}
WIKIMEDIA_USERNAME: ${{ secrets.WIKIMEDIA_USERNAME }}
WIKIMEDIA_PASSWORD: ${{ secrets.WIKIMEDIA_PASSWORD }}
S3_KEY_ID: ${{ secrets.S3_KEY_ID }}
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
SFTP_USER: ${{ secrets.SFTP_USER }}
SFTP_PASSWORD: ${{ secrets.SFTP_PASSWORD }}
SFTP_HOST: ${{ secrets.SFTP_HOST }}
SFTP_PATH: ${{ secrets.SFTP_PATH }}
ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
ZULIP_API_KEY: ${{ secrets.ZULIP_API_KEY }}
MWMCONTINUE: ${{ inputs.map-generator-continue }}
MWMCOUNTRIES: ${{ inputs.map-generator-countries }}
DEBIAN_FRONTEND: noninteractive
TZ: Etc/UTC
jobs:
copy-coasts:
if: inputs.jobs == 'copy-coasts' || inputs.jobs == 'all'
name: Copy Previously Generated Coasts
clone-repos:
name: Clone Git Repos
runs-on: mapfilemaker
container:
image: ubuntu:latest
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /media/4tbexternal:/media/4tbexternal
- /mnt/4tbexternal:/mnt/4tbexternal
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- uses: actions/cache@v4
with:
path: "~"
key: cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Checkout main repo
shell: bash
run: |
echo "Cloning $FORGEJO_SERVER_URL/$FORGEJO_REPOSITORY branch $FORGEJO_REF_NAME"
cd ~
git clone --recurse-submodules --shallow-submodules -b $FORGEJO_REF_NAME --single-branch $FORGEJO_SERVER_URL/$FORGEJO_REPOSITORY.git comaps
- name: Checkout wikiparser repo
shell: bash
run: |
cd ~
git clone https://codeberg.org/comaps/wikiparser.git
- name: Checkout subways repo
shell: bash
run: |
cd ~
git clone https://codeberg.org/comaps/subways.git
copy-coasts:
if: inputs.jobs == 'copy-coasts' || inputs.jobs == 'all-except-upload'
name: Copy Previously Generated Coasts
runs-on: mapfilemaker
needs:
- clone-repos
container:
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
@@ -47,336 +99,403 @@ jobs:
- name: Copy Coasts
shell: bash
run: |
if [ -f /media/4tbexternal/osm-maps/*/intermediate_data/WorldCoasts.geom ]; then
cp /media/4tbexternal/osm-maps/*/intermediate_data/WorldCoasts.geom /media/4tbexternal/osm-planet/latest_coasts.geom
cp /media/4tbexternal/osm-maps/*/intermediate_data/WorldCoasts.rawgeom /media/4tbexternal/osm-planet/latest_coasts.rawgeom
echo "WorldCoasts available:"
ls -al /mnt/4tbexternal/osm-maps/*/intermediate_data/WorldCoasts.*
if [ -f /mnt/4tbexternal/osm-maps/*/intermediate_data/WorldCoasts.geom ]; then
echo "Before:"
ls -al /home/planet/latest_coasts*
cp -p /mnt/4tbexternal/osm-maps/*/intermediate_data/WorldCoasts.geom /home/planet/latest_coasts.geom
cp -p /mnt/4tbexternal/osm-maps/*/intermediate_data/WorldCoasts.rawgeom /home/planet/latest_coasts.rawgeom
echo "After:"
ls -al /home/planet/latest_coasts*
else
echo "No WorldCoasts found."
fi
update-planet:
if: inputs.jobs == 'planet' || inputs.jobs == 'all'
if: inputs.jobs == 'planet' || inputs.jobs == 'all-except-upload'
name: Update Planet
runs-on: mapfilemaker
needs:
- clone-repos
container:
image: ubuntu:latest
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /media/4tbexternal:/media/4tbexternal
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Install dependencies
shell: bash
run: |
apt-get update -y
apt-get install -y pyosmium osmium-tool python3-venv python3-pip wget2
rm -f /usr/lib/python*/EXTERNALLY-MANAGED
pip3 install "protobuf<4"
- name: Download Planet File if Absent
shell: bash
# TODO: replace wget2 with curl -Z
run: |
if [ ! -d /media/4tbexternal/osm-planet/planet/ ]; then
mkdir -p /media/4tbexternal/osm-planet/planet/
if [ ! -d /home/planet/planet/ ]; then
mkdir -p /home/planet/planet/
fi
if [ ! -f /media/4tbexternal/osm-planet/planet/planet-latest.osm.pbf ]; then
cd /media/4tbexternal/osm-planet/planet/
wget2 --verbose --progress=bar --continue --debug https://ftpmirror.your.org/pub/openstreetmap/pbf/planet-latest.osm.pbf
if [ ! -f /home/planet/planet/planet-latest.osm.pbf ]; then
cd /home/planet/planet/
wget2 --verbose --progress=bar --continue https://ftpmirror.your.org/pub/openstreetmap/pbf/planet-latest.osm.pbf
else
echo "planet-latest.osm.pbf was found, raw download not required."
fi
- name: Update Planet
shell: bash
run: |
cd /media/4tbexternal/osm-planet/planet/
pyosmium-up-to-date planet-latest.osm.pbf -o planet-latest-new.osm.pbf -vv --size 16384
cd /home/planet/planet/
rm -f planet-latest-new.osm.pbf
pyosmium-up-to-date planet-latest.osm.pbf -o planet-latest-new.osm.pbf -v --size 16384
mv planet-latest-new.osm.pbf planet-latest.osm.pbf
- name: Converting planet-latest.osm.pbf to planet.o5m
run: /root/OM/osmctools/osmconvert planet-latest.osm.pbf -o=planet.o5m
# TODO: better to run osmupdate (not convert) just before starting the maps jobs - for max fresh data.
run: |
echo "Starting..."
cd /home/planet/planet/
osmconvert -v --drop-author --drop-version --hash-memory=4000 planet-latest.osm.pbf -o=planet.o5m
echo "Done."
- name: Notify Zulip
run: |
curl -X POST https://comaps.zulipchat.com/api/v1/messages \
-u $ZULIP_BOT_EMAIL:$ZULIP_API_KEY \
--data-urlencode type=stream \
--data-urlencode 'to="DevOps"' \
--data-urlencode topic=codeberg-bot \
--data-urlencode 'content=Planet update is done!'
wiki-update:
if: inputs.jobs == 'wiki' || inputs.jobs == 'all'
if: inputs.jobs == 'wiki' || inputs.jobs == 'all-except-upload'
name: Update Wikipedia
runs-on: mapfilemaker
needs:
- clone-repos
container:
image: ubuntu:latest
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /media/4tbexternal:/media/4tbexternal
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Install dependencies
shell: bash
run: |
apt-get update -y
apt-get install -y jq curl wget2 rustc cargo git ca-certificates
- name: Clone wikiparser if necessary
shell: bash
run: |
if [ ! -d /media/4tbexternal/wikiparser ]; then
cd /media/4tbexternal
git clone https://codeberg.org/comaps/wikiparser.git
fi
- uses: actions/cache@v4
with:
path: "~"
key: cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Check for planet file
shell: bash
# TODO: remove debug output
run: |
if [ ! -f /media/4tbexternal/osm-planet/planet/planet-latest.osm.pbf ]; then
echo "ERROR: No file at /media/4tbexternal/osm-planet/planet/planet-latest.osm.pbf"
ls -al /media/4tbexternal/
ls -al /media/4tbexternal/osm-planet/
ls -al /media/4tbexternal/osm-planet/planet/
if [ ! -f /home/planet/planet/planet-latest.osm.pbf ]; then
echo "ERROR: No file at /home/planet/planet/planet-latest.osm.pbf"
ls -al /home/planet/
ls -al /home/planet/planet/
exit 1
fi
- name: Only get new dumps once per 30 days
shell: bash
run: |
if [[ '${{ inputs.reset }}' == 'wiki-ratelimit' ]]; then
echo "Bypassing wiki rate limit upon request."
exit 0
fi
datediff() {
d1=$(date -d "$1" +%s)
d2=$(date -d "$2" +%s)
echo $(( (d1 - d2) / 86400 ))
}
RECENTDUMPDATE=$(find /home/planet/wikipedia/dumps/ -mindepth 1 -maxdepth 1 -iname "2*" -type d | sort -n -r | head -1 | cut -d/ -f6)
TODAY=$(date +%Y%m%d)
DATEDIFF=$(datediff $TODAY $RECENTDUMPDATE)
if [ $DATEDIFF -lt 30 ]; then
echo "ERROR: The most recent wiki dump is from $RECENTDUMPDATE, $DATEDIFF days ago. Wikimedia limits users to 15 snapshot requests per month."
echo "Set the 'reset' option to 'wiki-ratelimit' to bypass this."
ls -al /home/planet/wikipedia/dumps/
exit 1
fi
- name: Update Wikipedia from Enterprise API
shell: bash
run: |
mkdir -p /media/4tbexternal/osm-planet/wikipedia/dumps
mkdir -p /media/4tbexternal/osm-planet/wikipedia/build
cd /media/4tbexternal/wikiparser
#todo: curl in download.sh can fail when rate limited and even save error messages to the output. need to validate.
#downloading all languages can also trigger rate limits or fail as well. needs work.
#also: a failure to download means a failure to build, and could result in no wiki descriptions etc.
#also-also: do we want to remove old wiki data in planet between builds? pastk: no need, its being updated / augmented
mkdir -p /home/planet/wikipedia/dumps
mkdir -p /home/planet/wikipedia/build
cd ~/wikiparser
ls -al
echo "Downloading ..."
./download.sh /media/4tbexternal/osm-planet/wikipedia/dumps
./download.sh /home/planet/wikipedia/dumps
ls -al /home/planet/wikipedia/dumps/*
echo "Running ..."
./run.sh /media/4tbexternal/osm-planet/wikipedia/build \
/media/4tbexternal/osm-planet/planet/planet-latest.osm.pbf \
/media/4tbexternal/osm-planet/wikipedia/dumps/latest/*.tar.gz
./run.sh /home/planet/wikipedia/build \
/home/planet/planet/planet-latest.osm.pbf \
/home/planet/wikipedia/dumps/latest/*.tar.gz
echo "DONE"
- name: Check that the latest dumps are present, recent, and not super tiny
shell: bash
run: |
FAILCHECK=0
# Check all .tar.gz files in /home/planet/wikipedia/dumps/latest/
for file in /home/planet/wikipedia/dumps/latest/*.tar.gz; do
# Check if file exists (handles case where glob doesn't match)
[ -e "$file" ] || continue
# Get file size in MB and modification time in days
size_mb=$(stat -f%z "$file" 2>/dev/null | awk '{print int($1/1024/1024)}' || stat -c%s "$file" | awk
'{print int($1/1024/1024)}')
days_old=$(find "$file" -mtime -7 | wc -l)
# Verify conditions
if [ "$size_mb" -lt 100 ]; then
echo "FAIL: $file is only ${size_mb}MB (< 100MB)"
FAILCHECK=1
elif [ "$days_old" -eq 0 ]; then
echo "FAIL: $file is older than 7 days"
ls -al $file
FAILCHECK=1
else
echo "PASS: $file (${size_mb}MB, modified within 7 days)"
fi
done
exit $FAILCHECK
- name: Notify Zulip
run: |
curl -X POST https://comaps.zulipchat.com/api/v1/messages \
-u $ZULIP_BOT_EMAIL:$ZULIP_API_KEY \
--data-urlencode type=stream \
--data-urlencode 'to="DevOps"' \
--data-urlencode topic=codeberg-bot \
--data-urlencode 'content=Wiki update is done!'
update-isolines:
if: inputs.jobs == 'isolines' || inputs.jobs == 'all'
if: inputs.jobs == 'isolines' || inputs.jobs == 'all-except-upload'
name: Update Isolines
runs-on: mapfilemaker
needs:
- clone-repos
container:
image: ubuntu:latest
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /media/4tbexternal:/media/4tbexternal
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Install dependencies
shell: bash
run: |
apt-get update -qq \
&& apt-get install -y --no-install-recommends \
curl \
osmctools \
rclone \
git \
ca-certificates \
openssh-client \
sshpass \
vim \
wget \
build-essential \
clang \
cmake \
python3 \
python3-pip \
python3.12-venv \
qt6-base-dev \
qt6-positioning-dev \
libc++-dev \
libfreetype-dev \
libglvnd-dev \
libgl1-mesa-dev \
libharfbuzz-dev \
libicu-dev \
libqt6svg6-dev \
libqt6positioning6-plugins \
libqt6positioning6 \
libsqlite3-dev \
libxrandr-dev \
libxinerama-dev \
libxcursor-dev \
libxi-dev \
zlib1g-dev
rm -f /usr/lib/python*/EXTERNALLY-MANAGED
pip3 install "protobuf<4"
- name: Clone main repo if necessary
shell: bash
run: |
if [ ! -d /media/4tbexternal/comaps-init ]; then
apt-get update -qq && apt-get install -y --no-install-recommends git
cd /media/4tbexternal
git clone --recurse-submodules --shallow-submodules -b rebase-generator-pastk-wb251014 --single-branch https://codeberg.org/comaps/comaps.git comaps-init
fi
- uses: actions/cache@v4
with:
path: "~"
key: cache-${{ github.run_id }}-${{ github.run_attempt }}
# TODO: we only need to update these if our SRTM or countries change
# TODO: after update, verify that sizable files exist: /home/planet/isolines/*.isolines
- name: Update Isolines
shell: bash
# TODO: preserve previous isolines version?
# TODO: cleanup the tmp-tiles dir after completion
run: |
cd /media/4tbexternal/comaps-init/
./tools/unix/build_omim.sh -R topography_generator_tool
rm -rf ../osm-planet/isolines/
mkdir ../osm-planet/isolines/
../omim-build-relwithdebinfo/topography_generator_tool \
cd ~/comaps/
./tools/unix/build_omim.sh -p ~ -R topography_generator_tool
rm -rf /home/planet/isolines/
mkdir /home/planet/isolines/
~/omim-build-relwithdebinfo/topography_generator_tool \
--profiles_path=./data/conf/isolines/isolines-profiles.json \
--countries_to_generate_path=./data/conf/isolines/countries-to-generate.json \
--tiles_isolines_out_dir=../osm-planet/isolines/tmp-tiles/ \
--countries_isolines_out_dir=../osm-planet/isolines/ \
--tiles_isolines_out_dir=/home/planet/isolines/tmp-tiles/ \
--countries_isolines_out_dir=/home/planet/isolines/ \
--data_dir=./data/ \
--srtm_path=../osm-planet/SRTM-patched-europe/ \
--threads=22
--srtm_path=/home/planet/SRTM-patched-europe/ \
--threads=96
- name: Check isolines
shell: bash
run: |
NUMISO=$(ls -al /home/planet/isolines/*.isolines | wc -l)
echo "Found $NUMISO isolines"
if [ $NUMISO -lt 10 ]; then
echo "ERROR: Did generation fail?"
exit 1
fi
- name: Notify Zulip
run: |
curl -X POST https://comaps.zulipchat.com/api/v1/messages \
-u $ZULIP_BOT_EMAIL:$ZULIP_API_KEY \
--data-urlencode type=stream \
--data-urlencode 'to="DevOps"' \
--data-urlencode topic=codeberg-bot \
--data-urlencode 'content=Isolines are done!'
update-subways:
if: inputs.jobs == 'subways' || inputs.jobs == 'all'
if: inputs.jobs == 'subways' || inputs.jobs == 'all-except-upload'
name: Update Subways
runs-on: mapfilemaker
needs:
- clone-repos
container:
image: ubuntu:latest
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /media/4tbexternal:/media/4tbexternal
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Install dependencies
shell: bash
run: |
apt-get update -qq && apt-get install -y --no-install-recommends curl osmctools osmium-tool python3-venv ca-certificates git python3-pip
rm -f /usr/lib/python*/EXTERNALLY-MANAGED
pip3 install "protobuf<4"
- name: Clone subways if necessary
shell: bash
run: |
if [ ! -d /media/4tbexternal/subways ]; then
cd /media/4tbexternal
git clone https://codeberg.org/comaps/subways.git
fi
- name: Clone main repo if necessary
shell: bash
run: |
if [ ! -d /media/4tbexternal/comaps-init ]; then
cd /media/4tbexternal
git clone --recurse-submodules --shallow-submodules -b rebase-generator-pastk-wb251014 --single-branch https://codeberg.org/comaps/comaps.git comaps-init
fi
- uses: actions/cache@v4
with:
path: "~"
key: cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Update Subways
shell: bash
run: |
cd /media/4tbexternal/comaps-init/
cd ~/comaps/
cp tools/unix/maps/settings.sh.prod tools/unix/maps/settings.sh
./tools/unix/maps/generate_subways.sh
- name: Notify Zulip
run: |
curl -X POST https://comaps.zulipchat.com/api/v1/messages \
-u $ZULIP_BOT_EMAIL:$ZULIP_API_KEY \
--data-urlencode type=stream \
--data-urlencode 'to="DevOps"' \
--data-urlencode topic=codeberg-bot \
--data-urlencode 'content=Subways are done!'
update-tiger:
if: inputs.jobs == 'tiger' || inputs.jobs == 'all'
if: inputs.jobs == 'tiger' || inputs.jobs == 'all-except-upload'
name: Update TIGER
runs-on: mapfilemaker
needs:
- clone-repos
container:
image: ubuntu:latest
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /media/4tbexternal:/media/4tbexternal
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Install dependencies
shell: bash
run: |
apt-get update -qq && apt-get install -y --no-install-recommends \
build-essential \
clang \
cmake \
ninja-build \
ca-certificates \
git \
wget2
- name: Clone main repo if necessary
shell: bash
run: |
if [ ! -d /media/4tbexternal/comaps-init ]; then
cd /media/4tbexternal
git clone --recurse-submodules --shallow-submodules -b rebase-generator-pastk-wb251014 --single-branch https://codeberg.org/comaps/comaps.git comaps-init
fi
- uses: actions/cache@v4
with:
path: "~"
key: cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Build address_parser
shell: bash
run: |
cd /media/4tbexternal/comaps-init
rm -rf ../omim-build-relwithdebinfo/CMakeCache.txt
rm -rf ../omim-build-relwithdebinfo/CMakeFiles
./tools/unix/build_omim.sh -R address_parser_tool
cd ~/comaps
#rm -rf ~/omim-build-relwithdebinfo/CMakeCache.txt
#rm -rf ~/omim-build-relwithdebinfo/CMakeFiles
./tools/unix/build_omim.sh -p ~ -R address_parser_tool
- name: Update TIGER from Nominatim
shell: bash
# TODO: use curl instead of wget2
run: |
cd /media/4tbexternal/osm-planet/
# TODO: maybe remove old osm-planet/tiger first?
cd /home/planet/
mkdir -p tiger
wget2 https://nominatim.org/data/tiger-nominatim-preprocessed-latest.csv.tar.gz
tar -xOzf tiger-nominatim-preprocessed-latest.csv.tar.gz | /media/4tbexternal/omim-build-relwithdebinfo/address_parser_tool --output_path=./tiger
cd ~/comaps
tar -xOzf /home/planet/tiger-nominatim-preprocessed-latest.csv.tar.gz | ~/omim-build-relwithdebinfo/address_parser_tool --output_path=/home/planet/tiger
generate-maps:
if: inputs.jobs == 'maps' || inputs.jobs == 'all'
if: inputs.jobs == 'maps' || inputs.jobs == 'all-except-upload'
name: Generate Maps
runs-on: mapfilemaker
needs:
- clone-repos
timeout-minutes: 40320
container:
image: ubuntu:latest
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /media/4tbexternal:/media/4tbexternal
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
options: --ulimit nofile=262144:262144
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Install dependencies
shell: bash
run: |
apt-get update -qq \
&& apt-get install -y --no-install-recommends \
curl \
osmctools \
rclone \
git \
ca-certificates \
openssh-client \
sshpass \
vim \
wget \
build-essential \
clang \
cmake \
ninja-build \
python3 \
python3-pip \
python3.12-venv \
qt6-base-dev \
qt6-positioning-dev \
libc++-dev \
libfreetype-dev \
libglvnd-dev \
libgl1-mesa-dev \
libharfbuzz-dev \
libicu-dev \
libqt6svg6-dev \
libqt6positioning6-plugins \
libqt6positioning6 \
libsqlite3-dev \
libxrandr-dev \
libxinerama-dev \
libxcursor-dev \
libxi-dev \
zlib1g-dev
- name: Clone repo if necessary
shell: bash
run: |
if [ ! -d /media/4tbexternal/comaps-init ]; then
cd /media/4tbexternal
git clone --recurse-submodules --shallow-submodules -b rebase-generator-pastk-wb251014 --single-branch https://codeberg.org/comaps/comaps.git comaps-init
fi
- uses: actions/cache@v4
with:
path: "~"
key: cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Make output folders if necessary
shell: bash
run: |
if [ ! -d /media/4tbexternal/osm-maps ]; then
mkdir -p /media/4tbexternal/osm-maps
if [ ! -d /mnt/4tbexternal/osm-maps ]; then
mkdir -p /mnt/4tbexternal/osm-maps
fi
- name: Get SRTM if necessary
# TODO: it should be a separate step like Wiki or isolines
shell: bash
run: |
if [ ! -d /media/4tbexternal/osm-planet/SRTM-patched-europe/ ]; then
if [ ! -d /home/planet/SRTM-patched-europe/ ]; then
echo "ERROR: NO SRTM"
exit 1
fi
- name: Symlink paths for repo scripts
shell: bash
run: |
mkdir -p /root/OM
ln -s /media/4tbexternal/comaps-init /root/OM/organicmaps
ln -s /media/4tbexternal/osm-planet /home/planet
ln -s /media/4tbexternal/osm-maps /root/OM/maps_build
- name: Run docker_maps_generator.sh
shell: bash
run: |
cd /root/OM/organicmaps
./tools/unix/docker_maps_generator.sh
cd ~/comaps
bash ./tools/unix/maps/docker_maps_generator.sh
- name: Notify Zulip
run: |
curl -X POST https://comaps.zulipchat.com/api/v1/messages \
-u $ZULIP_BOT_EMAIL:$ZULIP_API_KEY \
--data-urlencode type=stream \
--data-urlencode 'to="DevOps"' \
--data-urlencode topic=codeberg-bot \
--data-urlencode 'content=Generator is done!'
upload-maps:
if: inputs.jobs == 'upload'
name: Upload Maps
runs-on: mapfilemaker
container:
image: codeberg.org/comaps/maps_generator:f6d53d54f794
volumes:
- /mnt/4tbexternal/:/mnt/4tbexternal/
- /mnt/4tbexternal/osm-planet:/home/planet
concurrency:
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Write config file
run: |
mkdir -p ~/.config/rclone/
echo "${{ secrets.RCLONE_CONF }}" > ~/.config/rclone/rclone.conf
- name: Upload map files to CDNs
shell: bash
run: |
shopt -s nullglob
buildfolder=$(find /mnt/4tbexternal/osm-maps/ -mindepth 1 -maxdepth 1 -iname "2*" -type d | sort -n -r | head -1 | cut -d/ -f5)
builddate=$(find /mnt/4tbexternal/osm-maps/*/ -mindepth 1 -maxdepth 1 -iname "2*" -type d | sort -n -r | head -1 | cut -d/ -f6)
mwmfiles=( /mnt/4tbexternal/osm-maps/$buildfolder/$builddate/*.mwm )
if (( ${#mwmfiles[@]} )); then
echo "<$(date +%T)> Uploading maps from $buildfolder/$builddate..."
cd ~/comaps/tools/unix/maps
./upload_to_cdn.sh /mnt/4tbexternal/osm-maps/$buildfolder/$builddate
echo "<$(date +%T)> Finished uploading maps from $buildfolder/$builddate."
else
echo "<$(date +%T)> No MWM files in /mnt/4tbexternal/osm-maps/$buildfolder/$builddate/*.mwm, not uploading maps."
echo "<$(date +%T)> Found top level: $(ls -alt /mnt/4tbexternal/osm-maps/*)"
echo "<$(date +%T)> Found second level: $(ls -alt /mnt/4tbexternal/osm-maps/$buildfolder/*)"
fi
- name: Notify Zulip
run: |
curl -X POST https://comaps.zulipchat.com/api/v1/messages \
-u $ZULIP_BOT_EMAIL:$ZULIP_API_KEY \
--data-urlencode type=stream \
--data-urlencode 'to="DevOps"' \
--data-urlencode topic=codeberg-bot \
--data-urlencode 'content=Upload is done!'

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@ Makefile.Release
object_script.*.Debug
object_script.*.Release
compile_commands.json
*.local.*
stxxl.errlog
stxxl.log

View File

@@ -357,7 +357,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
private MenuBottomSheetItem getCancelMenuItem()
{
return new MenuBottomSheetItem(R.string.cancel, R.drawable.ic_cancel, () -> onCancelActionSelected(mSelectedItem));
return new MenuBottomSheetItem(R.string.cancel, R.drawable.ic_close, () -> onCancelActionSelected(mSelectedItem));
}
private class ItemViewHolder extends BaseInnerViewHolder<CountryItem>

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

@@ -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

@@ -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

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,536L284,732Q273,743 256,743Q239,743 228,732Q217,721 217,704Q217,687 228,676L424,480L228,284Q217,273 217,256Q217,239 228,228Q239,217 256,217Q273,217 284,228L480,424L676,228Q687,217 704,217Q721,217 732,228Q743,239 743,256Q743,273 732,284L536,480L732,676Q743,687 743,704Q743,721 732,732Q721,743 704,743Q687,743 676,732L480,536Z"/>
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,536L284,732Q273,743 256,743Q239,743 228,732Q217,721 217,704Q217,687 228,676L424,480L228,284Q217,273 217,256Q217,239 228,228Q239,217 256,217Q273,217 284,228L480,424L676,228Q687,217 704,217Q721,217 732,228Q743,239 743,256Q743,273 732,284L536,480L732,676Q743,687 743,704Q743,721 732,732Q721,743 704,743Q687,743 676,732L480,536Z"/>
</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

@@ -3,7 +3,13 @@
android:height="20dp"
android:viewportWidth="960"
android:viewportHeight="960">
<group
android:pivotX="370"
android:pivotY="480"
android:scaleX="2.2"
android:scaleY="1.7">
<path
android:pathData="M420,652q-8,0 -14,-5.5t-6,-14.5v-304q0,-9 6,-14.5t14,-5.5q2,0 14,6l145,145q5,5 7,10t2,11q0,6 -2,11t-7,10L434,646q-3,3 -6.5,4.5T420,652Z"
android:fillColor="#1f1f1f"/>
android:pathData="M640,760 L200,480l440,-280v560Z"
android:fillColor="#FFFFFF"/>
</group>
</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

@@ -22,8 +22,8 @@
android:clipChildren="false">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/floating_triangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/margin_half"
android:layout_height="@dimen/margin_half"
android:elevation="@dimen/margin_eighth"
android:layout_centerVertical="true"
app:tint="@android:color/white"

View File

@@ -36,7 +36,6 @@
android:layout_height="match_parent"
android:padding="@dimen/margin_half_double_plus"/>
</LinearLayout>
<include layout="@layout/item_divider"/>
<LinearLayout
android:orientation="horizontal"
android:minHeight="@dimen/height_block_base"
@@ -58,7 +57,6 @@
android:layout_height="match_parent"
android:padding="@dimen/margin_half_double_plus"/>
</LinearLayout>
<include layout="@layout/item_divider"/>
<LinearLayout
android:orientation="horizontal"
android:minHeight="@dimen/height_block_base"
@@ -80,7 +78,6 @@
android:layout_height="match_parent"
android:padding="@dimen/margin_half_double_plus"/>
</LinearLayout>
<include layout="@layout/item_divider"/>
<LinearLayout
android:orientation="horizontal"
android:minHeight="@dimen/height_block_base"
@@ -102,7 +99,6 @@
android:layout_height="match_parent"
android:padding="@dimen/margin_half_double_plus"/>
</LinearLayout>
<include layout="@layout/item_divider"/>
<LinearLayout
android:orientation="horizontal"
android:minHeight="@dimen/height_block_base"
@@ -124,7 +120,6 @@
android:padding="@dimen/margin_half_double_plus"
android:layout_height="match_parent"/>
</LinearLayout>
<include layout="@layout/item_divider"/>
<LinearLayout
android:orientation="horizontal"
android:minHeight="@dimen/height_block_base"

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

@@ -3,4 +3,4 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/MwmWidget.TextView.Search"
android:text="@string/clear_search"
app:drawableStartCompat="@drawable/ic_cancel"/>
app:drawableStartCompat="@drawable/ic_close"/>

View File

@@ -54,7 +54,7 @@
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/clear_the_search"
android:scaleType="center"
app:srcCompat="@drawable/ic_cancel"/>
app:srcCompat="@drawable/ic_close"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/voice_input"

View File

@@ -885,4 +885,5 @@
<string name="editor_socket">Rediger kontakt</string>
<string name="charge_socket_type1">Type 1</string>
<string name="edit_socket_info_tooltip">Opprett nye kontakter eller rediger eksisterende.</string>
<string name="avoid_paved">Unngå asfalterte veier</string>
</resources>

View File

@@ -372,7 +372,7 @@
<!-- The message when user did not find anything in the search. -->
<string name="search_not_found_query">Pobierz region, w którym szukasz lub spróbuj dodać nazwę pobliskiego miasta/wsi.</string>
<string name="search_history_title">Historia wyszukiwania</string>
<string name="search_history_text">Uzyskaj szybki dostęp do ostatniego hasła wyszukiwania.</string>
<string name="search_history_text">Zobacz swoje ostatnie wyszukiwania</string>
<string name="clear_search">Wyczyść historię wyszukiwania</string>
<!-- Place Page link to Wikipedia article (if map object has it). -->
<string name="read_in_wikipedia">Wikipedia</string>

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

@@ -28,9 +28,9 @@
<string name="type.amenity.gambling">Gambling</string>
<string name="type.leisure.adult_gaming_centre">Spillehal for voksne</string>
<string name="type.leisure.amusement_arcade">Arkadespil</string>
<string name="type.amenity.charging_station">Ladestander</string>
<string name="type.amenity.charging_station.bicycle">Cykelladestander</string>
<string name="type.amenity.charging_station.motorcar">Billadestander</string>
<string name="type.amenity.charging_station">Ladestation</string>
<string name="type.amenity.charging_station.bicycle">Ladestation til elcykler</string>
<string name="type.amenity.charging_station.motorcar">Ladestation til elbiler</string>
<string name="type.amenity.childcare">Vuggestue</string>
<string name="type.amenity.cinema">Biograf</string>
<string name="type.leisure.bowling_alley">Bowlinghal</string>
@@ -83,17 +83,17 @@
<string name="type.amenity.parking.street_side">Parkeringslomme</string>
<string name="type.amenity.parking.street_side.fee">Parkeringslomme</string>
<string name="type.amenity.parking.street_side.private">Privat parkeringslomme</string>
<string name="type.amenity.parking.lane">Parkering i vejside</string>
<string name="type.amenity.parking.lane.fee">Parkering i vejside</string>
<string name="type.amenity.parking.lane.private">Privat parkering i vejside</string>
<string name="type.amenity.parking_entrance">Parkeringsindkørsel</string>
<string name="type.amenity.parking_entrance.private">Privat parkeringsindkørsel</string>
<string name="type.amenity.parking_entrance.permissive">Parkeringsindkørsel</string>
<string name="type.amenity.parking_space">Parkeringsplads</string>
<string name="type.amenity.parking_space.permissive">Parkeringsplads</string>
<string name="type.amenity.parking_space.private">Parkeringsplads</string>
<string name="type.amenity.parking_space.underground">Parkeringsplads</string>
<string name="type.amenity.parking_space.disabled">Handicapparkeringsplads</string>
<string name="type.amenity.parking.lane">Gadeparkering</string>
<string name="type.amenity.parking.lane.fee">Gadeparkering</string>
<string name="type.amenity.parking.lane.private">Privat gadeparkering</string>
<string name="type.amenity.parking_entrance">Indkørsel til parkeringshus</string>
<string name="type.amenity.parking_entrance.private">Indkørsel til privat parkeringshus</string>
<string name="type.amenity.parking_entrance.permissive">Indkørsel til parkeringshus</string>
<string name="type.amenity.parking_space">Parkeringss</string>
<string name="type.amenity.parking_space.permissive">Parkeringss</string>
<string name="type.amenity.parking_space.private">Parkeringss</string>
<string name="type.amenity.parking_space.underground">Parkeringss</string>
<string name="type.amenity.parking_space.disabled">Handicapparkeringss</string>
<string name="type.amenity.payment_terminal">Betalingsautomat</string>
<string name="type.amenity.pharmacy">Apotek</string>
<string name="type.amenity.place_of_worship">Tilbedelsessted</string>
@@ -393,7 +393,7 @@
<string name="type.man_made.bridge">Bro</string>
<!-- These translations are used for all type.highway.*.tunnel. -->
<string name="type.highway.road.tunnel">Tunnel</string>
<string name="type.highway.secondary">Sækunder hovedvej</string>
<string name="type.highway.secondary">Sekundær hovedvej</string>
<!-- These translations are used for all type.highway.*.bridge. -->
<string name="type.highway.secondary.bridge">Bro</string>
<!-- These translations are used for all type.highway.*.tunnel. -->
@@ -964,7 +964,7 @@
<string name="type.shop.curtain">Gardinhandel</string>
<string name="type.shop.deli">Delikatessebutik</string>
<string name="type.shop.department_store">Stormagasin</string>
<string name="type.shop.doityourself">Isenkræmmer</string>
<string name="type.shop.doityourself">Byggemarked</string>
<string name="type.shop.dry_cleaning">Renseri</string>
<string name="type.shop.electronics">Elektronikbutik</string>
<string name="type.shop.erotic">Erotikbutik</string>
@@ -984,7 +984,7 @@
<string name="type.shop.hearing_aids">Høreapparatbutik</string>
<string name="type.shop.herbalist">Urtebutik</string>
<string name="type.shop.hifi">HiFi lyd</string>
<string name="type.shop.houseware">Husholdningsartikler butik</string>
<string name="type.shop.houseware">Isenkræmmer</string>
<string name="type.shop.jewelry">Smykkebutik</string>
<string name="type.shop.kitchen">Køkkenforretning</string>
<string name="type.shop.laundry">Vaskeri</string>
@@ -993,21 +993,21 @@
<string name="type.shop.mobile_phone">Mobiltelefonbutik</string>
<string name="type.shop.money_lender">Pengeudlåner</string>
<string name="type.shop.motorcycle">Motorcykelforhandler</string>
<string name="type.shop.motorcycle_repair">Motorcykel reparation</string>
<string name="type.shop.motorcycle_repair">Motorcykelværksted</string>
<string name="type.shop.music">Pladebutik</string>
<string name="type.shop.musical_instrument">Butik med musikinstrumenter</string>
<string name="type.shop.musical_instrument">Instrumentbutik</string>
<string name="type.shop.newsagent">Avis-kiosk</string>
<string name="type.shop.optician">Optiker</string>
<string name="type.shop.outdoor">Fritidsudstyr</string>
<string name="type.shop.outdoor">Friluftsbutik</string>
<string name="type.shop.outpost">Afhentningssted</string>
<string name="type.shop.pasta">Pasta butik</string>
<string name="type.shop.pasta">Pastabutik</string>
<string name="type.shop.pastry">Bagværk</string>
<string name="type.shop.pawnbroker">Pantelåner</string>
<string name="type.shop.pet">Dyrehandel</string>
<string name="type.shop.pet_grooming">Kæledyrspleje</string>
<string name="type.shop.photo">Fotobutik</string>
<string name="type.shop.rental">Udlejningsbutik</string>
<string name="type.shop.rental.bicycle">Cykeludlejningsbutik</string>
<string name="type.shop.rental.bicycle">Cykeludlejning</string>
<string name="type.shop.seafood">Fiskehandler</string>
<string name="type.shop.second_hand">Genbrugsbutik</string>
<string name="type.shop.shoes">Skobutik</string>
@@ -1015,7 +1015,7 @@
<string name="type.shop.stationery">Kontorartikler</string>
<string name="type.shop.supermarket">Supermarked</string>
<string name="type.shop.tattoo">Tatovør</string>
<string name="type.shop.tea">Tebutik</string>
<string name="type.shop.tea">Tehandel</string>
<string name="type.shop.ticket">Billetkontor</string>
<string name="type.shop.toys">Legetøjsbutik</string>
<string name="type.shop.travel_agency">Rejsebureau</string>
@@ -1026,7 +1026,7 @@
<string name="type.shop.wine">Vinhandel</string>
<string name="type.shop.agrarian">Landbrugsbutik</string>
<string name="type.shop.antiques">Antikvitetsbutik</string>
<string name="type.shop.appliance">Hvidevarer butik</string>
<string name="type.shop.appliance">Hvidevareforretning</string>
<!-- maybe change to Art Gallery for en-US when supported -->
<string name="type.shop.art">Kunstbutik</string>
<string name="type.shop.baby_goods">Børnebutik</string>
@@ -1036,8 +1036,8 @@
<string name="type.shop.charity">Velgørenhedsbutik</string>
<string name="type.shop.cheese">Ostebutik</string>
<string name="type.shop.craft">Kunst og kunsthåndværk</string>
<string name="type.shop.dairy">Mejeriprodukter</string>
<string name="type.shop.electrical">El-butik</string>
<string name="type.shop.dairy">Mejeributik</string>
<string name="type.shop.electrical">Elektrikerbutik</string>
<string name="type.shop.fishing">Fiskeributik</string>
<string name="type.shop.interior_decoration">Brugskunsthandel</string>
<string name="type.shop.lottery">Lottobutik</string>
@@ -1058,7 +1058,7 @@
<string name="type.sport.australian_football">Australsk fodbold</string>
<string name="type.sport.baseball">Baseball</string>
<string name="type.sport.basketball">Basketball</string>
<string name="type.sport.beachvolleyball">Beachvolley</string>
<string name="type.sport.beachvolleyball">Strandvolley</string>
<string name="type.sport.chess">Skak</string>
<string name="type.sport.curling">Curling</string>
<string name="type.sport.equestrian">Ridesport</string>
@@ -1163,7 +1163,7 @@
<string name="type.highway.bridleway">Ridesti</string>
<string name="type.highway.elevator">Elevator</string>
<string name="type.highway.bridleway.permissive">Ridesti</string>
<string name="type.amenity.biergarten">Traktørsted</string>
<string name="type.amenity.biergarten">Biergarten</string>
<string name="type.aerialway">Svævebane</string>
<string name="type.aerialway.cable_car">Kabinelift</string>
<string name="type.aerialway.drag_lift">Træklift</string>
@@ -1220,7 +1220,7 @@
<string name="type.cuisine.bubble_tea">Boblete</string>
<string name="type.barrier.wall">Mur</string>
<string name="type.cuisine.fish_and_chips">Fish and Chips</string>
<string name="type.highway">Hovedvej</string>
<string name="type.highway">Vej</string>
<string name="type.highway.services">Rasteplads</string>
<string name="type.internet_access">Internet</string>
<string name="type.internet_access.wlan">Trådløst internet</string>
@@ -1305,7 +1305,7 @@
<string name="type.railway.subway">Metrolinje</string>
<string name="type.public_transport.platform">Stoppested</string>
<string name="type.railway.subway.tunnel">Metrolinjetunnel</string>
<string name="type.shop.hardware">Byggemarked</string>
<string name="type.shop.hardware">Isenkræmmer</string>
<string name="type.aerialway.t.bar">Ankerlift</string>
<string name="type.traffic_calming.bump">Vejbump</string>
<string name="type.route.ferry">Færgerute</string>
@@ -1389,8 +1389,32 @@
<string name="type.barrier.wicket_gate">Portlåge</string>
<string name="type.natural.wetland.reedbed">Rørskov</string>
<string name="type.shop.lighting">Lysbutik</string>
<string name="type.amenity.bench.backless">Rygløs bænk</string>
<string name="type.amenity.charging_station.motorcar.small">Opladningspunkt til biler</string>
<string name="type.leisure.sports_centre.sport.multi">Sportscenter</string>
<string name="type.leisure.sports_centre.sport.american_football">Sportscenter</string>
<string name="type.amenity.bench.backless">Bænk</string>
<string name="type.amenity.charging_station.motorcar.small">Ladestander til biler</string>
<string name="type.leisure.sports_centre.sport.multi">Idrætscenter</string>
<string name="type.leisure.sports_centre.sport.american_football">Idrætscenter</string>
<string name="type.amenity.car_pooling">Samkørsel</string>
<string name="type.shop.telecommunication">Telefonibutik</string>
<string name="type.disusedbusiness">Ledig forretning</string>
<string name="type.amenity.boat_rental">Bådudlejning</string>
<string name="type.man_made.observatory">Observatorium</string>
<string name="type.amenity.lounger">Solseng</string>
<string name="type.leisure.bandstand">Scenepavillon</string>
<string name="type.leisure.indoor_play">Legeland</string>
<string name="type.leisure.sports_centre.sport.archery">Bueskydningscenter</string>
<string name="type.leisure.sports_centre.sport.athletics">Atletikcenter</string>
<string name="type.leisure.sports_centre.sport.baseball">Baseballcenter</string>
<string name="type.leisure.sports_centre.sport.badminton">Badmintoncenter</string>
<string name="type.leisure.sports_centre.sport.basketball">Basketballcenter</string>
<string name="type.leisure.sports_centre.sport.golf">Golfcenter</string>
<string name="type.leisure.sports_centre.sport.gymnastics">Gymnastikcenter</string>
<string name="type.man_made.telescope">Teleskop</string>
<string name="type.man_made.telescope.optical">Teleskop (Optisk)</string>
<string name="type.man_made.telescope.radio">Teleskop (Radio)</string>
<string name="type.man_made.telescope.gamma">Teleskop (Gamma)</string>
<string name="type.leisure.sports_centre.sport.swimming">Svømmehal</string>
<string name="type.amenity.food_bank">Fødevarebank</string>
<string name="type.amenity.soup_kitchen">Suppekøkken</string>
<string name="type.amenity.food_sharing">Fødevarerdeling</string>
<string name="type.amenity.give_box">Donationsbøsse</string>
</resources>

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

@@ -1363,4 +1363,13 @@
<string name="type.railway.funicular.tunnel">Kabelbanetunnel</string>
<string name="type.military">Militært</string>
<string name="type.landuse.education">Utdanningsinstitusjon</string>
<string name="type.man_made.telescope">Teleskop</string>
<string name="type.amenity.food_bank">Matsentral</string>
<string name="type.man_made.telescope.gamma">Teleskop (Gamma)</string>
<string name="type.man_made.telescope.radio">Teleskop (Radio)</string>
<string name="type.amenity.soup_kitchen">Suppekjøkken</string>
<string name="type.amenity.car_pooling">Samkjøring</string>
<string name="type.shop.telecommunication">Telekommunikasjonsbutikk</string>
<string name="type.amenity.boat_rental">Båtutleie</string>
<string name="type.man_made.observatory">Observatorium</string>
</resources>

View File

@@ -1435,4 +1435,15 @@
<string name="type.leisure.sports_centre.sport.yoga">Centrum sportowe</string>
<string name="type.leisure.fitness_centre.sport.yoga">Studio Jogi</string>
<string name="type.disusedbusiness">Pusty lokal</string>
<string name="type.amenity.boat_rental">Wypożyczalnia łodzi</string>
<string name="type.man_made.telescope">Teleskop</string>
<string name="type.man_made.telescope.optical">Teleskop optyczny</string>
<string name="type.man_made.telescope.radio">Radioteleskop</string>
<string name="type.man_made.telescope.gamma">Teleskop (prom. gamma)</string>
<string name="type.man_made.observatory">Obserwatorium</string>
<string name="type.amenity.car_pooling">Car Pooling</string>
<string name="type.shop.telecommunication">Sklep dostawcy usług telekomunikacyjnych</string>
<string name="type.amenity.food_bank">Bank żywności</string>
<string name="type.amenity.soup_kitchen">Jadłodajnia</string>
<string name="type.amenity.food_sharing">Jadłodzielnia</string>
</resources>

View File

@@ -154,4 +154,10 @@
<string name="type.amenity.charging_station.motorcar.small">Polnilno mesto za avtomobile</string>
<string name="type.amenity.childcare">Vrtec</string>
<string name="type.amenity.cinema">Kino</string>
<string name="type.amenity.boat_rental">Izposoja čolnov</string>
<string name="type.man_made.telescope">Teleskop</string>
<string name="type.man_made.telescope.optical">Teleskop (svetlobni)</string>
<string name="type.man_made.telescope.radio">Teleskop (radijski)</string>
<string name="type.man_made.telescope.gamma">Teleskop (gama žarki)</string>
<string name="type.man_made.observatory">Zvezdarna</string>
</resources>

View File

@@ -1230,7 +1230,7 @@
<string name="type.sport.soccer">Фудбал</string>
<string name="type.sport.swimming">Пливање</string>
<string name="type.sport.table_tennis">Стони тенис</string>
<string name="type.sport.tennis">Тенис</string>
<string name="type.sport.tennis">Тениски терен</string>
<string name="type.sport.volleyball">Одбојка</string>
<string name="type.sport.10pin">Куглање</string>
<string name="type.sport.9pin">Куглање</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>

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

@@ -427,7 +427,9 @@
"amenity-payment_centre": "Payment Centre",
"amenity-public_bath": "Public Bath",
"amenity-shower": "Shower",
"emergency-access_point": "5Emergency Rescue Point|Emergency Location|Emergency Marker|Emergency Access Point",
"emergency-assembly_point": "Emergency 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",

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;
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="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;}

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

@@ -2360,6 +2360,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 +2369,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 +2393,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="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

@@ -2366,6 +2366,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 +2375,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 +2399,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

@@ -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

@@ -27,7 +27,7 @@
"type.amenity.bicycle_parking" = "Cykelparkering";
"type.amenity.bicycle_rental" = "Cykeludlejning";
"type.amenity.bicycle_repair_station" = "Cykelreparationsstation";
"type.amenity.biergarten" = "Traktørsted";
"type.amenity.biergarten" = "Biergarten";
"type.amenity.brothel" = "Bordel";
"type.amenity.bureau_de_change" = "Valutaveksling";
"type.amenity.bus_station" = "Rutebilstation";
@@ -40,9 +40,9 @@
"type.amenity.gambling" = "Gambling";
"type.leisure.adult_gaming_centre" = "Spillehal for voksne";
"type.leisure.amusement_arcade" = "Arkadespil";
"type.amenity.charging_station" = "Ladestander";
"type.amenity.charging_station.bicycle" = "Cykelladestander";
"type.amenity.charging_station.motorcar" = "Billadestander";
"type.amenity.charging_station" = "Ladestation";
"type.amenity.charging_station.bicycle" = "Ladestation til elcykler";
"type.amenity.charging_station.motorcar" = "Ladestation til elbiler";
"type.amenity.childcare" = "Vuggestue";
"type.amenity.cinema" = "Biograf";
"type.leisure.bowling_alley" = "Bowlinghal";
@@ -99,17 +99,17 @@
"type.amenity.parking.street_side" = "Parkeringslomme";
"type.amenity.parking.street_side.fee" = "Parkeringslomme";
"type.amenity.parking.street_side.private" = "Privat parkeringslomme";
"type.amenity.parking.lane" = "Parkering i vejside";
"type.amenity.parking.lane.fee" = "Parkering i vejside";
"type.amenity.parking.lane.private" = "Privat parkering i vejside";
"type.amenity.parking_entrance" = "Parkeringsindkørsel";
"type.amenity.parking_entrance.private" = "Privat parkeringsindkørsel";
"type.amenity.parking_entrance.permissive" = "Parkeringsindkørsel";
"type.amenity.parking_space" = "Parkeringsplads";
"type.amenity.parking_space.permissive" = "Parkeringsplads";
"type.amenity.parking_space.private" = "Parkeringsplads";
"type.amenity.parking_space.underground" = "Parkeringsplads";
"type.amenity.parking_space.disabled" = "Handicapparkeringsplads";
"type.amenity.parking.lane" = "Gadeparkering";
"type.amenity.parking.lane.fee" = "Gadeparkering";
"type.amenity.parking.lane.private" = "Privat gadeparkering";
"type.amenity.parking_entrance" = "Indkørsel til parkeringshus";
"type.amenity.parking_entrance.private" = "Indkørsel til privat parkeringshus";
"type.amenity.parking_entrance.permissive" = "Indkørsel til parkeringshus";
"type.amenity.parking_space" = "Parkeringss";
"type.amenity.parking_space.permissive" = "Parkeringss";
"type.amenity.parking_space.private" = "Parkeringss";
"type.amenity.parking_space.underground" = "Parkeringss";
"type.amenity.parking_space.disabled" = "Handicapparkeringss";
"type.amenity.payment_terminal" = "Betalingsautomat";
"type.amenity.pharmacy" = "Apotek";
"type.amenity.place_of_worship" = "Tilbedelsessted";
@@ -384,7 +384,7 @@
"type.healthcare.psychotherapist" = "Psykoterapi";
"type.healthcare.sample_collection" = "Prøvetagning";
"type.healthcare.speech_therapist" = "Tale terapi";
"type.highway" = "Hovedvej";
"type.highway" = "Vej";
"type.highway.bridleway" = "Ridesti";
/* These translations are used for all type.highway.*.bridge. */
@@ -503,7 +503,7 @@
/* These translations are used for all type.highway.*.tunnel. */
"type.highway.road.tunnel" = "Tunnel";
"type.highway.secondary" = "Sækunder hovedvej";
"type.highway.secondary" = "Sekundær hovedvej";
/* These translations are used for all type.highway.*.bridge. */
"type.highway.secondary.bridge" = "Bro";
@@ -1216,7 +1216,7 @@
"type.shop.curtain" = "Gardinhandel";
"type.shop.deli" = "Delikatessebutik";
"type.shop.department_store" = "Stormagasin";
"type.shop.doityourself" = "Isenkræmmer";
"type.shop.doityourself" = "Byggemarked";
"type.shop.dry_cleaning" = "Renseri";
"type.shop.electronics" = "Elektronikbutik";
"type.shop.erotic" = "Erotikbutik";
@@ -1232,12 +1232,12 @@
"type.shop.greengrocer" = "Grønthandler";
"type.shop.grocery" = "Købmand";
"type.shop.hairdresser" = "Frisør";
"type.shop.hardware" = "Byggemarked";
"type.shop.hardware" = "Isenkræmmer";
"type.shop.health_food" = "Helsekostbutik";
"type.shop.hearing_aids" = "Høreapparatbutik";
"type.shop.herbalist" = "Urtebutik";
"type.shop.hifi" = "HiFi lyd";
"type.shop.houseware" = "Husholdningsartikler butik";
"type.shop.houseware" = "Isenkræmmer";
"type.shop.jewelry" = "Smykkebutik";
"type.shop.kiosk" = "Kiosk";
"type.shop.kitchen" = "Køkkenforretning";
@@ -1247,21 +1247,21 @@
"type.shop.mobile_phone" = "Mobiltelefonbutik";
"type.shop.money_lender" = "Pengeudlåner";
"type.shop.motorcycle" = "Motorcykelforhandler";
"type.shop.motorcycle_repair" = "Motorcykel reparation";
"type.shop.motorcycle_repair" = "Motorcykelværksted";
"type.shop.music" = "Pladebutik";
"type.shop.musical_instrument" = "Butik med musikinstrumenter";
"type.shop.musical_instrument" = "Instrumentbutik";
"type.shop.newsagent" = "Avis-kiosk";
"type.shop.optician" = "Optiker";
"type.shop.outdoor" = "Fritidsudstyr";
"type.shop.outdoor" = "Friluftsbutik";
"type.shop.outpost" = "Afhentningssted";
"type.shop.pasta" = "Pasta butik";
"type.shop.pasta" = "Pastabutik";
"type.shop.pastry" = "Bagværk";
"type.shop.pawnbroker" = "Pantelåner";
"type.shop.pet" = "Dyrehandel";
"type.shop.pet_grooming" = "Kæledyrspleje";
"type.shop.photo" = "Fotobutik";
"type.shop.rental" = "Udlejningsbutik";
"type.shop.rental.bicycle" = "Cykeludlejningsbutik";
"type.shop.rental.bicycle" = "Cykeludlejning";
"type.shop.seafood" = "Fiskehandler";
"type.shop.second_hand" = "Genbrugsbutik";
"type.shop.shoes" = "Skobutik";
@@ -1269,7 +1269,7 @@
"type.shop.stationery" = "Kontorartikler";
"type.shop.supermarket" = "Supermarked";
"type.shop.tattoo" = "Tatovør";
"type.shop.tea" = "Tebutik";
"type.shop.tea" = "Tehandel";
"type.shop.ticket" = "Billetkontor";
"type.shop.toys" = "Legetøjsbutik";
"type.shop.travel_agency" = "Rejsebureau";
@@ -1280,7 +1280,7 @@
"type.shop.wine" = "Vinhandel";
"type.shop.agrarian" = "Landbrugsbutik";
"type.shop.antiques" = "Antikvitetsbutik";
"type.shop.appliance" = "Hvidevarer butik";
"type.shop.appliance" = "Hvidevareforretning";
/* maybe change to Art Gallery for en-US when supported */
"type.shop.art" = "Kunstbutik";
@@ -1291,8 +1291,8 @@
"type.shop.charity" = "Velgørenhedsbutik";
"type.shop.cheese" = "Ostebutik";
"type.shop.craft" = "Kunst og kunsthåndværk";
"type.shop.dairy" = "Mejeriprodukter";
"type.shop.electrical" = "El-butik";
"type.shop.dairy" = "Mejeributik";
"type.shop.electrical" = "Elektrikerbutik";
"type.shop.fishing" = "Fiskeributik";
"type.shop.interior_decoration" = "Brugskunsthandel";
"type.shop.lottery" = "Lottobutik";
@@ -1313,7 +1313,7 @@
"type.sport.australian_football" = "Australsk fodbold";
"type.sport.baseball" = "Baseball";
"type.sport.basketball" = "Basketball";
"type.sport.beachvolleyball" = "Beachvolley";
"type.sport.beachvolleyball" = "Strandvolley";
"type.sport.bowls" = "Bowls";
"type.sport.chess" = "Skak";
"type.sport.cricket" = "Cricket";
@@ -1489,7 +1489,31 @@
"type.power.portal" = "Power Portal";
"type.building.guardhouse" = "Sikkerhedsbås";
"type.shop.lighting" = "Lysbutik";
"type.amenity.charging_station.motorcar.small" = "Opladningspunkt til biler";
"type.leisure.sports_centre.sport.american_football" = "Sportscenter";
"type.leisure.sports_centre.sport.multi" = "Sportscenter";
"type.amenity.bench.backless" = "Rygløs bænk";
"type.amenity.charging_station.motorcar.small" = "Ladestander til biler";
"type.leisure.sports_centre.sport.american_football" = "Idrætscenter";
"type.leisure.sports_centre.sport.multi" = "Idrætscenter";
"type.amenity.bench.backless" = "Bænk";
"type.man_made.observatory" = "Observatorium";
"type.man_made.telescope.optical" = "Teleskop (Optisk)";
"type.man_made.telescope.radio" = "Teleskop (Radio)";
"type.amenity.food_sharing" = "Fødevarerdeling";
"type.amenity.food_bank" = "Fødevarebank";
"type.amenity.soup_kitchen" = "Suppekøkken";
"type.man_made.telescope" = "Teleskop";
"type.amenity.give_box" = "Donationsbøsse";
"type.man_made.telescope.gamma" = "Teleskop (Gamma)";
"type.amenity.car_pooling" = "Samkørsel";
"type.shop.telecommunication" = "Telefonibutik";
"type.disusedbusiness" = "Ledig forretning";
"type.amenity.boat_rental" = "Bådudlejning";
"type.amenity.lounger" = "Solseng";
"type.leisure.bandstand" = "Scenepavillon";
"type.leisure.indoor_play" = "Legeland";
"type.leisure.sports_centre.sport.archery" = "Bueskydningscenter";
"type.leisure.sports_centre.sport.athletics" = "Atletikcenter";
"type.leisure.sports_centre.sport.baseball" = "Baseballcenter";
"type.leisure.sports_centre.sport.badminton" = "Badmintoncenter";
"type.leisure.sports_centre.sport.basketball" = "Basketballcenter";
"type.leisure.sports_centre.sport.golf" = "Golfcenter";
"type.leisure.sports_centre.sport.gymnastics" = "Gymnastikcenter";
"type.leisure.sports_centre.sport.swimming" = "Svømmehal";

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";

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";

View File

@@ -1099,3 +1099,4 @@
"offline_explanation_title" = "Offline-kart";
"avoid_steps" = "Unngå trapper";
"editor_place_doesnt_exist_description" = "Beskriv hvordan stedet ser ut nå for å sende en feilmelding til OpenStreetMap-fellesskapet";
"avoid_paved" = "Unngå asfalterte veier";

View File

@@ -1525,3 +1525,12 @@
"type.shop.lighting" = "Lampebutikk";
"type.leisure.sports_centre.sport.swimming" = "Svømmesenter";
"type.amenity.bench.backless" = "Benk uten rygg";
"type.man_made.telescope.radio" = "Teleskop (Radio)";
"type.amenity.food_bank" = "Matsentral";
"type.amenity.soup_kitchen" = "Suppekjøkken";
"type.man_made.telescope" = "Teleskop";
"type.man_made.telescope.gamma" = "Teleskop (Gamma)";
"type.amenity.car_pooling" = "Samkjøring";
"type.man_made.observatory" = "Observatorium";
"type.shop.telecommunication" = "Telekommunikasjonsbutikk";
"type.amenity.boat_rental" = "Båtutleie";

View File

@@ -487,7 +487,7 @@
/* The message when user did not find anything in the search. */
"search_not_found_query" = "Pobierz region, w którym szukasz lub spróbuj dodać nazwę pobliskiego miasta/wsi.";
"search_history_title" = "Historia wyszukiwania";
"search_history_text" = "Uzyskaj szybki dostęp do ostatniego hasła wyszukiwania.";
"search_history_text" = "Zobacz swoje ostatnie wyszukiwania.";
"clear_search" = "Wyczyść historię wyszukiwania";
/* Place Page link to Wikipedia article (if map object has it). */

View File

@@ -1527,3 +1527,14 @@
"type.leisure.bandstand" = "Muszla koncertowa";
"type.disusedbusiness" = "Pusty lokal";
"type.amenity.lounger" = "Leżak";
"type.man_made.observatory" = "Obserwatorium";
"type.man_made.telescope.optical" = "Teleskop optyczny";
"type.man_made.telescope.radio" = "Radioteleskop";
"type.man_made.telescope" = "Teleskop";
"type.man_made.telescope.gamma" = "Teleskop (prom. gamma)";
"type.amenity.boat_rental" = "Wypożyczalnia łodzi";
"type.amenity.food_sharing" = "Jadłodzielnia";
"type.amenity.food_bank" = "Bank żywności";
"type.amenity.soup_kitchen" = "Jadłodajnia";
"type.amenity.car_pooling" = "Car Pooling";
"type.shop.telecommunication" = "Sklep dostawcy usług telekomunikacyjnych";

View File

@@ -153,3 +153,9 @@
"type.amenity.love_hotel" = "Hotel za zaljubljence";
"type.amenity.charging_station.motorcar.small" = "Polnilno mesto za avtomobile";
"type.amenity.cinema" = "Kino";
"type.man_made.observatory" = "Zvezdarna";
"type.man_made.telescope.optical" = "Teleskop (svetlobni)";
"type.man_made.telescope.radio" = "Teleskop (radijski)";
"type.man_made.telescope" = "Teleskop";
"type.man_made.telescope.gamma" = "Teleskop (gama žarki)";
"type.amenity.boat_rental" = "Izposoja čolnov";

View File

@@ -190,7 +190,7 @@ UNIT_TEST(LevenshteinDFA_ErrorsMade)
}
{
vector<UniString> const allowedMisprints = {MakeUniString("yj")};
array<UniString, 11> const allowedMisprints = {MakeUniString("yj")};
size_t const prefixSize = 1;
size_t const maxErrors = 1;
string const str = "yekaterinburg";

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();

View File

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

View File

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

View File

@@ -52,7 +52,7 @@ optional<Score> GetFrcScore(Graph::Edge const & e, FunctionalRoadClass functiona
return hwClass == HighwayClass::Motorway || hwClass == HighwayClass::Trunk ? optional<Score>(kMaxScoreForFrc) : nullopt;
case FunctionalRoadClass::FRC1:
return (HighwayClass::Motorway || hwClass == HighwayClass::Trunk || hwClass == HighwayClass::Primary) ? optional<Score>(kMaxScoreForFrc)
return (hwClass == HighwayClass::Motorway || hwClass == HighwayClass::Trunk || hwClass == HighwayClass::Primary) ? optional<Score>(kMaxScoreForFrc)
: nullopt;
case FunctionalRoadClass::FRC2:

View File

@@ -0,0 +1,68 @@
Edit the rclone conf secret for Codeberg Actions, to deliver maps to i.e. /var/www/html/maps/251231 via a limited user.
apt update
apt install nginx vim
### set hostname for ssh sanity (will show in console upon next bash launch):
vim /etc/hostname
hostname cdn-XX-1
### for SSL:
sudo snap install --classic certbot
sudo certbot --nginx
### remove IPs from logging on line ~36:
vim /etc/nginx/nginx.conf
```
##
# Logging Settings
##
log_format comaps '0.0.0.0 - - [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log comaps;
```
### set up monitoring:
apt install goaccess
edit /etc/goaccess/goaccess.conf and uncomment time-format %H:%M:%S, date-format %Y-%m-%d, log-format COMBINED
vim /etc/crontab
`*/5 * * * * root /usr/bin/goaccess /var/log/nginx/access.log -o /var/www/html/monitor.html`
### set up basic http pages/responses:
cd /var/www/html/
mkdir maps
rm index.nginx-debian.html
wget https://www.comaps.app/favicon.ico
vim robots.txt
```
User-agent: *
Disallow: /
```
vim index.html
```
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>CoMaps CDN</title>
</head>
<body>
<h1>This is a CDN for <a href="https://comaps.app">CoMaps</a></h1>
<h2>Resources:</h2>
<ol>
<li>CoMaps <a href="https://cdn.comaps.app/subway/">subway validator</a></li>
<li>CoMaps <a href="https://comaps.app/news/">News</a></li>
<li><a href="https://comaps.app/donate/">Donate</a></li>
</ol>
</body>
</html>
```

View File

@@ -1,5 +1,5 @@
import os
import subprocess
class MapsGeneratorError(Exception):
pass
@@ -35,9 +35,24 @@ class FailedTest(MapsGeneratorError):
def wait_and_raise_if_fail(p):
if p.wait() != os.EX_OK:
args = p.args
logs = p.output.name
if p.error.name != logs:
logs += " and " + p.error.name
msg = f"The launch of {args.pop(0)} failed.\nArguments used: {' '.join(args)}\nSee details in {logs}"
raise BadExitStatusError(msg)
if type(p) is subprocess.Popen:
args = p.args
stdout = p.stdout
stderr = p.stderr
logs = None
errors = None
if type(stdout) is not type(None):
logs = stdout.read(256).decode()
if type(stderr) is not type(None):
errors = stderr.read(256).decode()
if errors != logs:
logs += " and " + errors
msg = f"The launch of {args.pop(0)} failed.\nArguments used: {' '.join(args)}\nSee details in {logs}"
raise BadExitStatusError(msg)
else:
args = p.args
logs = p.output.name
if p.error.name != logs:
logs += " and " + p.error.name
msg = f"The launch of {args.pop(0)} failed.\nArguments used: {' '.join(args)}\nSee details in {logs}"
raise BadExitStatusError(msg)

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