mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-21 13:53:37 +00:00
Compare commits
3 Commits
yannikblos
...
release/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abe97b2ce0 | ||
|
|
2e91e64056 | ||
|
|
d1bac84c7a |
@@ -1,382 +0,0 @@
|
|||||||
name: map-generator
|
|
||||||
on:
|
|
||||||
workflow_dispatch: # Manual trigger
|
|
||||||
inputs:
|
|
||||||
jobs:
|
|
||||||
description: 'Which job(s) to run right now?'
|
|
||||||
required: true
|
|
||||||
default: 'all'
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- all
|
|
||||||
- copy-coasts
|
|
||||||
- planet
|
|
||||||
- wiki
|
|
||||||
- isolines
|
|
||||||
- subways
|
|
||||||
- tiger
|
|
||||||
- maps
|
|
||||||
|
|
||||||
env:
|
|
||||||
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 }}
|
|
||||||
DEBIAN_FRONTEND: noninteractive
|
|
||||||
TZ: Etc/UTC
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
copy-coasts:
|
|
||||||
if: inputs.jobs == 'copy-coasts' || inputs.jobs == 'all'
|
|
||||||
name: Copy Previously Generated Coasts
|
|
||||||
runs-on: mapfilemaker
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
volumes:
|
|
||||||
- /media/4tbexternal:/media/4tbexternal
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-map-generator-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
steps:
|
|
||||||
- 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
|
|
||||||
fi
|
|
||||||
|
|
||||||
update-planet:
|
|
||||||
if: inputs.jobs == 'planet' || inputs.jobs == 'all'
|
|
||||||
name: Update Planet
|
|
||||||
runs-on: mapfilemaker
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
volumes:
|
|
||||||
- /media/4tbexternal:/media/4tbexternal
|
|
||||||
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
|
|
||||||
run: |
|
|
||||||
if [ ! -d /media/4tbexternal/osm-planet/planet/ ]; then
|
|
||||||
mkdir -p /media/4tbexternal/osm-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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
|
|
||||||
wiki-update:
|
|
||||||
if: inputs.jobs == 'wiki' || inputs.jobs == 'all'
|
|
||||||
name: Update Wikipedia
|
|
||||||
runs-on: mapfilemaker
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
volumes:
|
|
||||||
- /media/4tbexternal:/media/4tbexternal
|
|
||||||
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
|
|
||||||
- name: Check for planet file
|
|
||||||
shell: bash
|
|
||||||
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/
|
|
||||||
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
|
|
||||||
ls -al
|
|
||||||
echo "Downloading ..."
|
|
||||||
./download.sh /media/4tbexternal/osm-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
|
|
||||||
echo "DONE"
|
|
||||||
|
|
||||||
update-isolines:
|
|
||||||
if: inputs.jobs == 'isolines' || inputs.jobs == 'all'
|
|
||||||
name: Update Isolines
|
|
||||||
runs-on: mapfilemaker
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
volumes:
|
|
||||||
- /media/4tbexternal:/media/4tbexternal
|
|
||||||
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
|
|
||||||
- name: Update Isolines
|
|
||||||
shell: bash
|
|
||||||
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 \
|
|
||||||
--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/ \
|
|
||||||
--data_dir=./data/ \
|
|
||||||
--srtm_path=../osm-planet/SRTM-patched-europe/ \
|
|
||||||
--threads=22
|
|
||||||
|
|
||||||
update-subways:
|
|
||||||
if: inputs.jobs == 'subways' || inputs.jobs == 'all'
|
|
||||||
name: Update Subways
|
|
||||||
runs-on: mapfilemaker
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
volumes:
|
|
||||||
- /media/4tbexternal:/media/4tbexternal
|
|
||||||
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
|
|
||||||
- name: Update Subways
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cd /media/4tbexternal/comaps-init/
|
|
||||||
cp tools/unix/maps/settings.sh.prod tools/unix/maps/settings.sh
|
|
||||||
./tools/unix/maps/generate_subways.sh
|
|
||||||
|
|
||||||
update-tiger:
|
|
||||||
if: inputs.jobs == 'tiger' || inputs.jobs == 'all'
|
|
||||||
name: Update TIGER
|
|
||||||
runs-on: mapfilemaker
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
volumes:
|
|
||||||
- /media/4tbexternal:/media/4tbexternal
|
|
||||||
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
|
|
||||||
- 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
|
|
||||||
- name: Update TIGER from Nominatim
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cd /media/4tbexternal/osm-planet/
|
|
||||||
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
|
|
||||||
|
|
||||||
generate-maps:
|
|
||||||
if: inputs.jobs == 'maps' || inputs.jobs == 'all'
|
|
||||||
name: Generate Maps
|
|
||||||
runs-on: mapfilemaker
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
volumes:
|
|
||||||
- /media/4tbexternal:/media/4tbexternal
|
|
||||||
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
|
|
||||||
- name: Make output folders if necessary
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ ! -d /media/4tbexternal/osm-maps ]; then
|
|
||||||
mkdir -p /media/4tbexternal/osm-maps
|
|
||||||
fi
|
|
||||||
- name: Get SRTM if necessary
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ ! -d /media/4tbexternal/osm-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
|
|
||||||
@@ -175,10 +175,10 @@ if (NOT PLATFORM_IPHONE AND NOT PLATFORM_ANDROID)
|
|||||||
find_package(Qt6 COMPONENTS REQUIRED ${qt_components} PATHS $ENV{QT_PATH} /opt/homebrew/opt/qt@6 /usr/local/opt/qt@6 /usr/lib/x86_64-linux-gnu/qt6)
|
find_package(Qt6 COMPONENTS REQUIRED ${qt_components} PATHS $ENV{QT_PATH} /opt/homebrew/opt/qt@6 /usr/local/opt/qt@6 /usr/lib/x86_64-linux-gnu/qt6)
|
||||||
|
|
||||||
set(MINIMUM_REQUIRED_QT_VERSION 6.4.0)
|
set(MINIMUM_REQUIRED_QT_VERSION 6.4.0)
|
||||||
if (Qt6_VERSION VERSION_LESS ${MINIMUM_REQUIRED_QT_VERSION})
|
if (Qt6Widgets_VERSION VERSION_LESS ${MINIMUM_REQUIRED_QT_VERSION})
|
||||||
message(FATAL_ERROR "Unsupported Qt version: ${Qt6_VERSION}, the minimum required is ${MINIMUM_REQUIRED_QT_VERSION}")
|
message(FATAL_ERROR "Unsupported Qt version: ${Qt6Widgets_VERSION}, the minimum required is ${MINIMUM_REQUIRED_QT_VERSION}")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Found Qt version: ${Qt6_VERSION}")
|
message(STATUS "Found Qt version: ${Qt6Widgets_VERSION}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,10 @@
|
|||||||
<img src="https://img.shields.io/github/license/comaps/comaps?style=for-the-badge&logo=opensourceinitiative&logoColor=white&color=588157" alt="License"/>
|
<img src="https://img.shields.io/github/license/comaps/comaps?style=for-the-badge&logo=opensourceinitiative&logoColor=white&color=588157" alt="License"/>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/comaps/comaps/actions/workflows/android-check.yaml">
|
<a href="https://github.com/comaps/comaps/actions/workflows/android-check.yaml">
|
||||||
<img src="https://img.shields.io/github/actions/workflow/status/comaps/comaps/.github/workflows/android-check.yaml?label=Android%20Build&logo=android&logoColor=white&style=for-the-badge" alt="Android Build Status"/>
|
<img src="https://img.shields.io/github/actions/workflow/status/comaps/comaps/.github/workflows/android-check.yaml?label=Android%20Build&logo=android&logoColor=white&style=for-the-badge&color=588157" alt="Android Build Status"/>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/comaps/comaps/actions/workflows/ios-check.yaml">
|
<a href="https://github.com/comaps/comaps/actions/workflows/ios-check.yaml">
|
||||||
<img src="https://img.shields.io/github/actions/workflow/status/comaps/comaps/.github/workflows/ios-check.yaml?label=iOS%20Build&logo=apple&logoColor=white&style=for-the-badge" alt="iOS Build Status"/>
|
<img src="https://img.shields.io/github/actions/workflow/status/comaps/comaps/.github/workflows/ios-check.yaml?label=iOS%20Build&logo=apple&logoColor=white&style=for-the-badge&color=588157" alt="iOS Build Status"/>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://opencollective.com/comaps">
|
<a href="https://opencollective.com/comaps">
|
||||||
<img src="https://img.shields.io/opencollective/all/comaps?label=Open%20Collective%20Donors&logo=opencollective&logoColor=white&style=for-the-badge&color=588157" alt="Open Collective Donors"/>
|
<img src="https://img.shields.io/opencollective/all/comaps?label=Open%20Collective%20Donors&logo=opencollective&logoColor=white&style=for-the-badge&color=588157" alt="Open Collective Donors"/>
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
CoMaps - Mapas ensin conexón con privacidá
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Лесна навигация - Открийте повече от вашето пътуване - Подкрепен от общността
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
CoMaps - Хайкинг, Велосипед, Пътуване без Интернет
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
• OpenStreetMap-Daten vom 4. November
|
• Karten-Daten vom 6. September
|
||||||
• Aktualisierte Karten-Icons, inkl. Farben für Unterhaltungs-, Sport- & andere Unternehmen
|
• Zeitstrafen für Radrouting
|
||||||
• Informationen zu Steckdosen an EV-Ladestationen
|
• Farbige POI-Beschriftungen in Autonavigation
|
||||||
• Symbole für Sportzentren, Veranstaltungsorte, Massagesalons, Gästehäuser und einige stillgelegte Unternehmen
|
• POI-Suche nach Filialnamen
|
||||||
• Verbesserungen bei der Suche
|
• Abspannportale, Sicherheitskabinen & Büros hinzugefügt
|
||||||
• Behebung eines Absturzes bei der Suche
|
• Aktualisierte Symbole für Türme, Nachtclubs, Apotheken und Fahnenmasten
|
||||||
• Verbesserte Sprachführung während der Navigation
|
• Lesezeichen-Farbe in GPX-Exporten
|
||||||
Weitere Änderungen finden in unseren Codeberg-Versionshinweisen!
|
• Farbfüllung von Fußgängerbereiche auf Plätzen
|
||||||
|
• Android Auto: Anzeige Ausfahrtsnummern in Kreisverkehren
|
||||||
|
Weitere Änderungen in Codeberg-Versionshinweisen!
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
• OpenStreetMap data as of November 4
|
• OpenStreetMap data as of September 6
|
||||||
• Recategorized map icons including some new colors for entertainment, sports and other businesses
|
• Turn penalties for bicycle routing
|
||||||
• Display info about available sockets on charging stations
|
• Colored POI labels for car navigation map style
|
||||||
• Added bandstands, backless benches and loungers
|
• Search POIs by branch name
|
||||||
• New icons for different sport centres, event venues, massage salons, guest houses and some disused businesses
|
• Added power portals, security booths and offices
|
||||||
• Multiple search improvements and crash fix
|
• Update icons for towers, nightclubs, chemists, flagpoles
|
||||||
• Improved voice guidance during navigation
|
• Save bookmark color to GPX exports
|
||||||
|
• Color fill pedestrian parts of squares
|
||||||
|
• Android Auto: display roundabout exit numbers
|
||||||
Check our Codeberg release notes for more changes!
|
Check our Codeberg release notes for more changes!
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
• Datos OSM del 04/11
|
• Datos a 6 de septiembre
|
||||||
• Iconos del mapa recategorizados, incluyendo nuevos colores
|
• Penalizaciones de giros en rutas de bici
|
||||||
• Visualización de información sobre enchufes disponibles en estaciones de recarga
|
• Etiquetas de puntos de interés en color en navegación
|
||||||
• Adición de iconos para diferentes centros deportivos, lugares de eventos, salones de masajes, posadas y algunos establecimientos comerciales desactivados
|
• Buscar por nombre de sucursal
|
||||||
• Varias mejoras y correcciones de errores en la búsqueda
|
• Añadir portales de energía, cabinas de seguridad y oficinas
|
||||||
• Mejora en la orientación por voz durante la navegación
|
• Nuevos iconos: torres, discotecas, parafarmacias y mástiles
|
||||||
|
• Guardar color en exportaciones GPX
|
||||||
|
• Colorear áreas peatonales de plazas
|
||||||
|
• Android Auto: mostrar números de salida de rotondas
|
||||||
Más detalles en Codeberg
|
Más detalles en Codeberg
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
• Données OpenStreetMap au 4 novembre
|
• Données OSM du 06 septembre
|
||||||
• Recatégorisation des icônes sur la carte avec ajout de nouvelles couleurs pour certains types de lieux
|
• Pénalités dans les calculs d'itinéraires vélos
|
||||||
• Affichage des prises sur les bornes électriques
|
• Ajout de labels colorés en mode navigation
|
||||||
• Ajout d'icônes pour les centres sportifs, salles d'événements, salon de massage et autres lieux
|
• Support du tag branch dans la recherche
|
||||||
• Multiple améliorations dans la recherche
|
• Ajout des portiques électriques, postes de sécurité
|
||||||
• Correction d'un plantage dans la recherche
|
• Mise à jour des icônes de tours, boîtes de nuits, chimiste et mat
|
||||||
• Amélioration de la synthèse vocale durant la navigation
|
• Enregistrement de la couleur des signets dans les exports GPX
|
||||||
|
• Android Auto: Affichage du numéro de sortie des ronds-points
|
||||||
Plus d'informations sur notre Codeberg
|
Plus d'informations sur notre Codeberg
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
Aplikasi peta gratis & sumber terbuka yang dipimpin komunitas, berbasis data OpenStreetMap dan diperkuat dengan komitmen terhadap transparansi, privasi, serta non-profit. CoMaps adalah turunan dari Organic Maps, yang merupakan turunan dari Maps.ME.
|
|
||||||
|
|
||||||
Baca lebih lanjut tentang alasan proyek ini dan arahnya di <b><i>codeberg.org/comaps</i></b>.
|
|
||||||
Bergabunglah dengan komunitas dan bantu menjadikan aplikasi peta terbaik
|
|
||||||
• Gunakan aplikasi ini dan sebarkan
|
|
||||||
• Beri masukan dan laporkan masalah
|
|
||||||
• Perbarui data peta di aplikasi atau di situs OpenStreetMap
|
|
||||||
|
|
||||||
‣ <b>Fokus Offline</b>: Rencanakan dan navigasikan perjalananmu di luar negeri tanpa perlu layanan seluler, cari titik saat hiking jauh, dll. Semua fungsi aplikasi dirancang untuk bekerja offline.
|
|
||||||
‣ <b>Menghormati Privasi</b>: Aplikasi ini dirancang dengan privasi sebagai prioritas – tidak mengidentifikasi orang, tidak melacak, dan tidak mengumpulkan informasi pribadi. Bebas iklan.
|
|
||||||
‣ <b>Sederhana dan Rapi</b>: fitur penting yang mudah digunakan dan langsung berfungsi.
|
|
||||||
‣ <b>Hemat Baterai dan Ruang</b>: Tidak menguras baterai seperti aplikasi navigasi lain. Peta ringkas menghemat ruang berharga di ponselmu.
|
|
||||||
‣ <b>Gratis dan Dibangun oleh Komunitas</b>: Orang seperti kamu membantu membangun aplikasi ini dengan menambahkan tempat ke OpenStreetMap, menguji serta memberi masukan fitur, dan menyumbangkan keterampilan pengembangan maupun dana.
|
|
||||||
‣ <b>Terbuka dan Transparan</b>: Pengambilan keputusan dan keuangan transparan, non-profit, dan sepenuhnya sumber terbuka.
|
|
||||||
|
|
||||||
<b>Fitur Utama</b>:
|
|
||||||
• Peta detail yang bisa diunduh, dengan tempat yang tidak ada di Google Maps
|
|
||||||
• Mode outdoor dengan sorotan jalur hiking, area berkemah, sumber air, puncak, garis kontur, dll
|
|
||||||
• Jalur pejalan kaki dan jalur sepeda
|
|
||||||
• Titik menarik seperti restoran, SPBU, hotel, toko, tempat wisata, dan banyak lagi
|
|
||||||
• Pencarian berdasarkan nama, alamat, atau kategori titik menarik
|
|
||||||
• Navigasi dengan suara untuk berjalan, bersepeda, atau berkendara
|
|
||||||
• Tandai tempat favoritmu dengan sekali tap
|
|
||||||
• Artikel Wikipedia offline
|
|
||||||
• Layer dan rute transportasi subway
|
|
||||||
• Rekaman jejak
|
|
||||||
• Ekspor dan impor bookmark serta jejak dalam format KML, KMZ, GPX
|
|
||||||
• Mode gelap untuk digunakan saat malam
|
|
||||||
• Tingkatkan data peta untuk semua orang dengan editor bawaan sederhana
|
|
||||||
|
|
||||||
<b>Kebebasan Ada di Sini</b>
|
|
||||||
Temukan perjalananmu, jelajahi dunia dengan privasi dan komunitas di garis depan!
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Navigasi peta mudah – Temukan lebih banyak – Didukung oleh komunitas
|
|
||||||
10
android/app/src/fdroid/play/listings/it-IT/release-notes.txt
Normal file
10
android/app/src/fdroid/play/listings/it-IT/release-notes.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
• OpenStreetMap aggiornato al 6 Settembre
|
||||||
|
• Bici: miglior stima del tempo di percorrenza
|
||||||
|
• Auto: punti d'interesse colorati
|
||||||
|
• Cerca i punti d'interesse tramite filiale
|
||||||
|
• Aggiunte strutture alta tensione, cabine di sicurezza e uffici
|
||||||
|
• Aggiornate le icone per torri, discoteche, farmacie e aste per bandiere
|
||||||
|
• Salva il colore dei Preferiti nel GPX
|
||||||
|
• Evidenziate le aree pedonali nelle piazze
|
||||||
|
• AndroidAuto: aggiunto il numero dell'uscita nelle rotonde
|
||||||
|
Visita Codeberg per ulteriori dettagli
|
||||||
@@ -1 +1 @@
|
|||||||
Enkel kartnavigering - Opplev mere på din reise - Drevet av felleskapet
|
Lett kart navigasjon - Opplev mere på din reise - Drevet av felleskapet
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
CoMaps - Gå, sykle, kjøre offline med personvern
|
CoMaps - Gå tur, sykkel, kjør - med personvern
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Łatwa nawigacja po mapie - Odkryj więcej z podróży - Wspierane przez społeczność
|
Łatwa nawigacja – Odkryj więcej ze swojej podróży – Wspierane przez społeczność
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
• Dados OSM de 04/11
|
• Dados OSM de 6/09
|
||||||
• Ícones do mapa recategorizados, incluindo novas cores
|
• Penalidades de conversão para bicicleta
|
||||||
• Exibição de informações sobre tomadas disponíveis em eletropostos
|
• Etiquetas de POI coloridas para o estilo do mapa de navegação de carros
|
||||||
• Adição de ícones para diferentes centros esportivos, locais de eventos, salões de massagem, pousadas e alguns estabelecimentos comerciais desativados
|
• Busca de POIs por nome de filial
|
||||||
• Diversas melhorias e correção de erro na busca
|
• Adição de portais de energia, guaritas e escritórios
|
||||||
• Melhoria na orientação por voz durante a navegação
|
• Atualização de ícones para torres, discotecas, farmácias e mastros
|
||||||
Confira nossas notas de lançamento no Codeberg para mais detalhes!
|
• Salva a cor dos favoritos nas exportações GPX
|
||||||
|
• Preenchimento de praças pavimentadas
|
||||||
|
• Android Auto: exibe números de saída de rotatória
|
||||||
|
Confira nossas notas de lançamento do Codeberg para mais mudanças
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
Uma aplicação pela comunidade, grátis e ‘open-source’, de mapas baseada em dados do OpenStreetMap e reforçada com compromisso para transparência, privacidade e sem fins lucrativos. CoMaps é um fork/spin-off de Organic Maps, que, por sua vez, é um fork de Maps.ME
|
|
||||||
|
|
||||||
Leia sobre as razões deste projeto e a sua direção em <b><i>codeberg.org/comaps</i></b>.
|
|
||||||
Junte-se à comunidade e ajude a fazer a melhor aplicação de mapas
|
|
||||||
• Use a aplicação e partilhe-a com outros
|
|
||||||
• Dê ‘feedback’ e reporte problemas
|
|
||||||
• Atualize os dados de mapa na aplicação ou no site do OpenStreetMap
|
|
||||||
|
|
||||||
‣ <b>Simples e Polida</b>: funcionalidades essenciais fáceis que “somente funcionam”.
|
|
||||||
‣ <b>Foco Offline</b>: Planeie e navegue as suas viagens no estrangeiro sem dados móveis, procure locais numa caminhada distante, etc. Todas as funções da aplicação foram criadas com intenção de serem usadas sem internet.
|
|
||||||
‣ <b>Respeita a privacidade</b>: A aplicação foi criada com privacidade em mente — não identifica o utilizador, não rastreia, e não usa a sua informação pessoal. Sem anúncios.
|
|
||||||
‣ <b>Saves Your Battery and Space</b>: Não esgota a sua bateria ao contrário de outras aplicações. Mapas compactos salvam espaço no seu telemóvel.
|
|
||||||
‣ <b>Gratuita e Feita pela Comunidade</b>: Pessoas como si ajudam a criar a aplicação ao adicionar locais ao OpenStreetMap, testando e dando opiniões em funcionalidades e contribuindo com dotes de desenvolvimento e dinheiro.
|
|
||||||
‣ <b>Decisões e Finanças Abertas e Transparentes, Sem fins lucrativos e ‘Open-Source’.</b>
|
|
||||||
|
|
||||||
<b>Funcionalidades principais</b>:
|
|
||||||
• Mapas detalhados descarregáveis com locais que não estão disponíveis com o Google Maps
|
|
||||||
• Modo ao Ar Livre com trilhos de caminhada destacados, acampamentos, fontes de água, cumes, curvas de nível, etc
|
|
||||||
• Caminhos pedestres e ciclovias
|
|
||||||
• Pontos de interesse como restaurantes, estações de serviço, hotéis, lojas, atrações e muitos mais
|
|
||||||
• Pesquise por nome, endereço, ou por categoria de ponto de interesse
|
|
||||||
• Navegação com anúncios de voz ao caminhar, pedalar ou conduzir
|
|
||||||
• Marque os seus locais favoritos com um único clique
|
|
||||||
• Artigos da Wikipédia Offline
|
|
||||||
• Camada de metro e direções
|
|
||||||
• Gravação de Percursos
|
|
||||||
• Exportar e importar marcadores e percursos em formatos KML, KMZ, GPX
|
|
||||||
• Um modo escuro para usar durante a noite
|
|
||||||
• Melhore a informação do mapa para todos com um editor básico embebido
|
|
||||||
|
|
||||||
<b>A liberdade chegou</b>
|
|
||||||
Descubra a sua jornada, navegue o mundo com privacidade e a comunidade à frente!
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
• Карты OpenStreetMap от 4 ноября
|
• Данные на 6 сентября
|
||||||
• Обновлены цвета иконок на карте, добавлены новые цвета для развлечений, спорта, некоторых бизнесов
|
• Предупреждения на веломаршруте
|
||||||
• На зарядных станциях показываются имеющиеся типы разъёмов
|
• Цветные метки POI при автонавигации
|
||||||
• Добавлены эстрады, скамейки без спинок и лежаки
|
• Поиск POI по названию ветки
|
||||||
• Новые иконки для разных спорт центров, массажных салонов, гостевых домов, некоторых закрытых бизнесов
|
• Добавлены высоковольтные опоры, помещения охраны и офисы
|
||||||
• Несколько улучшений и исправлений в поиске
|
• Обновлены значки башен,вышек,мачт,ночных клубов,аптек
|
||||||
• Улучшены голосовые подсказки при навигации
|
• Сохранение цвета закладок при экспорте в GPX (через OM)
|
||||||
Подробнее смотрите на codeberg.org/comaps/comaps/releases
|
• Отображение цветом пешеходных зон
|
||||||
|
• Android Auto: отображение номеров съездов на кольцевых развязках
|
||||||
|
Посмотрите примечания к выпуску Codeberg, чтобы узнать о других изменениях!
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
Brezplačno in odprtokodno zemljevidno orodje, ki ga vodi skupnost, temelji na podatkih OpenStreetMap in je okrepljena s predanostjo transparentnosti, zasebnosti in nedobičkonosnosti. CoMaps je izpeljanka OrganicMaps, ta pa je izpeljanka Maps.ME.
|
|
||||||
|
|
||||||
Preverite si o razlogih za ta projekt in njegovi usmerjenosti na <b><i>codeberg.org/comaps</i></b>.
|
|
||||||
Pridružite se skupnosti in pomagajte narediti najboljše zemljevidno orodje
|
|
||||||
• Uporabljajte orodje in širite glas o njem
|
|
||||||
• Dajajte povratne informacije in poročajte o napakah
|
|
||||||
• Posodabljajte podatke zemljevida v tem orodju ali na spletni strani OpenStreetMap
|
|
||||||
|
|
||||||
‣ <b>Osredotočeno na uporabo brez povezave</b>: Načrtujte in se usmerjajte na vašem potovanju v tujini vrez potrebe po mobilnih podatkih, iščite vmesne točke potocanja ko ste na daljšem pohodu ipd. Vse zmogljivosti orodja so zasnovane za delo brez povezave.
|
|
||||||
‣ <b>Spoštovanje zasebnosti</b>: orodje je zasnovano z mislijo na zasebnost – ne prepoznava oseb, ne sledi in ne zbira osebnih podatkov. Brez oglasov.
|
|
||||||
‣ <b>Preprosto in dodelano</b>: nujne zmogljivosti, enostavne za uporabo, ki preprosto delujejo.
|
|
||||||
‣ <b>Prihrani vašo baterijo in prostor.</b>: ne izčrpava vaše baterije kakor druga usmerjevalna orodja. Strnjeni zemljevidi prihranijo dragocen prostor na vašem telefonu.
|
|
||||||
‣ <b>Brezplačno in ustvarjeno v skupnosti</b>: ljudje kot ste vi pomagajo ustvarjati to orodje, tako da dodajajo kraje na OpenStreetMap, preizkušajo in dajejo povratne informacije o zmogljivostih in prispevajo svoje razvijalske sposobnosti in sredstva.
|
|
||||||
‣ <b>Odprto in transparentno odločanje in finance, nedobičkonosno in popolnoma odprtokodno.</b>
|
|
||||||
|
|
||||||
<b>Glavne zmogljivosti</b>:
|
|
||||||
• Prenosljivi podrobni zemljevidi s kraji, ki na Googlovoh zemljevidih niso na voljo.
|
|
||||||
• Prikaz za dejavnosti na prostem s poudarjenimi pohodniškimi potmi, tabornimi prostori, vodnimi viri, vrhovi, plastnicami itd.
|
|
||||||
• Pešpoti in kolesarke poti
|
|
||||||
• Kraji zanimanja, npr. restavracije, bencinske črpalke, hoteli, trgovine, znamenitosti in mnogo več
|
|
||||||
• Iščite po imenu, hišnemu naslovu ali po vrsti
|
|
||||||
• Usmerjanje z glasovnimi obvestili za hojo, kolesarjenje ali vožnjo avtomobila.
|
|
||||||
• Zaznamujte svoje najljubše kraje s preprostim dotikom
|
|
||||||
• Wikipedijini članki brez povezave
|
|
||||||
• Prometna plast podzemne železnice z usmerjanjem
|
|
||||||
• Izvozite ali uvozite zaznamke in sledi v oblikah KML, KMZ, GPX
|
|
||||||
• Temni prikaz za uporabo ponoči
|
|
||||||
• Izboljšajtw podatke zemljevida za vse z uporabo vgrajenega urejevalnika
|
|
||||||
|
|
||||||
<b>Svoboda je tu</b>
|
|
||||||
Odkijte več o vašem potovanju, usmerjajte se po svetu s poudarkom na zasebnosti in skupnostnem delovanju!
|
|
||||||
@@ -1 +1 @@
|
|||||||
Enostavno usmerjanje – Odkrij več o svojem potovanju – Podprto v skupnosti
|
Enostavna navigacija – Odkrij več o svojem potovanju – Podprto v skupnosti
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Comaps- Vandra, Cykla, Kör Offline, Privat
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
这是一个由社区主导、以 OpenStreetMap 数据为基础的自由开源地图应用,建立在我们对运营透明、隐私安全和非营利性的承诺之上。CoMaps 是 Organic Maps 的分叉/衍生产品,而 Organic Maps 则是 Maps.ME 的分叉。
|
这是一个由社区主导、以 OpenStreetMap 数据为基础的免费开源地图应用,建立在我们对运营透明、隐私安全和非营利性的承诺之上。CoMaps 是 Organic Maps 的分叉/衍生产品,而 Organic Maps 则是 Maps.ME 的分叉。
|
||||||
|
|
||||||
如需了解此项目诞生的原因及未来方向,请访问 <b><i>codeberg.org/comaps</i></b>。
|
如需了解此项目诞生的原因及未来方向,请访问 <b><i>codeberg.org/comaps</i></b>。
|
||||||
加入以上社区,和大家一起打造最优质的地图应用
|
加入以上社区,和大家一起打造最优质的地图应用
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
‣ <b>尊重隐私</b>:开发者们在设计 CoMaps 时,优先考虑的是保护用户隐私。CoMaps 无法识别用户身份、无法跟踪用户活动,也无法收集个人信息。此外,CoMaps 不会也不能显示任何广告。
|
‣ <b>尊重隐私</b>:开发者们在设计 CoMaps 时,优先考虑的是保护用户隐私。CoMaps 无法识别用户身份、无法跟踪用户活动,也无法收集个人信息。此外,CoMaps 不会也不能显示任何广告。
|
||||||
‣ <b>简洁精致</b>:轻便易用、不出差错的基本功能。
|
‣ <b>简洁精致</b>:轻便易用、不出差错的基本功能。
|
||||||
‣ <b>节省电池电量和空间</b>:不会像其他导航应用那样耗电。精简的地图可以节省宝贵的手机空间。
|
‣ <b>节省电池电量和空间</b>:不会像其他导航应用那样耗电。精简的地图可以节省宝贵的手机空间。
|
||||||
‣ <b>自由且社区共建</b>:如同您一样的用户通过向 OpenStreetMap 添加地点、测试功能并提供反馈、无私地贡献自己的编程技能和资金,协力开发了 CoMaps。
|
‣ <b>由社区合作创建的免费应用</b>:如同您一样的用户通过向 OpenStreetMap 添加地点、测试功能并提供反馈、无私地贡献自己的编程技能和资金,协力开发了 CoMaps。
|
||||||
‣ <b>决策问责、财务透明、非营利性、完全开源。</b>
|
‣ <b>决策问责、财务透明、非营利性、完全开源。</b>
|
||||||
|
|
||||||
<b>主要功能</b>:
|
<b>主要功能</b>:
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
• 地铁交通图层和路线指示
|
• 地铁交通图层和路线指示
|
||||||
• 轨迹记录
|
• 轨迹记录
|
||||||
• 以 KML、KMZ 和 GPX 格式导出和导入书签和轨迹
|
• 以 KML、KMZ 和 GPX 格式导出和导入书签和轨迹
|
||||||
• 深色模式,适配夜间使用场景
|
• 选择天暗后自动开启的黑暗模式
|
||||||
• 使用基本的内置编辑器来编辑 OpenStreetMap 地点,帮助大家改进地图数据
|
• 使用基本的内置编辑器来编辑 OpenStreetMap 地点,帮助大家改进地图数据
|
||||||
|
|
||||||
<b>自由在此</b>
|
<b>自由在此</b>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
version: 2025.03.02-7-FDroid+25030207
|
version: 2025.10.08-3-FDroid+25100803
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Лесна навигация - Открийте повече от вашето пътуване - Подкрепен от общността
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
CoMaps - Пътуване с Приватност
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Navigasi peta mudah – Temukan lebih banyak – Didukung oleh komunitas
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
CoMaps - Jelajah dengan Privat
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Enkel kartnavigering - Opplev mere på din reise - Drevet av felleskapet
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
CoMaps -Naviger med personvern
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Łatwa nawigacja po mapie - Odkryj więcej z podróży - Wspierane przez społeczność
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
Uma aplicação pela comunidade, grátis e ‘open-source’, de mapas baseada em dados do OpenStreetMap e reforçada com compromisso para transparência, privacidade e sem fins lucrativos.
|
|
||||||
|
|
||||||
Junte-se à comunidade e ajude a fazer a melhor aplicação de mapas
|
|
||||||
• Use a aplicação e partilhe-a com outros
|
|
||||||
• Dê ‘feedback’ e reporte problemas
|
|
||||||
• Atualize os dados de mapa na aplicação ou no site do OpenStreetMap
|
|
||||||
|
|
||||||
<i>O seu ‘feedback’ e ‘reviews’ de 5 estrelas são a melhor maneira de nos ajudar!</i>
|
|
||||||
|
|
||||||
‣ <b>Simples e Polida</b>: funcionalidades essenciais fáceis que “somente funcionam”.
|
|
||||||
‣ <b>Foco Offline</b>: Planeie e navegue as suas viagens no estrangeiro sem dados móveis, procure locais numa caminhada distante, etc. Todas as funções da aplicação foram criadas com intenção de serem usadas sem internet.
|
|
||||||
‣ <b>Respeita a privacidade</b>: A aplicação foi criada com privacidade em mente — não identifica o utilizador, não rastreia, e não usa a sua informação pessoal. Sem anúncios.
|
|
||||||
‣ <b>Saves Your Battery and Space</b>: Não esgota a sua bateria ao contrário de outras aplicações. Mapas compactos salvam espaço no seu telemóvel.
|
|
||||||
‣ <b>Gratuita e Feita pela Comunidade</b>: Pessoas como si ajudam a criar a aplicação ao adicionar locais ao OpenStreetMap, testando e dando opiniões em funcionalidades e contribuindo com dotes de desenvolvimento e dinheiro.
|
|
||||||
‣ <b>Decisões e Finanças Abertas e Transparentes, Sem fins lucrativos e ‘Open-Source’.</b>
|
|
||||||
|
|
||||||
<b>Funcionalidades principais</b>:
|
|
||||||
• Mapas detalhados descarregáveis com locais que não estão disponíveis com o Google Maps
|
|
||||||
• Modo ao Ar Livre com trilhos de caminhada destacados, acampamentos, fontes de água, cumes, curvas de nível, etc
|
|
||||||
• Caminhos pedestres e ciclovias
|
|
||||||
• Pontos de interesse como restaurantes, estações de serviço, hotéis, lojas, atrações e muitos mais
|
|
||||||
• Pesquise por nome, endereço, ou por categoria de ponto de interesse
|
|
||||||
• Navegação com anúncios de voz ao caminhar, pedalar ou conduzir
|
|
||||||
• Marque os seus locais favoritos com um único clique
|
|
||||||
• Artigos da Wikipédia Offline
|
|
||||||
• Camada de metro e direções
|
|
||||||
• Gravação de Percursos
|
|
||||||
• Exportar e importar marcadores e percursos em formatos KML, KMZ, GPX
|
|
||||||
• Um modo escuro para usar durante a noite
|
|
||||||
• Melhore a informação do mapa para todos com um editor básico embebido
|
|
||||||
• Suporte para ‘Android Auto’
|
|
||||||
|
|
||||||
Por favor, reporte problemas da aplicação, sugira ideias e junte-se à nossa comunidade no website <b><i>comaps.app</i></b>.
|
|
||||||
|
|
||||||
<b>A liberdade chegou</b>
|
|
||||||
Descubra a sua jornada, navegue o mundo com privacidade e a comunidade à frente!
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
Skupnostno vodena brezplačna in odprtokodna aplikacija za zemljevide, ki temelji na podatkih OpenStreetMap, ter je okrepljena z zavezanostjo k transparentnosti, zasebnosti, in ostajanju neprofitne organizacije.
|
|
||||||
|
|
||||||
Pridružite se skupnosti in pomagajte ustvariti najboljšo aplikacijo za zemljevide.
|
|
||||||
• Uporabljajte aplikacijo in jo priporočajte drugim.
|
|
||||||
• Podajte povratne informacije in poročajte o težavah.
|
|
||||||
• Posodobite podatke zemljevida v aplikaciji ali na spletni strani OpenStreetMap.
|
|
||||||
|
|
||||||
<i>Vaše povratne informacije in 5-zvezdične ocene so najboljša podpora za nas!</i>
|
|
||||||
|
|
||||||
‣ <b>Preprostost in izpopolnjenost</b>: bistvene, enostavne za uporabo funkcije, ki preprosto delujejo.
|
|
||||||
‣ <b>Osredotočena na delovanje brez internetne povezave</b>: načrtujte in navigirajte svoje potovanje v tujini brez potrebe po mobilni povezavi, iščite točke na poti med daljšo pohodniško turo, itd. Vse funkcije aplikacije so zasnovane za delovanje brez internetne povezave.
|
|
||||||
‣ <b>Spoštovanje zasebnosti</b>: aplikacija je zasnovana z mislijo na zasebnost – ne identificira ljudi, ne sledi in ne zbira osebnih podatkov. Brez oglasov.
|
|
||||||
‣ <b>Varčuje z baterijo in prostorom</b>: ne izčrpava baterije kot druge navigacijske aplikacije. Kompaktni zemljevidi varčujejo dragoceni prostor na vašem telefonu.
|
|
||||||
‣ <b>Brezplačna in ustvarjena s pomočjo skupnosti</b>: ljudje, kot ste vi, so pomagali ustvariti aplikacijo z dodajanjem krajev v OpenStreetMap, testiranjem in dajanjem povratnih informacij o funkcijah ter prispevanjem svojih razvojnih veščin in denarja.
|
|
||||||
‣ <b>Odprto in pregledno odločanje in finance, neprofitna in popolnoma odprtokodna aplikacija.
|
|
||||||
|
|
||||||
<b>Glavne značilnosti</b>:
|
|
||||||
• Podrobni zemljevidi z mesti, ki niso na voljo v Google Maps, ki jih lahko prenesete
|
|
||||||
• Način za uporabo na prostem z označenimi pohodniškimi potmi, kampi, vodnimi viri, vrhovi, višinskimi krivuljami itd.
|
|
||||||
• Pešpoti in kolesarske poti
|
|
||||||
• Zanimivosti, kot so restavracije, bencinske črpalke, hoteli, trgovine, znamenitosti in še veliko več
|
|
||||||
• Iskanje po imenu, naslovu ali kategoriji zanimivih točk
|
|
||||||
• Navigacija z glasovnimi napovedmi za hojo, kolesarjenje ali vožnjo
|
|
||||||
• Z enim dotikom dodajte svoje priljubljene kraje v zaznamke
|
|
||||||
• Članki iz Wikipedije za uporabo brez internetne povezave
|
|
||||||
• Plast podzemne železnice in navodila za pot
|
|
||||||
• Sledenje poti
|
|
||||||
• Izvoz in uvoz zaznamkov in poti v formatih KML, KMZ, GPX
|
|
||||||
• Temni način za uporabo ponoči
|
|
||||||
• Izboljšajte zemljevidne podatke za vse z uporabo vgrajenega osnovnega urejevalnika.
|
|
||||||
• Podpora za Android Auto.
|
|
||||||
|
|
||||||
Prijavite težave z aplikacijo, predlagajte ideje in se pridružite naši skupnosti na spletni strani <b><i>comaps.app</i></b>.
|
|
||||||
|
|
||||||
<b>Svoboda je tu</b>
|
|
||||||
Odkrijte svojo pot, raziskujte svet z zasebnostjo in skupnostjo v ospredju!
|
|
||||||
@@ -1 +1 @@
|
|||||||
Enostavno usmerjanje – Odkrij več o svojem potovanju – Podprto v skupnosti
|
Enostavna navigacija – Odkrij več o svojem potovanju – Podprto v skupnosti
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
CoMaps - Usmerjajte zasebno
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Comaps- Navigera Privat
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
这是一个由社区主导、以 OpenStreetMap 数据为基础的自由开源地图应用,建立在我们对运营透明、隐私安全和非营利性的承诺之上。
|
这是一个由社区主导、以 OpenStreetMap 数据为基础的免费开源地图应用,建立在我们对运营透明、隐私安全和非营利性的承诺之上。
|
||||||
|
|
||||||
加入社区,和大家一起打造最优质的地图应用
|
加入社区,和大家一起打造最优质的地图应用
|
||||||
• 使用 CoMaps 的同时也分享推荐给周围的人
|
• 使用 CoMaps 的同时也分享推荐给周围的人
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
‣ <b>以提供离线服务为核心</b>:无需移动网络即可规划和导航您的海外旅行,郊外远足时仍可搜索航点等等。所有功能均可离线使用。
|
‣ <b>以提供离线服务为核心</b>:无需移动网络即可规划和导航您的海外旅行,郊外远足时仍可搜索航点等等。所有功能均可离线使用。
|
||||||
‣ <b>尊重隐私</b>:开发者们在设计 CoMaps 时,优先考虑的是保护用户隐私。CoMaps 无法识别用户身份、无法跟踪用户活动,也无法收集个人信息。此外,CoMaps 不会也不能显示任何广告。
|
‣ <b>尊重隐私</b>:开发者们在设计 CoMaps 时,优先考虑的是保护用户隐私。CoMaps 无法识别用户身份、无法跟踪用户活动,也无法收集个人信息。此外,CoMaps 不会也不能显示任何广告。
|
||||||
‣ <b>节省电池电量和空间</b>:不会像其他导航应用那样耗电。精简的地图可以节省宝贵的手机空间。
|
‣ <b>节省电池电量和空间</b>:不会像其他导航应用那样耗电。精简的地图可以节省宝贵的手机空间。
|
||||||
‣ <b>自由且社区共建</b>:如同您一样的用户通过向 OpenStreetMap 添加地点、测试功能并提供反馈、无私地贡献自己的编程技能和资金,协力开发了 CoMaps。
|
‣ <b>由社区合作创建的免费应用</b>:如同您一样的用户通过向 OpenStreetMap 添加地点、测试功能并提供反馈、无私地贡献自己的编程技能和资金,协力开发了 CoMaps。
|
||||||
‣ <b>决策问责、财务透明、非营利性、完全开源。</b>
|
‣ <b>决策问责、财务透明、非营利性、完全开源。</b>
|
||||||
|
|
||||||
<b>主要功能</b>:
|
<b>主要功能</b>:
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
• 地铁交通图层和路线指示
|
• 地铁交通图层和路线指示
|
||||||
• 轨迹记录
|
• 轨迹记录
|
||||||
• 以 KML、KMZ 和 GPX 格式导出和导入书签和轨迹
|
• 以 KML、KMZ 和 GPX 格式导出和导入书签和轨迹
|
||||||
• 深色模式,适配夜间使用场景
|
• 选择天暗后自动开启的黑暗模式
|
||||||
• 使用基本的内置编辑器来编辑 OpenStreetMap 地点,帮助大家改进地图数据
|
• 使用基本的内置编辑器来编辑 OpenStreetMap 地点,帮助大家改进地图数据
|
||||||
• 支持 Android Auto
|
• 支持 Android Auto
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,6 @@
|
|||||||
<!-- Allows for config and orientation change without killing/restarting main activity -->
|
<!-- Allows for config and orientation change without killing/restarting main activity -->
|
||||||
<activity
|
<activity
|
||||||
android:name="app.organicmaps.SplashActivity"
|
android:name="app.organicmaps.SplashActivity"
|
||||||
android:theme="@style/MwmTheme.Splash"
|
|
||||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
|
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
|
||||||
android:screenOrientation="fullUser"
|
android:screenOrientation="fullUser"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
@@ -350,7 +349,6 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="app.organicmaps.DownloadResourcesLegacyActivity"
|
android:name="app.organicmaps.DownloadResourcesLegacyActivity"
|
||||||
android:theme="@style/MwmTheme.DownloadResourcesLegacy"
|
|
||||||
android:configChanges="orientation|screenLayout|screenSize"
|
android:configChanges="orientation|screenLayout|screenSize"
|
||||||
android:screenOrientation="fullUser"/>
|
android:screenOrientation="fullUser"/>
|
||||||
|
|
||||||
@@ -367,7 +365,6 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="app.organicmaps.MwmActivity"
|
android:name="app.organicmaps.MwmActivity"
|
||||||
android:theme="@style/MwmTheme.MainActivity"
|
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:configChanges="uiMode"
|
android:configChanges="uiMode"
|
||||||
android:screenOrientation="fullUser"
|
android:screenOrientation="fullUser"
|
||||||
@@ -389,7 +386,6 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="app.organicmaps.search.SearchActivity"
|
android:name="app.organicmaps.search.SearchActivity"
|
||||||
android:theme="@style/MwmTheme.CardBg"
|
|
||||||
android:configChanges="orientation|screenLayout|screenSize"
|
android:configChanges="orientation|screenLayout|screenSize"
|
||||||
android:screenOrientation="fullUser"
|
android:screenOrientation="fullUser"
|
||||||
android:label="@string/search_map"
|
android:label="@string/search_map"
|
||||||
@@ -416,7 +412,6 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="app.organicmaps.bookmarks.BookmarkCategoriesActivity"
|
android:name="app.organicmaps.bookmarks.BookmarkCategoriesActivity"
|
||||||
android:theme="@style/MwmTheme.WindowBg"
|
|
||||||
android:configChanges="orientation|screenLayout|screenSize"
|
android:configChanges="orientation|screenLayout|screenSize"
|
||||||
android:screenOrientation="fullUser"
|
android:screenOrientation="fullUser"
|
||||||
android:label="@string/bookmarks_and_tracks"
|
android:label="@string/bookmarks_and_tracks"
|
||||||
@@ -425,7 +420,6 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="app.organicmaps.bookmarks.BookmarkListActivity"
|
android:name="app.organicmaps.bookmarks.BookmarkListActivity"
|
||||||
android:theme="@style/MwmTheme.CardBg"
|
|
||||||
android:configChanges="orientation|screenLayout|screenSize"
|
android:configChanges="orientation|screenLayout|screenSize"
|
||||||
android:screenOrientation="fullUser"
|
android:screenOrientation="fullUser"
|
||||||
android:label="@string/bookmarks"
|
android:label="@string/bookmarks"
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import androidx.annotation.CallSuper;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import app.organicmaps.base.BaseMwmFragmentActivity;
|
import app.organicmaps.base.BaseMwmFragmentActivity;
|
||||||
import app.organicmaps.downloader.MapManagerHelper;
|
import app.organicmaps.downloader.MapManagerHelper;
|
||||||
@@ -437,4 +438,11 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||||||
.setOnDismissListener(dialog -> mAlertDialog = null)
|
.setOnDismissListener(dialog -> mAlertDialog = null)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StyleRes
|
||||||
|
public int getThemeResourceId(@NonNull String theme)
|
||||||
|
{
|
||||||
|
return R.style.MwmTheme_DownloadResourcesLegacy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
210
android/app/src/main/java/app/organicmaps/MapFragment.java
Normal file
210
android/app/src/main/java/app/organicmaps/MapFragment.java
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
package app.organicmaps;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.res.ConfigurationHelper;
|
||||||
|
import app.organicmaps.base.BaseMwmFragment;
|
||||||
|
import app.organicmaps.sdk.Map;
|
||||||
|
import app.organicmaps.sdk.MapRenderingListener;
|
||||||
|
import app.organicmaps.sdk.display.DisplayType;
|
||||||
|
import app.organicmaps.sdk.util.log.Logger;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
|
public class MapFragment extends BaseMwmFragment implements View.OnTouchListener, SurfaceHolder.Callback
|
||||||
|
{
|
||||||
|
private static final String TAG = MapFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Map mMap = new Map(DisplayType.Device);
|
||||||
|
|
||||||
|
public void updateCompassOffset(int offsetX, int offsetY)
|
||||||
|
{
|
||||||
|
mMap.updateCompassOffset(requireContext(), offsetX, offsetY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBottomWidgetsOffset(int offsetX, int offsetY)
|
||||||
|
{
|
||||||
|
mMap.updateBottomWidgetsOffset(requireContext(), offsetX, offsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMyPositionRoutingOffset(int offsetY)
|
||||||
|
{
|
||||||
|
mMap.updateMyPositionRoutingOffset(offsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroySurface(boolean activityIsChangingConfigurations)
|
||||||
|
{
|
||||||
|
mMap.onSurfaceDestroyed(activityIsChangingConfigurations, isAdded());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isContextCreated()
|
||||||
|
{
|
||||||
|
return mMap.isContextCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
int densityDpi;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||||
|
densityDpi = ConfigurationHelper.getDensityDpi(requireContext().getResources());
|
||||||
|
else
|
||||||
|
densityDpi = getDensityDpiOld();
|
||||||
|
|
||||||
|
mMap.onSurfaceCreated(requireContext(), surfaceHolder.getSurface(), surfaceHolder.getSurfaceFrame(), densityDpi);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
mMap.onSurfaceChanged(requireContext(), surfaceHolder.getSurface(), surfaceHolder.getSurfaceFrame(),
|
||||||
|
surfaceHolder.isCreating());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
mMap.onSurfaceDestroyed(requireActivity().isChangingConfigurations(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
super.onAttach(context);
|
||||||
|
|
||||||
|
mMap.setLocationHelper(MwmApplication.from(requireContext()).getLocationHelper());
|
||||||
|
mMap.setMapRenderingListener((MapRenderingListener) context);
|
||||||
|
mMap.setCallbackUnsupported(this::reportUnsupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetach()
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
super.onDetach();
|
||||||
|
mMap.setMapRenderingListener(null);
|
||||||
|
mMap.setCallbackUnsupported(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle b)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
super.onCreate(b);
|
||||||
|
setRetainInstance(true);
|
||||||
|
boolean launchByDeepLink = false;
|
||||||
|
Bundle args = getArguments();
|
||||||
|
if (args != null)
|
||||||
|
launchByDeepLink = args.getBoolean(Map.ARG_LAUNCH_BY_DEEP_LINK);
|
||||||
|
mMap.onCreate(launchByDeepLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart()
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
super.onStart();
|
||||||
|
mMap.onStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop()
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
super.onStop();
|
||||||
|
mMap.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause()
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
super.onPause();
|
||||||
|
mMap.onPause(requireContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume()
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
super.onResume();
|
||||||
|
mMap.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
final View view = inflater.inflate(R.layout.fragment_map, container, false);
|
||||||
|
final SurfaceView mSurfaceView = view.findViewById(R.id.map_surfaceview);
|
||||||
|
mSurfaceView.getHolder().addCallback(this);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View view, MotionEvent event)
|
||||||
|
{
|
||||||
|
int action = event.getActionMasked();
|
||||||
|
int pointerIndex = event.getActionIndex();
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case MotionEvent.ACTION_POINTER_UP -> action = Map.NATIVE_ACTION_UP;
|
||||||
|
case MotionEvent.ACTION_UP ->
|
||||||
|
{
|
||||||
|
action = Map.NATIVE_ACTION_UP;
|
||||||
|
pointerIndex = 0;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_POINTER_DOWN -> action = Map.NATIVE_ACTION_DOWN;
|
||||||
|
case MotionEvent.ACTION_DOWN ->
|
||||||
|
{
|
||||||
|
action = Map.NATIVE_ACTION_DOWN;
|
||||||
|
pointerIndex = 0;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_MOVE ->
|
||||||
|
{
|
||||||
|
action = Map.NATIVE_ACTION_MOVE;
|
||||||
|
pointerIndex = Map.INVALID_POINTER_MASK;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_CANCEL -> action = Map.NATIVE_ACTION_CANCEL;
|
||||||
|
}
|
||||||
|
Map.onTouch(action, event, pointerIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyOnSurfaceDestroyed(@NonNull Runnable task)
|
||||||
|
{
|
||||||
|
mMap.onSurfaceDestroyed(false, true);
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportUnsupported()
|
||||||
|
{
|
||||||
|
new MaterialAlertDialogBuilder(requireContext(), R.style.MwmTheme_AlertDialog)
|
||||||
|
.setMessage(R.string.unsupported_phone)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(R.string.close, (dlg, which) -> requireActivity().moveTaskToBack(true))
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getDensityDpiOld()
|
||||||
|
{
|
||||||
|
final DisplayMetrics metrics = new DisplayMetrics();
|
||||||
|
requireActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||||
|
return metrics.densityDpi;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,7 @@ import androidx.annotation.CallSuper;
|
|||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -84,7 +85,6 @@ import app.organicmaps.routing.RoutingPlanInplaceController;
|
|||||||
import app.organicmaps.sdk.ChoosePositionMode;
|
import app.organicmaps.sdk.ChoosePositionMode;
|
||||||
import app.organicmaps.sdk.Framework;
|
import app.organicmaps.sdk.Framework;
|
||||||
import app.organicmaps.sdk.Map;
|
import app.organicmaps.sdk.Map;
|
||||||
import app.organicmaps.sdk.MapController;
|
|
||||||
import app.organicmaps.sdk.MapRenderingListener;
|
import app.organicmaps.sdk.MapRenderingListener;
|
||||||
import app.organicmaps.sdk.PlacePageActivationListener;
|
import app.organicmaps.sdk.PlacePageActivationListener;
|
||||||
import app.organicmaps.sdk.Router;
|
import app.organicmaps.sdk.Router;
|
||||||
@@ -138,10 +138,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class MwmActivity extends BaseMwmFragmentActivity
|
public class MwmActivity extends BaseMwmFragmentActivity
|
||||||
implements PlacePageActivationListener, MapRenderingListener, RoutingController.Container, LocationListener,
|
implements PlacePageActivationListener, View.OnTouchListener, MapRenderingListener, RoutingController.Container,
|
||||||
SensorListener, LocationState.ModeChangeListener, RoutingPlanInplaceController.RoutingPlanListener,
|
LocationListener, SensorListener, LocationState.ModeChangeListener,
|
||||||
RoutingBottomMenuListener, BookmarkManager.BookmarksLoadingListener,
|
RoutingPlanInplaceController.RoutingPlanListener, RoutingBottomMenuListener,
|
||||||
FloatingSearchToolbarController.SearchToolbarListener,
|
BookmarkManager.BookmarksLoadingListener, FloatingSearchToolbarController.SearchToolbarListener,
|
||||||
MenuBottomSheetFragment.MenuBottomSheetInterfaceWithHeader,
|
MenuBottomSheetFragment.MenuBottomSheetInterfaceWithHeader,
|
||||||
PlacePageController.PlacePageRouteSettingsListener, MapButtonsController.MapButtonClickListener,
|
PlacePageController.PlacePageRouteSettingsListener, MapButtonsController.MapButtonClickListener,
|
||||||
DisplayChangedListener
|
DisplayChangedListener
|
||||||
@@ -171,9 +171,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
|
|
||||||
private static final String POWER_SAVE_DISCLAIMER_SHOWN = "POWER_SAVE_DISCLAIMER_SHOWN";
|
private static final String POWER_SAVE_DISCLAIMER_SHOWN = "POWER_SAVE_DISCLAIMER_SHOWN";
|
||||||
|
|
||||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
@Nullable
|
||||||
@NonNull
|
private MapFragment mMapFragment;
|
||||||
private MapController mMapController;
|
|
||||||
|
|
||||||
private View mPointChooser;
|
private View mPointChooser;
|
||||||
private MaterialToolbar mPointChooserToolbar;
|
private MaterialToolbar mPointChooserToolbar;
|
||||||
@@ -246,7 +245,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
ManageRouteBottomSheet mManageRouteBottomSheet;
|
ManageRouteBottomSheet mManageRouteBottomSheet;
|
||||||
|
|
||||||
private boolean mRemoveDisplayListener = true;
|
private boolean mRemoveDisplayListener = true;
|
||||||
private static int mLastUiMode = Configuration.UI_MODE_TYPE_UNDEFINED;
|
private int mLastUiMode = Configuration.UI_MODE_TYPE_UNDEFINED;
|
||||||
|
|
||||||
public interface LeftAnimationTrackListener
|
public interface LeftAnimationTrackListener
|
||||||
{
|
{
|
||||||
@@ -456,12 +455,25 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StyleRes
|
||||||
|
protected int getThemeResourceId(@NonNull String theme)
|
||||||
|
{
|
||||||
|
if (Config.UiTheme.isDefault(theme))
|
||||||
|
return R.style.MwmTheme_MainActivity;
|
||||||
|
|
||||||
|
if (Config.UiTheme.isNight(theme))
|
||||||
|
return R.style.MwmTheme_Night_MainActivity;
|
||||||
|
|
||||||
|
return super.getThemeResourceId(theme);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisplayChangedToCar(@NonNull Runnable onTaskFinishedCallback)
|
public void onDisplayChangedToCar(@NonNull Runnable onTaskFinishedCallback)
|
||||||
{
|
{
|
||||||
mRemoveDisplayListener = false;
|
mRemoveDisplayListener = false;
|
||||||
startActivity(new Intent(this, MapPlaceholderActivity.class));
|
startActivity(new Intent(this, MapPlaceholderActivity.class));
|
||||||
mMapController.setOnDestroyListener(onTaskFinishedCallback);
|
Objects.requireNonNull(mMapFragment).notifyOnSurfaceDestroyed(onTaskFinishedCallback);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,15 +482,13 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
{
|
{
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
|
|
||||||
final int newType = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
|
final int newUiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
|
||||||
final int oldType = mLastUiMode & Configuration.UI_MODE_TYPE_MASK;
|
final boolean newUiModeIsCarConnected = newUiMode == Configuration.UI_MODE_TYPE_CAR;
|
||||||
|
final boolean newUiModeIsCarDisconnected =
|
||||||
|
mLastUiMode == Configuration.UI_MODE_TYPE_CAR && newUiMode == Configuration.UI_MODE_TYPE_NORMAL;
|
||||||
|
mLastUiMode = newUiMode;
|
||||||
|
|
||||||
mLastUiMode = newConfig.uiMode;
|
if (newUiModeIsCarConnected || newUiModeIsCarDisconnected)
|
||||||
|
|
||||||
final boolean carModeChanged =
|
|
||||||
newType != oldType && (newType == Configuration.UI_MODE_TYPE_CAR || oldType == Configuration.UI_MODE_TYPE_CAR);
|
|
||||||
|
|
||||||
if (carModeChanged)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
makeNavigationBarTransparentInLightMode();
|
makeNavigationBarTransparentInLightMode();
|
||||||
@@ -540,7 +550,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
updateViewsInsets();
|
updateViewsInsets();
|
||||||
|
|
||||||
if (getIntent().getBooleanExtra(EXTRA_UPDATE_THEME, false))
|
if (getIntent().getBooleanExtra(EXTRA_UPDATE_THEME, false))
|
||||||
ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
|
ThemeSwitcher.INSTANCE.restart(isMapRendererActive());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* onRenderingInitializationFinished() hook is not called when MwmActivity is recreated with the already
|
* onRenderingInitializationFinished() hook is not called when MwmActivity is recreated with the already
|
||||||
@@ -608,10 +618,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
|
|
||||||
private void initViews(boolean isLaunchByDeeplink)
|
private void initViews(boolean isLaunchByDeeplink)
|
||||||
{
|
{
|
||||||
mMapController = new MapController(findViewById(R.id.map), MwmApplication.from(this).getLocationHelper(), this,
|
initMap(isLaunchByDeeplink);
|
||||||
this::reportUnsupported, isLaunchByDeeplink);
|
|
||||||
getLifecycle().addObserver(mMapController);
|
|
||||||
|
|
||||||
initNavigationButtons();
|
initNavigationButtons();
|
||||||
|
|
||||||
if (!mIsTabletLayout)
|
if (!mIsTabletLayout)
|
||||||
@@ -725,7 +732,16 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
private void showPositionChooser(ChoosePositionMode mode, boolean isBusiness, boolean applyPosition)
|
private void showPositionChooser(ChoosePositionMode mode, boolean isBusiness, boolean applyPosition)
|
||||||
{
|
{
|
||||||
closeFloatingToolbarsAndPanels(false);
|
closeFloatingToolbarsAndPanels(false);
|
||||||
|
if (mMapFragment != null)
|
||||||
|
{
|
||||||
|
final View mapView = mMapFragment.getView();
|
||||||
|
if (mapView != null)
|
||||||
|
{
|
||||||
|
int width = mapView.getWidth();
|
||||||
|
int height = mapView.getHeight();
|
||||||
|
Framework.nativeSetVisibleRect(0, 0, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
UiUtils.show(mPointChooser);
|
UiUtils.show(mPointChooser);
|
||||||
mMapButtonsViewModel.setButtonsHidden(true);
|
mMapButtonsViewModel.setButtonsHidden(true);
|
||||||
ChoosePositionMode.set(mode, isBusiness, applyPosition);
|
ChoosePositionMode.set(mode, isBusiness, applyPosition);
|
||||||
@@ -744,6 +760,29 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initMap(boolean isLaunchByDeepLink)
|
||||||
|
{
|
||||||
|
final FragmentManager manager = getSupportFragmentManager();
|
||||||
|
mMapFragment = (MapFragment) manager.findFragmentByTag(MapFragment.class.getName());
|
||||||
|
if (mMapFragment == null)
|
||||||
|
{
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putBoolean(Map.ARG_LAUNCH_BY_DEEP_LINK, isLaunchByDeepLink);
|
||||||
|
final FragmentFactory factory = manager.getFragmentFactory();
|
||||||
|
mMapFragment = (MapFragment) factory.instantiate(getClassLoader(), MapFragment.class.getName());
|
||||||
|
mMapFragment.setArguments(args);
|
||||||
|
manager.beginTransaction()
|
||||||
|
.replace(R.id.map_fragment_container, mMapFragment, MapFragment.class.getName())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
View container = findViewById(R.id.map_fragment_container);
|
||||||
|
if (container != null)
|
||||||
|
{
|
||||||
|
container.setOnTouchListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initNavigationButtons()
|
private void initNavigationButtons()
|
||||||
{
|
{
|
||||||
prepareNavigationButtons();
|
prepareNavigationButtons();
|
||||||
@@ -1172,7 +1211,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
{
|
{
|
||||||
setIntent(intent);
|
setIntent(intent);
|
||||||
super.onNewIntent(intent);
|
super.onNewIntent(intent);
|
||||||
if (mMapController.isRenderingActive())
|
if (isMapRendererActive())
|
||||||
processIntent();
|
processIntent();
|
||||||
if (intent.getAction() != null && intent.getAction().equals(TrackRecordingService.STOP_TRACK_RECORDING))
|
if (intent.getAction() != null && intent.getAction().equals(TrackRecordingService.STOP_TRACK_RECORDING))
|
||||||
{
|
{
|
||||||
@@ -1182,12 +1221,17 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isMapRendererActive()
|
||||||
|
{
|
||||||
|
return mMapFragment != null && Map.isEngineCreated() && mMapFragment.isContextCreated();
|
||||||
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
super.onResume();
|
super.onResume();
|
||||||
ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
|
ThemeSwitcher.INSTANCE.restart(isMapRendererActive());
|
||||||
refreshSearchToolbar();
|
refreshSearchToolbar();
|
||||||
setFullscreen(isFullscreen());
|
setFullscreen(isFullscreen());
|
||||||
makeNavigationBarTransparentInLightMode();
|
makeNavigationBarTransparentInLightMode();
|
||||||
@@ -1205,6 +1249,15 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
MwmApplication.from(this).getSensorHelper().addListener(this);
|
MwmApplication.from(this).getSensorHelper().addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recreate()
|
||||||
|
{
|
||||||
|
// Explicitly destroy surface before activity recreation.
|
||||||
|
if (mMapFragment != null)
|
||||||
|
mMapFragment.destroySurface(true);
|
||||||
|
super.recreate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResumeFragments()
|
protected void onResumeFragments()
|
||||||
{
|
{
|
||||||
@@ -1406,6 +1459,12 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
return super.onGenericMotionEvent(event);
|
return super.onGenericMotionEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View view, MotionEvent event)
|
||||||
|
{
|
||||||
|
return mMapFragment != null && mMapFragment.onTouch(view, event);
|
||||||
|
}
|
||||||
|
|
||||||
public void customOnNavigateUp()
|
public void customOnNavigateUp()
|
||||||
{
|
{
|
||||||
if (removeCurrentFragment(true))
|
if (removeCurrentFragment(true))
|
||||||
@@ -1421,7 +1480,10 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
|
|
||||||
void updateCompassOffset(int offsetY, int offsetX)
|
void updateCompassOffset(int offsetY, int offsetX)
|
||||||
{
|
{
|
||||||
mMapController.updateCompassOffset(offsetX, offsetY);
|
if (mMapFragment == null || !mMapFragment.isAdded())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMapFragment.updateCompassOffset(offsetX, offsetY);
|
||||||
|
|
||||||
final double north = MwmApplication.from(this).getSensorHelper().getSavedNorth();
|
final double north = MwmApplication.from(this).getSensorHelper().getSavedNorth();
|
||||||
if (!Double.isNaN(north))
|
if (!Double.isNaN(north))
|
||||||
@@ -1440,6 +1502,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
|
|
||||||
public void updateBottomWidgetsOffset(int offsetX)
|
public void updateBottomWidgetsOffset(int offsetX)
|
||||||
{
|
{
|
||||||
|
if (mMapFragment == null || !mMapFragment.isAdded())
|
||||||
|
return;
|
||||||
|
|
||||||
int offsetY = mNavBarHeight;
|
int offsetY = mNavBarHeight;
|
||||||
final Float bottomButtonHeight = mMapButtonsViewModel.getBottomButtonsHeight().getValue();
|
final Float bottomButtonHeight = mMapButtonsViewModel.getBottomButtonsHeight().getValue();
|
||||||
if (bottomButtonHeight != null)
|
if (bottomButtonHeight != null)
|
||||||
@@ -1454,8 +1519,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
|
|
||||||
if (mDisplayManager.isDeviceDisplayUsed())
|
if (mDisplayManager.isDeviceDisplayUsed())
|
||||||
{
|
{
|
||||||
mMapController.updateBottomWidgetsOffset(offsetX, offsetY);
|
mMapFragment.updateBottomWidgetsOffset(offsetX, offsetY);
|
||||||
mMapController.updateMyPositionRoutingOffset(offsetY);
|
mMapFragment.updateMyPositionRoutingOffset(offsetY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1673,7 +1738,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
public void onNavigationCancelled()
|
public void onNavigationCancelled()
|
||||||
{
|
{
|
||||||
closeFloatingToolbarsAndPanels(true);
|
closeFloatingToolbarsAndPanels(true);
|
||||||
ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
|
ThemeSwitcher.INSTANCE.restart(isMapRendererActive());
|
||||||
if (mRoutingPlanInplaceController == null)
|
if (mRoutingPlanInplaceController == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1689,7 +1754,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
public void onNavigationStarted()
|
public void onNavigationStarted()
|
||||||
{
|
{
|
||||||
closeFloatingToolbarsAndPanels(true);
|
closeFloatingToolbarsAndPanels(true);
|
||||||
ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
|
ThemeSwitcher.INSTANCE.restart(isMapRendererActive());
|
||||||
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.navigation);
|
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.navigation);
|
||||||
refreshLightStatusBar();
|
refreshLightStatusBar();
|
||||||
|
|
||||||
@@ -1725,7 +1790,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
public void onResetToPlanningState()
|
public void onResetToPlanningState()
|
||||||
{
|
{
|
||||||
closeFloatingToolbarsAndPanels(true);
|
closeFloatingToolbarsAndPanels(true);
|
||||||
ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
|
ThemeSwitcher.INSTANCE.restart(isMapRendererActive());
|
||||||
NavigationService.stopService(this);
|
NavigationService.stopService(this);
|
||||||
mMapButtonsViewModel.setSearchOption(null);
|
mMapButtonsViewModel.setSearchOption(null);
|
||||||
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.planning);
|
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.planning);
|
||||||
@@ -2554,13 +2619,4 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||||||
window.setNavigationBarContrastEnforced(false);
|
window.setNavigationBarContrastEnforced(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reportUnsupported()
|
|
||||||
{
|
|
||||||
new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
|
|
||||||
.setMessage(R.string.unsupported_phone)
|
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton(R.string.close, (dlg, which) -> this.moveTaskToBack(true))
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,15 @@ public class SplashActivity extends AppCompatActivity
|
|||||||
protected void onCreate(@Nullable Bundle savedInstanceState)
|
protected void onCreate(@Nullable Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
final String theme = Config.UiTheme.getCurrent();
|
||||||
|
if (Config.UiTheme.isDefault(theme))
|
||||||
|
setTheme(R.style.MwmTheme_Splash);
|
||||||
|
else if (Config.UiTheme.isNight(theme))
|
||||||
|
setTheme(R.style.MwmTheme_Night_Splash);
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme);
|
||||||
|
|
||||||
UiThread.cancelDelayedTasks(mInitCoreDelayedTask);
|
UiThread.cancelDelayedTasks(mInitCoreDelayedTask);
|
||||||
setContentView(R.layout.activity_splash);
|
setContentView(R.layout.activity_splash);
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
package app.organicmaps.background;
|
package app.organicmaps.background;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.work.Constraints;
|
import androidx.work.Constraints;
|
||||||
import androidx.work.ExistingWorkPolicy;
|
import androidx.work.ExistingWorkPolicy;
|
||||||
import androidx.work.NetworkType;
|
import androidx.work.NetworkType;
|
||||||
import androidx.work.OneTimeWorkRequest;
|
import androidx.work.OneTimeWorkRequest;
|
||||||
import androidx.work.OutOfQuotaPolicy;
|
|
||||||
import androidx.work.WorkManager;
|
import androidx.work.WorkManager;
|
||||||
import androidx.work.Worker;
|
import androidx.work.Worker;
|
||||||
import androidx.work.WorkerParameters;
|
import androidx.work.WorkerParameters;
|
||||||
@@ -37,11 +35,7 @@ public class OsmUploadWork extends Worker
|
|||||||
if (Editor.nativeHasSomethingToUpload() && OsmOAuth.isAuthorized())
|
if (Editor.nativeHasSomethingToUpload() && OsmOAuth.isAuthorized())
|
||||||
{
|
{
|
||||||
final Constraints c = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
|
final Constraints c = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
|
||||||
OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(OsmUploadWork.class).setConstraints(c);
|
final OneTimeWorkRequest wr = new OneTimeWorkRequest.Builder(OsmUploadWork.class).setConstraints(c).build();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
builder.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST);
|
|
||||||
}
|
|
||||||
final OneTimeWorkRequest wr = builder.build();
|
|
||||||
WorkManager.getInstance(context).beginUniqueWork("UploadOsmChanges", ExistingWorkPolicy.KEEP, wr).enqueue();
|
WorkManager.getInstance(context).beginUniqueWork("UploadOsmChanges", ExistingWorkPolicy.KEEP, wr).enqueue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,23 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StyleRes;
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import app.organicmaps.R;
|
||||||
|
import app.organicmaps.util.ThemeUtils;
|
||||||
|
|
||||||
public class BaseMwmDialogFragment extends DialogFragment
|
public class BaseMwmDialogFragment extends DialogFragment
|
||||||
{
|
{
|
||||||
|
@StyleRes
|
||||||
|
protected final int getFullscreenTheme()
|
||||||
|
{
|
||||||
|
return ThemeUtils.isNightTheme() ? getFullscreenDarkTheme() : getFullscreenLightTheme();
|
||||||
|
}
|
||||||
|
|
||||||
protected int getStyle()
|
protected int getStyle()
|
||||||
{
|
{
|
||||||
return STYLE_NORMAL;
|
return STYLE_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@StyleRes
|
protected @StyleRes int getCustomTheme()
|
||||||
protected int getCustomTheme()
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -34,6 +40,18 @@ public class BaseMwmDialogFragment extends DialogFragment
|
|||||||
setStyle(style, theme);
|
setStyle(style, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@StyleRes
|
||||||
|
protected int getFullscreenLightTheme()
|
||||||
|
{
|
||||||
|
return R.style.MwmTheme_DialogFragment_Fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StyleRes
|
||||||
|
protected int getFullscreenDarkTheme()
|
||||||
|
{
|
||||||
|
return R.style.MwmTheme_DialogFragment_Fullscreen_Night;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
protected Application getAppContextOrThrow()
|
protected Application getAppContextOrThrow()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import androidx.activity.SystemBarStyle;
|
|||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentFactory;
|
import androidx.fragment.app.FragmentFactory;
|
||||||
@@ -19,6 +20,7 @@ import app.organicmaps.MwmApplication;
|
|||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.SplashActivity;
|
import app.organicmaps.SplashActivity;
|
||||||
import app.organicmaps.sdk.util.Config;
|
import app.organicmaps.sdk.util.Config;
|
||||||
|
import app.organicmaps.sdk.util.concurrency.UiThread;
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
import app.organicmaps.sdk.util.log.Logger;
|
||||||
import app.organicmaps.util.RtlUtils;
|
import app.organicmaps.util.RtlUtils;
|
||||||
import com.google.android.material.appbar.MaterialToolbar;
|
import com.google.android.material.appbar.MaterialToolbar;
|
||||||
@@ -30,9 +32,24 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
|||||||
|
|
||||||
private boolean mSafeCreated;
|
private boolean mSafeCreated;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private String mThemeName;
|
||||||
|
|
||||||
|
@StyleRes
|
||||||
|
protected int getThemeResourceId(@NonNull String theme)
|
||||||
|
{
|
||||||
|
if (Config.UiTheme.isDefault(theme))
|
||||||
|
return R.style.MwmTheme;
|
||||||
|
|
||||||
|
if (Config.UiTheme.isNight(theme))
|
||||||
|
return R.style.MwmTheme_Night;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows splash screen and initializes the core in case when it was not initialized.
|
* Shows splash screen and initializes the core in case when it was not initialized.
|
||||||
* <p>
|
*
|
||||||
* Do not override this method!
|
* Do not override this method!
|
||||||
* Use {@link #onSafeCreate(Bundle savedInstanceState)}
|
* Use {@link #onSafeCreate(Bundle savedInstanceState)}
|
||||||
*/
|
*/
|
||||||
@@ -41,6 +58,8 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
|||||||
protected final void onCreate(@Nullable Bundle savedInstanceState)
|
protected final void onCreate(@Nullable Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
mThemeName = Config.UiTheme.getCurrent();
|
||||||
|
setTheme(getThemeResourceId(mThemeName));
|
||||||
EdgeToEdge.enable(this, SystemBarStyle.dark(Color.TRANSPARENT));
|
EdgeToEdge.enable(this, SystemBarStyle.dark(Color.TRANSPARENT));
|
||||||
RtlUtils.manageRtl(this);
|
RtlUtils.manageRtl(this);
|
||||||
if (!MwmApplication.from(this).getOrganicMaps().arePlatformAndCoreInitialized())
|
if (!MwmApplication.from(this).getOrganicMaps().arePlatformAndCoreInitialized())
|
||||||
@@ -94,6 +113,18 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
|||||||
mSafeCreated = false;
|
mSafeCreated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
@Override
|
||||||
|
public void onPostResume()
|
||||||
|
{
|
||||||
|
super.onPostResume();
|
||||||
|
if (!mThemeName.equals(Config.UiTheme.getCurrent()))
|
||||||
|
{
|
||||||
|
// Workaround described in https://code.google.com/p/android/issues/detail?id=93731
|
||||||
|
UiThread.runLater(this::recreate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item)
|
public boolean onOptionsItemSelected(MenuItem item)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ import android.os.Bundle;
|
|||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.base.BaseToolbarActivity;
|
import app.organicmaps.base.BaseToolbarActivity;
|
||||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||||
|
import app.organicmaps.util.ThemeUtils;
|
||||||
|
|
||||||
public class BookmarkCategoriesActivity extends BaseToolbarActivity
|
public class BookmarkCategoriesActivity extends BaseToolbarActivity
|
||||||
{
|
{
|
||||||
@@ -36,6 +38,13 @@ public class BookmarkCategoriesActivity extends BaseToolbarActivity
|
|||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StyleRes
|
||||||
|
public int getThemeResourceId(@NonNull String theme)
|
||||||
|
{
|
||||||
|
return ThemeUtils.getWindowBgThemeResourceId(theme);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<? extends Fragment> getFragmentClass()
|
protected Class<? extends Fragment> getFragmentClass()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
|||||||
ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
|
ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
|
||||||
if (mSelectedCategory != null)
|
if (mSelectedCategory != null)
|
||||||
{
|
{
|
||||||
items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_edit,
|
items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_settings,
|
||||||
() -> onSettingsActionSelected(mSelectedCategory)));
|
() -> onSettingsActionSelected(mSelectedCategory)));
|
||||||
items.add(new MenuBottomSheetItem(mSelectedCategory.isVisible() ? R.string.hide : R.string.show,
|
items.add(new MenuBottomSheetItem(mSelectedCategory.isVisible() ? R.string.hide : R.string.show,
|
||||||
mSelectedCategory.isVisible() ? R.drawable.ic_hide : R.drawable.ic_show,
|
mSelectedCategory.isVisible() ? R.drawable.ic_hide : R.drawable.ic_show,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ public class BookmarkCategorySettingsFragment extends BaseMwmToolbarFragment
|
|||||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
View root = inflater.inflate(R.layout.fragment_bookmark_category_settings, container, false);
|
View root = inflater.inflate(R.layout.fragment_bookmark_category_settings, container, false);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
initViews(root);
|
initViews(root);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
@@ -84,7 +85,7 @@ public class BookmarkCategorySettingsFragment extends BaseMwmToolbarFragment
|
|||||||
});
|
});
|
||||||
mEditDescView = root.findViewById(R.id.edit_description);
|
mEditDescView = root.findViewById(R.id.edit_description);
|
||||||
mEditDescView.setText(mCategory.getDescription());
|
mEditDescView.setText(mCategory.getDescription());
|
||||||
mSaveView = root.findViewById(R.id.save);
|
mSaveView = root.findViewById(R.id.done);
|
||||||
mSaveView.setOnClickListener(v -> onEditDoneClicked());
|
mSaveView.setOnClickListener(v -> onEditDoneClicked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import android.os.Bundle;
|
|||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.base.BaseToolbarActivity;
|
import app.organicmaps.base.BaseToolbarActivity;
|
||||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||||
|
import app.organicmaps.util.ThemeUtils;
|
||||||
|
|
||||||
public class BookmarkListActivity extends BaseToolbarActivity
|
public class BookmarkListActivity extends BaseToolbarActivity
|
||||||
{
|
{
|
||||||
@@ -35,6 +37,13 @@ public class BookmarkListActivity extends BaseToolbarActivity
|
|||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StyleRes
|
||||||
|
public int getThemeResourceId(@NonNull String theme)
|
||||||
|
{
|
||||||
|
return ThemeUtils.getCardBgThemeResourceId(theme);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<? extends Fragment> getFragmentClass()
|
protected Class<? extends Fragment> getFragmentClass()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -466,10 +466,12 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
|||||||
View desc = inflater.inflate(R.layout.item_category_description, parent, false);
|
View desc = inflater.inflate(R.layout.item_category_description, parent, false);
|
||||||
MaterialTextView moreBtn = desc.findViewById(R.id.more_btn);
|
MaterialTextView moreBtn = desc.findViewById(R.id.more_btn);
|
||||||
MaterialTextView text = desc.findViewById(R.id.text);
|
MaterialTextView text = desc.findViewById(R.id.text);
|
||||||
|
MaterialTextView title = desc.findViewById(R.id.title);
|
||||||
setMoreButtonVisibility(text, moreBtn);
|
setMoreButtonVisibility(text, moreBtn);
|
||||||
holder = new Holders.DescriptionViewHolder(desc, mSectionsDataSource.getCategory());
|
holder = new Holders.DescriptionViewHolder(desc, mSectionsDataSource.getCategory());
|
||||||
text.setOnClickListener(v -> onMoreButtonClicked(text, moreBtn));
|
text.setOnClickListener(v -> onMoreButtonClicked(text, moreBtn));
|
||||||
moreBtn.setOnClickListener(v -> onMoreButtonClicked(text, moreBtn));
|
moreBtn.setOnClickListener(v -> onMoreButtonClicked(text, moreBtn));
|
||||||
|
title.setOnClickListener(v -> onMoreButtonClicked(text, moreBtn));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -282,11 +282,11 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
|||||||
{
|
{
|
||||||
if (isEmptySearchResults())
|
if (isEmptySearchResults())
|
||||||
{
|
{
|
||||||
requirePlaceholder().setContent(R.string.search_not_found, R.string.search_not_found_query, R.drawable.ic_search_fail);
|
requirePlaceholder().setContent(R.string.search_not_found, R.string.search_not_found_query);
|
||||||
}
|
}
|
||||||
else if (isEmpty())
|
else if (isEmpty())
|
||||||
{
|
{
|
||||||
requirePlaceholder().setContent(R.string.bookmarks_empty_list_title, R.string.bookmarks_empty_list_message, R.drawable.ic_bookmarks);
|
requirePlaceholder().setContent(R.string.bookmarks_empty_list_title, R.string.bookmarks_empty_list_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEmptyRecycler = isEmpty() || isEmptySearchResults();
|
boolean isEmptyRecycler = isEmpty() || isEmptySearchResults();
|
||||||
@@ -771,7 +771,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
|||||||
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx,
|
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx,
|
||||||
() -> onShareOptionSelected(KmlFileType.Gpx)));
|
() -> onShareOptionSelected(KmlFileType.Gpx)));
|
||||||
}
|
}
|
||||||
items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_edit, this::onSettingsOptionSelected));
|
items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_settings, this::onSettingsOptionSelected));
|
||||||
if (!isLastOwnedCategory())
|
if (!isLastOwnedCategory())
|
||||||
items.add(new MenuBottomSheetItem(R.string.delete_list, R.drawable.ic_delete, this::onDeleteOptionSelected));
|
items.add(new MenuBottomSheetItem(R.string.delete_list, R.drawable.ic_delete, this::onDeleteOptionSelected));
|
||||||
return items;
|
return items;
|
||||||
|
|||||||
@@ -438,17 +438,21 @@ public class Holders
|
|||||||
static final float SPACING_MULTIPLE = 1.0f;
|
static final float SPACING_MULTIPLE = 1.0f;
|
||||||
static final float SPACING_ADD = 0.0f;
|
static final float SPACING_ADD = 0.0f;
|
||||||
@NonNull
|
@NonNull
|
||||||
|
private final MaterialTextView mTitle;
|
||||||
|
@NonNull
|
||||||
private final MaterialTextView mDescText;
|
private final MaterialTextView mDescText;
|
||||||
|
|
||||||
DescriptionViewHolder(@NonNull View itemView, @NonNull BookmarkCategory category)
|
DescriptionViewHolder(@NonNull View itemView, @NonNull BookmarkCategory category)
|
||||||
{
|
{
|
||||||
super(itemView);
|
super(itemView);
|
||||||
mDescText = itemView.findViewById(R.id.text);
|
mDescText = itemView.findViewById(R.id.text);
|
||||||
|
mTitle = itemView.findViewById(R.id.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void bind(@NonNull SectionPosition position, @NonNull BookmarkListAdapter.SectionsDataSource sectionsDataSource)
|
void bind(@NonNull SectionPosition position, @NonNull BookmarkListAdapter.SectionsDataSource sectionsDataSource)
|
||||||
{
|
{
|
||||||
|
mTitle.setText(sectionsDataSource.getCategory().getName());
|
||||||
bindDescription(sectionsDataSource.getCategory());
|
bindDescription(sectionsDataSource.getCategory());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,12 +462,9 @@ public class Holders
|
|||||||
|
|
||||||
String formattedDesc = desc.replace("\n", "<br>");
|
String formattedDesc = desc.replace("\n", "<br>");
|
||||||
Spanned spannedDesc = Utils.fromHtml(formattedDesc);
|
Spanned spannedDesc = Utils.fromHtml(formattedDesc);
|
||||||
if (!TextUtils.isEmpty(spannedDesc)) {
|
mDescText.setText(spannedDesc);
|
||||||
mDescText.setText(spannedDesc);
|
|
||||||
}
|
UiUtils.showIf(!TextUtils.isEmpty(spannedDesc), mDescText);
|
||||||
else {
|
|
||||||
mDescText.setText(R.string.list_description_empty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,9 @@ import androidx.lifecycle.DefaultLifecycleObserver;
|
|||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
|
||||||
import app.organicmaps.car.renderer.RendererFactory;
|
|
||||||
import app.organicmaps.car.screens.ErrorScreen;
|
import app.organicmaps.car.screens.ErrorScreen;
|
||||||
import app.organicmaps.car.screens.MapPlaceholderScreen;
|
import app.organicmaps.car.screens.MapPlaceholderScreen;
|
||||||
import app.organicmaps.car.screens.MapScreen;
|
import app.organicmaps.car.screens.MapScreen;
|
||||||
import app.organicmaps.car.screens.NavigationScreen;
|
|
||||||
import app.organicmaps.car.screens.PlaceScreen;
|
import app.organicmaps.car.screens.PlaceScreen;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.screens.download.DownloadMapsScreen;
|
import app.organicmaps.car.screens.download.DownloadMapsScreen;
|
||||||
@@ -52,9 +49,8 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final SessionInfo mSessionInfo;
|
private final SessionInfo mSessionInfo;
|
||||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Renderer mSurfaceRenderer;
|
private final SurfaceRenderer mSurfaceRenderer;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final ScreenManager mScreenManager;
|
private final ScreenManager mScreenManager;
|
||||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||||
@@ -71,6 +67,7 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||||||
{
|
{
|
||||||
getLifecycle().addObserver(this);
|
getLifecycle().addObserver(this);
|
||||||
mSessionInfo = sessionInfo;
|
mSessionInfo = sessionInfo;
|
||||||
|
mSurfaceRenderer = new SurfaceRenderer(getCarContext(), getLifecycle());
|
||||||
mScreenManager = getCarContext().getCarService(ScreenManager.class);
|
mScreenManager = getCarContext().getCarService(ScreenManager.class);
|
||||||
mCurrentCountryChangedListener = new CurrentCountryChangedListener();
|
mCurrentCountryChangedListener = new CurrentCountryChangedListener();
|
||||||
}
|
}
|
||||||
@@ -117,8 +114,6 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||||||
mSensorsManager = new CarSensorsManager(getCarContext());
|
mSensorsManager = new CarSensorsManager(getCarContext());
|
||||||
mDisplayManager = MwmApplication.from(getCarContext()).getDisplayManager();
|
mDisplayManager = MwmApplication.from(getCarContext()).getDisplayManager();
|
||||||
mDisplayManager.addListener(DisplayType.Car, this);
|
mDisplayManager.addListener(DisplayType.Car, this);
|
||||||
mSurfaceRenderer = RendererFactory.create(getCarContext(), mDisplayManager,
|
|
||||||
MwmApplication.from(getCarContext()).getLocationHelper(), this);
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,19 +281,7 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||||||
private void restoreRoute()
|
private void restoreRoute()
|
||||||
{
|
{
|
||||||
final RoutingController routingController = RoutingController.get();
|
final RoutingController routingController = RoutingController.get();
|
||||||
final boolean isNavigating = routingController.isNavigating();
|
if (routingController.isPlanning() || routingController.isNavigating() || routingController.hasSavedRoute())
|
||||||
final boolean hasNavigatingScreen = hasNavigationScreenInStack();
|
|
||||||
|
|
||||||
if (!isNavigating && hasNavigatingScreen)
|
|
||||||
mScreenManager.popToRoot();
|
|
||||||
|
|
||||||
if (isNavigating && routingController.getLastRouterType() == PlaceScreen.ROUTER && hasNavigatingScreen)
|
|
||||||
{
|
|
||||||
mScreenManager.popTo(NavigationScreen.MARKER);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routingController.isPlanning() || isNavigating || routingController.hasSavedRoute())
|
|
||||||
{
|
{
|
||||||
final PlaceScreen placeScreen = new PlaceScreen.Builder(getCarContext(), mSurfaceRenderer)
|
final PlaceScreen placeScreen = new PlaceScreen.Builder(getCarContext(), mSurfaceRenderer)
|
||||||
.setMapObject(routingController.getEndPoint())
|
.setMapObject(routingController.getEndPoint())
|
||||||
@@ -307,14 +290,4 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||||||
mScreenManager.push(placeScreen);
|
mScreenManager.push(placeScreen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNavigationScreenInStack()
|
|
||||||
{
|
|
||||||
for (final Screen screen : mScreenManager.getScreenStack())
|
|
||||||
{
|
|
||||||
if (NavigationScreen.MARKER.equals(screen.getMarker()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
package app.organicmaps.car;
|
||||||
|
|
||||||
|
import static app.organicmaps.sdk.display.DisplayType.Car;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.view.Surface;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.car.app.AppManager;
|
||||||
|
import androidx.car.app.CarContext;
|
||||||
|
import androidx.car.app.CarToast;
|
||||||
|
import androidx.car.app.SurfaceCallback;
|
||||||
|
import androidx.car.app.SurfaceContainer;
|
||||||
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
|
import androidx.lifecycle.Lifecycle;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import app.organicmaps.MwmApplication;
|
||||||
|
import app.organicmaps.R;
|
||||||
|
import app.organicmaps.sdk.Framework;
|
||||||
|
import app.organicmaps.sdk.Map;
|
||||||
|
import app.organicmaps.sdk.MapRenderingListener;
|
||||||
|
import app.organicmaps.sdk.settings.UnitLocale;
|
||||||
|
import app.organicmaps.sdk.util.concurrency.UiThread;
|
||||||
|
import app.organicmaps.sdk.util.log.Logger;
|
||||||
|
|
||||||
|
public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallback, MapRenderingListener
|
||||||
|
{
|
||||||
|
private static final String TAG = SurfaceRenderer.class.getSimpleName();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final CarContext mCarContext;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Map mMap = new Map(Car);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Rect mVisibleArea = new Rect();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Surface mSurface = null;
|
||||||
|
|
||||||
|
private boolean mIsRunning;
|
||||||
|
|
||||||
|
public SurfaceRenderer(@NonNull CarContext carContext, @NonNull Lifecycle lifecycle)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "SurfaceRenderer()");
|
||||||
|
mCarContext = carContext;
|
||||||
|
mIsRunning = true;
|
||||||
|
lifecycle.addObserver(this);
|
||||||
|
mMap.setMapRenderingListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceAvailable(@NonNull SurfaceContainer surfaceContainer)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "Surface available " + surfaceContainer);
|
||||||
|
|
||||||
|
if (mSurface != null)
|
||||||
|
mSurface.release();
|
||||||
|
mSurface = surfaceContainer.getSurface();
|
||||||
|
|
||||||
|
mMap.setLocationHelper(MwmApplication.from(mCarContext).getLocationHelper());
|
||||||
|
mMap.onSurfaceCreated(mCarContext, mSurface,
|
||||||
|
new Rect(0, 0, surfaceContainer.getWidth(), surfaceContainer.getHeight()),
|
||||||
|
surfaceContainer.getDpi());
|
||||||
|
mMap.updateBottomWidgetsOffset(mCarContext, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVisibleAreaChanged(@NonNull Rect visibleArea)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "Visible area changed. visibleArea: " + visibleArea);
|
||||||
|
mVisibleArea = visibleArea;
|
||||||
|
|
||||||
|
if (!mVisibleArea.isEmpty())
|
||||||
|
Framework.nativeSetVisibleRect(mVisibleArea.left, mVisibleArea.top, mVisibleArea.right, mVisibleArea.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStableAreaChanged(@NonNull Rect stableArea)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "Stable area changed. stableArea: " + stableArea);
|
||||||
|
|
||||||
|
if (!stableArea.isEmpty())
|
||||||
|
Framework.nativeSetVisibleRect(stableArea.left, stableArea.top, stableArea.right, stableArea.bottom);
|
||||||
|
else if (!mVisibleArea.isEmpty())
|
||||||
|
Framework.nativeSetVisibleRect(mVisibleArea.left, mVisibleArea.top, mVisibleArea.right, mVisibleArea.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceDestroyed(@NonNull SurfaceContainer surfaceContainer)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "Surface destroyed");
|
||||||
|
if (mSurface != null)
|
||||||
|
{
|
||||||
|
mSurface.release();
|
||||||
|
mSurface = null;
|
||||||
|
}
|
||||||
|
mMap.onSurfaceDestroyed(false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@NonNull LifecycleOwner owner)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
mCarContext.getCarService(AppManager.class).setSurfaceCallback(this);
|
||||||
|
mMap.onCreate(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart(@NonNull LifecycleOwner owner)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
mMap.onStart();
|
||||||
|
mMap.setCallbackUnsupported(this::reportUnsupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume(@NonNull LifecycleOwner owner)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
mMap.onResume();
|
||||||
|
if (MwmApplication.from(mCarContext).getDisplayManager().isCarDisplayUsed())
|
||||||
|
UiThread.runLater(() -> mMap.updateMyPositionRoutingOffset(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause(@NonNull LifecycleOwner owner)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
mMap.onPause(mCarContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop(@NonNull LifecycleOwner owner)
|
||||||
|
{
|
||||||
|
Logger.d(TAG);
|
||||||
|
mMap.onStop();
|
||||||
|
mMap.setCallbackUnsupported(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScroll(float distanceX, float distanceY)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "distanceX: " + distanceX + ", distanceY: " + distanceY);
|
||||||
|
mMap.onScroll(distanceX, distanceY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFling(float velocityX, float velocityY)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "velocityX: " + velocityX + ", velocityY: " + velocityY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onZoomIn()
|
||||||
|
{
|
||||||
|
Map.zoomIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onZoomOut()
|
||||||
|
{
|
||||||
|
Map.zoomOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScale(float focusX, float focusY, float scaleFactor)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "focusX: " + focusX + ", focusY: " + focusY + ", scaleFactor: " + scaleFactor);
|
||||||
|
float x = focusX;
|
||||||
|
float y = focusY;
|
||||||
|
|
||||||
|
if (!mVisibleArea.isEmpty())
|
||||||
|
{
|
||||||
|
// If a focal point value is negative, use the center point of the visible area.
|
||||||
|
if (x < 0)
|
||||||
|
x = mVisibleArea.centerX();
|
||||||
|
if (y < 0)
|
||||||
|
y = mVisibleArea.centerY();
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean animated = Float.compare(scaleFactor, 2f) == 0;
|
||||||
|
|
||||||
|
Map.onScale(scaleFactor, x, y, animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(float x, float y)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "x: " + x + ", y: " + y);
|
||||||
|
Map.onClick(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable()
|
||||||
|
{
|
||||||
|
if (!mIsRunning)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "Already disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCarContext.getCarService(AppManager.class).setSurfaceCallback(null);
|
||||||
|
mMap.onSurfaceDestroyed(false, true);
|
||||||
|
mMap.onStop();
|
||||||
|
mMap.setCallbackUnsupported(null);
|
||||||
|
mMap.setMapRenderingListener(null);
|
||||||
|
|
||||||
|
mIsRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enable()
|
||||||
|
{
|
||||||
|
if (mIsRunning)
|
||||||
|
{
|
||||||
|
Logger.d(TAG, "Already enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCarContext.getCarService(AppManager.class).setSurfaceCallback(this);
|
||||||
|
mMap.onStart();
|
||||||
|
mMap.setCallbackUnsupported(this::reportUnsupported);
|
||||||
|
mMap.setMapRenderingListener(this);
|
||||||
|
UiThread.runLater(() -> mMap.updateMyPositionRoutingOffset(0));
|
||||||
|
|
||||||
|
mIsRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRenderingActive()
|
||||||
|
{
|
||||||
|
return mIsRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportUnsupported()
|
||||||
|
{
|
||||||
|
String message = mCarContext.getString(R.string.unsupported_phone);
|
||||||
|
Logger.e(TAG, message);
|
||||||
|
CarToast.makeText(mCarContext, message, CarToast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRenderingCreated()
|
||||||
|
{
|
||||||
|
UnitLocale.initializeCurrentUnits();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
package app.organicmaps.car.renderer;
|
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.car.app.AppManager;
|
|
||||||
import androidx.car.app.CarContext;
|
|
||||||
import androidx.car.app.SurfaceCallback;
|
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import app.organicmaps.sdk.Map;
|
|
||||||
import app.organicmaps.sdk.MapRenderingListener;
|
|
||||||
import app.organicmaps.sdk.display.DisplayManager;
|
|
||||||
import app.organicmaps.sdk.location.LocationHelper;
|
|
||||||
import app.organicmaps.sdk.settings.UnitLocale;
|
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
|
||||||
|
|
||||||
public abstract class Renderer implements DefaultLifecycleObserver
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private final String TAG;
|
|
||||||
|
|
||||||
private SurfaceCallback mSurfaceCallback;
|
|
||||||
|
|
||||||
private boolean mIsRunning;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected final CarContext mCarContext;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected final DisplayManager mDisplayManager;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected final LocationHelper mLocationHelper;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected final LifecycleOwner mLifecycleOwner;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final MapRenderingListener mMapRenderingListener = new MapRenderingListener() {
|
|
||||||
@Override
|
|
||||||
public void onRenderingCreated()
|
|
||||||
{
|
|
||||||
UnitLocale.initializeCurrentUnits();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public Renderer(@NonNull CarContext carContext, @NonNull DisplayManager displayManager,
|
|
||||||
@NonNull LocationHelper locationHelper, @NonNull LifecycleOwner lifecycleOwner)
|
|
||||||
{
|
|
||||||
TAG = getClass().getSimpleName();
|
|
||||||
Logger.d(TAG, "SurfaceRenderer()");
|
|
||||||
mIsRunning = true;
|
|
||||||
mCarContext = carContext;
|
|
||||||
mDisplayManager = displayManager;
|
|
||||||
mLocationHelper = locationHelper;
|
|
||||||
mLifecycleOwner = lifecycleOwner;
|
|
||||||
mLifecycleOwner.getLifecycle().addObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setSurfaceCallback(@NonNull SurfaceCallback surfaceCallback)
|
|
||||||
{
|
|
||||||
mSurfaceCallback = surfaceCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRenderingActive()
|
|
||||||
{
|
|
||||||
return mIsRunning;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MapRenderingListener getMapRenderingListener()
|
|
||||||
{
|
|
||||||
return mMapRenderingListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
@Override
|
|
||||||
public void onCreate(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
if (mSurfaceCallback == null)
|
|
||||||
throw new IllegalStateException("SurfaceCallback must be set before onCreate()");
|
|
||||||
mCarContext.getCarService(AppManager.class).setSurfaceCallback(mSurfaceCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
@Override
|
|
||||||
public void onDestroy(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
mCarContext.getCarService(AppManager.class).setSurfaceCallback(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void enable()
|
|
||||||
{
|
|
||||||
if (isRenderingActive())
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Already enabled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mSurfaceCallback == null)
|
|
||||||
throw new IllegalStateException("SurfaceCallback must be set before enable()");
|
|
||||||
mCarContext.getCarService(AppManager.class).setSurfaceCallback(mSurfaceCallback);
|
|
||||||
mIsRunning = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void disable()
|
|
||||||
{
|
|
||||||
if (!isRenderingActive())
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Already disabled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mCarContext.getCarService(AppManager.class).setSurfaceCallback(null);
|
|
||||||
mIsRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onZoomIn()
|
|
||||||
{
|
|
||||||
Map.zoomIn();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onZoomOut()
|
|
||||||
{
|
|
||||||
Map.zoomOut();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package app.organicmaps.car.renderer;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.car.app.CarContext;
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import app.organicmaps.sdk.display.DisplayManager;
|
|
||||||
import app.organicmaps.sdk.location.LocationHelper;
|
|
||||||
|
|
||||||
public final class RendererFactory
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
public static Renderer create(@NonNull CarContext carContext, @NonNull DisplayManager displayManager,
|
|
||||||
@NonNull LocationHelper locationHelper, @NonNull LifecycleOwner lifecycleOwner)
|
|
||||||
{
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= 23)
|
|
||||||
return new SurfaceRenderer(carContext, displayManager, locationHelper, lifecycleOwner);
|
|
||||||
else
|
|
||||||
return new SurfaceRendererLegacy(carContext, displayManager, locationHelper, lifecycleOwner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
package app.organicmaps.car.renderer;
|
|
||||||
|
|
||||||
import android.app.Presentation;
|
|
||||||
import android.hardware.display.DisplayManager;
|
|
||||||
import android.hardware.display.VirtualDisplay;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewParent;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.car.app.CarContext;
|
|
||||||
import androidx.car.app.SurfaceContainer;
|
|
||||||
import app.organicmaps.sdk.MapController;
|
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
|
||||||
|
|
||||||
@RequiresApi(23)
|
|
||||||
class SurfaceCallback extends SurfaceCallbackBase
|
|
||||||
{
|
|
||||||
private static final String TAG = SurfaceCallback.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final String VIRTUAL_DISPLAY_NAME = "OM_Android_Auto_Display";
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final MapController mMapController;
|
|
||||||
|
|
||||||
private VirtualDisplay mVirtualDisplay;
|
|
||||||
private Presentation mPresentation;
|
|
||||||
|
|
||||||
public SurfaceCallback(@NonNull CarContext carContext, @NonNull MapController mapController)
|
|
||||||
{
|
|
||||||
super(carContext);
|
|
||||||
mMapController = mapController;
|
|
||||||
mMapController.getView().getHolder().addCallback(new SurfaceHolder.Callback() {
|
|
||||||
@Override
|
|
||||||
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height)
|
|
||||||
{
|
|
||||||
mMapController.updateMyPositionRoutingOffset(0);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void surfaceCreated(@NonNull SurfaceHolder holder)
|
|
||||||
{
|
|
||||||
mMapController.updateMyPositionRoutingOffset(0);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void surfaceDestroyed(@NonNull SurfaceHolder holder)
|
|
||||||
{}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceAvailable(@NonNull SurfaceContainer surfaceContainer)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Surface available " + surfaceContainer);
|
|
||||||
|
|
||||||
mVirtualDisplay =
|
|
||||||
mCarContext.getSystemService(DisplayManager.class)
|
|
||||||
.createVirtualDisplay(VIRTUAL_DISPLAY_NAME, surfaceContainer.getWidth(), surfaceContainer.getHeight(),
|
|
||||||
surfaceContainer.getDpi(), surfaceContainer.getSurface(), 0);
|
|
||||||
mPresentation = new Presentation(mCarContext, mVirtualDisplay.getDisplay());
|
|
||||||
|
|
||||||
mPresentation.setContentView(prepareViewForPresentation(mMapController.getView()));
|
|
||||||
mPresentation.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceDestroyed(@NonNull SurfaceContainer surfaceContainer)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Surface destroyed");
|
|
||||||
mPresentation.dismiss();
|
|
||||||
mVirtualDisplay.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopPresenting()
|
|
||||||
{
|
|
||||||
if (mPresentation != null)
|
|
||||||
mPresentation.dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
void startPresenting()
|
|
||||||
{
|
|
||||||
if (mPresentation != null)
|
|
||||||
mPresentation.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private View prepareViewForPresentation(@NonNull View view)
|
|
||||||
{
|
|
||||||
final ViewParent parent = view.getParent();
|
|
||||||
if (parent instanceof ViewGroup)
|
|
||||||
((ViewGroup) parent).removeView(view);
|
|
||||||
|
|
||||||
final FrameLayout container = new FrameLayout(mCarContext);
|
|
||||||
container.addView(
|
|
||||||
view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
package app.organicmaps.car.renderer;
|
|
||||||
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.car.app.CarContext;
|
|
||||||
import androidx.car.app.SurfaceCallback;
|
|
||||||
import app.organicmaps.sdk.Framework;
|
|
||||||
import app.organicmaps.sdk.Map;
|
|
||||||
import app.organicmaps.sdk.util.concurrency.UiThread;
|
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
|
||||||
|
|
||||||
abstract class SurfaceCallbackBase implements SurfaceCallback
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private final String TAG;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected final CarContext mCarContext;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected Rect mVisibleArea = new Rect();
|
|
||||||
|
|
||||||
public SurfaceCallbackBase(@NonNull CarContext carContext)
|
|
||||||
{
|
|
||||||
TAG = getClass().getSimpleName();
|
|
||||||
mCarContext = carContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onVisibleAreaChanged(@NonNull Rect visibleArea)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Visible area changed. visibleArea: " + visibleArea);
|
|
||||||
mVisibleArea = visibleArea;
|
|
||||||
|
|
||||||
if (!mVisibleArea.isEmpty())
|
|
||||||
UiThread.runLater(()
|
|
||||||
-> Framework.nativeSetVisibleRect(mVisibleArea.left, mVisibleArea.top, mVisibleArea.right,
|
|
||||||
mVisibleArea.bottom));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStableAreaChanged(@NonNull Rect stableArea)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Stable area changed. stableArea: " + stableArea);
|
|
||||||
|
|
||||||
if (!mVisibleArea.isEmpty())
|
|
||||||
UiThread.runLater(()
|
|
||||||
-> Framework.nativeSetVisibleRect(mVisibleArea.left, mVisibleArea.top, mVisibleArea.right,
|
|
||||||
mVisibleArea.bottom));
|
|
||||||
else if (!stableArea.isEmpty())
|
|
||||||
UiThread.runLater(
|
|
||||||
() -> Framework.nativeSetVisibleRect(stableArea.left, stableArea.top, stableArea.right, stableArea.bottom));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScroll(float distanceX, float distanceY)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "distanceX: " + distanceX + ", distanceY: " + distanceY);
|
|
||||||
Map.onScroll(distanceX, distanceY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFling(float velocityX, float velocityY)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "velocityX: " + velocityX + ", velocityY: " + velocityY);
|
|
||||||
// TODO: Implement fling in the native code.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScale(float focusX, float focusY, float scaleFactor)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "focusX: " + focusX + ", focusY: " + focusY + ", scaleFactor: " + scaleFactor);
|
|
||||||
float x = focusX;
|
|
||||||
float y = focusY;
|
|
||||||
|
|
||||||
if (!mVisibleArea.isEmpty())
|
|
||||||
{
|
|
||||||
// If a focal point value is negative, use the center point of the visible area.
|
|
||||||
if (x < 0)
|
|
||||||
x = mVisibleArea.centerX();
|
|
||||||
if (y < 0)
|
|
||||||
y = mVisibleArea.centerY();
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean animated = Float.compare(scaleFactor, 2f) == 0;
|
|
||||||
|
|
||||||
Map.onScale(scaleFactor, x, y, animated);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(float x, float y)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "x: " + x + ", y: " + y);
|
|
||||||
Map.onClick(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package app.organicmaps.car.renderer;
|
|
||||||
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.view.Surface;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.car.app.CarContext;
|
|
||||||
import androidx.car.app.SurfaceContainer;
|
|
||||||
import app.organicmaps.sdk.Map;
|
|
||||||
import app.organicmaps.sdk.location.LocationHelper;
|
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
|
||||||
|
|
||||||
class SurfaceCallbackLegacy extends SurfaceCallbackBase
|
|
||||||
{
|
|
||||||
private static final String TAG = SurfaceCallbackLegacy.class.getSimpleName();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Map mMap;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final LocationHelper mLocationHelper;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Surface mSurface = null;
|
|
||||||
|
|
||||||
public SurfaceCallbackLegacy(@NonNull CarContext carContext, @NonNull Map map, @NonNull LocationHelper locationHelper)
|
|
||||||
{
|
|
||||||
super(carContext);
|
|
||||||
mMap = map;
|
|
||||||
mLocationHelper = locationHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceAvailable(@NonNull SurfaceContainer surfaceContainer)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Surface available " + surfaceContainer);
|
|
||||||
|
|
||||||
if (mSurface != null)
|
|
||||||
mSurface.release();
|
|
||||||
mSurface = surfaceContainer.getSurface();
|
|
||||||
|
|
||||||
mMap.setLocationHelper(mLocationHelper);
|
|
||||||
mMap.onSurfaceCreated(mCarContext, mSurface,
|
|
||||||
new Rect(0, 0, surfaceContainer.getWidth(), surfaceContainer.getHeight()),
|
|
||||||
surfaceContainer.getDpi());
|
|
||||||
mMap.updateBottomWidgetsOffset(mCarContext, -1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceDestroyed(@NonNull SurfaceContainer surfaceContainer)
|
|
||||||
{
|
|
||||||
Logger.d(TAG, "Surface destroyed");
|
|
||||||
if (mSurface != null)
|
|
||||||
{
|
|
||||||
mSurface.release();
|
|
||||||
mSurface = null;
|
|
||||||
}
|
|
||||||
mMap.onSurfaceDestroyed(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package app.organicmaps.car.renderer;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.car.app.CarContext;
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import app.organicmaps.sdk.MapController;
|
|
||||||
import app.organicmaps.sdk.MapView;
|
|
||||||
import app.organicmaps.sdk.display.DisplayManager;
|
|
||||||
import app.organicmaps.sdk.display.DisplayType;
|
|
||||||
import app.organicmaps.sdk.location.LocationHelper;
|
|
||||||
|
|
||||||
@RequiresApi(23)
|
|
||||||
class SurfaceRenderer extends Renderer
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private final MapController mMapController;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final SurfaceCallback mSurfaceCallback;
|
|
||||||
|
|
||||||
public SurfaceRenderer(@NonNull CarContext carContext, @NonNull DisplayManager displayManager,
|
|
||||||
@NonNull LocationHelper locationHelper, @NonNull LifecycleOwner lifecycleOwner)
|
|
||||||
{
|
|
||||||
super(carContext, displayManager, locationHelper, lifecycleOwner);
|
|
||||||
|
|
||||||
mMapController = new MapController(new MapView(carContext, DisplayType.Car), locationHelper,
|
|
||||||
getMapRenderingListener(), null, false);
|
|
||||||
mLifecycleOwner.getLifecycle().addObserver(mMapController);
|
|
||||||
mSurfaceCallback = new SurfaceCallback(mCarContext, mMapController);
|
|
||||||
setSurfaceCallback(mSurfaceCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enable()
|
|
||||||
{
|
|
||||||
super.enable();
|
|
||||||
|
|
||||||
mMapController.onStart(mLifecycleOwner);
|
|
||||||
mMapController.updateMyPositionRoutingOffset(0);
|
|
||||||
mSurfaceCallback.startPresenting();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disable()
|
|
||||||
{
|
|
||||||
super.disable();
|
|
||||||
|
|
||||||
mMapController.onPause(mLifecycleOwner);
|
|
||||||
mSurfaceCallback.stopPresenting();
|
|
||||||
mMapController.onStop(mLifecycleOwner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package app.organicmaps.car.renderer;
|
|
||||||
|
|
||||||
import static app.organicmaps.sdk.display.DisplayType.Car;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.car.app.CarContext;
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import app.organicmaps.sdk.Map;
|
|
||||||
import app.organicmaps.sdk.display.DisplayManager;
|
|
||||||
import app.organicmaps.sdk.location.LocationHelper;
|
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
|
||||||
|
|
||||||
class SurfaceRendererLegacy extends Renderer
|
|
||||||
{
|
|
||||||
private static final String TAG = SurfaceRendererLegacy.class.getSimpleName();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Map mMap = new Map(Car);
|
|
||||||
|
|
||||||
public SurfaceRendererLegacy(@NonNull CarContext carContext, @NonNull DisplayManager displayManager,
|
|
||||||
@NonNull LocationHelper locationHelper, @NonNull LifecycleOwner lifecycleOwner)
|
|
||||||
{
|
|
||||||
super(carContext, displayManager, locationHelper, lifecycleOwner);
|
|
||||||
setSurfaceCallback(new SurfaceCallbackLegacy(mCarContext, mMap, mLocationHelper));
|
|
||||||
mMap.setMapRenderingListener(getMapRenderingListener());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
super.onCreate(owner);
|
|
||||||
mMap.onCreate(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
if (mDisplayManager.isCarDisplayUsed())
|
|
||||||
mMap.onStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
if (mDisplayManager.isCarDisplayUsed())
|
|
||||||
{
|
|
||||||
mMap.onResume();
|
|
||||||
mMap.updateMyPositionRoutingOffset(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
if (mDisplayManager.isCarDisplayUsed())
|
|
||||||
mMap.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
if (mDisplayManager.isCarDisplayUsed())
|
|
||||||
mMap.onStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enable()
|
|
||||||
{
|
|
||||||
super.enable();
|
|
||||||
|
|
||||||
mMap.onStart();
|
|
||||||
mMap.setMapRenderingListener(getMapRenderingListener());
|
|
||||||
mMap.updateMyPositionRoutingOffset(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disable()
|
|
||||||
{
|
|
||||||
super.disable();
|
|
||||||
|
|
||||||
mMap.onPause();
|
|
||||||
mMap.onSurfaceDestroyed(false);
|
|
||||||
mMap.onStop();
|
|
||||||
mMap.setMapRenderingListener(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,29 +15,30 @@ import androidx.car.app.model.Template;
|
|||||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||||
import androidx.core.graphics.drawable.IconCompat;
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.screens.search.SearchOnMapScreen;
|
import app.organicmaps.car.screens.search.SearchOnMapScreen;
|
||||||
|
import app.organicmaps.car.util.ThemeUtils;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class CategoriesScreen extends BaseMapScreen
|
public class CategoriesScreen extends BaseMapScreen
|
||||||
{
|
{
|
||||||
private record CategoryData(@StringRes int nameResId, @DrawableRes int iconResId) {}
|
private record CategoryData(@StringRes int nameResId, @DrawableRes int iconResId, @DrawableRes int iconNightResId) {}
|
||||||
|
|
||||||
private static final List<CategoryData> CATEGORIES =
|
private static final List<CategoryData> CATEGORIES = Arrays.asList(
|
||||||
Arrays.asList(new CategoryData(R.string.category_fuel, R.drawable.ic_category_fuel),
|
new CategoryData(R.string.category_fuel, R.drawable.ic_category_fuel, R.drawable.ic_category_fuel_night),
|
||||||
new CategoryData(R.string.category_parking, R.drawable.ic_category_parking),
|
new CategoryData(R.string.category_parking, R.drawable.ic_category_parking, R.drawable.ic_category_parking_night),
|
||||||
new CategoryData(R.string.category_eat, R.drawable.ic_category_eat),
|
new CategoryData(R.string.category_eat, R.drawable.ic_category_eat, R.drawable.ic_category_eat_night),
|
||||||
new CategoryData(R.string.category_food, R.drawable.ic_category_food),
|
new CategoryData(R.string.category_food, R.drawable.ic_category_food, R.drawable.ic_category_food_night),
|
||||||
new CategoryData(R.string.category_hotel, R.drawable.ic_category_hotel),
|
new CategoryData(R.string.category_hotel, R.drawable.ic_category_hotel, R.drawable.ic_category_hotel_night),
|
||||||
new CategoryData(R.string.category_toilet, R.drawable.ic_category_toilet),
|
new CategoryData(R.string.category_toilet, R.drawable.ic_category_toilet, R.drawable.ic_category_toilet_night),
|
||||||
new CategoryData(R.string.category_rv, R.drawable.ic_category_rv));
|
new CategoryData(R.string.category_rv, R.drawable.ic_category_rv, R.drawable.ic_category_rv_night));
|
||||||
|
|
||||||
private final int MAX_CATEGORIES_SIZE;
|
private final int MAX_CATEGORIES_SIZE;
|
||||||
|
|
||||||
public CategoriesScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public CategoriesScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
final ConstraintManager constraintManager = getCarContext().getCarService(ConstraintManager.class);
|
final ConstraintManager constraintManager = getCarContext().getCarService(ConstraintManager.class);
|
||||||
@@ -46,7 +47,7 @@ public class CategoriesScreen extends BaseMapScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
@@ -66,6 +67,7 @@ public class CategoriesScreen extends BaseMapScreen
|
|||||||
@NonNull
|
@NonNull
|
||||||
private GridTemplate createCategoriesListTemplate()
|
private GridTemplate createCategoriesListTemplate()
|
||||||
{
|
{
|
||||||
|
final boolean isNightMode = ThemeUtils.isNightMode(getCarContext());
|
||||||
final ItemList.Builder builder = new ItemList.Builder();
|
final ItemList.Builder builder = new ItemList.Builder();
|
||||||
final int categoriesSize = Math.min(CATEGORIES.size(), MAX_CATEGORIES_SIZE);
|
final int categoriesSize = Math.min(CATEGORIES.size(), MAX_CATEGORIES_SIZE);
|
||||||
for (int i = 0; i < categoriesSize; ++i)
|
for (int i = 0; i < categoriesSize; ++i)
|
||||||
@@ -73,7 +75,7 @@ public class CategoriesScreen extends BaseMapScreen
|
|||||||
final GridItem.Builder itemBuilder = new GridItem.Builder();
|
final GridItem.Builder itemBuilder = new GridItem.Builder();
|
||||||
final String title = getCarContext().getString(CATEGORIES.get(i).nameResId);
|
final String title = getCarContext().getString(CATEGORIES.get(i).nameResId);
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
final int iconResId = CATEGORIES.get(i).iconResId;
|
final int iconResId = isNightMode ? CATEGORIES.get(i).iconNightResId : CATEGORIES.get(i).iconResId;
|
||||||
|
|
||||||
itemBuilder.setTitle(title);
|
itemBuilder.setTitle(title);
|
||||||
itemBuilder.setImage(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), iconResId)).build());
|
itemBuilder.setImage(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), iconResId)).build());
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class ErrorScreen extends BaseScreen implements UserActionRequired
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getCarContext().getString(mErrorMessage));
|
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getCarContext().getString(mErrorMessage));
|
||||||
|
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ import androidx.car.app.model.Template;
|
|||||||
import androidx.car.app.navigation.model.NavigationTemplate;
|
import androidx.car.app.navigation.model.NavigationTemplate;
|
||||||
import androidx.core.graphics.drawable.IconCompat;
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
|
|
||||||
public class FreeDriveScreen extends BaseMapScreen
|
public class FreeDriveScreen extends BaseMapScreen
|
||||||
{
|
{
|
||||||
public FreeDriveScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public FreeDriveScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final NavigationTemplate.Builder builder = new NavigationTemplate.Builder();
|
final NavigationTemplate.Builder builder = new NavigationTemplate.Builder();
|
||||||
builder.setMapActionStrip(UiHelpers.createMapActionStrip(getCarContext(), getSurfaceRenderer()));
|
builder.setMapActionStrip(UiHelpers.createMapActionStrip(getCarContext(), getSurfaceRenderer()));
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class MapPlaceholderScreen extends BaseScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MessageTemplate.Builder builder =
|
final MessageTemplate.Builder builder =
|
||||||
new MessageTemplate.Builder(getCarContext().getString(R.string.car_used_on_the_phone_screen));
|
new MessageTemplate.Builder(getCarContext().getString(R.string.car_used_on_the_phone_screen));
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import androidx.car.app.model.Template;
|
|||||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||||
import androidx.core.graphics.drawable.IconCompat;
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.screens.bookmarks.BookmarkCategoriesScreen;
|
import app.organicmaps.car.screens.bookmarks.BookmarkCategoriesScreen;
|
||||||
import app.organicmaps.car.screens.search.SearchScreen;
|
import app.organicmaps.car.screens.search.SearchScreen;
|
||||||
@@ -24,14 +24,14 @@ import app.organicmaps.car.util.UiHelpers;
|
|||||||
|
|
||||||
public class MapScreen extends BaseMapScreen
|
public class MapScreen extends BaseMapScreen
|
||||||
{
|
{
|
||||||
public MapScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public MapScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
SuggestionsHelpers.updateSuggestions(getCarContext());
|
SuggestionsHelpers.updateSuggestions(getCarContext());
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import androidx.lifecycle.LifecycleOwner;
|
|||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.CarAppService;
|
import app.organicmaps.car.CarAppService;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.screens.settings.DrivingOptionsScreen;
|
import app.organicmaps.car.screens.settings.DrivingOptionsScreen;
|
||||||
import app.organicmaps.car.util.Colors;
|
import app.organicmaps.car.util.Colors;
|
||||||
@@ -70,7 +70,7 @@ public class NavigationScreen extends BaseMapScreen implements RoutingController
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final NavigationTemplate.Builder builder = new NavigationTemplate.Builder();
|
final NavigationTemplate.Builder builder = new NavigationTemplate.Builder();
|
||||||
builder.setBackgroundColor(Colors.NAVIGATION_TEMPLATE_BACKGROUND);
|
builder.setBackgroundColor(Colors.NAVIGATION_TEMPLATE_BACKGROUND);
|
||||||
@@ -104,11 +104,7 @@ public class NavigationScreen extends BaseMapScreen implements RoutingController
|
|||||||
public void onAutoDriveEnabled()
|
public void onAutoDriveEnabled()
|
||||||
{
|
{
|
||||||
Logger.i(TAG);
|
Logger.i(TAG);
|
||||||
|
final JunctionInfo[] points = Framework.nativeGetRouteJunctionPoints();
|
||||||
/// @todo Pass maxDistM from RouteSimulationProvider?
|
|
||||||
/// Result speed between points will be in range (25, 50] km/h (for 1 second update interval).
|
|
||||||
final double kMaxDistM = 13.9; // 13.9 m/s == 50 km/h
|
|
||||||
final JunctionInfo[] points = Framework.nativeGetRouteJunctionPoints(kMaxDistM);
|
|
||||||
if (points == null)
|
if (points == null)
|
||||||
{
|
{
|
||||||
Logger.e(TAG, "Navigation has not started yet");
|
Logger.e(TAG, "Navigation has not started yet");
|
||||||
@@ -125,8 +121,6 @@ public class NavigationScreen extends BaseMapScreen implements RoutingController
|
|||||||
if (!mNavigationCancelled)
|
if (!mNavigationCancelled)
|
||||||
CarToast.makeText(getCarContext(), getCarContext().getString(R.string.trip_finished), CarToast.LENGTH_LONG)
|
CarToast.makeText(getCarContext(), getCarContext().getString(R.string.trip_finished), CarToast.LENGTH_LONG)
|
||||||
.show();
|
.show();
|
||||||
NavigationService.stopService(getCarContext());
|
|
||||||
ThemeUtils.update(getCarContext());
|
|
||||||
finish();
|
finish();
|
||||||
getScreenManager().popToRoot();
|
getScreenManager().popToRoot();
|
||||||
}
|
}
|
||||||
@@ -134,7 +128,7 @@ public class NavigationScreen extends BaseMapScreen implements RoutingController
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(@NonNull LifecycleOwner owner)
|
public void onCreate(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onCreate(owner);
|
Logger.d(TAG);
|
||||||
mRoutingController.attach(this);
|
mRoutingController.attach(this);
|
||||||
ThemeUtils.update(getCarContext());
|
ThemeUtils.update(getCarContext());
|
||||||
mNavigationManager.setNavigationManagerCallback(this);
|
mNavigationManager.setNavigationManagerCallback(this);
|
||||||
@@ -150,19 +144,20 @@ public class NavigationScreen extends BaseMapScreen implements RoutingController
|
|||||||
@Override
|
@Override
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
public void onResume(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onResume(owner);
|
Logger.d(TAG);
|
||||||
mRoutingController.attach(this);
|
mRoutingController.attach(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy(@NonNull LifecycleOwner owner)
|
public void onDestroy(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onDestroy(owner);
|
NavigationService.stopService(getCarContext());
|
||||||
MwmApplication.from(getCarContext()).getLocationHelper().removeListener(mLocationListener);
|
MwmApplication.from(getCarContext()).getLocationHelper().removeListener(mLocationListener);
|
||||||
|
|
||||||
if (mRoutingController.isNavigating())
|
if (mRoutingController.isNavigating())
|
||||||
mRoutingController.onSaveState();
|
mRoutingController.onSaveState();
|
||||||
mRoutingController.detach();
|
mRoutingController.detach();
|
||||||
|
ThemeUtils.update(getCarContext());
|
||||||
mNavigationManager.navigationEnded();
|
mNavigationManager.navigationEnded();
|
||||||
mNavigationManager.clearNavigationManagerCallback();
|
mNavigationManager.clearNavigationManagerCallback();
|
||||||
}
|
}
|
||||||
@@ -262,9 +257,9 @@ public class NavigationScreen extends BaseMapScreen implements RoutingController
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final CarContext mCarContext;
|
private final CarContext mCarContext;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Renderer mSurfaceRenderer;
|
private final SurfaceRenderer mSurfaceRenderer;
|
||||||
|
|
||||||
public Builder(@NonNull final CarContext carContext, @NonNull final Renderer surfaceRenderer)
|
public Builder(@NonNull final CarContext carContext, @NonNull final SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
mCarContext = carContext;
|
mCarContext = carContext;
|
||||||
mSurfaceRenderer = surfaceRenderer;
|
mSurfaceRenderer = surfaceRenderer;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import androidx.core.graphics.drawable.IconCompat;
|
|||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.screens.download.DownloadMapsScreenBuilder;
|
import app.organicmaps.car.screens.download.DownloadMapsScreenBuilder;
|
||||||
import app.organicmaps.car.screens.settings.DrivingOptionsScreen;
|
import app.organicmaps.car.screens.settings.DrivingOptionsScreen;
|
||||||
@@ -46,7 +46,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public class PlaceScreen extends BaseMapScreen implements OnBackPressedCallback.Callback, RoutingController.Container
|
public class PlaceScreen extends BaseMapScreen implements OnBackPressedCallback.Callback, RoutingController.Container
|
||||||
{
|
{
|
||||||
public static final Router ROUTER = Router.Vehicle;
|
private static final Router ROUTER = Router.Vehicle;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MapObject mMapObject;
|
private MapObject mMapObject;
|
||||||
@@ -68,7 +68,7 @@ public class PlaceScreen extends BaseMapScreen implements OnBackPressedCallback.
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
@@ -80,7 +80,6 @@ public class PlaceScreen extends BaseMapScreen implements OnBackPressedCallback.
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(@NonNull LifecycleOwner owner)
|
public void onCreate(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onCreate(owner);
|
|
||||||
mRoutingController.restore();
|
mRoutingController.restore();
|
||||||
if (mRoutingController.isNavigating() && mRoutingController.getLastRouterType() == ROUTER)
|
if (mRoutingController.isNavigating() && mRoutingController.getLastRouterType() == ROUTER)
|
||||||
{
|
{
|
||||||
@@ -113,14 +112,12 @@ public class PlaceScreen extends BaseMapScreen implements OnBackPressedCallback.
|
|||||||
@Override
|
@Override
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
public void onResume(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onResume(owner);
|
|
||||||
mRoutingController.attach(this);
|
mRoutingController.attach(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy(@NonNull LifecycleOwner owner)
|
public void onDestroy(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onDestroy(owner);
|
|
||||||
if (mRoutingController.isPlanning())
|
if (mRoutingController.isPlanning())
|
||||||
mRoutingController.onSaveState();
|
mRoutingController.onSaveState();
|
||||||
if (!mRoutingController.isNavigating())
|
if (!mRoutingController.isNavigating())
|
||||||
@@ -343,11 +340,11 @@ public class PlaceScreen extends BaseMapScreen implements OnBackPressedCallback.
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final CarContext mCarContext;
|
private final CarContext mCarContext;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Renderer mSurfaceRenderer;
|
private final SurfaceRenderer mSurfaceRenderer;
|
||||||
@Nullable
|
@Nullable
|
||||||
private MapObject mMapObject;
|
private MapObject mMapObject;
|
||||||
|
|
||||||
public Builder(@NonNull final CarContext carContext, @NonNull final Renderer surfaceRenderer)
|
public Builder(@NonNull final CarContext carContext, @NonNull final SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
mCarContext = carContext;
|
mCarContext = carContext;
|
||||||
mSurfaceRenderer = surfaceRenderer;
|
mSurfaceRenderer = surfaceRenderer;
|
||||||
|
|||||||
@@ -2,21 +2,21 @@ package app.organicmaps.car.screens.base;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.car.app.CarContext;
|
import androidx.car.app.CarContext;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
|
|
||||||
public abstract class BaseMapScreen extends BaseScreen
|
public abstract class BaseMapScreen extends BaseScreen
|
||||||
{
|
{
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Renderer mSurfaceRenderer;
|
private final SurfaceRenderer mSurfaceRenderer;
|
||||||
|
|
||||||
public BaseMapScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public BaseMapScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext);
|
super(carContext);
|
||||||
mSurfaceRenderer = surfaceRenderer;
|
mSurfaceRenderer = surfaceRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
protected Renderer getSurfaceRenderer()
|
protected SurfaceRenderer getSurfaceRenderer()
|
||||||
{
|
{
|
||||||
return mSurfaceRenderer;
|
return mSurfaceRenderer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,15 @@
|
|||||||
package app.organicmaps.car.screens.base;
|
package app.organicmaps.car.screens.base;
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.car.app.CarContext;
|
import androidx.car.app.CarContext;
|
||||||
import androidx.car.app.Screen;
|
import androidx.car.app.Screen;
|
||||||
import androidx.car.app.model.Template;
|
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
|
||||||
|
|
||||||
public abstract class BaseScreen extends Screen implements DefaultLifecycleObserver
|
public abstract class BaseScreen extends Screen implements DefaultLifecycleObserver
|
||||||
{
|
{
|
||||||
@NonNull
|
|
||||||
private final String TAG;
|
|
||||||
|
|
||||||
public BaseScreen(@NonNull CarContext carContext)
|
public BaseScreen(@NonNull CarContext carContext)
|
||||||
{
|
{
|
||||||
super(carContext);
|
super(carContext);
|
||||||
TAG = getClass().getSimpleName();
|
|
||||||
|
|
||||||
getLifecycle().addObserver(this);
|
getLifecycle().addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected abstract Template onGetTemplateImpl();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public final Template onGetTemplate()
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
return onGetTemplateImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void onCreate(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void onStart(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void onPause(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void onStop(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
public void onDestroy(@NonNull LifecycleOwner owner)
|
|
||||||
{
|
|
||||||
Logger.d(TAG);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import androidx.car.app.model.Row;
|
|||||||
import androidx.car.app.model.Template;
|
import androidx.car.app.model.Template;
|
||||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||||
@@ -23,7 +23,7 @@ public class BookmarkCategoriesScreen extends BaseMapScreen
|
|||||||
{
|
{
|
||||||
private final int MAX_CATEGORIES_SIZE;
|
private final int MAX_CATEGORIES_SIZE;
|
||||||
|
|
||||||
public BookmarkCategoriesScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public BookmarkCategoriesScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
final ConstraintManager constraintManager = getCarContext().getCarService(ConstraintManager.class);
|
final ConstraintManager constraintManager = getCarContext().getCarService(ConstraintManager.class);
|
||||||
@@ -32,7 +32,7 @@ public class BookmarkCategoriesScreen extends BaseMapScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import androidx.car.app.navigation.model.MapWithContentTemplate;
|
|||||||
import androidx.core.graphics.drawable.IconCompat;
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||||
@@ -31,7 +31,7 @@ public class BookmarksScreen extends BaseMapScreen
|
|||||||
|
|
||||||
private boolean mIsOnSortingScreen = false;
|
private boolean mIsOnSortingScreen = false;
|
||||||
|
|
||||||
public BookmarksScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer,
|
public BookmarksScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer,
|
||||||
@NonNull BookmarkCategory bookmarkCategory)
|
@NonNull BookmarkCategory bookmarkCategory)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
@@ -41,7 +41,7 @@ public class BookmarksScreen extends BaseMapScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
@@ -52,7 +52,6 @@ public class BookmarksScreen extends BaseMapScreen
|
|||||||
@Override
|
@Override
|
||||||
public void onStop(@NonNull LifecycleOwner owner)
|
public void onStop(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStop(owner);
|
|
||||||
if (!mIsOnSortingScreen)
|
if (!mIsOnSortingScreen)
|
||||||
mBookmarksLoader.cancel();
|
mBookmarksLoader.cancel();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import androidx.core.graphics.drawable.IconCompat;
|
|||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||||
@@ -38,7 +38,7 @@ class SortingScreen extends BaseMapScreen
|
|||||||
|
|
||||||
private @BookmarkManager.SortingType int mNewSortingType;
|
private @BookmarkManager.SortingType int mNewSortingType;
|
||||||
|
|
||||||
public SortingScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer,
|
public SortingScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer,
|
||||||
@NonNull BookmarkCategory bookmarkCategory)
|
@NonNull BookmarkCategory bookmarkCategory)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
@@ -53,7 +53,7 @@ class SortingScreen extends BaseMapScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ class DownloadMapsForFirstLaunchScreen extends DownloadMapsScreen
|
|||||||
@Override
|
@Override
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
public void onResume(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onResume(owner);
|
|
||||||
// Attempting to streamline initial download by including the current country in the list of missing maps for
|
// Attempting to streamline initial download by including the current country in the list of missing maps for
|
||||||
// simultaneous retrieval.
|
// simultaneous retrieval.
|
||||||
final Location location = MwmApplication.from(getCarContext()).getLocationHelper().getSavedLocation();
|
final Location location = MwmApplication.from(getCarContext()).getLocationHelper().getSavedLocation();
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public abstract class DownloadMapsScreen extends BaseScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected final Template onGetTemplateImpl()
|
public final Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getText(getMapsSize(mMissingMaps)));
|
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getText(getMapsSize(mMissingMaps)));
|
||||||
final Header.Builder headerBuilder = new Header.Builder();
|
final Header.Builder headerBuilder = new Header.Builder();
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ class DownloaderScreen extends BaseScreen
|
|||||||
@Override
|
@Override
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
public void onResume(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onResume(owner);
|
|
||||||
if (mSubscriptionSlot == 0)
|
if (mSubscriptionSlot == 0)
|
||||||
mSubscriptionSlot = MapManager.nativeSubscribe(mStorageCallback);
|
mSubscriptionSlot = MapManager.nativeSubscribe(mStorageCallback);
|
||||||
for (final var item : mMissingMaps.entrySet())
|
for (final var item : mMissingMaps.entrySet())
|
||||||
@@ -115,7 +114,6 @@ class DownloaderScreen extends BaseScreen
|
|||||||
@Override
|
@Override
|
||||||
public void onPause(@NonNull LifecycleOwner owner)
|
public void onPause(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onPause(owner);
|
|
||||||
if (!mIsDownloadFailed)
|
if (!mIsDownloadFailed)
|
||||||
cancelMapsDownloading();
|
cancelMapsDownloading();
|
||||||
if (mSubscriptionSlot != 0)
|
if (mSubscriptionSlot != 0)
|
||||||
@@ -127,7 +125,7 @@ class DownloaderScreen extends BaseScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getText());
|
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getText());
|
||||||
builder.setLoading(true);
|
builder.setLoading(true);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class RequestPermissionsScreenWithApi extends BaseScreen implements UserA
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MessageTemplate.Builder builder =
|
final MessageTemplate.Builder builder =
|
||||||
new MessageTemplate.Builder(getCarContext().getString(R.string.aa_request_permission_activity_text));
|
new MessageTemplate.Builder(getCarContext().getString(R.string.aa_request_permission_activity_text));
|
||||||
@@ -63,7 +63,6 @@ public class RequestPermissionsScreenWithApi extends BaseScreen implements UserA
|
|||||||
@Override
|
@Override
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
public void onResume(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onResume(owner);
|
|
||||||
// Let's review the permissions once more, as we might enter this function following an ErrorScreen situation
|
// Let's review the permissions once more, as we might enter this function following an ErrorScreen situation
|
||||||
// where the user manually enabled location permissions.
|
// where the user manually enabled location permissions.
|
||||||
if (LocationUtils.checkFineLocationPermission(getCarContext()))
|
if (LocationUtils.checkFineLocationPermission(getCarContext()))
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class RequestPermissionsScreenWithNotification extends BaseScreen impleme
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MessageTemplate.Builder builder =
|
final MessageTemplate.Builder builder =
|
||||||
new MessageTemplate.Builder(getCarContext().getString(R.string.aa_location_permissions_request));
|
new MessageTemplate.Builder(getCarContext().getString(R.string.aa_location_permissions_request));
|
||||||
@@ -66,7 +66,6 @@ public class RequestPermissionsScreenWithNotification extends BaseScreen impleme
|
|||||||
@RequiresPermission(value = Manifest.permission.POST_NOTIFICATIONS)
|
@RequiresPermission(value = Manifest.permission.POST_NOTIFICATIONS)
|
||||||
public void onStart(@NonNull LifecycleOwner owner)
|
public void onStart(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStart(owner);
|
|
||||||
mIsPermissionCheckEnabled = true;
|
mIsPermissionCheckEnabled = true;
|
||||||
mBackgroundExecutor.execute(this::checkPermissions);
|
mBackgroundExecutor.execute(this::checkPermissions);
|
||||||
sendPermissionsRequestNotification();
|
sendPermissionsRequestNotification();
|
||||||
@@ -75,14 +74,12 @@ public class RequestPermissionsScreenWithNotification extends BaseScreen impleme
|
|||||||
@Override
|
@Override
|
||||||
public void onStop(@NonNull LifecycleOwner owner)
|
public void onStop(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStop(owner);
|
|
||||||
mIsPermissionCheckEnabled = false;
|
mIsPermissionCheckEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy(@NonNull LifecycleOwner owner)
|
public void onDestroy(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onDestroy(owner);
|
|
||||||
NotificationManagerCompat.from(getCarContext()).cancel(NOTIFICATION_ID);
|
NotificationManagerCompat.from(getCarContext()).cancel(NOTIFICATION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import androidx.core.graphics.drawable.IconCompat;
|
|||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
import app.organicmaps.sdk.bookmarks.data.MapObject;
|
import app.organicmaps.sdk.bookmarks.data.MapObject;
|
||||||
@@ -54,7 +54,7 @@ public class SearchOnMapScreen extends BaseMapScreen implements SearchListener
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
@@ -136,14 +136,12 @@ public class SearchOnMapScreen extends BaseMapScreen implements SearchListener
|
|||||||
@Override
|
@Override
|
||||||
public void onStart(@NonNull LifecycleOwner owner)
|
public void onStart(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStart(owner);
|
|
||||||
SearchEngine.INSTANCE.addListener(this);
|
SearchEngine.INSTANCE.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume(@NonNull LifecycleOwner owner)
|
public void onResume(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onResume(owner);
|
|
||||||
SearchEngine.INSTANCE.cancel();
|
SearchEngine.INSTANCE.cancel();
|
||||||
|
|
||||||
final MapObject location = MwmApplication.from(getCarContext()).getLocationHelper().getMyPosition();
|
final MapObject location = MwmApplication.from(getCarContext()).getLocationHelper().getMyPosition();
|
||||||
@@ -158,7 +156,6 @@ public class SearchOnMapScreen extends BaseMapScreen implements SearchListener
|
|||||||
@Override
|
@Override
|
||||||
public void onStop(@NonNull LifecycleOwner owner)
|
public void onStop(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStop(owner);
|
|
||||||
SearchEngine.INSTANCE.removeListener(this);
|
SearchEngine.INSTANCE.removeListener(this);
|
||||||
SearchEngine.INSTANCE.cancel();
|
SearchEngine.INSTANCE.cancel();
|
||||||
}
|
}
|
||||||
@@ -180,7 +177,7 @@ public class SearchOnMapScreen extends BaseMapScreen implements SearchListener
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final CarContext mCarContext;
|
private final CarContext mCarContext;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Renderer mSurfaceRenderer;
|
private final SurfaceRenderer mSurfaceRenderer;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private String mQuery = "";
|
private String mQuery = "";
|
||||||
@@ -188,7 +185,7 @@ public class SearchOnMapScreen extends BaseMapScreen implements SearchListener
|
|||||||
private String mLocale;
|
private String mLocale;
|
||||||
private boolean mIsCategory;
|
private boolean mIsCategory;
|
||||||
|
|
||||||
public Builder(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public Builder(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
mCarContext = carContext;
|
mCarContext = carContext;
|
||||||
mSurfaceRenderer = surfaceRenderer;
|
mSurfaceRenderer = surfaceRenderer;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import androidx.core.graphics.drawable.IconCompat;
|
|||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.sdk.bookmarks.data.MapObject;
|
import app.organicmaps.sdk.bookmarks.data.MapObject;
|
||||||
import app.organicmaps.sdk.search.SearchEngine;
|
import app.organicmaps.sdk.search.SearchEngine;
|
||||||
@@ -50,7 +50,7 @@ public class SearchScreen extends BaseMapScreen implements SearchTemplate.Search
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final SearchTemplate.Builder builder = new SearchTemplate.Builder(this);
|
final SearchTemplate.Builder builder = new SearchTemplate.Builder(this);
|
||||||
builder.setHeaderAction(Action.BACK);
|
builder.setHeaderAction(Action.BACK);
|
||||||
@@ -106,14 +106,12 @@ public class SearchScreen extends BaseMapScreen implements SearchTemplate.Search
|
|||||||
@Override
|
@Override
|
||||||
public void onStart(@NonNull LifecycleOwner owner)
|
public void onStart(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStart(owner);
|
|
||||||
SearchEngine.INSTANCE.addListener(this);
|
SearchEngine.INSTANCE.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop(@NonNull LifecycleOwner owner)
|
public void onStop(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStop(owner);
|
|
||||||
SearchEngine.INSTANCE.removeListener(this);
|
SearchEngine.INSTANCE.removeListener(this);
|
||||||
SearchEngine.INSTANCE.cancel();
|
SearchEngine.INSTANCE.cancel();
|
||||||
}
|
}
|
||||||
@@ -211,14 +209,14 @@ public class SearchScreen extends BaseMapScreen implements SearchTemplate.Search
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final CarContext mCarContext;
|
private final CarContext mCarContext;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Renderer mSurfaceRenderer;
|
private final SurfaceRenderer mSurfaceRenderer;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private String mQuery = "";
|
private String mQuery = "";
|
||||||
@NonNull
|
@NonNull
|
||||||
private String mLocale;
|
private String mLocale;
|
||||||
|
|
||||||
public Builder(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public Builder(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
mCarContext = carContext;
|
mCarContext = carContext;
|
||||||
mSurfaceRenderer = surfaceRenderer;
|
mSurfaceRenderer = surfaceRenderer;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import androidx.car.app.model.Template;
|
|||||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.Toggle;
|
import app.organicmaps.car.util.Toggle;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
@@ -31,14 +31,12 @@ public class DrivingOptionsScreen extends BaseMapScreen
|
|||||||
private final DrivingOption[] mDrivingOptions = {new DrivingOption(RoadType.Toll, R.string.avoid_tolls),
|
private final DrivingOption[] mDrivingOptions = {new DrivingOption(RoadType.Toll, R.string.avoid_tolls),
|
||||||
new DrivingOption(RoadType.Dirty, R.string.avoid_unpaved),
|
new DrivingOption(RoadType.Dirty, R.string.avoid_unpaved),
|
||||||
new DrivingOption(RoadType.Ferry, R.string.avoid_ferry),
|
new DrivingOption(RoadType.Ferry, R.string.avoid_ferry),
|
||||||
new DrivingOption(RoadType.Motorway, R.string.avoid_motorways),
|
new DrivingOption(RoadType.Motorway, R.string.avoid_motorways)};
|
||||||
new DrivingOption(RoadType.Steps, R.string.avoid_steps),
|
|
||||||
new DrivingOption(RoadType.Paved, R.string.avoid_paved)};
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Map<RoadType, Boolean> mInitialDrivingOptionsState = new HashMap<>();
|
private final Map<RoadType, Boolean> mInitialDrivingOptionsState = new HashMap<>();
|
||||||
|
|
||||||
public DrivingOptionsScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public DrivingOptionsScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
|
|
||||||
@@ -47,7 +45,7 @@ public class DrivingOptionsScreen extends BaseMapScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
@@ -58,7 +56,6 @@ public class DrivingOptionsScreen extends BaseMapScreen
|
|||||||
@Override
|
@Override
|
||||||
public void onStop(@NonNull LifecycleOwner owner)
|
public void onStop(@NonNull LifecycleOwner owner)
|
||||||
{
|
{
|
||||||
super.onStop(owner);
|
|
||||||
for (final DrivingOption drivingOption : mDrivingOptions)
|
for (final DrivingOption drivingOption : mDrivingOptions)
|
||||||
{
|
{
|
||||||
if (Boolean.TRUE.equals(mInitialDrivingOptionsState.get(drivingOption.roadType))
|
if (Boolean.TRUE.equals(mInitialDrivingOptionsState.get(drivingOption.roadType))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import androidx.car.app.model.Template;
|
|||||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||||
import app.organicmaps.BuildConfig;
|
import app.organicmaps.BuildConfig;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
import app.organicmaps.sdk.Framework;
|
import app.organicmaps.sdk.Framework;
|
||||||
@@ -20,14 +20,14 @@ import app.organicmaps.sdk.util.DateUtils;
|
|||||||
|
|
||||||
public class HelpScreen extends BaseMapScreen
|
public class HelpScreen extends BaseMapScreen
|
||||||
{
|
{
|
||||||
public HelpScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public HelpScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import androidx.car.app.model.Row;
|
|||||||
import androidx.car.app.model.Template;
|
import androidx.car.app.model.Template;
|
||||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.ThemeUtils;
|
import app.organicmaps.car.util.ThemeUtils;
|
||||||
import app.organicmaps.car.util.Toggle;
|
import app.organicmaps.car.util.Toggle;
|
||||||
@@ -33,14 +33,14 @@ public class SettingsScreen extends BaseMapScreen
|
|||||||
void set(boolean newValue);
|
void set(boolean newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SettingsScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public SettingsScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import androidx.car.app.model.Template;
|
|||||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||||
import androidx.core.graphics.drawable.IconCompat;
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.util.ThemeUtils;
|
import app.organicmaps.car.util.ThemeUtils;
|
||||||
import app.organicmaps.car.util.UiHelpers;
|
import app.organicmaps.car.util.UiHelpers;
|
||||||
@@ -24,7 +24,7 @@ public class ThemeScreen extends BaseMapScreen
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final CarIcon mRadioButtonSelectedIcon;
|
private final CarIcon mRadioButtonSelectedIcon;
|
||||||
|
|
||||||
public ThemeScreen(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer)
|
public ThemeScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
super(carContext, surfaceRenderer);
|
super(carContext, surfaceRenderer);
|
||||||
mRadioButtonIcon =
|
mRadioButtonIcon =
|
||||||
@@ -35,7 +35,7 @@ public class ThemeScreen extends BaseMapScreen
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Template onGetTemplateImpl()
|
public Template onGetTemplate()
|
||||||
{
|
{
|
||||||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import androidx.car.app.notification.CarPendingIntent;
|
|||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.api.Const;
|
import app.organicmaps.api.Const;
|
||||||
import app.organicmaps.car.CarAppService;
|
import app.organicmaps.car.CarAppService;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.NavigationScreen;
|
import app.organicmaps.car.screens.NavigationScreen;
|
||||||
import app.organicmaps.car.screens.search.SearchScreen;
|
import app.organicmaps.car.screens.search.SearchScreen;
|
||||||
import app.organicmaps.sdk.Framework;
|
import app.organicmaps.sdk.Framework;
|
||||||
@@ -30,7 +30,7 @@ public final class IntentUtils
|
|||||||
|
|
||||||
private static final int SEARCH_IN_VIEWPORT_ZOOM = 16;
|
private static final int SEARCH_IN_VIEWPORT_ZOOM = 16;
|
||||||
|
|
||||||
public static void processIntent(@NonNull CarContext carContext, @NonNull Renderer surfaceRenderer,
|
public static void processIntent(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer,
|
||||||
@NonNull Intent intent)
|
@NonNull Intent intent)
|
||||||
{
|
{
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
@@ -50,8 +50,8 @@ public final class IntentUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.android.com/reference/androidx/car/app/CarContext#startCarApp(android.content.Intent)
|
// https://developer.android.com/reference/androidx/car/app/CarContext#startCarApp(android.content.Intent)
|
||||||
private static void processNavigationIntent(@NonNull CarContext carContext,
|
private static void processNavigationIntent(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer,
|
||||||
@NonNull Renderer surfaceRenderer, @NonNull Intent intent)
|
@NonNull Intent intent)
|
||||||
{
|
{
|
||||||
// TODO (AndrewShkrob): This logic will need to be revised when we introduce support for adding stops during
|
// TODO (AndrewShkrob): This logic will need to be revised when we introduce support for adding stops during
|
||||||
// navigation or route planning. Skip navigation intents during navigation
|
// navigation or route planning. Skip navigation intents during navigation
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import androidx.car.app.navigation.model.MapController;
|
|||||||
import androidx.core.graphics.drawable.IconCompat;
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.car.renderer.Renderer;
|
import app.organicmaps.car.SurfaceRenderer;
|
||||||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||||
import app.organicmaps.car.screens.settings.SettingsScreen;
|
import app.organicmaps.car.screens.settings.SettingsScreen;
|
||||||
import app.organicmaps.sdk.Map;
|
import app.organicmaps.sdk.Map;
|
||||||
@@ -33,14 +33,13 @@ public final class UiHelpers
|
|||||||
{
|
{
|
||||||
@NonNull
|
@NonNull
|
||||||
public static ActionStrip createSettingsActionStrip(@NonNull BaseMapScreen mapScreen,
|
public static ActionStrip createSettingsActionStrip(@NonNull BaseMapScreen mapScreen,
|
||||||
@NonNull Renderer surfaceRenderer)
|
@NonNull SurfaceRenderer surfaceRenderer)
|
||||||
{
|
{
|
||||||
return new ActionStrip.Builder().addAction(createSettingsAction(mapScreen, surfaceRenderer)).build();
|
return new ActionStrip.Builder().addAction(createSettingsAction(mapScreen, surfaceRenderer)).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static ActionStrip createMapActionStrip(@NonNull CarContext context,
|
public static ActionStrip createMapActionStrip(@NonNull CarContext context, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
@NonNull Renderer surfaceRenderer)
|
|
||||||
{
|
{
|
||||||
final CarIcon iconPlus = new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_plus)).build();
|
final CarIcon iconPlus = new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_plus)).build();
|
||||||
final CarIcon iconMinus = new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_minus)).build();
|
final CarIcon iconMinus = new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_minus)).build();
|
||||||
@@ -59,30 +58,27 @@ public final class UiHelpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static MapController createMapController(@NonNull CarContext context,
|
public static MapController createMapController(@NonNull CarContext context, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
@NonNull Renderer surfaceRenderer)
|
|
||||||
{
|
{
|
||||||
return new MapController.Builder().setMapActionStrip(createMapActionStrip(context, surfaceRenderer)).build();
|
return new MapController.Builder().setMapActionStrip(createMapActionStrip(context, surfaceRenderer)).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Action createSettingsAction(@NonNull BaseMapScreen mapScreen,
|
public static Action createSettingsAction(@NonNull BaseMapScreen mapScreen, @NonNull SurfaceRenderer surfaceRenderer)
|
||||||
@NonNull Renderer surfaceRenderer)
|
|
||||||
{
|
{
|
||||||
return createSettingsAction(mapScreen, surfaceRenderer, null);
|
return createSettingsAction(mapScreen, surfaceRenderer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Action createSettingsActionForResult(@NonNull BaseMapScreen mapScreen,
|
public static Action createSettingsActionForResult(@NonNull BaseMapScreen mapScreen,
|
||||||
@NonNull Renderer surfaceRenderer,
|
@NonNull SurfaceRenderer surfaceRenderer,
|
||||||
@NonNull OnScreenResultListener onScreenResultListener)
|
@NonNull OnScreenResultListener onScreenResultListener)
|
||||||
{
|
{
|
||||||
return createSettingsAction(mapScreen, surfaceRenderer, onScreenResultListener);
|
return createSettingsAction(mapScreen, surfaceRenderer, onScreenResultListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static Action createSettingsAction(@NonNull BaseMapScreen mapScreen,
|
private static Action createSettingsAction(@NonNull BaseMapScreen mapScreen, @NonNull SurfaceRenderer surfaceRenderer,
|
||||||
@NonNull Renderer surfaceRenderer,
|
|
||||||
@Nullable OnScreenResultListener onScreenResultListener)
|
@Nullable OnScreenResultListener onScreenResultListener)
|
||||||
{
|
{
|
||||||
final CarContext context = mapScreen.getCarContext();
|
final CarContext context = mapScreen.getCarContext();
|
||||||
@@ -124,7 +120,7 @@ public final class UiHelpers
|
|||||||
|
|
||||||
final Row.Builder builder = new Row.Builder();
|
final Row.Builder builder = new Row.Builder();
|
||||||
builder.setImage(
|
builder.setImage(
|
||||||
new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_opening_hours)).build());
|
new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_operating_hours)).build());
|
||||||
|
|
||||||
if (isEmptyTT)
|
if (isEmptyTT)
|
||||||
builder.setTitle(ohStr);
|
builder.setTitle(ohStr);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public class EditTextDialogFragment extends BaseMwmDialogFragment
|
|||||||
private String mHint;
|
private String mHint;
|
||||||
private TextInputEditText mEtInput;
|
private TextInputEditText mEtInput;
|
||||||
private TextInputLayout mEtInputLayout;
|
private TextInputLayout mEtInputLayout;
|
||||||
|
private Button mPositiveButton;
|
||||||
private Validator mInputValidator;
|
private Validator mInputValidator;
|
||||||
private OnTextSaveListener mTextSaveListener;
|
private OnTextSaveListener mTextSaveListener;
|
||||||
|
|
||||||
@@ -116,20 +117,21 @@ public class EditTextDialogFragment extends BaseMwmDialogFragment
|
|||||||
AlertDialog editTextDialog = new MaterialAlertDialogBuilder(requireActivity(), R.style.MwmTheme_AlertDialog)
|
AlertDialog editTextDialog = new MaterialAlertDialogBuilder(requireActivity(), R.style.MwmTheme_AlertDialog)
|
||||||
.setView(buildView())
|
.setView(buildView())
|
||||||
.setNegativeButton(negativeButtonText, null)
|
.setNegativeButton(negativeButtonText, null)
|
||||||
.setPositiveButton(positiveButtonText, null)
|
.setPositiveButton(positiveButtonText,
|
||||||
|
(dialog, which) -> {
|
||||||
|
final String result = mEtInput.getText().toString();
|
||||||
|
processInput(result);
|
||||||
|
dismiss();
|
||||||
|
})
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
// Set up onClick listener for mPositiveButton.
|
// Wait till alert is shown to get mPositiveButton.
|
||||||
editTextDialog.setOnShowListener((dialog) -> {
|
editTextDialog.setOnShowListener((dialog) -> {
|
||||||
Button positiveButton = editTextDialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
mPositiveButton = editTextDialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||||
|
final FragmentActivity activity = getActivity();
|
||||||
positiveButton.setOnClickListener(view -> {
|
if (activity == null)
|
||||||
final String result = mEtInput.getText().toString();
|
return;
|
||||||
if (validateInput(requireActivity(), result)) {
|
this.validateInput(activity, mInitialText);
|
||||||
processInput(result);
|
|
||||||
editTextDialog.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup validation on input edit.
|
// Setup validation on input edit.
|
||||||
@@ -147,16 +149,14 @@ public class EditTextDialogFragment extends BaseMwmDialogFragment
|
|||||||
return editTextDialog;
|
return editTextDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateInput(@NonNull FragmentActivity activity, @Nullable String input)
|
private void validateInput(@NonNull FragmentActivity activity, @Nullable String input)
|
||||||
{
|
{
|
||||||
if (mInputValidator != null)
|
if (mPositiveButton != null && mInputValidator != null)
|
||||||
{
|
{
|
||||||
final String maybeError = mInputValidator.validate(activity, input);
|
final String maybeError = mInputValidator.validate(activity, input);
|
||||||
|
mPositiveButton.setEnabled(maybeError == null);
|
||||||
mEtInputLayout.getEditText().setError(maybeError);
|
mEtInputLayout.getEditText().setError(maybeError);
|
||||||
mEtInputLayout.requestFocus();
|
|
||||||
return maybeError == null;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processInput(@Nullable String text)
|
private void processInput(@Nullable String text)
|
||||||
|
|||||||
@@ -222,10 +222,10 @@ public class DownloaderFragment
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (mAdapter != null && mAdapter.isSearchResultsMode())
|
if (mAdapter != null && mAdapter.isSearchResultsMode())
|
||||||
placeholder.setContent(R.string.search_not_found, R.string.search_not_found_query, R.drawable.ic_search_fail);
|
placeholder.setContent(R.string.search_not_found, R.string.search_not_found_query);
|
||||||
else
|
else
|
||||||
placeholder.setContent(R.string.downloader_no_downloaded_maps_title,
|
placeholder.setContent(R.string.downloader_no_downloaded_maps_title,
|
||||||
R.string.downloader_no_downloaded_maps_message, R.drawable.ic_download);
|
R.string.downloader_no_downloaded_maps_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,19 +1,13 @@
|
|||||||
package app.organicmaps.editor;
|
package app.organicmaps.editor;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AutoCompleteTextView;
|
|
||||||
import android.widget.GridLayout;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.IdRes;
|
import androidx.annotation.IdRes;
|
||||||
@@ -28,7 +22,6 @@ import app.organicmaps.base.BaseMwmFragment;
|
|||||||
import app.organicmaps.dialog.EditTextDialogFragment;
|
import app.organicmaps.dialog.EditTextDialogFragment;
|
||||||
import app.organicmaps.editor.data.TimeFormatUtils;
|
import app.organicmaps.editor.data.TimeFormatUtils;
|
||||||
import app.organicmaps.sdk.Framework;
|
import app.organicmaps.sdk.Framework;
|
||||||
import app.organicmaps.sdk.bookmarks.data.ChargeSocketDescriptor;
|
|
||||||
import app.organicmaps.sdk.bookmarks.data.Metadata;
|
import app.organicmaps.sdk.bookmarks.data.Metadata;
|
||||||
import app.organicmaps.sdk.editor.Editor;
|
import app.organicmaps.sdk.editor.Editor;
|
||||||
import app.organicmaps.sdk.editor.OpeningHours;
|
import app.organicmaps.sdk.editor.OpeningHours;
|
||||||
@@ -37,33 +30,26 @@ import app.organicmaps.sdk.editor.data.LocalizedStreet;
|
|||||||
import app.organicmaps.sdk.editor.data.Timetable;
|
import app.organicmaps.sdk.editor.data.Timetable;
|
||||||
import app.organicmaps.sdk.util.StringUtils;
|
import app.organicmaps.sdk.util.StringUtils;
|
||||||
import app.organicmaps.sdk.util.Utils;
|
import app.organicmaps.sdk.util.Utils;
|
||||||
import app.organicmaps.sdk.util.log.Logger;
|
|
||||||
import app.organicmaps.util.Graphics;
|
import app.organicmaps.util.Graphics;
|
||||||
import app.organicmaps.util.InputUtils;
|
import app.organicmaps.util.InputUtils;
|
||||||
import app.organicmaps.util.UiUtils;
|
import app.organicmaps.util.UiUtils;
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.google.android.material.card.MaterialCardView;
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.imageview.ShapeableImageView;
|
import com.google.android.material.imageview.ShapeableImageView;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.google.android.material.textview.MaterialTextView;
|
import com.google.android.material.textview.MaterialTextView;
|
||||||
import java.text.DecimalFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class EditorFragment extends BaseMwmFragment implements View.OnClickListener
|
public class EditorFragment extends BaseMwmFragment implements View.OnClickListener
|
||||||
{
|
{
|
||||||
final static String LAST_INDEX_OF_NAMES_ARRAY = "LastIndexOfNamesArray";
|
final static String LAST_INDEX_OF_NAMES_ARRAY = "LastIndexOfNamesArray";
|
||||||
private static final String CHARGE_SOCKETS_TAG = "CHARGE_SOCKETS_TAG";
|
|
||||||
|
|
||||||
private MaterialTextView mCategory;
|
private MaterialTextView mCategory;
|
||||||
private View mCardName;
|
private View mCardName;
|
||||||
private View mCardAddress;
|
private View mCardAddress;
|
||||||
private View mCardChargingStation;
|
|
||||||
private View mCardDetails;
|
private View mCardDetails;
|
||||||
private View mCardSocialMedia;
|
private View mCardSocialMedia;
|
||||||
private View mCardBuilding;
|
private View mCardBuilding;
|
||||||
@@ -144,8 +130,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
|
|||||||
private TextInputLayout mInputHouseNumber;
|
private TextInputLayout mInputHouseNumber;
|
||||||
private TextInputLayout mInputBuildingLevels;
|
private TextInputLayout mInputBuildingLevels;
|
||||||
|
|
||||||
private View mChargeSockets;
|
|
||||||
|
|
||||||
private View mEmptyOpeningHours;
|
private View mEmptyOpeningHours;
|
||||||
private MaterialTextView mOpeningHours;
|
private MaterialTextView mOpeningHours;
|
||||||
private View mEditOpeningHours;
|
private View mEditOpeningHours;
|
||||||
@@ -222,7 +206,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
|
|||||||
mWifi.setChecked(Editor.nativeHasWifi());
|
mWifi.setChecked(Editor.nativeHasWifi());
|
||||||
// TODO Reimplement this to avoid https://github.com/organicmaps/organicmaps/issues/9049
|
// TODO Reimplement this to avoid https://github.com/organicmaps/organicmaps/issues/9049
|
||||||
// mOutdoorSeating.setChecked(Editor.nativeGetSwitchInput(Metadata.MetadataType.FMD_OUTDOOR_SEATING.toInt(),"yes"));
|
// mOutdoorSeating.setChecked(Editor.nativeGetSwitchInput(Metadata.MetadataType.FMD_OUTDOOR_SEATING.toInt(),"yes"));
|
||||||
refreshChargeSockets();
|
|
||||||
refreshOpeningTime();
|
refreshOpeningTime();
|
||||||
refreshEditableFields();
|
refreshEditableFields();
|
||||||
refreshResetButton();
|
refreshResetButton();
|
||||||
@@ -346,15 +329,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
|
|||||||
|
|
||||||
final int[] editableDetails = Editor.nativeGetEditableProperties();
|
final int[] editableDetails = Editor.nativeGetEditableProperties();
|
||||||
|
|
||||||
// charge sockets have their own card; check whether we should display it.
|
|
||||||
boolean hasChargeSockets = false;
|
|
||||||
for (int type : editableDetails)
|
|
||||||
{
|
|
||||||
hasChargeSockets = hasChargeSockets || (type == Metadata.MetadataType.FMD_CHARGE_SOCKETS.toInt());
|
|
||||||
}
|
|
||||||
// Hide socket until https://codeberg.org/comaps/comaps/issues/2368 is fixed
|
|
||||||
//UiUtils.showIf(hasChargeSockets, mCardChargingStation);
|
|
||||||
|
|
||||||
setCardVisibility(mCardDetails, mDetailsBlocks, editableDetails);
|
setCardVisibility(mCardDetails, mDetailsBlocks, editableDetails);
|
||||||
setCardVisibility(mCardSocialMedia, mSocialMediaBlocks, editableDetails);
|
setCardVisibility(mCardSocialMedia, mSocialMediaBlocks, editableDetails);
|
||||||
}
|
}
|
||||||
@@ -377,283 +351,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
|
|||||||
UiUtils.showIf(anyBlockElement, card);
|
UiUtils.showIf(anyBlockElement, card);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a dialog for editing or adding a charge socket.
|
|
||||||
*
|
|
||||||
* @param socketIndex The index of the socket to edit, or -1 to add a new socket.
|
|
||||||
* @param type The current type of the socket (e.g., "type2", "type2_combo").
|
|
||||||
* @param count The current number of sockets of this type or 0 for new socket.
|
|
||||||
* @param power The current power output of the socket in kW or 0 for new socket.
|
|
||||||
* @return A MaterialAlertDialogBuilder instance for the configured dialog.
|
|
||||||
*/
|
|
||||||
private MaterialAlertDialogBuilder buildChargeSocketDialog(int socketIndex, String type, int count, double power)
|
|
||||||
{
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(getActivity());
|
|
||||||
View dialogView = inflater.inflate(R.layout.dialog_edit_socket, null);
|
|
||||||
|
|
||||||
GridLayout typeBtns = dialogView.findViewById(R.id.edit_socket_type_grid);
|
|
||||||
typeBtns.removeAllViews();
|
|
||||||
|
|
||||||
List<String> SOCKET_TYPES = Arrays.stream(getResources().getStringArray(R.array.charge_socket_types)).toList();
|
|
||||||
for (String socket : SOCKET_TYPES)
|
|
||||||
{
|
|
||||||
MaterialButton btn = (MaterialButton) inflater.inflate(R.layout.button_socket_type, typeBtns, false);
|
|
||||||
|
|
||||||
btn.setTag(R.id.socket_type, socket);
|
|
||||||
|
|
||||||
// load SVG icon converted into VectorDrawable in res/drawable
|
|
||||||
@SuppressLint("DiscouragedApi")
|
|
||||||
int resIconId =
|
|
||||||
getResources().getIdentifier("ic_charge_socket_" + socket, "drawable", requireContext().getPackageName());
|
|
||||||
if (resIconId != 0)
|
|
||||||
{
|
|
||||||
btn.setIcon(getResources().getDrawable(resIconId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("DiscouragedApi")
|
|
||||||
int resTypeId =
|
|
||||||
getResources().getIdentifier("charge_socket_" + socket, "string", requireContext().getPackageName());
|
|
||||||
if (resTypeId != 0)
|
|
||||||
{
|
|
||||||
btn.setText(getResources().getString(resTypeId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (socket.equals(type))
|
|
||||||
{
|
|
||||||
btn.setChecked(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
typeBtns.addView(btn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// manage the grid of socket type buttons as a single 'radio group'
|
|
||||||
// (this can not be done with a MaterialButtonToggleGroup because it does
|
|
||||||
// not support GridLayout)
|
|
||||||
List<MaterialButton> buttonList = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int i = 0; i < typeBtns.getChildCount(); i++)
|
|
||||||
{
|
|
||||||
View child = typeBtns.getChildAt(i);
|
|
||||||
if (child instanceof MaterialButton button)
|
|
||||||
{
|
|
||||||
buttonList.add(button);
|
|
||||||
|
|
||||||
button.setOnClickListener(view -> {
|
|
||||||
// deselect all
|
|
||||||
for (MaterialButton b : buttonList)
|
|
||||||
{
|
|
||||||
b.setChecked(false);
|
|
||||||
}
|
|
||||||
// select clicked
|
|
||||||
button.setChecked(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextInputLayout countInputLayout = dialogView.findViewById(R.id.edit_socket_count_layout);
|
|
||||||
AutoCompleteTextView countView = dialogView.findViewById(R.id.edit_socket_count);
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
countView.setText(String.valueOf(count));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a TextWatcher to validate on text change
|
|
||||||
countView.addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
validatePositiveField(s.toString(), countInputLayout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
TextInputLayout powerInputLayout = dialogView.findViewById(R.id.edit_socket_power_layout);
|
|
||||||
AutoCompleteTextView powerView = dialogView.findViewById(R.id.edit_socket_power);
|
|
||||||
if (power > 0)
|
|
||||||
{
|
|
||||||
powerView.setText(String.valueOf(power));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a TextWatcher to validate on text change
|
|
||||||
powerView.addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
validatePositiveField(s.toString(), powerInputLayout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return new MaterialAlertDialogBuilder(requireActivity(), R.style.MwmTheme_AlertDialog)
|
|
||||||
.setTitle(R.string.editor_socket)
|
|
||||||
.setView(dialogView)
|
|
||||||
.setPositiveButton(R.string.save,
|
|
||||||
(dialog, which) -> {
|
|
||||||
String socketType = "";
|
|
||||||
for (MaterialButton b : buttonList)
|
|
||||||
{
|
|
||||||
if (b.isChecked())
|
|
||||||
{
|
|
||||||
socketType = b.getTag(R.id.socket_type).toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int countValue = 0; // 0 means 'unknown count'
|
|
||||||
try
|
|
||||||
{
|
|
||||||
countValue = Integer.parseInt(countView.getText().toString());
|
|
||||||
}
|
|
||||||
catch (NumberFormatException ignored)
|
|
||||||
{
|
|
||||||
Logger.w(CHARGE_SOCKETS_TAG, "Invalid count value for socket:" + countView.getText().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (countValue < 0)
|
|
||||||
{
|
|
||||||
countValue = 0;
|
|
||||||
Logger.w(CHARGE_SOCKETS_TAG, "Invalid count value for socket:" + countView.getText().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
double powerValue = 0; // 0 means 'unknown power'
|
|
||||||
try
|
|
||||||
{
|
|
||||||
powerValue = Double.parseDouble(powerView.getText().toString());
|
|
||||||
}
|
|
||||||
catch (NumberFormatException ignored)
|
|
||||||
{
|
|
||||||
Logger.w(CHARGE_SOCKETS_TAG, "Invalid power value for socket:" + powerView.getText().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (powerValue < 0)
|
|
||||||
{
|
|
||||||
powerValue = 0;
|
|
||||||
Logger.w(CHARGE_SOCKETS_TAG, "Invalid power value for socket:" + powerView.getText().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
ChargeSocketDescriptor socket =
|
|
||||||
new ChargeSocketDescriptor(socketType, countValue, powerValue);
|
|
||||||
|
|
||||||
updateChargeSockets(socketIndex, socket);
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.cancel, (dialog, which) -> { dialog.dismiss(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method for validation logic
|
|
||||||
private boolean validatePositiveField(String text, TextInputLayout layout) {
|
|
||||||
if (text.isEmpty()) {
|
|
||||||
layout.setError(null); // No error if empty (assuming 0 is the default)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
double value = Double.parseDouble(text);
|
|
||||||
if (value < 0) {
|
|
||||||
layout.setError(getString(R.string.error_value_must_be_positive));
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
layout.setError(null);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
layout.setError(getString(R.string.error_invalid_number));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Updates the list of charge sockets.
|
|
||||||
* If socketIndex is >=0, it updates the socket at that index.
|
|
||||||
* Otherwise, it adds the new socket to the list.
|
|
||||||
*
|
|
||||||
* @param socketIndex The index of the socket to update, or -1 to add a new socket.
|
|
||||||
* @param socket The ChargeSocketDescriptor of the socket to add or update.
|
|
||||||
*/
|
|
||||||
private void updateChargeSockets(int socketIndex, ChargeSocketDescriptor socket)
|
|
||||||
{
|
|
||||||
ChargeSocketDescriptor[] sockets = Editor.nativeGetChargeSockets();
|
|
||||||
if (socketIndex >= 0)
|
|
||||||
{
|
|
||||||
sockets[socketIndex] = socket;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
List<ChargeSocketDescriptor> list = new ArrayList<>(Arrays.asList(sockets));
|
|
||||||
list.add(socket);
|
|
||||||
sockets = list.toArray(new ChargeSocketDescriptor[0]);
|
|
||||||
}
|
|
||||||
Editor.nativeSetChargeSockets(sockets);
|
|
||||||
|
|
||||||
refreshChargeSockets();
|
|
||||||
}
|
|
||||||
private void refreshChargeSockets()
|
|
||||||
{
|
|
||||||
ChargeSocketDescriptor[] sockets = Editor.nativeGetChargeSockets();
|
|
||||||
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(requireContext());
|
|
||||||
|
|
||||||
GridLayout socketsGrid = mChargeSockets.findViewById(R.id.socket_grid_editor);
|
|
||||||
socketsGrid.removeAllViews();
|
|
||||||
|
|
||||||
for (int i = 0; i < sockets.length; i++)
|
|
||||||
{
|
|
||||||
final int currentIndex = i;
|
|
||||||
ChargeSocketDescriptor socket = sockets[i];
|
|
||||||
|
|
||||||
View itemView = inflater.inflate(R.layout.item_charge_socket, socketsGrid, false);
|
|
||||||
|
|
||||||
MaterialTextView type = itemView.findViewById(R.id.socket_type);
|
|
||||||
ShapeableImageView icon = itemView.findViewById(R.id.socket_icon);
|
|
||||||
MaterialTextView power = itemView.findViewById(R.id.socket_power);
|
|
||||||
MaterialTextView count = itemView.findViewById(R.id.socket_count);
|
|
||||||
|
|
||||||
// load SVG icon converted into VectorDrawable in res/drawable
|
|
||||||
@SuppressLint("DiscouragedApi")
|
|
||||||
int resIconId = getResources().getIdentifier("ic_charge_socket_" + socket.type(), "drawable",
|
|
||||||
requireContext().getPackageName());
|
|
||||||
if (resIconId != 0)
|
|
||||||
{
|
|
||||||
icon.setImageResource(resIconId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("DiscouragedApi")
|
|
||||||
int resTypeId =
|
|
||||||
getResources().getIdentifier("charge_socket_" + socket.type(), "string", requireContext().getPackageName());
|
|
||||||
if (resTypeId != 0)
|
|
||||||
{
|
|
||||||
type.setText(resTypeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (socket.power() != 0)
|
|
||||||
{
|
|
||||||
DecimalFormat df = new DecimalFormat("#.##");
|
|
||||||
power.setText(getString(R.string.kw_label, df.format(socket.power())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (socket.count() != 0)
|
|
||||||
{
|
|
||||||
count.setText(getString(R.string.count_label, socket.count()));
|
|
||||||
}
|
|
||||||
|
|
||||||
itemView.setOnClickListener(v -> {
|
|
||||||
buildChargeSocketDialog(currentIndex, socket.type(), socket.count(), socket.power()).show();
|
|
||||||
});
|
|
||||||
socketsGrid.addView(itemView);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a 'new item' button at the end, to create new sockets
|
|
||||||
View btnNewItemView = inflater.inflate(R.layout.button_new_item, socketsGrid, false);
|
|
||||||
btnNewItemView.setOnClickListener(v -> {
|
|
||||||
buildChargeSocketDialog(-1, "unknown", -1, -1).show();
|
|
||||||
});
|
|
||||||
socketsGrid.addView(btnNewItemView);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshOpeningTime()
|
private void refreshOpeningTime()
|
||||||
{
|
{
|
||||||
final String openingHours = Editor.nativeGetOpeningHours();
|
final String openingHours = Editor.nativeGetOpeningHours();
|
||||||
@@ -738,7 +435,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
|
|||||||
mCategory = categoryBlock.findViewById(R.id.name);
|
mCategory = categoryBlock.findViewById(R.id.name);
|
||||||
mCardName = view.findViewById(R.id.cv__name);
|
mCardName = view.findViewById(R.id.cv__name);
|
||||||
mCardAddress = view.findViewById(R.id.cv__address);
|
mCardAddress = view.findViewById(R.id.cv__address);
|
||||||
mCardChargingStation = view.findViewById(R.id.cv__charging_station);
|
|
||||||
mCardDetails = view.findViewById(R.id.cv__details);
|
mCardDetails = view.findViewById(R.id.cv__details);
|
||||||
mCardSocialMedia = view.findViewById(R.id.cv__social_media);
|
mCardSocialMedia = view.findViewById(R.id.cv__social_media);
|
||||||
mCardBuilding = view.findViewById(R.id.cv__building);
|
mCardBuilding = view.findViewById(R.id.cv__building);
|
||||||
@@ -811,9 +507,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
|
|||||||
View blockOutdoorSeating = view.findViewById(R.id.block_outdoor_seating);
|
View blockOutdoorSeating = view.findViewById(R.id.block_outdoor_seating);
|
||||||
mOutdoorSeating = view.findViewById(R.id.sw__outdoor_seating);
|
mOutdoorSeating = view.findViewById(R.id.sw__outdoor_seating);
|
||||||
blockOutdoorSeating.setOnClickListener(this);
|
blockOutdoorSeating.setOnClickListener(this);
|
||||||
|
|
||||||
mChargeSockets = view.findViewById(R.id.block_charge_sockets);
|
|
||||||
|
|
||||||
View blockOpeningHours = view.findViewById(R.id.block_opening_hours);
|
View blockOpeningHours = view.findViewById(R.id.block_opening_hours);
|
||||||
mEditOpeningHours = blockOpeningHours.findViewById(R.id.edit_opening_hours);
|
mEditOpeningHours = blockOpeningHours.findViewById(R.id.edit_opening_hours);
|
||||||
mEditOpeningHours.setOnClickListener(this);
|
mEditOpeningHours.setOnClickListener(this);
|
||||||
@@ -1008,7 +701,7 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
|
|||||||
private void placeDoesntExist()
|
private void placeDoesntExist()
|
||||||
{
|
{
|
||||||
EditTextDialogFragment dialogFragment = EditTextDialogFragment.show(
|
EditTextDialogFragment dialogFragment = EditTextDialogFragment.show(
|
||||||
getString(R.string.editor_place_doesnt_exist), "", getString(R.string.editor_place_doesnt_exist_description),
|
getString(R.string.editor_place_doesnt_exist), "", getString(R.string.editor_comment_hint),
|
||||||
getString(R.string.editor_report_problem_send_button), getString(R.string.cancel), this,
|
getString(R.string.editor_report_problem_send_button), getString(R.string.cancel), this,
|
||||||
getDeleteCommentValidator());
|
getDeleteCommentValidator());
|
||||||
dialogFragment.setTextSaveListener(this::commitPlaceDoesntExists);
|
dialogFragment.setTextSaveListener(this::commitPlaceDoesntExists);
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
package app.organicmaps.editor;
|
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
|
|
||||||
import com.google.android.material.timepicker.MaterialTimePicker;
|
|
||||||
import com.google.android.material.timepicker.TimeFormat;
|
|
||||||
|
|
||||||
import app.organicmaps.R;
|
|
||||||
import app.organicmaps.sdk.editor.data.HoursMinutes;
|
|
||||||
import app.organicmaps.sdk.util.DateUtils;
|
|
||||||
|
|
||||||
public class FromToTimePicker
|
|
||||||
{
|
|
||||||
private final FragmentActivity mActivity;
|
|
||||||
private final FragmentManager mFragmentManager;
|
|
||||||
private final OnPickListener mListener;
|
|
||||||
private final int mId;
|
|
||||||
private final boolean mIs24HourFormat;
|
|
||||||
private final Resources mResources;
|
|
||||||
|
|
||||||
private HoursMinutes mFromTime;
|
|
||||||
private HoursMinutes mToTime;
|
|
||||||
private MaterialTimePicker mToTimePicker;
|
|
||||||
private MaterialTimePicker mFromTimePicker;
|
|
||||||
private boolean mIsFromTimePicked;
|
|
||||||
private int mInputMode;
|
|
||||||
|
|
||||||
public static void pickTime(@NonNull Fragment fragment,
|
|
||||||
@NonNull FromToTimePicker.OnPickListener listener,
|
|
||||||
@NonNull HoursMinutes fromTime,
|
|
||||||
@NonNull HoursMinutes toTime,
|
|
||||||
int id,
|
|
||||||
boolean startWithToTime)
|
|
||||||
{
|
|
||||||
FromToTimePicker timePicker = new FromToTimePicker(fragment,
|
|
||||||
listener,
|
|
||||||
fromTime,
|
|
||||||
toTime,
|
|
||||||
id);
|
|
||||||
|
|
||||||
if (startWithToTime)
|
|
||||||
timePicker.showToTimePicker();
|
|
||||||
else
|
|
||||||
timePicker.showFromTimePicker();
|
|
||||||
}
|
|
||||||
|
|
||||||
private FromToTimePicker(@NonNull Fragment fragment,
|
|
||||||
@NonNull FromToTimePicker.OnPickListener listener,
|
|
||||||
@NonNull HoursMinutes fromTime,
|
|
||||||
@NonNull HoursMinutes toTime,
|
|
||||||
int id)
|
|
||||||
{
|
|
||||||
mActivity = fragment.requireActivity();
|
|
||||||
mFragmentManager = fragment.getChildFragmentManager();
|
|
||||||
mListener = listener;
|
|
||||||
mFromTime = fromTime;
|
|
||||||
mToTime = toTime;
|
|
||||||
mId = id;
|
|
||||||
|
|
||||||
mIsFromTimePicked = false;
|
|
||||||
mInputMode = MaterialTimePicker.INPUT_MODE_CLOCK;
|
|
||||||
|
|
||||||
mIs24HourFormat = DateUtils.is24HourFormat(mActivity);
|
|
||||||
mResources = mActivity.getResources();
|
|
||||||
|
|
||||||
mActivity.addOnConfigurationChangedListener(this::handleConfigurationChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showFromTimePicker()
|
|
||||||
{
|
|
||||||
if (mFromTimePicker != null)
|
|
||||||
{
|
|
||||||
saveState(mFromTimePicker, true);
|
|
||||||
mFromTimePicker.dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
mFromTimePicker = buildFromTimePicker();
|
|
||||||
mFromTimePicker.show(mFragmentManager, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showToTimePicker()
|
|
||||||
{
|
|
||||||
if (mToTimePicker != null)
|
|
||||||
{
|
|
||||||
saveState(mToTimePicker, false);
|
|
||||||
mToTimePicker.dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
mToTimePicker = buildToTimePicker();
|
|
||||||
|
|
||||||
mToTimePicker.show(mFragmentManager, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MaterialTimePicker buildFromTimePicker()
|
|
||||||
{
|
|
||||||
MaterialTimePicker timePicker = buildTimePicker(mFromTime,
|
|
||||||
mResources.getString(R.string.editor_time_from),
|
|
||||||
mResources.getString(R.string.next_button),
|
|
||||||
null);
|
|
||||||
|
|
||||||
timePicker.addOnNegativeButtonClickListener(view -> finishTimePicking(false));
|
|
||||||
|
|
||||||
timePicker.addOnPositiveButtonClickListener(view ->
|
|
||||||
{
|
|
||||||
mIsFromTimePicked = true;
|
|
||||||
saveState(timePicker, true);
|
|
||||||
mFromTimePicker = null;
|
|
||||||
showToTimePicker();
|
|
||||||
});
|
|
||||||
|
|
||||||
timePicker.addOnCancelListener(view -> finishTimePicking(false));
|
|
||||||
|
|
||||||
return timePicker;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MaterialTimePicker buildToTimePicker()
|
|
||||||
{
|
|
||||||
MaterialTimePicker timePicker = buildTimePicker(mToTime,
|
|
||||||
mResources.getString(R.string.editor_time_to),
|
|
||||||
null,
|
|
||||||
mResources.getString(R.string.back));
|
|
||||||
|
|
||||||
timePicker.addOnNegativeButtonClickListener(view ->
|
|
||||||
{
|
|
||||||
saveState(timePicker, false);
|
|
||||||
mToTimePicker = null;
|
|
||||||
if (mIsFromTimePicked)
|
|
||||||
showFromTimePicker();
|
|
||||||
else
|
|
||||||
finishTimePicking(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
timePicker.addOnPositiveButtonClickListener(view ->
|
|
||||||
{
|
|
||||||
saveState(timePicker, false);
|
|
||||||
finishTimePicking(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
timePicker.addOnCancelListener(view -> finishTimePicking(false));
|
|
||||||
|
|
||||||
return timePicker;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private MaterialTimePicker buildTimePicker(@NonNull HoursMinutes time,
|
|
||||||
@NonNull String title,
|
|
||||||
@Nullable String positiveButtonTextOverride,
|
|
||||||
@Nullable String negativeButtonTextOverride)
|
|
||||||
{
|
|
||||||
MaterialTimePicker.Builder builder = new MaterialTimePicker.Builder()
|
|
||||||
.setTitleText(title)
|
|
||||||
.setTimeFormat(mIs24HourFormat ? TimeFormat.CLOCK_24H : TimeFormat.CLOCK_12H)
|
|
||||||
.setInputMode(mInputMode)
|
|
||||||
.setTheme(R.style.MwmMain_MaterialTimePicker)
|
|
||||||
.setHour((int) time.hours)
|
|
||||||
.setMinute((int) time.minutes);
|
|
||||||
|
|
||||||
if (positiveButtonTextOverride != null)
|
|
||||||
builder.setPositiveButtonText(positiveButtonTextOverride);
|
|
||||||
|
|
||||||
if (negativeButtonTextOverride != null)
|
|
||||||
builder.setNegativeButtonText(negativeButtonTextOverride);
|
|
||||||
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveState(@NonNull MaterialTimePicker timePicker, boolean isFromTime)
|
|
||||||
{
|
|
||||||
mInputMode = timePicker.getInputMode();
|
|
||||||
if (isFromTime)
|
|
||||||
mFromTime = getHoursMinutes(timePicker);
|
|
||||||
else
|
|
||||||
mToTime = getHoursMinutes(timePicker);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HoursMinutes getHoursMinutes(@NonNull MaterialTimePicker timePicker)
|
|
||||||
{
|
|
||||||
return new HoursMinutes(timePicker.getHour(), timePicker.getMinute(), mIs24HourFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finishTimePicking(boolean isConfirmed)
|
|
||||||
{
|
|
||||||
mActivity.removeOnConfigurationChangedListener(this::handleConfigurationChanged);
|
|
||||||
|
|
||||||
if (isConfirmed)
|
|
||||||
mListener.onHoursMinutesPicked(mFromTime, mToTime, mId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleConfigurationChanged(Configuration configuration)
|
|
||||||
{
|
|
||||||
if (mFromTimePicker != null && mFromTimePicker.isVisible())
|
|
||||||
showFromTimePicker();
|
|
||||||
else if (mToTimePicker != null && mToTimePicker.isVisible())
|
|
||||||
showToTimePicker();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnPickListener
|
|
||||||
{
|
|
||||||
void onHoursMinutesPicked(HoursMinutes from, HoursMinutes to, int id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
package app.organicmaps.editor;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.TimePicker;
|
||||||
|
import androidx.annotation.IntRange;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StyleRes;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import app.organicmaps.R;
|
||||||
|
import app.organicmaps.base.BaseMwmDialogFragment;
|
||||||
|
import app.organicmaps.sdk.editor.data.HoursMinutes;
|
||||||
|
import app.organicmaps.sdk.util.DateUtils;
|
||||||
|
import app.organicmaps.util.ThemeUtils;
|
||||||
|
import app.organicmaps.util.Utils;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
import com.google.android.material.textview.MaterialTextView;
|
||||||
|
|
||||||
|
public class HoursMinutesPickerFragment extends BaseMwmDialogFragment
|
||||||
|
{
|
||||||
|
private static final String EXTRA_FROM = "HoursMinutesFrom";
|
||||||
|
private static final String EXTRA_TO = "HoursMinutesTo";
|
||||||
|
private static final String EXTRA_SELECT_FIRST = "SelectedTab";
|
||||||
|
private static final String EXTRA_ID = "Id";
|
||||||
|
|
||||||
|
public static final int TAB_FROM = 0;
|
||||||
|
public static final int TAB_TO = 1;
|
||||||
|
|
||||||
|
private HoursMinutes mFrom;
|
||||||
|
private HoursMinutes mTo;
|
||||||
|
|
||||||
|
private TimePicker mPicker;
|
||||||
|
private View mPickerHoursLabel;
|
||||||
|
|
||||||
|
@IntRange(from = 0, to = 1)
|
||||||
|
private int mSelectedTab;
|
||||||
|
private TabLayout mTabs;
|
||||||
|
|
||||||
|
private int mId;
|
||||||
|
private Button mOkButton;
|
||||||
|
|
||||||
|
public interface OnPickListener
|
||||||
|
{
|
||||||
|
void onHoursMinutesPicked(HoursMinutes from, HoursMinutes to, int id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void pick(Context context, FragmentManager manager, @NonNull HoursMinutes from,
|
||||||
|
@NonNull HoursMinutes to, @IntRange(from = 0, to = 1) int selectedPosition, int id)
|
||||||
|
{
|
||||||
|
final Bundle args = new Bundle();
|
||||||
|
args.putParcelable(EXTRA_FROM, from);
|
||||||
|
args.putParcelable(EXTRA_TO, to);
|
||||||
|
args.putInt(EXTRA_SELECT_FIRST, selectedPosition);
|
||||||
|
args.putInt(EXTRA_ID, id);
|
||||||
|
|
||||||
|
final HoursMinutesPickerFragment fragment = (HoursMinutesPickerFragment) manager.getFragmentFactory().instantiate(
|
||||||
|
context.getClassLoader(), HoursMinutesPickerFragment.class.getName());
|
||||||
|
fragment.setArguments(args);
|
||||||
|
fragment.show(manager, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
readArgs();
|
||||||
|
final View root = createView();
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
mTabs.getTabAt(mSelectedTab).select();
|
||||||
|
|
||||||
|
@StyleRes
|
||||||
|
final int theme = ThemeUtils.isNightTheme() ? R.style.MwmMain_DialogFragment_TimePicker_Night
|
||||||
|
: R.style.MwmMain_DialogFragment_TimePicker;
|
||||||
|
final AlertDialog dialog = new MaterialAlertDialogBuilder(requireActivity(), theme)
|
||||||
|
.setView(root)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.setCancelable(true)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
dialog.setOnShowListener(dialogInterface -> {
|
||||||
|
mOkButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||||
|
mOkButton.setOnClickListener(v -> {
|
||||||
|
if (mSelectedTab == TAB_FROM)
|
||||||
|
{
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
mTabs.getTabAt(TAB_TO).select();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveHoursMinutes();
|
||||||
|
dismiss();
|
||||||
|
if (getParentFragment() instanceof OnPickListener)
|
||||||
|
((OnPickListener) getParentFragment()).onHoursMinutesPicked(mFrom, mTo, mId);
|
||||||
|
});
|
||||||
|
refreshPicker();
|
||||||
|
});
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readArgs()
|
||||||
|
{
|
||||||
|
final Bundle args = getArguments();
|
||||||
|
if (args == null)
|
||||||
|
throw new IllegalArgumentException("Args must not be null");
|
||||||
|
mFrom = Utils.getParcelable(args, EXTRA_FROM, HoursMinutes.class);
|
||||||
|
mTo = Utils.getParcelable(args, EXTRA_TO, HoursMinutes.class);
|
||||||
|
mSelectedTab = args.getInt(EXTRA_SELECT_FIRST);
|
||||||
|
mId = args.getInt(EXTRA_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createView()
|
||||||
|
{
|
||||||
|
final LayoutInflater inflater = LayoutInflater.from(requireActivity());
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
final View root = inflater.inflate(R.layout.fragment_timetable_picker, null);
|
||||||
|
|
||||||
|
mPicker = root.findViewById(R.id.picker);
|
||||||
|
mPicker.setIs24HourView(DateFormat.is24HourFormat(requireActivity()));
|
||||||
|
@SuppressLint("DiscouragedApi")
|
||||||
|
int id = getResources().getIdentifier("hours", "id", "android");
|
||||||
|
if (id != 0)
|
||||||
|
{
|
||||||
|
mPickerHoursLabel = mPicker.findViewById(id);
|
||||||
|
if (!(mPickerHoursLabel instanceof TextView))
|
||||||
|
mPickerHoursLabel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTabs = root.findViewById(R.id.tabs);
|
||||||
|
MaterialTextView tabView = (MaterialTextView) inflater.inflate(R.layout.tab_timepicker, mTabs, false);
|
||||||
|
tabView.setText(getResources().getString(R.string.editor_time_from));
|
||||||
|
final ColorStateList textColor = AppCompatResources.getColorStateList(
|
||||||
|
requireContext(),
|
||||||
|
ThemeUtils.isNightTheme() ? R.color.accent_color_selector_night : R.color.accent_color_selector);
|
||||||
|
tabView.setTextColor(textColor);
|
||||||
|
mTabs.addTab(mTabs.newTab().setCustomView(tabView), true);
|
||||||
|
tabView = (MaterialTextView) inflater.inflate(R.layout.tab_timepicker, mTabs, false);
|
||||||
|
tabView.setText(getResources().getString(R.string.editor_time_to));
|
||||||
|
tabView.setTextColor(textColor);
|
||||||
|
mTabs.addTab(mTabs.newTab().setCustomView(tabView), true);
|
||||||
|
mTabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onTabSelected(TabLayout.Tab tab)
|
||||||
|
{
|
||||||
|
if (!isInit())
|
||||||
|
return;
|
||||||
|
|
||||||
|
saveHoursMinutes();
|
||||||
|
mSelectedTab = tab.getPosition();
|
||||||
|
refreshPicker();
|
||||||
|
if (mPickerHoursLabel != null)
|
||||||
|
mPickerHoursLabel.performClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabUnselected(TabLayout.Tab tab)
|
||||||
|
{}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabReselected(TabLayout.Tab tab)
|
||||||
|
{}
|
||||||
|
});
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveHoursMinutes()
|
||||||
|
{
|
||||||
|
boolean is24HourFormat = DateUtils.is24HourFormat(requireContext());
|
||||||
|
final HoursMinutes hoursMinutes =
|
||||||
|
new HoursMinutes(mPicker.getCurrentHour(), mPicker.getCurrentMinute(), is24HourFormat);
|
||||||
|
if (mSelectedTab == TAB_FROM)
|
||||||
|
mFrom = hoursMinutes;
|
||||||
|
else
|
||||||
|
mTo = hoursMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInit()
|
||||||
|
{
|
||||||
|
return mOkButton != null && mPicker != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshPicker()
|
||||||
|
{
|
||||||
|
if (!isInit())
|
||||||
|
return;
|
||||||
|
|
||||||
|
HoursMinutes hoursMinutes;
|
||||||
|
int okBtnRes;
|
||||||
|
if (mSelectedTab == TAB_FROM)
|
||||||
|
{
|
||||||
|
hoursMinutes = mFrom;
|
||||||
|
okBtnRes = R.string.next_button;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hoursMinutes = mTo;
|
||||||
|
okBtnRes = R.string.ok;
|
||||||
|
}
|
||||||
|
mPicker.setCurrentMinute((int) hoursMinutes.minutes);
|
||||||
|
mPicker.setCurrentHour((int) hoursMinutes.hours);
|
||||||
|
mOkButton.setText(okBtnRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -113,6 +113,9 @@ public class PhoneListAdapter extends RecyclerView.Adapter<PhoneListAdapter.View
|
|||||||
|
|
||||||
deleteButton = itemView.findViewById(R.id.delete_icon);
|
deleteButton = itemView.findViewById(R.id.delete_icon);
|
||||||
deleteButton.setOnClickListener(this);
|
deleteButton.setOnClickListener(this);
|
||||||
|
// TODO: setting icons from code because icons defined in layout XML are white.
|
||||||
|
deleteButton.setImageResource(R.drawable.ic_delete);
|
||||||
|
((ShapeableImageView) itemView.findViewById(R.id.phone_icon)).setImageResource(R.drawable.ic_phone);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(int position)
|
public void setPosition(int position)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import app.organicmaps.util.UiUtils;
|
|||||||
import app.organicmaps.util.Utils;
|
import app.organicmaps.util.Utils;
|
||||||
import app.organicmaps.util.WindowInsetUtils;
|
import app.organicmaps.util.WindowInsetUtils;
|
||||||
import app.organicmaps.widget.StackedButtonDialogFragment;
|
import app.organicmaps.widget.StackedButtonDialogFragment;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.imageview.ShapeableImageView;
|
import com.google.android.material.imageview.ShapeableImageView;
|
||||||
import com.google.android.material.textview.MaterialTextView;
|
import com.google.android.material.textview.MaterialTextView;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
@@ -134,7 +135,14 @@ public class ProfileFragment extends BaseMwmToolbarFragment
|
|||||||
|
|
||||||
private void logout()
|
private void logout()
|
||||||
{
|
{
|
||||||
OsmOAuth.clearAuthorization();
|
new MaterialAlertDialogBuilder(requireContext(), R.style.MwmTheme_AlertDialog)
|
||||||
refreshViews();
|
.setMessage(R.string.osm_log_out_confirmation)
|
||||||
|
.setPositiveButton(R.string.yes,
|
||||||
|
(dialog, which) -> {
|
||||||
|
OsmOAuth.clearAuthorization();
|
||||||
|
refreshViews();
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.no, null)
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import androidx.annotation.IdRes;
|
import androidx.annotation.IdRes;
|
||||||
import androidx.annotation.IntRange;
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -30,13 +29,13 @@ import java.util.Calendar;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter.BaseTimetableViewHolder>
|
class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter.BaseTimetableViewHolder>
|
||||||
implements FromToTimePicker.OnPickListener, TimetableProvider
|
implements HoursMinutesPickerFragment.OnPickListener, TimetableProvider
|
||||||
{
|
{
|
||||||
private static final int TYPE_TIMETABLE = 0;
|
private static final int TYPE_TIMETABLE = 0;
|
||||||
private static final int TYPE_ADD_TIMETABLE = 1;
|
private static final int TYPE_ADD_TIMETABLE = 1;
|
||||||
|
|
||||||
private static final int ID_OPENING_TIME = 0;
|
private static final int ID_OPENING = 0;
|
||||||
private static final int ID_CLOSED_SPAN = 1;
|
private static final int ID_CLOSING = 1;
|
||||||
|
|
||||||
private static final int[] DAYS = {R.id.day1, R.id.day2, R.id.day3, R.id.day4, R.id.day5, R.id.day6, R.id.day7};
|
private static final int[] DAYS = {R.id.day1, R.id.day2, R.id.day3, R.id.day4, R.id.day5, R.id.day6, R.id.day7};
|
||||||
|
|
||||||
@@ -70,7 +69,7 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter
|
|||||||
@Override
|
@Override
|
||||||
public String getTimetables()
|
public String getTimetables()
|
||||||
{
|
{
|
||||||
return OpeningHours.nativeTimetablesToString(mItems.toArray(new Timetable[0]));
|
return OpeningHours.nativeTimetablesToString(mItems.toArray(new Timetable[mItems.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -102,7 +101,7 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter
|
|||||||
|
|
||||||
private void addTimetable()
|
private void addTimetable()
|
||||||
{
|
{
|
||||||
mItems.add(OpeningHours.nativeGetComplementTimetable(mItems.toArray(new Timetable[0])));
|
mItems.add(OpeningHours.nativeGetComplementTimetable(mItems.toArray(new Timetable[mItems.size()])));
|
||||||
notifyItemInserted(mItems.size() - 1);
|
notifyItemInserted(mItems.size() - 1);
|
||||||
refreshComplement();
|
refreshComplement();
|
||||||
}
|
}
|
||||||
@@ -116,31 +115,25 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter
|
|||||||
|
|
||||||
private void refreshComplement()
|
private void refreshComplement()
|
||||||
{
|
{
|
||||||
mComplementItem = OpeningHours.nativeGetComplementTimetable(mItems.toArray(new Timetable[0]));
|
mComplementItem = OpeningHours.nativeGetComplementTimetable(mItems.toArray(new Timetable[mItems.size()]));
|
||||||
notifyItemChanged(getItemCount() - 1);
|
notifyItemChanged(getItemCount() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pickTime(int position,
|
private void pickTime(int position,
|
||||||
@IntRange(from = ID_OPENING_TIME, to = ID_CLOSED_SPAN) int id,
|
@IntRange(from = HoursMinutesPickerFragment.TAB_FROM, to = HoursMinutesPickerFragment.TAB_TO)
|
||||||
boolean startWithToTime)
|
int tab, @IntRange(from = ID_OPENING, to = ID_CLOSING) int id)
|
||||||
{
|
{
|
||||||
final Timetable data = mItems.get(position);
|
final Timetable data = mItems.get(position);
|
||||||
mPickingPosition = position;
|
mPickingPosition = position;
|
||||||
|
HoursMinutesPickerFragment.pick(mFragment.requireActivity(), mFragment.getChildFragmentManager(),
|
||||||
FromToTimePicker.pickTime(mFragment,
|
data.workingTimespan.start, data.workingTimespan.end, tab, id);
|
||||||
this,
|
|
||||||
data.workingTimespan.start,
|
|
||||||
data.workingTimespan.end,
|
|
||||||
id,
|
|
||||||
startWithToTime);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHoursMinutesPicked(HoursMinutes from, HoursMinutes to, int id)
|
public void onHoursMinutesPicked(HoursMinutes from, HoursMinutes to, int id)
|
||||||
{
|
{
|
||||||
final Timetable item = mItems.get(mPickingPosition);
|
final Timetable item = mItems.get(mPickingPosition);
|
||||||
if (id == ID_OPENING_TIME)
|
if (id == ID_OPENING)
|
||||||
mItems.set(mPickingPosition, OpeningHours.nativeSetOpeningTime(item, new Timespan(from, to)));
|
mItems.set(mPickingPosition, OpeningHours.nativeSetOpeningTime(item, new Timespan(from, to)));
|
||||||
else
|
else
|
||||||
mItems.set(mPickingPosition, OpeningHours.nativeAddClosedSpan(item, new Timespan(from, to)));
|
mItems.set(mPickingPosition, OpeningHours.nativeAddClosedSpan(item, new Timespan(from, to)));
|
||||||
@@ -155,7 +148,7 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter
|
|||||||
|
|
||||||
private void addWorkingDay(int day, int position)
|
private void addWorkingDay(int day, int position)
|
||||||
{
|
{
|
||||||
final Timetable[] tts = mItems.toArray(new Timetable[0]);
|
final Timetable[] tts = mItems.toArray(new Timetable[mItems.size()]);
|
||||||
mItems = new ArrayList<>(Arrays.asList(OpeningHours.nativeAddWorkingDay(tts, position, day)));
|
mItems = new ArrayList<>(Arrays.asList(OpeningHours.nativeAddWorkingDay(tts, position, day)));
|
||||||
refreshComplement();
|
refreshComplement();
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
@@ -163,7 +156,7 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter
|
|||||||
|
|
||||||
private void removeWorkingDay(int day, int position)
|
private void removeWorkingDay(int day, int position)
|
||||||
{
|
{
|
||||||
final Timetable[] tts = mItems.toArray(new Timetable[0]);
|
final Timetable[] tts = mItems.toArray(new Timetable[mItems.size()]);
|
||||||
mItems = new ArrayList<>(Arrays.asList(OpeningHours.nativeRemoveWorkingDay(tts, position, day)));
|
mItems = new ArrayList<>(Arrays.asList(OpeningHours.nativeRemoveWorkingDay(tts, position, day)));
|
||||||
refreshComplement();
|
refreshComplement();
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
@@ -269,13 +262,13 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter<SimpleTimetableAdapter
|
|||||||
{
|
{
|
||||||
final int id = v.getId();
|
final int id = v.getId();
|
||||||
if (id == R.id.time_open)
|
if (id == R.id.time_open)
|
||||||
pickTime(getBindingAdapterPosition(), ID_OPENING_TIME, false);
|
pickTime(getBindingAdapterPosition(), HoursMinutesPickerFragment.TAB_FROM, ID_OPENING);
|
||||||
else if (id == R.id.time_close)
|
else if (id == R.id.time_close)
|
||||||
pickTime(getBindingAdapterPosition(), ID_OPENING_TIME, true);
|
pickTime(getBindingAdapterPosition(), HoursMinutesPickerFragment.TAB_TO, ID_OPENING);
|
||||||
else if (id == R.id.tv__remove_timetable)
|
else if (id == R.id.tv__remove_timetable)
|
||||||
removeTimetable(getBindingAdapterPosition());
|
removeTimetable(getBindingAdapterPosition());
|
||||||
else if (id == R.id.tv__add_closed)
|
else if (id == R.id.tv__add_closed)
|
||||||
pickTime(getBindingAdapterPosition(), ID_CLOSED_SPAN, false);
|
pickTime(getBindingAdapterPosition(), HoursMinutesPickerFragment.TAB_FROM, ID_CLOSING);
|
||||||
else if (id == R.id.allday)
|
else if (id == R.id.allday)
|
||||||
swAllday.toggle();
|
swAllday.toggle();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.base.BaseMwmRecyclerFragment;
|
import app.organicmaps.base.BaseMwmRecyclerFragment;
|
||||||
|
import app.organicmaps.sdk.editor.data.HoursMinutes;
|
||||||
|
|
||||||
public class SimpleTimetableFragment extends BaseMwmRecyclerFragment<SimpleTimetableAdapter>
|
public class SimpleTimetableFragment extends BaseMwmRecyclerFragment<SimpleTimetableAdapter>
|
||||||
implements TimetableProvider
|
implements TimetableProvider, HoursMinutesPickerFragment.OnPickListener
|
||||||
{
|
{
|
||||||
private SimpleTimetableAdapter mAdapter;
|
private SimpleTimetableAdapter mAdapter;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -56,4 +57,10 @@ public class SimpleTimetableFragment extends BaseMwmRecyclerFragment<SimpleTimet
|
|||||||
{
|
{
|
||||||
mInitTimetables = timetables;
|
mInitTimetables = timetables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHoursMinutesPicked(HoursMinutes from, HoursMinutes to, int id)
|
||||||
|
{
|
||||||
|
mAdapter.onHoursMinutesPicked(from, to, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package app.organicmaps.maplayer;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import androidx.annotation.AttrRes;
|
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
@@ -14,7 +13,9 @@ import app.organicmaps.util.ThemeUtils;
|
|||||||
public class LayerBottomSheetItem
|
public class LayerBottomSheetItem
|
||||||
{
|
{
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
private final int mDrawableResId;
|
private final int mEnabledStateDrawableResId;
|
||||||
|
@DrawableRes
|
||||||
|
private final int mDisabledStateDrawableResId;
|
||||||
@StringRes
|
@StringRes
|
||||||
private final int mTitleResId;
|
private final int mTitleResId;
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -22,10 +23,12 @@ public class LayerBottomSheetItem
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final OnItemClickListener<LayerBottomSheetItem> mItemClickListener;
|
private final OnItemClickListener<LayerBottomSheetItem> mItemClickListener;
|
||||||
|
|
||||||
LayerBottomSheetItem(@DrawableRes int drawableResId, @StringRes int titleResId, @NonNull Mode mode,
|
LayerBottomSheetItem(@DrawableRes int enabledStateDrawableResId, @DrawableRes int disabledStateDrawableResId,
|
||||||
|
@StringRes int titleResId, @NonNull Mode mode,
|
||||||
@NonNull OnItemClickListener<LayerBottomSheetItem> itemClickListener)
|
@NonNull OnItemClickListener<LayerBottomSheetItem> itemClickListener)
|
||||||
{
|
{
|
||||||
mDrawableResId = drawableResId;
|
mEnabledStateDrawableResId = enabledStateDrawableResId;
|
||||||
|
mDisabledStateDrawableResId = disabledStateDrawableResId;
|
||||||
mTitleResId = titleResId;
|
mTitleResId = titleResId;
|
||||||
mMode = mode;
|
mMode = mode;
|
||||||
mItemClickListener = itemClickListener;
|
mItemClickListener = itemClickListener;
|
||||||
@@ -34,30 +37,35 @@ public class LayerBottomSheetItem
|
|||||||
public static LayerBottomSheetItem create(@NonNull Context mContext, Mode mode,
|
public static LayerBottomSheetItem create(@NonNull Context mContext, Mode mode,
|
||||||
@NonNull OnItemClickListener<LayerBottomSheetItem> layerItemClickListener)
|
@NonNull OnItemClickListener<LayerBottomSheetItem> layerItemClickListener)
|
||||||
{
|
{
|
||||||
@DrawableRes
|
int disabledResource = 0;
|
||||||
int drawableResId = 0;
|
int enabledResource = 0;
|
||||||
@StringRes
|
|
||||||
int buttonTextResource = R.string.layers_title;
|
int buttonTextResource = R.string.layers_title;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case OUTDOORS:
|
case OUTDOORS:
|
||||||
drawableResId = R.drawable.ic_layers_outdoors;
|
disabledResource = R.attr.outdoorsMenuDisabled;
|
||||||
|
enabledResource = R.attr.outdoorsMenuEnabled;
|
||||||
buttonTextResource = R.string.button_layer_outdoor;
|
buttonTextResource = R.string.button_layer_outdoor;
|
||||||
break;
|
break;
|
||||||
case SUBWAY:
|
case SUBWAY:
|
||||||
drawableResId = R.drawable.ic_layers_subway;
|
disabledResource = R.attr.subwayMenuDisabled;
|
||||||
|
enabledResource = R.attr.subwayMenuEnabled;
|
||||||
buttonTextResource = R.string.subway;
|
buttonTextResource = R.string.subway;
|
||||||
break;
|
break;
|
||||||
case ISOLINES:
|
case ISOLINES:
|
||||||
drawableResId = R.drawable.ic_layers_isoline;
|
disabledResource = R.attr.isoLinesMenuDisabled;
|
||||||
|
enabledResource = R.attr.isoLinesMenuEnabled;
|
||||||
buttonTextResource = R.string.button_layer_isolines;
|
buttonTextResource = R.string.button_layer_isolines;
|
||||||
break;
|
break;
|
||||||
case TRAFFIC:
|
case TRAFFIC:
|
||||||
drawableResId = R.drawable.ic_layers_traffic;
|
disabledResource = R.attr.trafficMenuDisabled;
|
||||||
|
enabledResource = R.attr.trafficMenuEnabled;
|
||||||
buttonTextResource = R.string.button_layer_traffic;
|
buttonTextResource = R.string.button_layer_traffic;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new LayerBottomSheetItem(drawableResId, buttonTextResource, mode, layerItemClickListener);
|
int disabled = ThemeUtils.getResource(mContext, disabledResource);
|
||||||
|
int enabled = ThemeUtils.getResource(mContext, enabledResource);
|
||||||
|
return new LayerBottomSheetItem(enabled, disabled, buttonTextResource, mode, layerItemClickListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -67,9 +75,15 @@ public class LayerBottomSheetItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
public int getDrawable()
|
public int getEnabledStateDrawable()
|
||||||
{
|
{
|
||||||
return mDrawableResId;
|
return mEnabledStateDrawableResId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
public int getDisabledStateDrawable()
|
||||||
|
{
|
||||||
|
return mDisabledStateDrawableResId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ public class LayersAdapter extends RecyclerView.Adapter<LayerHolder>
|
|||||||
holder.mTitle.setText(item.getTitle());
|
holder.mTitle.setText(item.getTitle());
|
||||||
boolean isNewLayer = SharedPropertiesUtils.shouldShowNewMarkerForLayerMode(item.getMode());
|
boolean isNewLayer = SharedPropertiesUtils.shouldShowNewMarkerForLayerMode(item.getMode());
|
||||||
UiUtils.showIf(isNewLayer, holder.mNewMarker);
|
UiUtils.showIf(isNewLayer, holder.mNewMarker);
|
||||||
holder.mButton.setBackgroundResource(item.getDrawable());
|
holder.mButton.setImageResource(isEnabled ? item.getEnabledStateDrawable() : item.getDisabledStateDrawable());
|
||||||
holder.mButton.setActivated(isEnabled);
|
|
||||||
holder.mListener = item::onClick;
|
holder.mListener = item::onClick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,19 +43,20 @@ public class TrafficButton
|
|||||||
void turnOff()
|
void turnOff()
|
||||||
{
|
{
|
||||||
stopWaitingAnimation();
|
stopWaitingAnimation();
|
||||||
mButton.setImageResource(R.drawable.ic_traffic_on);
|
mButton.setImageResource(ThemeUtils.isNightTheme() ? R.drawable.ic_traffic_on_night : R.drawable.ic_traffic_on);
|
||||||
}
|
}
|
||||||
|
|
||||||
void turnOn()
|
void turnOn()
|
||||||
{
|
{
|
||||||
stopWaitingAnimation();
|
stopWaitingAnimation();
|
||||||
mButton.setImageResource(R.drawable.ic_traffic_on);
|
mButton.setImageResource(ThemeUtils.isNightTheme() ? R.drawable.ic_traffic_on_night : R.drawable.ic_traffic_on);
|
||||||
}
|
}
|
||||||
|
|
||||||
void markAsOutdated()
|
void markAsOutdated()
|
||||||
{
|
{
|
||||||
stopWaitingAnimation();
|
stopWaitingAnimation();
|
||||||
mButton.setImageResource(R.drawable.ic_traffic_outdated);
|
mButton.setImageResource(ThemeUtils.isNightTheme() ? R.drawable.ic_traffic_outdated_night
|
||||||
|
: R.drawable.ic_traffic_outdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startWaitingAnimation()
|
void startWaitingAnimation()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.google.android.material.textview.MaterialTextView;
|
|||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.sdk.search.DisplayedCategories;
|
import app.organicmaps.sdk.search.DisplayedCategories;
|
||||||
import app.organicmaps.sdk.util.Language;
|
import app.organicmaps.sdk.util.Language;
|
||||||
|
import app.organicmaps.util.ThemeUtils;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -90,7 +91,11 @@ class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ViewHolde
|
|||||||
@DrawableRes
|
@DrawableRes
|
||||||
private static int getDrawableResIdByKey(@NonNull Context context, @NonNull String packageName, @NonNull String key)
|
private static int getDrawableResIdByKey(@NonNull Context context, @NonNull String packageName, @NonNull String key)
|
||||||
{
|
{
|
||||||
return context.getResources().getIdentifier("ic_" + key, "drawable", packageName);
|
final boolean isNightTheme = ThemeUtils.isNightTheme();
|
||||||
|
String iconId = "ic_" + key;
|
||||||
|
if (isNightTheme)
|
||||||
|
iconId = iconId + "_night";
|
||||||
|
return context.getResources().getIdentifier(iconId, "drawable", packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -33,6 +33,13 @@ public class SearchActivity extends BaseMwmFragmentActivity
|
|||||||
activity.startActivity(i);
|
activity.startActivity(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StyleRes
|
||||||
|
public int getThemeResourceId(@NonNull String theme)
|
||||||
|
{
|
||||||
|
return ThemeUtils.getCardBgThemeResourceId(theme);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<? extends Fragment> getFragmentClass()
|
protected Class<? extends Fragment> getFragmentClass()
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user