Merge commit '05cc660641' into traffic

# Conflicts:
#	CMakeLists.txt
#	android/app/src/main/java/app/organicmaps/settings/SettingsPrefsFragment.java
#	android/sdk/src/main/cpp/app/organicmaps/sdk/Framework.hpp
#	android/sdk/src/main/cpp/app/organicmaps/sdk/OrganicMaps.cpp
#	android/sdk/src/main/cpp/app/organicmaps/sdk/util/Config.cpp
#	libs/indexer/data_source.hpp
#	libs/indexer/feature.hpp
#	libs/indexer/ftypes_matcher.hpp
#	libs/map/framework.cpp
#	libs/map/traffic_manager.cpp
#	libs/routing/absent_regions_finder.cpp
#	libs/routing/edge_estimator.hpp
#	libs/routing/index_router.cpp
#	libs/routing/index_router.hpp
#	libs/routing/routing_session.hpp
#	libs/routing_common/num_mwm_id.hpp
#	libs/traffic/traffic_info.cpp
#	qt/mainwindow.hpp
#	qt/preferences_dialog.cpp
#	tools/openlr/helpers.hpp
#	tools/openlr/openlr_decoder.cpp
#	tools/openlr/openlr_decoder.hpp
#	tools/openlr/openlr_stat/openlr_stat.cpp
#	tools/openlr/router.hpp
#	tools/openlr/score_candidate_paths_getter.cpp
#	tools/openlr/score_candidate_paths_getter.hpp
#	xcode/CoMaps.xcworkspace/contents.xcworkspacedata
This commit is contained in:
mvglasow
2025-09-10 21:22:40 +03:00
4644 changed files with 82377 additions and 85029 deletions

View File

@@ -3,7 +3,6 @@ BasedOnStyle: Google
AccessModifierOffset: -2 AccessModifierOffset: -2
AlignAfterOpenBracket: Align AlignAfterOpenBracket: Align
AlignArrayOfStructures: Right
AlignConsecutiveMacros: AcrossEmptyLinesAndComments AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignEscapedNewlines: LeftWithLastLine AlignEscapedNewlines: LeftWithLastLine
AlignOperands: AlignAfterOperator AlignOperands: AlignAfterOperator
@@ -40,8 +39,10 @@ ColumnLimit: 120
ConstructorInitializerIndentWidth: 2 ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 4 ContinuationIndentWidth: 4
DerivePointerAlignment: false DerivePointerAlignment: false
EmptyLineBeforeAccessModifier: Always
IncludeBlocks: Preserve IncludeBlocks: Preserve
IndentAccessModifiers: false IndentAccessModifiers: false
IndentCaseLabels: false
IndentExternBlock: NoIndent IndentExternBlock: NoIndent
InsertBraces: false InsertBraces: false
InsertNewlineAtEOF: true InsertNewlineAtEOF: true
@@ -49,6 +50,7 @@ LambdaBodyIndentation: OuterScope
PackConstructorInitializers: CurrentLine PackConstructorInitializers: CurrentLine
PointerAlignment: Middle PointerAlignment: Middle
RemoveBracesLLVM: true RemoveBracesLLVM: true
RemoveSemicolon: true
QualifierAlignment: Right QualifierAlignment: Right
SpacesInContainerLiterals: false SpacesInContainerLiterals: false
Standard: Latest Standard: Latest

8
.clang-format-ignore Normal file
View File

@@ -0,0 +1,8 @@
# Files that should not be formatted.
./3party
# A patched copy of the https://registry.khronos.org/OpenGL/api/GLES3/gl3.h
./android/sdk/src/main/cpp/app/organicmaps/sdk/opengl/gl3stub.h
# Formatting it leads to crashes in runtime. Newer protobuf may fix it.
./libs/indexer/drules_struct.pb.cc
# No need to format this 3party tool.
tools/osmctools/*.c

View File

@@ -1,8 +1,9 @@
name: dco name: DCO
on: [pull_request] on: [pull_request]
jobs: jobs:
check: check:
runs-on: codeberg-tiny runs-on: ubuntu-latest
steps: steps:
- uses: https://github.com/KineticCafe/actions-dco@v1 - name: Check for Developer Certificate of Origin (DCO) compliance
uses: https://github.com/KineticCafe/actions-dco@fb284c903a7673a3d4b0bdd104479a6f0d46dae7 # v1.3.6

View File

@@ -3,7 +3,7 @@ on:
workflow_dispatch: # Manual trigger workflow_dispatch: # Manual trigger
pull_request: pull_request:
paths: paths:
- qt/res/app.comaps.comaps.desktop - qt/res/linux/app.comaps.comaps.desktop
- .forgejo/workflows/desktop-file-check.yaml # Run check on self change - .forgejo/workflows/desktop-file-check.yaml # Run check on self change
jobs: jobs:
@@ -16,7 +16,7 @@ jobs:
with: with:
fetch-depth: 1 fetch-depth: 1
sparse-checkout: | sparse-checkout: |
qt/res/app.comaps.comaps.desktop qt/res/linux/app.comaps.comaps.desktop
- name: Install desktop-file-validate tool - name: Install desktop-file-validate tool
shell: bash shell: bash
@@ -27,4 +27,4 @@ jobs:
- name: Validate desktop file - name: Validate desktop file
shell: bash shell: bash
run: desktop-file-validate qt/res/app.comaps.comaps.desktop && echo "Successfully validated .desktop file" run: desktop-file-validate qt/res/linux/app.comaps.comaps.desktop && echo "Successfully validated .desktop file"

View File

@@ -133,6 +133,14 @@ jobs:
with: with:
key: ${{ github.workflow }}-unity-${{ matrix.compiler.CC }}-${{ matrix.CMAKE_BUILD_TYPE }} key: ${{ github.workflow }}-unity-${{ matrix.compiler.CC }}-${{ matrix.CMAKE_BUILD_TYPE }}
- name: Configure repository
shell: bash
env:
SKIP_MAP_DOWNLOAD: 1
SKIP_GENERATE_SYMBOLS: 1
SKIP_GENERATE_DRULES: 1
run: ./configure.sh
- name: CMake - name: CMake
shell: bash shell: bash
env: env:

View File

@@ -23,6 +23,10 @@ jobs:
shell: bash shell: bash
run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20))
- name: Configure repository
shell: bash
run: SKIP_GENERATE_SYMBOLS=1 ./configure.sh
- name: Lint - name: Lint
shell: bash shell: bash
working-directory: android working-directory: android
@@ -62,6 +66,7 @@ jobs:
libxinerama-dev \ libxinerama-dev \
libxcursor-dev \ libxcursor-dev \
libxi-dev \ libxi-dev \
python3-protobuf \
zlib1g-dev zlib1g-dev
- name: Checkout sources - name: Checkout sources

View File

@@ -1,43 +0,0 @@
name: clang-format
on:
push:
branches: [ master ]
paths:
- 'android/app/src/**.java'
- '.clang-format'
- '.github/workflows/clang-format.yml'
pull_request:
branches: [ master ]
paths:
- 'android/app/src/**.java'
- '.clang-format'
- '.github/workflows/clang-format.yml'
jobs:
check-formatting:
runs-on: ubuntu-latest
continue-on-error: true # TODO(AB): Remove this line when ready to enforce formatting.
steps:
- uses: actions/checkout@v4
- name: Install clang-format
run: |
sudo apt-get update
sudo apt-get install -y clang-format-19
clang-format-19 --version
- name: Check Java formatting
run: |
JAVA_FILES=($(find android/app/src -name '*.java'))
FORMATTING_ISSUES=$(clang-format-19 --dry-run --Werror $JAVA_FILES 2>&1 || true)
if [ -n "$FORMATTING_ISSUES" ]; then
echo "$FORMATTING_ISSUES"
echo ""
echo "To fix formatting, please run:"
echo " clang-format -i <file>"
exit 1
fi

51
.github/workflows/code-style-check.yaml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Code style check
on:
pull_request:
branches: [ master ]
paths: # Should stay in sync with tools/unix/clang-format.sh
- '.github/workflows/code-style-check.yaml'
- 'android/app/src/**.java'
- 'android/sdk/src/**.java'
- 'android/sdk/src/main/cpp/**.[ch]pp'
- 'dev_sandbox/**.[ch]pp'
- 'generator/**.[ch]pp'
- 'iphone/**.[ch]pp'
- 'iphone/**.[hm]'
- 'iphone/**.mm'
- 'libs/**.[ch]pp'
- 'libs/**.[hm]'
- '!libs/indexer/drules_struct.pb.h'
- 'libs/**.mm'
- 'qt/**.[ch]pp'
- 'qt/**.h'
- 'tools/**.[ch]pp'
- '.clang-format'
- '.clang-format-ignore'
jobs:
code-style-check:
runs-on: ubuntu-latest
steps:
- name: Install clang-format
run: |
sudo apt purge -y clang-format-18 # Remove default old version of clang-format
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main' | sudo tee /etc/apt/sources.list.d/llvm-toolchain-noble-20.list
sudo apt-get update
sudo apt-get install -y clang-format-20
sudo update-alternatives --force --install /usr/bin/clang-format clang-format /usr/bin/clang-format-20 10
sudo update-alternatives --force --install /usr/bin/git-clang-format git-clang-format /usr/bin/git-clang-format-20 10
clang-format --version
- name: Checkout sources
uses: actions/checkout@v4
- name: Check code style
run: tools/unix/clang-format.sh
- name: Post clang-format comments
if: failure()
uses: reviewdog/action-suggester@v1.21.0
with:
tool_name: clang-format
fail_level: error

View File

@@ -30,6 +30,7 @@ jobs:
run: | run: |
brew install qt \ brew install qt \
optipng optipng
pip3 install "protobuf<3.21" --break-system-packages
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4 uses: actions/checkout@v4

20
.gitignore vendored
View File

@@ -14,12 +14,10 @@ stxxl.errlog
stxxl.log stxxl.log
screenlog.0 screenlog.0
data/symbols/*/design/
# symbols png/sdf are now generated at build # symbols png/sdf are now generated at build
data/symbols/**/symbols.png data/symbols/**/symbols.png
data/symbols/**/symbols.sdf data/symbols/**/symbols.sdf
data/colors_design.txt
data/patterns_design.txt
data/bookmarks data/bookmarks
data/edits.xml data/edits.xml
data/traffic.xml data/traffic.xml
@@ -28,11 +26,15 @@ data/WorldCoasts.mwm
data/world_mwm/* data/world_mwm/*
data/*_hash data/*_hash
data/drules_proto* data/drules_proto*
data/classificator.txt data/classificator.txt*
data/types.txt data/types.txt*
data/visibility.txt data/visibility.txt*
data/colors.txt data/colors.txt*
data/patterns.txt data/patterns.txt*
# TODO: designer is not used at the moment
# data/symbols/*/design/
# data/colors_design.txt
# data/patterns_design.txt
# Compiled Python # Compiled Python
*.pyc *.pyc
@@ -51,7 +53,7 @@ omim.sdf
*.suo *.suo
*.aps *.aps
*.rc *.rc
!qt/res/windows.rc !qt/res/windows/windows.rc
*.pdb *.pdb
out/ out/

4
.gitmodules vendored
View File

@@ -65,3 +65,7 @@
[submodule "3party/imgui/imgui"] [submodule "3party/imgui/imgui"]
path = 3party/imgui/imgui path = 3party/imgui/imgui
url = https://github.com/ocornut/imgui url = https://github.com/ocornut/imgui
[submodule "3party/glaze"]
path = 3party/glaze
url = https://github.com/stephenberry/glaze
branch = main

View File

@@ -57,6 +57,7 @@ endif()
add_subdirectory(agg) add_subdirectory(agg)
add_subdirectory(bsdiff-courgette) add_subdirectory(bsdiff-courgette)
add_subdirectory(glaze)
add_subdirectory(minizip) add_subdirectory(minizip)
add_subdirectory(open-location-code) add_subdirectory(open-location-code)
add_subdirectory(opening_hours) add_subdirectory(opening_hours)

View File

@@ -4,7 +4,9 @@ set(FT_DISABLE_HARFBUZZ ON)
add_subdirectory(freetype) add_subdirectory(freetype)
# Fix warning with ONE_PIXEL macro clash. # Fix warning with ONE_PIXEL macro clash.
target_compile_options(freetype PRIVATE -Wno-macro-redefined) if(NOT MSVC)
target_compile_options(freetype PRIVATE -Wno-macro-redefined)
endif()
# Use ft2build.h from the current directory instead of the default. # Use ft2build.h from the current directory instead of the default.
target_include_directories(freetype target_include_directories(freetype

1
3party/glaze Submodule

Submodule 3party/glaze added at 5a58d7936e

View File

@@ -11,14 +11,23 @@ target_include_directories(${PROJECT_NAME}
harfbuzz/src harfbuzz/src
) )
# Keep these settigns in sync with xcode/harfbuzz project. if (MSVC)
target_compile_options(${PROJECT_NAME} target_compile_options(${PROJECT_NAME}
PRIVATE PRIVATE
-fno-rtti /GR-
-fno-exceptions /EHsc-
-fno-threadsafe-statics /Zc:threadSafeInit-
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wno-format-pedantic> )
) else()
# Keep these settings in sync with xcode/harfbuzz project.
target_compile_options(${PROJECT_NAME}
PRIVATE
-fno-rtti
-fno-exceptions
-fno-threadsafe-statics
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wno-format-pedantic>
)
endif()
target_compile_definitions(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME}
PRIVATE PRIVATE
@@ -28,14 +37,20 @@ target_compile_definitions(${PROJECT_NAME}
#$<$<BOOL:${APPLE}>:HAVE_CORETEXT> #$<$<BOOL:${APPLE}>:HAVE_CORETEXT>
HAVE_ATEXIT HAVE_ATEXIT
HAVE_GETPAGESIZE HAVE_GETPAGESIZE
HAVE_MMAP
HAVE_MPROTECT HAVE_MPROTECT
HAVE_PTHREAD
HAVE_SYSCONF HAVE_SYSCONF
HAVE_SYS_MMAN_H
HAVE_UNISTD_H
) )
if (NOT MSVC)
target_compile_definitions(${PROJECT_NAME}
PRIVATE
HAVE_MMAP
HAVE_PTHREAD
HAVE_SYS_MMAN_H
HAVE_UNISTD_H
)
endif()
target_link_libraries(${PROJECT_NAME} Freetype::Freetype) target_link_libraries(${PROJECT_NAME} Freetype::Freetype)
add_library(harfbuzz::harfbuzz ALIAS harfbuzz) add_library(harfbuzz::harfbuzz ALIAS harfbuzz)

View File

@@ -172,6 +172,7 @@ add_library(icuuc
icu/icu4c/source/common/uvector.cpp icu/icu4c/source/common/uvector.cpp
icu/icu4c/source/common/uvectr32.cpp icu/icu4c/source/common/uvectr32.cpp
icu/icu4c/source/common/uvectr64.h icu/icu4c/source/common/uvectr64.h
icu/icu4c/source/common/wintz.cpp
icu/icu4c/source/common/wintz.h icu/icu4c/source/common/wintz.h
) )

View File

@@ -11,6 +11,7 @@ set(SRC
protobuf/src/google/protobuf/message_lite.cc protobuf/src/google/protobuf/message_lite.cc
protobuf/src/google/protobuf/repeated_field.cc protobuf/src/google/protobuf/repeated_field.cc
protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
protobuf/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
protobuf/src/google/protobuf/stubs/bytestream.cc protobuf/src/google/protobuf/stubs/bytestream.cc
protobuf/src/google/protobuf/stubs/common.cc protobuf/src/google/protobuf/stubs/common.cc
protobuf/src/google/protobuf/stubs/int128.cc protobuf/src/google/protobuf/stubs/int128.cc

View File

@@ -7,7 +7,6 @@
#include <boost/utility/enable_if.hpp> #include <boost/utility/enable_if.hpp>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/type_traits/is_pod.hpp> #include <boost/type_traits/is_pod.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include "mappable_vector.hpp" #include "mappable_vector.hpp"
@@ -283,12 +282,6 @@ namespace succinct { namespace mapper {
return mapper.bytes_read(); return mapper.bytes_read();
} }
template <typename T>
size_t map(T& val, boost::iostreams::mapped_file_source const& m, uint64_t flags = 0, const char* friendly_name = "<TOP>")
{
return map(val, m.data(), flags, friendly_name);
}
template <typename T> template <typename T>
uint64_t size_of(T& val) uint64_t size_of(T& val)
{ {

View File

@@ -8,7 +8,6 @@
#include <stdint.h> #include <stdint.h>
#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/iterator_facade.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
namespace succinct { namespace util { namespace succinct { namespace util {
@@ -205,29 +204,6 @@ namespace succinct { namespace util {
std::string m_cur_value; std::string m_cur_value;
}; };
struct mmap_lines
{
typedef buffer_line_iterator iterator;
typedef buffer_line_iterator const_iterator;
mmap_lines(std::string filename)
: m_map(filename)
{}
const_iterator begin() const
{
return const_iterator(m_map.data(), m_map.size());
}
const_iterator end() const
{
return const_iterator();
}
private:
boost::iostreams::mapped_file_source m_map;
};
struct input_error : std::invalid_argument struct input_error : std::invalid_argument
{ {
input_error(std::string const& what) input_error(std::string const& what)

View File

@@ -19,7 +19,18 @@ extern "C" {
#endif #endif
#include "vulkan_wrapper.h" #include "vulkan_wrapper.h"
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <dlfcn.h> #include <dlfcn.h>
#endif
int InitVulkan(void) { int InitVulkan(void) {
#if defined(__APPLE__) #if defined(__APPLE__)
@@ -30,6 +41,9 @@ int InitVulkan(void) {
if (!libvulkan) { if (!libvulkan) {
libvulkan = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL); libvulkan = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL);
} }
#elif defined( _WIN32 )
HMODULE libvulkan = LoadLibraryA("vulkan-1.dll");
auto dlsym = [](HMODULE h, char const * name) { return GetProcAddress(h, name); };
#else #else
void* libvulkan = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); void* libvulkan = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
if (!libvulkan) { if (!libvulkan) {

View File

@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.22.1)
project(omim C CXX) project(omim C CXX)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 23)
set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD 23)
# Our code does not rely on gnu extensions. # Our code does not rely on gnu extensions.
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_C_EXTENSIONS OFF) set(CMAKE_C_EXTENSIONS OFF)
@@ -39,18 +39,16 @@ if (APPLE AND NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL Android))
# https://gitlab.kitware.com/cmake/cmake/-/issues/21963 # https://gitlab.kitware.com/cmake/cmake/-/issues/21963
enable_language(OBJC) enable_language(OBJC)
set(CMAKE_OBJC_EXTENSIONS OFF) set(CMAKE_OBJC_EXTENSIONS OFF)
set(CMAKE_OBJC_STANDARD 11) set(CMAKE_OBJC_STANDARD 23)
set(CMAKE_OBJC_FLAGS -fobjc-arc) set(CMAKE_OBJC_FLAGS -fobjc-arc)
set(CMAKE_OBJC_VISIBILITY_PRESET hidden) set(CMAKE_OBJC_VISIBILITY_PRESET hidden)
enable_language(OBJCXX) enable_language(OBJCXX)
set(CMAKE_OBJCXX_EXTENSIONS OFF) set(CMAKE_OBJCXX_EXTENSIONS OFF)
set(CMAKE_OBJCXX_STANDARD 20) set(CMAKE_OBJCXX_STANDARD 23)
set(CMAKE_OBJCXX_FLAGS -fobjc-arc) set(CMAKE_OBJCXX_FLAGS -fobjc-arc)
set(CMAKE_OBJCXX_VISIBILITY_PRESET hidden) set(CMAKE_OBJCXX_VISIBILITY_PRESET hidden)
endif() endif()
execute_process(COMMAND "./configure.sh" WORKING_DIRECTORY ${OMIM_ROOT})
message(STATUS "Using compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "Using compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
if (CMAKE_UNITY_BUILD) if (CMAKE_UNITY_BUILD)
@@ -87,7 +85,7 @@ if (MSVC)
add_compile_options(/utf-8) add_compile_options(/utf-8)
add_link_options(/INCREMENTAL:NO) add_link_options(/INCREMENTAL:NO)
else() else()
add_compile_options(-ffast-math) add_compile_options(-ffast-math $<$<CXX_COMPILER_ID:GNU>:-Wno-psabi>)
endif() endif()
if (PLATFORM_WIN) if (PLATFORM_WIN)
@@ -185,7 +183,7 @@ if (NOT PLATFORM_IPHONE AND NOT PLATFORM_ANDROID)
endif() endif()
# To allow #include "base/file_name.hpp" in all sources. # To allow #include "base/file_name.hpp" in all sources.
include_directories(${CMAKE_HOME_DIRECTORY}) include_directories("${CMAKE_HOME_DIRECTORY}" "${CMAKE_HOME_DIRECTORY}/libs" "${CMAKE_HOME_DIRECTORY}/tools")
if (USE_PCH) if (USE_PCH)
message(STATUS "Precompiled headers are ON") message(STATUS "Precompiled headers are ON")
@@ -197,7 +195,7 @@ if (USE_PCH)
endif() endif()
# Should be on the root level, not in 3party, so tests can get these dependencies. # Should be on the root level, not in 3party, so tests can get these dependencies.
if (PLATFORM_LINUX OR PLATFORM_WIN) if (PLATFORM_LINUX)
find_package(ICU COMPONENTS uc i18n data REQUIRED) find_package(ICU COMPONENTS uc i18n data REQUIRED)
find_package(Freetype REQUIRED) find_package(Freetype REQUIRED)
find_package(harfbuzz REQUIRED) find_package(harfbuzz REQUIRED)
@@ -227,50 +225,22 @@ endif()
# Used in qt/ and shaders/ # Used in qt/ and shaders/
find_package(Python3 REQUIRED COMPONENTS Interpreter) find_package(Python3 REQUIRED COMPONENTS Interpreter)
add_subdirectory(base) add_subdirectory(libs)
add_subdirectory(coding)
add_subdirectory(descriptions)
add_subdirectory(drape)
add_subdirectory(drape_frontend)
add_subdirectory(editor)
add_subdirectory(ge0)
add_subdirectory(generator/mwm_diff)
add_subdirectory(geometry)
add_subdirectory(indexer)
add_subdirectory(kml)
add_subdirectory(map)
add_subdirectory(cppjansson)
add_subdirectory(platform)
add_subdirectory(routing)
add_subdirectory(routing_common)
add_subdirectory(search)
add_subdirectory(shaders)
add_subdirectory(storage)
add_subdirectory(tracking)
add_subdirectory(traffic)
add_subdirectory(traffxml)
add_subdirectory(transit)
if (PLATFORM_DESKTOP) if (PLATFORM_DESKTOP)
omim_add_tool_subdirectory(feature_list) add_subdirectory(dev_sandbox)
add_subdirectory(generator) add_subdirectory(generator)
add_subdirectory(openlr) add_subdirectory(tools)
add_subdirectory(poly_borders)
omim_add_tool_subdirectory(topography_generator)
add_subdirectory(track_analyzing)
omim_add_tool_subdirectory(track_generator)
if (NOT SKIP_QT_GUI) if (NOT SKIP_QT_GUI)
add_subdirectory(qt) add_subdirectory(qt)
omim_add_tool_subdirectory(skin_generator)
endif() endif()
if (GENERATOR_TOOL) if (GENERATOR_TOOL)
add_compile_options(-march=native -mtune=native) add_compile_options(-march=native -mtune=native)
message(STATUS "target CPU optimizations enabled, produced binaries will NOT work on a different CPU") message(STATUS "target CPU optimizations enabled, produced binaries will NOT work on a different CPU")
endif() endif()
add_subdirectory(dev_sandbox)
endif() endif()
omim_add_test_subdirectory(qt_tstfrm) omim_add_test_subdirectory(libs/qt_tstfrm)
if (PLATFORM_ANDROID) if (PLATFORM_ANDROID)
add_subdirectory(android/sdk/src/main/cpp) add_subdirectory(android/sdk/src/main/cpp)

View File

@@ -19,20 +19,20 @@
</div> </div>
<div align="center"> <div align="center">
<p align="center"> <p align="center">
<a href="https://codeberg.org/comaps/comaps/releases"> <a href="https://codeberg.org/comaps/comaps/src/branch/main/LICENSE">
<img src="https://img.shields.io/github/license/comaps/comaps?style=for-the-badge&logo=opensourceinitiative&logoColor=white&color=588157" alt="License" style="width: 90%; max-width: 150px;"/> <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&color=588157" alt="Android Build Status" style="width: 90%; max-width: 170px;"/> <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&color=588157" alt="iOS Build Status" style="width: 90%; max-width: 145px;"/> <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" style="width: 90%; max-width: 191px;"/> <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"/>
</a> </a>
<a href="https://liberapay.com/CoMaps"> <a href="https://liberapay.com/CoMaps">
<img src="https://img.shields.io/liberapay/patrons/CoMaps.svg?label=Liberapay%20Patrons&logo=liberapay&logoColor=white&style=for-the-badge&color=588157" alt="Liberapay Patrons" style="width: 90%; max-width: 160px;"/> <img src="https://img.shields.io/liberapay/patrons/CoMaps.svg?label=Liberapay%20Patrons&logo=liberapay&logoColor=white&style=for-the-badge&color=588157" alt="Liberapay Patrons"/>
</a> </a>
</p> </p>
</div> </div>
@@ -41,8 +41,6 @@
A community-led free & open source maps app based on [OpenStreetMap](https://www.openstreetmap.org), built for transparency, privacy, and not-for-profit values. A fork of Organic Maps, originally based on Maps.ME. A community-led free & open source maps app based on [OpenStreetMap](https://www.openstreetmap.org), built for transparency, privacy, and not-for-profit values. A fork of Organic Maps, originally based on Maps.ME.
**Available for:** Android, iOS, ARM macOS, and alpha Linux/macOS desktop builds (also usable on Linux phones).
<p align="center"> <p align="center">
<a href="https://apps.apple.com/app/comaps/id6747180809"> <a href="https://apps.apple.com/app/comaps/id6747180809">
<img src="docs/badges/apple-appstore.png" alt="App Store" width="160"/> <img src="docs/badges/apple-appstore.png" alt="App Store" width="160"/>
@@ -77,9 +75,10 @@ A community-led free & open source maps app based on [OpenStreetMap](https://www
## ⚡️ Highlights ## ⚡️ Highlights
- **Offline-first**: Navigate without a connection - **Offline-first**: Navigate without a connection
- **Privacy-respecting**: No tracking, Ads or data collection - **Privacy-respecting**: No tracking, ads or data collection
- **Lightweight**: Battery- and space-efficient - **Lightweight**: Battery- and space-efficient
- **Simple**: Polished, user-focused interface - **Simple**: Polished, user-focused interface
- **Cross-platform**: Available for Android, iOS, MacOS, and Linux.
- **Community-built**: Free, open source, and collaborative - **Community-built**: Free, open source, and collaborative
- **Transparent**: Open finances and governance - **Transparent**: Open finances and governance
@@ -140,7 +139,7 @@ There is a dedicated [Zulip](https://codeberg.org/comaps/Governance/src/branch/m
## 💸 Funding ## 💸 Funding
CoMaps is free. To stay that way, it relies on your support. CoMaps is free. To fund development, we rely on your voluntary support ♥️
Donate via [OpenCollective](https://opencollective.com/comaps/donate) or [Liberapay](https://liberapay.com/CoMaps). Donate via [OpenCollective](https://opencollective.com/comaps/donate) or [Liberapay](https://liberapay.com/CoMaps).
The project's financial information is completely open and transparent at [our Open Collective](https://opencollective.com/comaps). The project's financial information is completely open and transparent at [our Open Collective](https://opencollective.com/comaps).

View File

@@ -138,8 +138,6 @@ android {
disable 'MissingTranslation' disable 'MissingTranslation'
// https://github.com/organicmaps/organicmaps/issues/3551 // https://github.com/organicmaps/organicmaps/issues/3551
disable 'MissingQuantity', 'UnusedQuantity' disable 'MissingQuantity', 'UnusedQuantity'
// https://github.com/organicmaps/organicmaps/issues/3550
disable 'ByteOrderMark'
// https://github.com/organicmaps/organicmaps/issues/1077 // https://github.com/organicmaps/organicmaps/issues/1077
disable 'CustomSplashScreen' disable 'CustomSplashScreen'
// https://github.com/organicmaps/organicmaps/issues/3610 // https://github.com/organicmaps/organicmaps/issues/3610

View File

@@ -0,0 +1 @@
../../../../google/java/app/organicmaps/location

View File

@@ -1 +0,0 @@
../../../../../google/java/app/organicmaps/sdk/location

View File

@@ -0,0 +1 @@
মানচিত্র নেভিগেশন - আপনার যাত্রা সম্পর্কে আরও জানুন - সম্প্রদায় কর্তৃক পরিচালিত

View File

@@ -0,0 +1 @@
কোম্যাপস - অফলাইনে হাইকিং, সাইকেলিং ও ড্রাইভিং

View File

@@ -1 +0,0 @@
সহজ মানচিত্র নেভিগেশন - আপনার যাত্রা সম্পর্কে আরও জানুন - সম্প্রদায় কর্তৃক পরিচালিত

View File

@@ -1 +0,0 @@
কোম্যাপস - অফলাইনে হাইকিং, সাইকেলিং এবং ড্রাইভিং করুন গোপনীয়তা সহ

View File

@@ -1,7 +0,0 @@
• Data OpenStreetMap k 4. 8.
• vylepšené barvy mapy pro vodu, lesy, křoviny, různé vybavení, pěší zóny atd.
• přidány stanice lesní stráže, krytých parkovišť pro jízdní kola, únikových her, úschoven zavazadel, partnerských pošt
• vylepšeny výškové vrstevnice na 20 m pro některé oblíbené turistické oblasti
• podpora více zkratek a aliasů pro vyhledávání
• přidání ikon pro vyhledávání a záložky pro rychlé občerstvení, jízdní kola a dobíjecí stanice
• plynulejší pohyb šipky pro určení polohy

View File

@@ -1,7 +1,8 @@
• OpenStreetMap-Daten vom 4. August • OpenStreetMap-Daten vom 22. August
Verbesserte Farben für Wasser, Wälder, Gestrüpp, verschiedene Einrichtungen, Fussgängerbereiche etc. Neue Geschwindigkeitsanzeige & Details aufgezeichneter Strecken
• Besucherstationen, überdachte Fahrradparkplätze, Escaperooms, Gepäckschließfächer, und Postpartner hinzugefügt • Besserer dunkler Modus, neue farbige Labels
Konturhöhenlinien aktualisiert, bis zu 20m für beliebte Wanderregionen Anzeige wann Orte & Öffnungszeiten überprüft wurden
Unterstützung für mehr Such-Abkürzungen und Synonyme Routenplanung berücksichtigt Stoppschilder, Ampeln & bedingte Einschränkungen.
Such- und Lesezeichen-Symbole für Fast Food, Rad- und Lade-Stationen GPS-Peilung wird statt Kompass bevorzugt & höhere GPS-Frequenz.
Der Positionspfeil bewegt sich gleichmässiger Adressen & Notizen im OSM-Editor unterstützt.
• Mehr Verbesserungen an UI-Elementen & Kartenstil, alle Details in den Codeberg-Versionshinweisen!

View File

@@ -1,7 +1,9 @@
• OpenStreetMap data as of August 4 • OpenStreetMap data as of August 22
improve map colors for water, forests, scrubs, various amenities, pedestrian areas etc. New current speed indicator, display track info
add ranger stations, covered bicycle parkings, escape games, luggage lockers, post office partners Improved dark map style, added coloured labels
upgrade altitude contour lines to 20m step for some popular hiking regions Display when places & opening hours were last checked
support more search abbreviations and aliases Routing now considers turns, stop signs, lights & conditional restrictions
add search and bookmark icons for fast food, bicycle and charging stations Prefer GPS bearing over compass and increase location poll rate
more smooth position arrow movements Enable adding standalone addresses & notes in the editor
• Various UI element & map style improvements
Check our Codeberg release notes for more changes!

View File

@@ -1,7 +1,9 @@
• Datos de OpenStreetMap a fecha 2025.08.04 • Datos de OSM a 22-08-2025
Mejora de colores del mapa para agua, bosques, matorrales, servicios, zonas peatonales, etc. Nuevo indicador de velocidad e información de pista
Añadidas estaciones de guardabosques, aparcamientos cubiertos de bicis, juegos de escape, consignas y oficinas de correo Modo oscuro mejorado y nombres de POI coloreados
Nuevas curvas de nivel (20 m) en regiones populares para senderismo Indicador de última revisión de lugares y horarios de apertura
Más abreviaturas y alias de búsqueda Rutas mejoradas teniendo en cuenta giros, señales de STOP, semáforos y restricciones
Iconos de búsqueda y marcadores para comida rápida, bicicletas y estaciones de recarga Mayor precisión para determinar tu localización y sentido
Más fluidez de la flecha de posición Añade direcciones y notas con el editor
• Otras mejoras en elementos de la interfaz y estilo del mapa
Entra en nuestro Codeberg para más cambios!

View File

@@ -24,7 +24,7 @@ Sartu komunitatean eta lagundu maparik onena aplikatzen
• Lineaz kanpoko Wikipedia artikuluak • Lineaz kanpoko Wikipedia artikuluak
• Metroaren garraio geruza eta jarraibideak • Metroaren garraio geruza eta jarraibideak
• Arrastoen grabazioa • Arrastoen grabazioa
Laster-markak eta ibilbideak esportatu eta inportatu KML, KMZ, GPX formatuetan Markagailuak eta arrastoak esportatu eta inportatu KML, KMZ, GPX formatuetan
• Gauean erabiltzeko modu iluna • Gauean erabiltzeko modu iluna
• Hobetu mapako datuak guztiontzat oinarrizko editore integratua erabiliz • Hobetu mapako datuak guztiontzat oinarrizko editore integratua erabiliz

View File

@@ -1 +1 @@
CoMaps - کوه نوردی، دوچرخه سواری و رانندگی افلاین و خصوصی CoMaps - کوهنوردی، دوچرخهسواری و رانندگی آفلاین

View File

@@ -0,0 +1,9 @@
• Données OSM du 22 août
• Nouvel indicateur de vitesse et détails des pistes
• Amélioration du style sombre, ajout de labels colorées
• Affichage de la date de dernière vérification d'un lieu
• Support dans le routage des virages, signalisations et restrictions
• Amélioration de la boussole et de la précision GPS
• Support des adresses et des notes dans l'éditeur
• Diverses améliorations d'UI et du style de la carte
Plus d'informations sur notre Codeberg

View File

@@ -1 +1 @@
CoMaps - Pješačite, biciklirajte, vozite Offline i privatno CoMaps - Pješačite, biciklirajte, vozite Offline

View File

@@ -0,0 +1,32 @@
A CoMaps egy közösség által létrehozott, ingyenes és nyílt forráskódú térképalkalmazás, amely az OpenStreetMap térképadatain alapul, és amelyet az átláthatóság, a magánélet védelme és a nonprofit jelleg iránti elkötelezettség erősít. A CoMaps az Organic Maps villája, amely viszont a Maps.ME villája.
A projekt előzményeiről és az irányáról a <b><i>codeberg.org/comaps</i></b> oldalon olvashatsz.
Csatlakozz ott a közösséghez, és segíts a legjobb térképalkalmazás elkészítésében.
• Használd az alkalmazást és terjeszd a hírét
• Adj visszajelzést és jelentsd a problémákat
• Frissítsd és javítsd a térképadatokat az alkalmazásban vagy az OpenStreetMap weboldalán.
‣ <b>Offline-fókuszú:</b> Tervezd meg és navigáld külföldi útad mobilszolgáltatás nélkül, keress útpontokat egy távoli túra során stb. Az alkalmazás minden funkcióját úgy terveztük, hogy internetkapcsolat nélkül is működjön.
‣ <b>A magánélet tiszteletben tartása:</b> Az alkalmazás az adatvédelem szem előtt tartásával készült, nem azonosítja az embereket, nem követi nyomon és nem gyűjt személyes adatokat, és reklámmentes.
‣ <b>Takarékosdik az akkumulátorral és a tárhellyel:</b> Nem meríti le az akkumulátort, mint más navigációs alkalmazások. A jól összeállítot kis méretű térképek értékes helyet takarítanak meg a telefonon.
‣ <b>Egyszerű és szép grafikus felület,</b> nagyszerű és könnyen használható funkciók, amelyek egyszerűen működnek.
‣ <b>Ingyenes és a közösség által készített:</b> A hozzád hasonló emberek segítettek az alkalmazás létrehozásában azáltal, hogy hozzáadtak helyeket az OpenStreetMap térképhez, tesztelték és visszajelzést adtak a funkciókról, valamint hozzájárultak a fejlesztői képességeikkel és a pénzükkel.
‣ <b>Nyílt és átlátható döntéshozatal és pénzügyek, nonprofit és teljesen nyílt forráskódú.</b>
<b>Főbb jellemzők:</b>
• Letölthető részletes térképek olyan helyekkel, amelyek sok kereskedelmi térképen nem állnak rendelkezésre.
• Szabadtéri üzemmód kiemelt túraútvonalakkal, táborhelyekkel, vízforrásokkal, csúcsokkal, szintvonalakkal stb.
• Sétaútvonalak és kerékpárutak
• Érdekes pontok, mint például éttermek, benzinkutak, szállodák, üzletek, látnivalók és még sok minden más
• Keresés név, cím vagy az érdekes pontok kategóriája alapján
• Navigáció hangutasításokkal gyalogláshoz, kerékpározáshoz vagy vezetéshez
• Kedvenc helyeid könyvjelzővel láthatod el egyetlen érintéssel
• Wikipedia szócikkek internetkapcsolat nélkül
• Metró tranzit réteg és irányok
• Útvonal mentése
• Könyvjelzők és nyomvonalak exportálása és importálása KML, KMZ, GPX formátumokban
• Sötét üzemmód az éjszakai használathoz
• Térképadatok javítása mindenki számára egy alapvető beépített szerkesztő segítségével
<b>Itt van a szabadság</b>
Fedezd fel az utadat, navigálj a világban úgy, hogy a magánélet és a közösség kerüljön előtérbe!

View File

@@ -1 +0,0 @@
Navigation facile del mappa Discoperi tu viage Alimentate per le communitate

View File

@@ -1,4 +1,4 @@
Una app sviluppata dalla comunità, gratuita e open-source, basata su OpenStreetMap e sull'impegno alla trasparenza, al rispetto della Privacy senza scopo di lucro. CoMaps è uno spin-off di Organic Maps, che a sua volta deriva da Maps.ME. Una app realizzata dalla community gratuita e open-source, basata su OpenStreetMap e sull'impegno alla trasparenza, al rispetto della Privacy e senza scopo di lucro. CoMaps è uno spin-off di Organic Maps, che a sua volta deriva da Maps.ME.
Leggi delle ragioni del progetto e della sua direzione futura su <b><i>codeberg.org/comaps</i></b>. Leggi delle ragioni del progetto e della sua direzione futura su <b><i>codeberg.org/comaps</i></b>.
Unisciti alla nostra comunità e aiutaci a creare la migliore app di mappe. Unisciti alla nostra comunità e aiutaci a creare la migliore app di mappe.
@@ -15,7 +15,7 @@ Unisciti alla nostra comunità e aiutaci a creare la migliore app di mappe.
<b>Funzionalità principali</b>: <b>Funzionalità principali</b>:
• Scarica mappe dettagliate di luoghi che non sono disponibili su Google Maps • Scarica mappe dettagliate di luoghi che non sono disponibili su Google Maps
• Modalità Outdoor con percorsi escursionistici, campeggi, sorgenti d'acqua, picchi, dislivelli ed altro evidenziati • Modalità Outdoor con percorsi escursionistici, campeggi, sorgenti d'acqua, picchi, dislivelli ed altri punti d'interesse evidenziati
• Strade pedonali e piste ciclabili • Strade pedonali e piste ciclabili
• Punti d'interesse come ristoranti, stazioni di benzina, hotel, negozi, luoghi turistici e molto altro • Punti d'interesse come ristoranti, stazioni di benzina, hotel, negozi, luoghi turistici e molto altro
• Cerca per nome, indirizzo o categoria • Cerca per nome, indirizzo o categoria

View File

@@ -1,7 +0,0 @@
• Dati di OpenStreetMap aggiornati al 4 Agosto
• Migliorati i colori per acqua, foreste, servizi etc
• Aggiunte le stazioni delle guardie forestali, i parcheggi coperti per bici, gli escape games e altri servizi
• Aggiornato l'intervallo delle isolinee a 20 m per le zone escursionistiche più popolari
• Aggiunto il supporto per un maggior numero di alias
• Aggiunte le icone per i fast food, i punti di ricarica e le biciclette
• Resi più fluidi i movimenti della freccia di posizione

View File

@@ -1 +1 @@
Navigazione semplice - Immergiti nella tua avventura - Sviluppato dalla comunità Navigazione semplice - Immergiti nella tua avventura - Realizzato dalla comunità

View File

@@ -1 +1 @@
CoMaps - Wandel, fiets, rijdt offline met privacy CoMaps - Wandel, fiets, rijd offline met privacy

View File

@@ -0,0 +1 @@
Lett kart navigasjon - Opplev mere på din reise - Drevet av felleskapet

View File

@@ -0,0 +1 @@
CoMaps - Gå tur, sykkel, kjør - med personvern

View File

@@ -1,7 +1,8 @@
• Dados OSM de 4/08 • Dados OSM de 22/08
Melhoria nas cores para água, florestas, matagais, serviços, áreas de pedestres, etc. Novo indicador de velocidade e tela de informações de trilha
Adição de guarda-florestais, estacionamentos cobertos para bicicletas, jogos de fuga, armários para bagagem e parceiros postais Melhor estilo de mapa escuro, rótulos coloridos adicionados
Melhoria na precisão de curvas de nível para 20 m em algumas regiões populares Exibição da última atualização de locais e horários de funcionamento
Suporte a mais abreviações para busca O roteamento agora considera conversões, PARE, semáforos, e restrições condicionais
Adição de ícones de pesquisa e favoritos para fast food, bicicletas e estações de recarga Preferência por orientação GPS em vez de bússola e aumento da frequência de localização
Movimentos mais suaves para seta de posição Editor: adição de endereços e notas independentes
• Melhorias em elementos da interface e estilo de mapa

View File

@@ -1,32 +0,0 @@
Um aplicativo de mapas gratuito e de código aberto, liderado pela comunidade, baseado em dados do OpenStreetMap e reforçado pelo compromisso com a transparência, privacidade e sem fins lucrativos. O CoMaps é um fork/spin-off do Organic Maps, que por sua vez é um fork do Maps.ME.
Leia mais sobre os motivos do projeto e sua direção em <b><i>codeberg.org/comaps</i></b>.
Junte-se à comunidade e ajude a criar o melhor aplicativo de mapas.
• Use o aplicativo e divulgue-o.
• Envie feedback e relate problemas.
• Atualize os dados do mapa no aplicativo ou no site do OpenStreetMap.
‣ <b>Foco offline</b>: Planeje e navegue em sua viagem ao exterior sem a necessidade de sinal de celular, pesquise pontos de referência durante uma caminhada distante, etc. Todas as funções do aplicativo foram projetadas para funcionar offline.
‣ <b>Respeitando a privacidade</b>: O aplicativo foi projetado com a privacidade em mente - não identifica pessoas, não rastreia e não coleta informações pessoais. Sem anúncios.
‣ <b>Simples e sofisticado</b>: recursos essenciais e fáceis de usar que simplesmente funcionam.
‣ <b>Economiza bateria e espaço</b>: Não consome muita bateria como outros aplicativos de navegação. Mapas compactos economizam espaço precioso no seu celular.
‣ <b>Gratuito e desenvolvido pela comunidade</b>: Pessoas como você ajudaram a desenvolver o aplicativo adicionando lugares ao OpenStreetMap, testando e dando feedback sobre os recursos e contribuindo com suas habilidades de desenvolvimento e dinheiro.
‣ <b>Tomada de decisões e finanças abertas e transparentes, sem fins lucrativos e totalmente de código aberto.</b>
<b>Principais recursos</b>:
• Mapas detalhados para download com locais não disponíveis no Google Maps
• Modo ao ar livre com trilhas em destaque, acampamentos, fontes de água, picos, curvas de nível, etc.
• Trilhas para caminhada e ciclovias
• Pontos de interesse como restaurantes, postos de gasolina, hotéis, lojas, pontos turísticos e muito mais
• Pesquise por nome, endereço ou por categoria de ponto de interesse
• Navegação com anúncios de voz para caminhadas, ciclismo ou direção
• Marque seus lugares favoritos com um único toque
• Artigos offline da Wikipédia
• Camada e direções de transporte público do metrô
• Gravação de trilhas
• Exporte e importe favoritos e trilhas nos formatos KML, KMZ e GPX
• Um modo escuro para usar à noite
• Aprimore os dados do mapa para todos usando um editor básico integrado
<b>A Liberdade Chegou</b>
Descubra sua jornada, navegue pelo mundo com privacidade e comunidade em primeiro lugar!

View File

@@ -1 +0,0 @@
Navegação fácil nos mapas - Descubra mais sobre o seu percurso - Feito por todos

View File

@@ -1 +0,0 @@
CoMaps - Mapas e Navegação - Offline e Privada

View File

@@ -1 +1 @@
CoMaps - Drumeții, Ciclism, Condus Offline în confidențialitate CoMaps - călătorește offline cu confidențialitate

View File

@@ -1,7 +1,9 @@
Карты OpenStreetMap от 4 августа Данные 22 августа
Улучшен цвет воды, леса, кустарников, различных объектов инфраструктуры, пешеходных зон и т.д. Новый спидометр,информация о маршруте
Добавлены лесничества, крытые велопарковки, квесты, камеры хранения Улучшен тёмный стиль,цветные метки
Для некоторых популярных туристических регионов добавлены линии высот 20м Время последней проверки часов работы
• Поддержка дополнительных поисковых сокращений и синонимов • Построении маршрута учитывает повороты, знак «Стоп»,светофоры и ограничения
Добавлены иконки меток и результатов поиска для фастфуда, велопарковок и зарядных станций Предпочтение отдается GPS-координатам,а не компасу,увеличена частота опроса местоположения
Более плавное движение стрелки местоположения Можно добавлять отдельные адреса и заметки в редакторе
• Улучшены различные элементы пользовательского интерфейса и стиль карты
Ознакомьтесь с примечания к релизу про изменения!

View File

@@ -1,32 +1,32 @@
Бесплатна апликација отвореног кода коју је обављала заједница и заснива се на ОpenStreetMap-у подацима, усмерени транспарентност, приватност и непрофитни. CoMaps је Апликације за органске карте виљушка, које је пак форк Maps.ME. Бесплатна апликација отвореног кода коју одржава заједница, која се заснива на ОpenStreetMap подацима. Непрофитна, транспарентна и цени вашу приватност. CoMaps је настала од апликације Organic Maps, које је настала од апликације Maps.ME.
Прочитајте о разлозима пројекта и његовог правца на <b><i>codeberg.org/comaps</i></b> Прочитајте о разлозима пројекта и његовог правца на <b><i>codeberg.org/comaps</i></b>
Придружите се отвореној заједници и помозите да направимо најбољу апликацију за мапе Придружите се отвореној заједници и помозите да направимо најбољу апликацију за мапе
• Користите апликацију и проширите глас о томе • Користите апликацију и проширите глас о томе
• Дајте повратне информације и пријавите проблеме • Дајте повратне информације и пријавите проблеме
• Ажурирајте податке на мапи у апликацији или на веб локацији OpenStreetMap • Ажурирајте податке на мапи у апликацији или на сајту OpenStreetMap
‣ <b> фокусирано на офлајн Вар </b>: Планирајте и управљајте путовањем у иностранству без потребе за мобилним услугама, тражите путне тачке док је на даљинском покрету, итд. Све апликације су дизајниране за рад ван мреже. ‣ <b>Фокусирано на офлајн рад</b>: Планирајте и управљајте путовањем у иностранству без потребе за мобилним интернетом, тражите успутне тачке док сте на забаченом планинском путу, итд. Све функционалности су дизајниране за рад без интернета.
‣ <b> Поштовање приватности </b>: Апликација је осмишљена задржавања у уму приватност - не идентификује људе, не прати или прикупља личне податке. Нема реклама. ‣ <b>Поштовање приватности</b>: Апликација је осмишљена са приватношћу корисника на уму - не идентификује људе, не прати или прикупља личне податке. Нема реклама.
‣ <b> Једноставно и елегантно </b>: Апликација је тривијална за употребу и једноставно функционише. ‣ <b>Једноставно и елегантно</b>: Апликација је лака за употребу и једноставно функционише.
‣ <b> Чува вашу батерију и простор </b>: не конзумира батерију као остале навигационе апликације. Компактне картице сачувајте драгоцени простор на вашем телефону. ‣ <b>Чува вашу батерију и простор</b>: Не троши батерију као остале апликације за навигацију. Компактне мапе чувају драгоцени простор на вашем телефону.
‣ <b> Отворено и направио је заједницу </b>: Људи попут вас је помогли да додају апликацију додавањем локација на OpenStreetMap-у, тестирању и давање повратних информација о апликацији и доприносе вашим развојним вештинама и новцу. ‣ <b>Отворено и направљено од стране заједнице</b>: Људи попут вас су допринели развоју апликације додавањем локација на OpenStreetMap, тестирањем, давањем повратних информација о апликацији и помогли су својим програмерским вештинама и донацијама.
‣ <b> Отворено и транспарентно доношење одлука и употреба финансија, непрофитна и потпуно отворена извора. </b> ‣ <b>Отворено и транспарентно доношење одлука и употреба донација, непрофитна и потпуно отвореног кода.</b>
<b> Главне карактеристике </b>: <b> Главне карактеристике </b>:
• Преузмите детаљне мапе са локацијама које нису доступне са Гоогле мапама • Преузмимање детаљне мапе са локацијама које нису доступне са Google мапама
Улазнице за излете са истакнутим планинарским стазама, камповима, изворима воде, планинске врхове, контурне линије итд. Режим за излете са истакнутим планинарским стазама, камповима, изворима воде, планинским врховима, изохипсама итд.
• Стазе за планинарење и бицикле • Стазе за планинарење и бицикле
• Тачке интереса као што су ресторани, бензинске пумпе, хотели, продавнице, погледа и још много тога • Тачке интереса као што су ресторани, бензинске пумпе, хотели, продавнице, знаменитости и још много тога
• Претражите име или адресу или по категоријама камате • Претрага по називу, адреси или категоријама
навигација са гласовним најавама за ходање, бициклизам или аутомобил Навигација са гласовним инструкцијама за ходање, вожњу бицикла или аутомобила
• Означите своја омиљена места једним додиром • Означивање омиљених места једним додиром
• Офлајн чланци Википедије • Офлајн чланци Википедије
транзитни слој подземне пруге са навигацијом Транзитни слој подземне железнице са навигацијом
• Снимање ГПС трагова • Снимање ГПС путања
Ознака и увоз и увоз у KML, KMZ, GPX формате Увоз и увоз маркера и путања у KML, KMZ, GPX формате
• Тамни режим за употребу током ноћи • Тамни режим за употребу током ноћи
• Побољшајте карту за све кориснике, користећи основни уредни уредник мапе • Побољшајте карту за све кориснике, користећи основни едитор за мапе
<b> Слобода је овде </b> <b> Слобода је овде </b>
Откријте своје путовање, крећете се са свијетом са приватношћу и заједницом на првом месту! Откријте своје путовање, крећете се са светом са приватношћу и заједницом на првом месту!

View File

@@ -1,7 +0,0 @@
• подаци из OpenStreetMap-а од 4. августа
• побољшане боје на мапи за воду, шуме, жбуње, разне објекте, пешачке зоне итд.
• додате станице ренџера, наткривена паркинг места за бицикле, escape room-ови, ормарићи за пртљаг
• унапређене изохипсе на кораке од 20 м за популарне планинарске регионе
• подршка за више скраћеница и алтернативних назива у претрази
• додате иконе за претрагу и обележавање за брзу храну, бицикле и станице за пуњење
• равномерније кретање стрелице која приказује позицију

View File

@@ -1,4 +1,4 @@
package app.organicmaps.sdk.location; package app.organicmaps.location;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION;
@@ -10,6 +10,7 @@ import android.location.Location;
import android.os.Looper; import android.os.Looper;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission; import androidx.annotation.RequiresPermission;
import app.organicmaps.sdk.location.BaseLocationProvider;
import app.organicmaps.sdk.util.LocationUtils; import app.organicmaps.sdk.util.LocationUtils;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.ApiException;

View File

@@ -1,23 +1,25 @@
package app.organicmaps.sdk.location; package app.organicmaps.location;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import app.organicmaps.sdk.location.AndroidNativeProvider;
import app.organicmaps.sdk.location.BaseLocationProvider;
import app.organicmaps.sdk.location.LocationProviderFactory;
import app.organicmaps.sdk.util.Config; import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.common.GoogleApiAvailability;
public class LocationProviderFactory public class LocationProviderFactoryImpl implements LocationProviderFactory
{ {
private static final String TAG = LocationProviderFactory.class.getSimpleName(); private static final String TAG = LocationProviderFactoryImpl.class.getSimpleName();
public static boolean isGoogleLocationAvailable(@NonNull Context context) public boolean isGoogleLocationAvailable(@NonNull Context context)
{ {
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS; return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS;
} }
public static BaseLocationProvider getProvider(@NonNull Context context, public BaseLocationProvider getProvider(@NonNull Context context, @NonNull BaseLocationProvider.Listener listener)
@NonNull BaseLocationProvider.Listener listener)
{ {
if (isGoogleLocationAvailable(context) && Config.useGoogleServices()) if (isGoogleLocationAvailable(context) && Config.useGoogleServices())
{ {

View File

@@ -0,0 +1 @@
../../../../google/java/app/organicmaps/location

View File

@@ -1 +0,0 @@
../../../../../google/java/app/organicmaps/sdk/location

View File

@@ -6,7 +6,7 @@
<!-- Requiring "android.hardware.touchscreen" here breaks DeX mode --> <!-- Requiring "android.hardware.touchscreen" here breaks DeX mode -->
<uses-feature <uses-feature
android:glEsVersion="0x00020000" android:glEsVersion="0x00030000"
android:required="true"/> android:required="true"/>
<uses-feature <uses-feature
android:name="android.hardware.wifi" android:name="android.hardware.wifi"

View File

@@ -10,6 +10,8 @@ import androidx.core.content.ContextCompat;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager; import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.ElevationInfo; import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.bookmarks.data.TrackStatistics;
import app.organicmaps.util.ThemeUtils; import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import app.organicmaps.widget.placepage.AxisValueFormatter; import app.organicmaps.widget.placepage.AxisValueFormatter;
@@ -31,17 +33,16 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class ChartController implements OnChartValueSelectedListener, public class ChartController implements OnChartValueSelectedListener
BookmarkManager.OnElevationActivePointChangedListener,
BookmarkManager.OnElevationCurrentPositionChangedListener
{ {
private static final int CHART_Y_LABEL_COUNT = 3; private static final int CHART_Y_LABEL_COUNT = 3;
private static final int CHART_X_LABEL_COUNT = 6; private static final int CHART_X_LABEL_COUNT = 6;
private static final int CHART_ANIMATION_DURATION = 1500; private static final int CHART_ANIMATION_DURATION = 0;
private static final int CHART_FILL_ALPHA = (int) (0.12 * 255); private static final int CHART_FILL_ALPHA = (int) (0.12 * 255);
private static final int CHART_AXIS_GRANULARITY = 100; private static final int CHART_AXIS_GRANULARITY = 100;
private static final float CUBIC_INTENSITY = 0.2f; private static final float CUBIC_INTENSITY = 0.2f;
private static final int CURRENT_POSITION_OUT_OF_TRACK = -1; private static final int CURRENT_POSITION_OUT_OF_TRACK = -1;
private static final String ELEVATION_PROFILE_POINTS = "ELEVATION_PROFILE_POINTS";
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@NonNull @NonNull
@@ -62,6 +63,7 @@ public class ChartController implements OnChartValueSelectedListener,
private final Context mContext; private final Context mContext;
private long mTrackId = Utils.INVALID_ID; private long mTrackId = Utils.INVALID_ID;
private boolean mCurrentPositionOutOfTrack = true; private boolean mCurrentPositionOutOfTrack = true;
private boolean mInformSelectedActivePointToCore = true;
public ChartController(@NonNull Context context) public ChartController(@NonNull Context context)
{ {
@@ -70,8 +72,6 @@ public class ChartController implements OnChartValueSelectedListener,
public void initialize(@NonNull View view) public void initialize(@NonNull View view)
{ {
BookmarkManager.INSTANCE.setElevationActivePointChangedListener(this);
BookmarkManager.INSTANCE.setElevationCurrentPositionChangedListener(this);
final Resources resources = mContext.getResources(); final Resources resources = mContext.getResources();
mChart = view.findViewById(R.id.elevation_profile_chart); mChart = view.findViewById(R.id.elevation_profile_chart);
@@ -101,13 +101,6 @@ public class ChartController implements OnChartValueSelectedListener,
initAxises(); initAxises();
} }
@SuppressWarnings("unused")
public void destroy()
{
BookmarkManager.INSTANCE.setElevationActivePointChangedListener(null);
BookmarkManager.INSTANCE.setElevationCurrentPositionChangedListener(null);
}
private void highlightChartCurrentLocation() private void highlightChartCurrentLocation()
{ {
mChart.highlightValues(Collections.singletonList(getCurrentPosHighlight()), mChart.highlightValues(Collections.singletonList(getCurrentPosHighlight()),
@@ -142,15 +135,17 @@ public class ChartController implements OnChartValueSelectedListener,
mChart.getAxisRight().setEnabled(false); mChart.getAxisRight().setEnabled(false);
} }
public void setData(@NonNull ElevationInfo info) public void setData(Track track)
{ {
mTrackId = info.getId(); mTrackId = track.getTrackId();
ElevationInfo info = track.getElevationInfo();
TrackStatistics stats = track.getTrackStatistics();
List<Entry> values = new ArrayList<>(); List<Entry> values = new ArrayList<>();
for (ElevationInfo.Point point : info.getPoints()) for (ElevationInfo.Point point : info.getPoints())
values.add(new Entry((float) point.getDistance(), point.getAltitude())); values.add(new Entry((float) point.getDistance(), point.getAltitude(), point));
LineDataSet set = new LineDataSet(values, "Elevation_profile_points"); LineDataSet set = new LineDataSet(values, ELEVATION_PROFILE_POINTS);
set.setMode(LineDataSet.Mode.CUBIC_BEZIER); set.setMode(LineDataSet.Mode.CUBIC_BEZIER);
set.setCubicIntensity(CUBIC_INTENSITY); set.setCubicIntensity(CUBIC_INTENSITY);
set.setDrawFilled(true); set.setDrawFilled(true);
@@ -173,8 +168,8 @@ public class ChartController implements OnChartValueSelectedListener,
mChart.setData(data); mChart.setData(data);
mChart.animateX(CHART_ANIMATION_DURATION); mChart.animateX(CHART_ANIMATION_DURATION);
mMinAltitude.setText(Framework.nativeFormatAltitude(info.getMinAltitude())); mMinAltitude.setText(Framework.nativeFormatAltitude(stats.getMinElevation()));
mMaxAltitude.setText(Framework.nativeFormatAltitude(info.getMaxAltitude())); mMaxAltitude.setText(Framework.nativeFormatAltitude(stats.getMaxElevation()));
highlightActivePointManually(); highlightActivePointManually();
} }
@@ -192,7 +187,9 @@ public class ChartController implements OnChartValueSelectedListener,
if (mTrackId == Utils.INVALID_ID) if (mTrackId == Utils.INVALID_ID)
return; return;
BookmarkManager.INSTANCE.setElevationActivePoint(mTrackId, e.getX()); if (mInformSelectedActivePointToCore)
BookmarkManager.INSTANCE.setElevationActivePoint(mTrackId, e.getX(), (ElevationInfo.Point) e.getData());
mInformSelectedActivePointToCore = true;
} }
@NonNull @NonNull
@@ -211,7 +208,6 @@ public class ChartController implements OnChartValueSelectedListener,
highlightChartCurrentLocation(); highlightChartCurrentLocation();
} }
@Override
public void onCurrentPositionChanged() public void onCurrentPositionChanged()
{ {
if (mTrackId == Utils.INVALID_ID) if (mTrackId == Utils.INVALID_ID)
@@ -222,7 +218,6 @@ public class ChartController implements OnChartValueSelectedListener,
highlightActivePointManually(); highlightActivePointManually();
} }
@Override
public void onElevationActivePointChanged() public void onElevationActivePointChanged()
{ {
if (mTrackId == Utils.INVALID_ID) if (mTrackId == Utils.INVALID_ID)
@@ -234,6 +229,7 @@ public class ChartController implements OnChartValueSelectedListener,
private void highlightActivePointManually() private void highlightActivePointManually()
{ {
Highlight highlight = getActivePoint(); Highlight highlight = getActivePoint();
mInformSelectedActivePointToCore = false;
mChart.highlightValue(highlight, true); mChart.highlightValue(highlight, true);
} }

View File

@@ -27,6 +27,7 @@ import androidx.annotation.StringRes;
import androidx.annotation.StyleRes; 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.intent.Factory; import app.organicmaps.intent.Factory;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.downloader.CountryItem; import app.organicmaps.sdk.downloader.CountryItem;
@@ -35,7 +36,7 @@ import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.util.Config; import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.ConnectionState; import app.organicmaps.sdk.util.ConnectionState;
import app.organicmaps.sdk.util.StringUtils; import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener; import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener;
import com.google.android.material.button.MaterialButton; import com.google.android.material.button.MaterialButton;
@@ -116,10 +117,10 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
private final app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener mResourcesDownloadListener = private final app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener mResourcesDownloadListener =
new app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener() { new app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener() {
@Override @Override
public void onProgress(final int percent) public void onProgress(final int bytesDownloaded)
{ {
if (!isFinishing()) if (!isFinishing())
mProgress.setProgressCompat(percent, true); mProgress.setProgressCompat(bytesDownloaded, true);
} }
@Override @Override
@@ -150,14 +151,14 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
switch (item.newStatus) switch (item.newStatus)
{ {
case CountryItem.STATUS_DONE: case CountryItem.STATUS_DONE:
mAreResourcesDownloaded = true; mAreResourcesDownloaded = true;
showMap(); showMap();
return; return;
case CountryItem.STATUS_FAILED: case CountryItem.STATUS_FAILED:
MapManager.showError(DownloadResourcesLegacyActivity.this, item, null); MapManagerHelper.showError(DownloadResourcesLegacyActivity.this, item, null);
return; return;
} }
} }
} }
@@ -252,7 +253,8 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
setDownloadMessage(bytes); setDownloadMessage(bytes);
mProgress.setMax(bytes); mProgress.setMax(bytes);
mProgress.setProgressCompat(0, true); // Start progress at 1% according to M3 guidelines
mProgress.setProgressCompat(bytes/100, true);
} }
else else
finishFilesDownload(bytes); finishFilesDownload(bytes);
@@ -370,10 +372,11 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
String fileSizeString = StringUtils.getFileSizeString(this, item.totalSize); String fileSizeString = StringUtils.getFileSizeString(this, item.totalSize);
mTvMessage.setText(getString(R.string.downloading_country_can_proceed, item.name, fileSizeString)); mTvMessage.setText(getString(R.string.downloading_country_can_proceed, item.name, fileSizeString));
mProgress.setMax((int) item.totalSize); mProgress.setMax((int) item.totalSize);
mProgress.setProgressCompat(0, true); // Start progress at 1% according to M3 guidelines
mProgress.setProgressCompat((int) (item.totalSize/100), true);
mCountryDownloadListenerSlot = MapManager.nativeSubscribe(mCountryDownloadListener); mCountryDownloadListenerSlot = MapManager.nativeSubscribe(mCountryDownloadListener);
MapManager.startDownload(mCurrentCountry); MapManagerHelper.startDownload(mCurrentCountry);
setAction(PROCEED_TO_MAP); setAction(PROCEED_TO_MAP);
} }
else else

View File

@@ -23,6 +23,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
public class MapFragment extends BaseMwmFragment implements View.OnTouchListener, SurfaceHolder.Callback public class MapFragment extends BaseMwmFragment implements View.OnTouchListener, SurfaceHolder.Callback
{ {
private static final String TAG = MapFragment.class.getSimpleName(); private static final String TAG = MapFragment.class.getSimpleName();
@NonNull
private final Map mMap = new Map(DisplayType.Device); private final Map mMap = new Map(DisplayType.Device);
public void updateCompassOffset(int offsetX, int offsetY) public void updateCompassOffset(int offsetX, int offsetY)
@@ -84,6 +86,8 @@ public class MapFragment extends BaseMwmFragment implements View.OnTouchListener
{ {
Logger.d(TAG); Logger.d(TAG);
super.onAttach(context); super.onAttach(context);
mMap.setLocationHelper(MwmApplication.from(requireContext()).getLocationHelper());
mMap.setMapRenderingListener((MapRenderingListener) context); mMap.setMapRenderingListener((MapRenderingListener) context);
mMap.setCallbackUnsupported(this::reportUnsupported); mMap.setCallbackUnsupported(this::reportUnsupported);
} }
@@ -159,24 +163,24 @@ public class MapFragment extends BaseMwmFragment implements View.OnTouchListener
int pointerIndex = event.getActionIndex(); int pointerIndex = event.getActionIndex();
switch (action) switch (action)
{ {
case MotionEvent.ACTION_POINTER_UP -> action = Map.NATIVE_ACTION_UP; case MotionEvent.ACTION_POINTER_UP -> action = Map.NATIVE_ACTION_UP;
case MotionEvent.ACTION_UP -> case MotionEvent.ACTION_UP ->
{ {
action = Map.NATIVE_ACTION_UP; action = Map.NATIVE_ACTION_UP;
pointerIndex = 0; pointerIndex = 0;
} }
case MotionEvent.ACTION_POINTER_DOWN -> action = Map.NATIVE_ACTION_DOWN; case MotionEvent.ACTION_POINTER_DOWN -> action = Map.NATIVE_ACTION_DOWN;
case MotionEvent.ACTION_DOWN -> case MotionEvent.ACTION_DOWN ->
{ {
action = Map.NATIVE_ACTION_DOWN; action = Map.NATIVE_ACTION_DOWN;
pointerIndex = 0; pointerIndex = 0;
} }
case MotionEvent.ACTION_MOVE -> case MotionEvent.ACTION_MOVE ->
{ {
action = Map.NATIVE_ACTION_MOVE; action = Map.NATIVE_ACTION_MOVE;
pointerIndex = Map.INVALID_POINTER_MASK; pointerIndex = Map.INVALID_POINTER_MASK;
} }
case MotionEvent.ACTION_CANCEL -> action = Map.NATIVE_ACTION_CANCEL; case MotionEvent.ACTION_CANCEL -> action = Map.NATIVE_ACTION_CANCEL;
} }
Map.onTouch(action, event, pointerIndex); Map.onTouch(action, event, pointerIndex);
return true; return true;

View File

@@ -12,13 +12,13 @@ import static app.organicmaps.sdk.location.LocationState.FOLLOW;
import static app.organicmaps.sdk.location.LocationState.FOLLOW_AND_ROTATE; import static app.organicmaps.sdk.location.LocationState.FOLLOW_AND_ROTATE;
import static app.organicmaps.sdk.location.LocationState.LOCATION_TAG; import static app.organicmaps.sdk.location.LocationState.LOCATION_TAG;
import static app.organicmaps.sdk.util.PowerManagment.POWER_MANAGEMENT_TAG; import static app.organicmaps.sdk.util.PowerManagment.POWER_MANAGEMENT_TAG;
import static app.organicmaps.sdk.util.Utils.dimen;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -28,7 +28,6 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
@@ -66,7 +65,6 @@ import app.organicmaps.downloader.OnmapDownloader;
import app.organicmaps.editor.EditorActivity; import app.organicmaps.editor.EditorActivity;
import app.organicmaps.editor.EditorHostFragment; import app.organicmaps.editor.EditorHostFragment;
import app.organicmaps.editor.FeatureCategoryActivity; import app.organicmaps.editor.FeatureCategoryActivity;
import app.organicmaps.editor.OsmLoginActivity;
import app.organicmaps.editor.ReportFragment; import app.organicmaps.editor.ReportFragment;
import app.organicmaps.help.HelpActivity; import app.organicmaps.help.HelpActivity;
import app.organicmaps.intent.Factory; import app.organicmaps.intent.Factory;
@@ -82,7 +80,6 @@ import app.organicmaps.routing.ManageRouteBottomSheet;
import app.organicmaps.routing.NavigationController; import app.organicmaps.routing.NavigationController;
import app.organicmaps.routing.NavigationService; import app.organicmaps.routing.NavigationService;
import app.organicmaps.routing.RoutingBottomMenuListener; import app.organicmaps.routing.RoutingBottomMenuListener;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.routing.RoutingErrorDialogFragment; import app.organicmaps.routing.RoutingErrorDialogFragment;
import app.organicmaps.routing.RoutingPlanFragment; import app.organicmaps.routing.RoutingPlanFragment;
import app.organicmaps.routing.RoutingPlanInplaceController; import app.organicmaps.routing.RoutingPlanInplaceController;
@@ -100,7 +97,6 @@ import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.downloader.UpdateInfo; import app.organicmaps.sdk.downloader.UpdateInfo;
import app.organicmaps.sdk.editor.Editor; import app.organicmaps.sdk.editor.Editor;
import app.organicmaps.sdk.editor.OsmOAuth;
import app.organicmaps.sdk.location.LocationHelper; import app.organicmaps.sdk.location.LocationHelper;
import app.organicmaps.sdk.location.LocationListener; import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.location.LocationState; import app.organicmaps.sdk.location.LocationState;
@@ -108,6 +104,7 @@ import app.organicmaps.sdk.location.SensorListener;
import app.organicmaps.sdk.location.TrackRecorder; import app.organicmaps.sdk.location.TrackRecorder;
import app.organicmaps.sdk.maplayer.isolines.IsolinesState; import app.organicmaps.sdk.maplayer.isolines.IsolinesState;
import app.organicmaps.sdk.routing.RouteMarkType; import app.organicmaps.sdk.routing.RouteMarkType;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingOptions; import app.organicmaps.sdk.routing.RoutingOptions;
import app.organicmaps.sdk.search.SearchEngine; import app.organicmaps.sdk.search.SearchEngine;
import app.organicmaps.sdk.settings.RoadType; import app.organicmaps.sdk.settings.RoadType;
@@ -115,8 +112,6 @@ import app.organicmaps.sdk.settings.UnitLocale;
import app.organicmaps.sdk.util.Config; import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.LocationUtils; import app.organicmaps.sdk.util.LocationUtils;
import app.organicmaps.sdk.util.PowerManagment; import app.organicmaps.sdk.util.PowerManagment;
import app.organicmaps.sdk.util.ThemeSwitcher;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.sdk.widget.placepage.PlacePageData; import app.organicmaps.sdk.widget.placepage.PlacePageData;
import app.organicmaps.search.FloatingSearchToolbarController; import app.organicmaps.search.FloatingSearchToolbarController;
@@ -125,7 +120,9 @@ import app.organicmaps.search.SearchFragment;
import app.organicmaps.settings.DrivingOptionsActivity; import app.organicmaps.settings.DrivingOptionsActivity;
import app.organicmaps.settings.SettingsActivity; import app.organicmaps.settings.SettingsActivity;
import app.organicmaps.util.SharingUtils; import app.organicmaps.util.SharingUtils;
import app.organicmaps.util.ThemeSwitcher;
import app.organicmaps.util.ThemeUtils; import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment; import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem; import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
@@ -290,7 +287,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
} }
processIntent(); processIntent();
migrateOAuthCredentials();
} }
/** /**
@@ -345,36 +341,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
} }
} }
private void migrateOAuthCredentials()
{
if (OsmOAuth.containsOAuth1Credentials())
{
// Remove old OAuth v1 secrets
OsmOAuth.clearOAuth1Credentials();
// Notify user to re-login
dismissAlertDialog();
final DialogInterface.OnClickListener navigateToLoginHandler =
(dialog, which) -> startActivity(new Intent(MwmActivity.this, OsmLoginActivity.class));
final int marginBase = getResources().getDimensionPixelSize(R.dimen.margin_base);
final float textSize = getResources().getDimension(R.dimen.line_spacing_extra_1);
final TextView text = new TextView(this);
text.setText(getText(R.string.alert_reauth_message));
text.setPadding(marginBase, marginBase, marginBase, marginBase);
text.setTextSize(textSize);
text.setMovementMethod(LinkMovementMethod.getInstance());
mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.login_osm)
.setView(text)
.setPositiveButton(R.string.login, navigateToLoginHandler)
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener(dialog -> mAlertDialog = null)
.show();
}
}
private static void checkMeasurementSystem() private static void checkMeasurementSystem()
{ {
UnitLocale.initializeCurrentUnits(); UnitLocale.initializeCurrentUnits();
@@ -492,12 +458,10 @@ public class MwmActivity extends BaseMwmFragmentActivity
@StyleRes @StyleRes
protected int getThemeResourceId(@NonNull String theme) protected int getThemeResourceId(@NonNull String theme)
{ {
Context context = getApplicationContext(); if (Config.UiTheme.isDefault(theme))
if (ThemeUtils.isDefaultTheme(context, theme))
return R.style.MwmTheme_MainActivity; return R.style.MwmTheme_MainActivity;
if (ThemeUtils.isNightTheme(context, theme)) if (Config.UiTheme.isNight(theme))
return R.style.MwmTheme_Night_MainActivity; return R.style.MwmTheme_Night_MainActivity;
return super.getThemeResourceId(theme); return super.getThemeResourceId(theme);
@@ -619,7 +583,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void refreshLightStatusBar() private void refreshLightStatusBar()
{ {
UiUtils.setLightStatusBar(this, !(ThemeUtils.isNightTheme(this) || RoutingController.get().isPlanning() UiUtils.setLightStatusBar(this, !(ThemeUtils.isNightTheme() || RoutingController.get().isPlanning()
|| ChoosePositionMode.get() != ChoosePositionMode.None)); || ChoosePositionMode.get() != ChoosePositionMode.None));
} }
@@ -629,7 +593,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
UiUtils.setViewInsetsPaddingBottom(mPointChooser, windowInsets); UiUtils.setViewInsetsPaddingBottom(mPointChooser, windowInsets);
UiUtils.setViewInsetsPaddingNoBottom(mPointChooserToolbar, windowInsets); UiUtils.setViewInsetsPaddingNoBottom(mPointChooserToolbar, windowInsets);
final int trackRecorderOffset = final int trackRecorderOffset =
TrackRecorder.nativeIsTrackRecordingEnabled() ? UiUtils.dimen(this, R.dimen.map_button_size) : 0; TrackRecorder.nativeIsTrackRecordingEnabled() ? dimen(this, R.dimen.map_button_size) : 0;
mNavBarHeight = isFullscreen() ? 0 : windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; mNavBarHeight = isFullscreen() ? 0 : windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom;
// For the first loading, set compass top margin to status bar size // For the first loading, set compass top margin to status bar size
// The top inset will be then be updated by the routing controller // The top inset will be then be updated by the routing controller
@@ -683,29 +647,29 @@ public class MwmActivity extends BaseMwmFragmentActivity
mPointChooser.findViewById(R.id.done).setOnClickListener(v -> { mPointChooser.findViewById(R.id.done).setOnClickListener(v -> {
switch (ChoosePositionMode.get()) switch (ChoosePositionMode.get())
{ {
case Api: case Api:
final Intent apiResult = new Intent(); final Intent apiResult = new Intent();
final double[] center = Framework.nativeGetScreenRectCenter(); final double[] center = Framework.nativeGetScreenRectCenter();
apiResult.putExtra(Const.EXTRA_POINT_LAT, center[0]); apiResult.putExtra(Const.EXTRA_POINT_LAT, center[0]);
apiResult.putExtra(Const.EXTRA_POINT_LON, center[1]); apiResult.putExtra(Const.EXTRA_POINT_LON, center[1]);
apiResult.putExtra(Const.EXTRA_ZOOM_LEVEL, Framework.nativeGetDrawScale()); apiResult.putExtra(Const.EXTRA_ZOOM_LEVEL, Framework.nativeGetDrawScale());
setResult(Activity.RESULT_OK, apiResult); setResult(Activity.RESULT_OK, apiResult);
finish(); finish();
break; break;
case Editor: case Editor:
if (Framework.nativeIsDownloadedMapAtScreenCenter()) if (Framework.nativeIsDownloadedMapAtScreenCenter())
startActivity(new Intent(MwmActivity.this, FeatureCategoryActivity.class)); startActivity(new Intent(MwmActivity.this, FeatureCategoryActivity.class));
else else
{ {
dismissAlertDialog(); dismissAlertDialog();
mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog) mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.message_invalid_feature_position) .setTitle(R.string.message_invalid_feature_position)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.setOnDismissListener(dialog -> mAlertDialog = null) .setOnDismissListener(dialog -> mAlertDialog = null)
.show(); .show();
} }
break; break;
case None: throw new IllegalStateException("Unexpected Framework.nativeGetChoosePositionMode()"); case None: throw new IllegalStateException("Unexpected Framework.nativeGetChoosePositionMode()");
} }
closePositionChooser(); closePositionChooser();
}); });
@@ -772,9 +736,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
final View mapView = mMapFragment.getView(); final View mapView = mMapFragment.getView();
if (mapView != null) if (mapView != null)
{ {
int width = mapView.getWidth(); int width = mapView.getWidth();
int height = mapView.getHeight(); int height = mapView.getHeight();
Framework.nativeSetVisibleRect(0, 0, width, height); Framework.nativeSetVisibleRect(0, 0, width, height);
} }
} }
UiUtils.show(mPointChooser); UiUtils.show(mPointChooser);
@@ -972,24 +936,24 @@ public class MwmActivity extends BaseMwmFragmentActivity
{ {
switch (button) switch (button)
{ {
case zoomIn -> Map.zoomIn(); case zoomIn -> Map.zoomIn();
case zoomOut -> Map.zoomOut(); case zoomOut -> Map.zoomOut();
case myPosition -> case myPosition ->
{ {
Logger.i(LOCATION_TAG, "The location button pressed"); Logger.i(LOCATION_TAG, "The location button pressed");
// Calls onMyPositionModeChanged(mode + 1). // Calls onMyPositionModeChanged(mode + 1).
LocationState.nativeSwitchToNextMode(); LocationState.nativeSwitchToNextMode();
} }
case toggleMapLayer -> toggleMapLayerBottomSheet(); case toggleMapLayer -> toggleMapLayerBottomSheet();
case bookmarks -> showBookmarks(); case bookmarks -> showBookmarks();
case search -> showSearch(""); case search -> showSearch("");
case menu -> case menu ->
{ {
closeFloatingPanels(); closeFloatingPanels();
showBottomSheet(MAIN_MENU_ID); showBottomSheet(MAIN_MENU_ID);
} }
case help -> showHelp(); case help -> showHelp();
case trackRecordingStatus -> showTrackSaveDialog(); case trackRecordingStatus -> showTrackSaveDialog();
} }
} }
@@ -1223,21 +1187,22 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void onIsolinesStateChanged(@NonNull IsolinesState type) private void onIsolinesStateChanged(@NonNull IsolinesState type)
{ {
if (type != IsolinesState.EXPIREDDATA) if (type == IsolinesState.NODATA)
{ {
type.activate(this, findViewById(R.id.coordinator), findViewById(R.id.menu_frame)); Toast.makeText(this, R.string.isolines_location_error_dialog, Toast.LENGTH_SHORT).show();
return;
} }
dismissAlertDialog(); if (type == IsolinesState.EXPIREDDATA)
mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog) {
.setTitle(R.string.downloader_update_maps) mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
.setMessage(R.string.isolines_activation_error_dialog) .setTitle(R.string.downloader_update_maps)
.setPositiveButton(R.string.ok, .setMessage(R.string.isolines_activation_error_dialog)
(dialog, which) -> startActivity(new Intent(this, DownloaderActivity.class))) .setPositiveButton(
.setNegativeButton(R.string.cancel, null) R.string.ok, (dialog, which) -> startActivity(new Intent(this, DownloaderActivity.class)))
.setOnDismissListener(dialog -> mAlertDialog = null) .setNegativeButton(R.string.cancel, null)
.show(); .setOnDismissListener(dialog -> mAlertDialog = null)
.show();
}
} }
@Override @Override
@@ -1682,17 +1647,17 @@ public class MwmActivity extends BaseMwmFragmentActivity
final int orientation = getResources().getConfiguration().orientation; final int orientation = getResources().getConfiguration().orientation;
final boolean isTrackRecordingEnabled = TrackRecorder.nativeIsTrackRecordingEnabled(); final boolean isTrackRecordingEnabled = TrackRecorder.nativeIsTrackRecordingEnabled();
if (isTrackRecordingEnabled && (orientation != Configuration.ORIENTATION_LANDSCAPE)) if (isTrackRecordingEnabled && (orientation != Configuration.ORIENTATION_LANDSCAPE))
offsetY += UiUtils.dimen(this, R.dimen.map_button_size); offsetY += dimen(this, R.dimen.map_button_size);
if (orientation == Configuration.ORIENTATION_LANDSCAPE) if (orientation == Configuration.ORIENTATION_LANDSCAPE)
{ {
if (show) if (show)
{ {
final boolean isSmallScreen = UiUtils.getDisplayTotalHeight(this) < UiUtils.dimen(this, R.dimen.dp_400); final boolean isSmallScreen = UiUtils.getDisplayTotalHeight(this) < dimen(this, R.dimen.dp_400);
if (!isSmallScreen || TrackRecorder.nativeIsTrackRecordingEnabled()) if (!isSmallScreen || TrackRecorder.nativeIsTrackRecordingEnabled())
offsetX += UiUtils.dimen(this, R.dimen.map_button_size); offsetX += dimen(this, R.dimen.map_button_size);
} }
else if (isTrackRecordingEnabled) else if (isTrackRecordingEnabled)
offsetY += UiUtils.dimen(this, R.dimen.map_button_size); offsetY += dimen(this, R.dimen.map_button_size);
} }
updateCompassOffset(offsetY, offsetX); updateCompassOffset(offsetY, offsetX);
} }
@@ -2428,18 +2393,18 @@ public class MwmActivity extends BaseMwmFragmentActivity
{ {
switch (keyCode) switch (keyCode)
{ {
case KeyEvent.KEYCODE_DPAD_DOWN: Map.zoomOut(); return true; case KeyEvent.KEYCODE_DPAD_DOWN: Map.zoomOut(); return true;
case KeyEvent.KEYCODE_DPAD_UP: Map.zoomIn(); return true; case KeyEvent.KEYCODE_DPAD_UP: Map.zoomIn(); return true;
case KeyEvent.KEYCODE_ESCAPE: case KeyEvent.KEYCODE_ESCAPE:
final Intent currIntent = getIntent(); final Intent currIntent = getIntent();
final String backUrl = Framework.nativeGetParsedBackUrl(); final String backUrl = Framework.nativeGetParsedBackUrl();
if (TextUtils.isEmpty(backUrl) || (currIntent != null && Factory.isStartedForApiResult(currIntent))) if (TextUtils.isEmpty(backUrl) || (currIntent != null && Factory.isStartedForApiResult(currIntent)))
{ {
finish(); finish();
return true; return true;
} }
return super.onKeyUp(keyCode, event); return super.onKeyUp(keyCode, event);
default: return super.onKeyUp(keyCode, event); default: return super.onKeyUp(keyCode, event);
} }
} }
@@ -2491,7 +2456,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
if (mCurrentWindowInsets != null) if (mCurrentWindowInsets != null)
{ {
final int offset = mCurrentWindowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).top; final int offset = mCurrentWindowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).top;
updateCompassOffset(offset + UiUtils.dimen(this, R.dimen.map_button_size)); updateCompassOffset(offset + dimen(this, R.dimen.map_button_size));
} }
Toast.makeText(this, R.string.track_recording, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.track_recording, Toast.LENGTH_SHORT).show();
TrackRecordingService.startForegroundService(getApplicationContext()); TrackRecordingService.startForegroundService(getApplicationContext());
@@ -2584,7 +2549,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
items.add(new MenuBottomSheetItem(R.string.download_maps, R.drawable.ic_download, getDownloadMapsCounter(), items.add(new MenuBottomSheetItem(R.string.download_maps, R.drawable.ic_download, getDownloadMapsCounter(),
this::onDownloadMapsOptionSelected)); this::onDownloadMapsOptionSelected));
mDonatesUrl = Config.getDonateUrl(getApplicationContext()); mDonatesUrl = Utils.getDonateUrl(getApplicationContext());
if (!mDonatesUrl.isEmpty()) if (!mDonatesUrl.isEmpty())
items.add(new MenuBottomSheetItem(R.string.donate, R.drawable.ic_donate, this::onDonateOptionSelected)); items.add(new MenuBottomSheetItem(R.string.donate, R.drawable.ic_donate, this::onDonateOptionSelected));

View File

@@ -14,11 +14,12 @@ import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner; import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.preference.PreferenceManager;
import app.organicmaps.background.OsmUploadWork; import app.organicmaps.background.OsmUploadWork;
import app.organicmaps.downloader.DownloaderNotifier; import app.organicmaps.downloader.DownloaderNotifier;
import app.organicmaps.location.LocationProviderFactoryImpl;
import app.organicmaps.location.TrackRecordingService; import app.organicmaps.location.TrackRecordingService;
import app.organicmaps.routing.NavigationService; import app.organicmaps.routing.NavigationService;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Map; import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.OrganicMaps; import app.organicmaps.sdk.OrganicMaps;
import app.organicmaps.sdk.display.DisplayManager; import app.organicmaps.sdk.display.DisplayManager;
@@ -28,9 +29,11 @@ import app.organicmaps.sdk.location.SensorHelper;
import app.organicmaps.sdk.location.TrackRecorder; import app.organicmaps.sdk.location.TrackRecorder;
import app.organicmaps.sdk.maplayer.isolines.IsolinesManager; import app.organicmaps.sdk.maplayer.isolines.IsolinesManager;
import app.organicmaps.sdk.maplayer.subway.SubwayManager; import app.organicmaps.sdk.maplayer.subway.SubwayManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config; import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.ConnectionState; import app.organicmaps.sdk.util.ConnectionState;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.util.ThemeSwitcher;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@@ -40,6 +43,9 @@ public class MwmApplication extends Application implements Application.ActivityL
@NonNull @NonNull
private static final String TAG = MwmApplication.class.getSimpleName(); private static final String TAG = MwmApplication.class.getSimpleName();
@NonNull
private final LocationProviderFactoryImpl mLocationProviderFactory = new LocationProviderFactoryImpl();
@SuppressWarnings("NotNullFieldNotInitialized") @SuppressWarnings("NotNullFieldNotInitialized")
@NonNull @NonNull
private OrganicMaps mOrganicMaps; private OrganicMaps mOrganicMaps;
@@ -98,6 +104,12 @@ public class MwmApplication extends Application implements Application.ActivityL
return mOrganicMaps; return mOrganicMaps;
} }
@NonNull
public LocationProviderFactoryImpl getLocationProviderFactory()
{
return mLocationProviderFactory;
}
@NonNull @NonNull
public static MwmApplication from(@NonNull Context context) public static MwmApplication from(@NonNull Context context)
{ {
@@ -118,7 +130,10 @@ public class MwmApplication extends Application implements Application.ActivityL
sInstance = this; sInstance = this;
mOrganicMaps = new OrganicMaps(getApplicationContext()); PreferenceManager.setDefaultValues(this, R.xml.prefs_main, false);
mOrganicMaps = new OrganicMaps(getApplicationContext(), BuildConfig.FLAVOR, BuildConfig.APPLICATION_ID,
BuildConfig.VERSION_CODE, BuildConfig.VERSION_NAME,
BuildConfig.FILE_PROVIDER_AUTHORITY, mLocationProviderFactory);
ConnectionState.INSTANCE.initialize(this); ConnectionState.INSTANCE.initialize(this);
@@ -133,6 +148,8 @@ public class MwmApplication extends Application implements Application.ActivityL
public boolean initOrganicMaps(@NonNull Runnable onComplete) throws IOException public boolean initOrganicMaps(@NonNull Runnable onComplete) throws IOException
{ {
return mOrganicMaps.init(() -> { return mOrganicMaps.init(() -> {
ThemeSwitcher.INSTANCE.initialize(this);
ThemeSwitcher.INSTANCE.restart(false);
ProcessLifecycleOwner.get().getLifecycle().addObserver(mProcessLifecycleObserver); ProcessLifecycleOwner.get().getLifecycle().addObserver(mProcessLifecycleObserver);
onComplete.run(); onComplete.run();
}); });

View File

@@ -9,7 +9,8 @@ import androidx.annotation.IntegerRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.sdk.util.Utils;
import app.organicmaps.util.UiUtils;
import org.chromium.base.ObserverList; import org.chromium.base.ObserverList;
class PanelAnimator class PanelAnimator
@@ -26,7 +27,7 @@ class PanelAnimator
PanelAnimator(MwmActivity activity) PanelAnimator(MwmActivity activity)
{ {
mActivity = activity; mActivity = activity;
mWidth = UiUtils.dimen(activity.getApplicationContext(), R.dimen.panel_width); mWidth = Utils.dimen(activity.getApplicationContext(), R.dimen.panel_width);
mPanel = mActivity.findViewById(R.id.fragment_container); mPanel = mActivity.findViewById(R.id.fragment_container);
mDuration = mActivity.getResources().getInteger(R.integer.anim_panel); mDuration = mActivity.getResources().getInteger(R.integer.anim_panel);
} }

View File

@@ -60,11 +60,10 @@ public class SplashActivity extends AppCompatActivity
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
final Context context = getApplicationContext(); final String theme = Config.UiTheme.getCurrent();
final String theme = Config.getCurrentUiTheme(context); if (Config.UiTheme.isDefault(theme))
if (ThemeUtils.isDefaultTheme(context, theme))
setTheme(R.style.MwmTheme_Splash); setTheme(R.style.MwmTheme_Splash);
else if (ThemeUtils.isNightTheme(context, theme)) else if (Config.UiTheme.isNight(theme))
setTheme(R.style.MwmTheme_Night_Splash); setTheme(R.style.MwmTheme_Night_Splash);
else else
throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme); throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme);

View File

@@ -9,7 +9,7 @@ import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import app.organicmaps.base.OnBackPressListener; import app.organicmaps.base.OnBackPressListener;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
public abstract class WebContainerDelegate implements OnBackPressListener public abstract class WebContainerDelegate implements OnBackPressListener
{ {

View File

@@ -1,6 +1,7 @@
package app.organicmaps.backup; package app.organicmaps.backup;
import static app.organicmaps.sdk.util.StorageUtils.isFolderWritable; import static app.organicmaps.sdk.util.StorageUtils.isFolderWritable;
import static app.organicmaps.sdk.util.Utils.dimen;
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_DEFAULT_COUNT; import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_DEFAULT_COUNT;
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_KEY; import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_KEY;
@@ -15,8 +16,8 @@ import android.text.style.AbsoluteSizeSpan;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.documentfile.provider.DocumentFile; import androidx.documentfile.provider.DocumentFile;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.util.UiUtils;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
@@ -50,14 +51,14 @@ public class BackupUtils
String volumeName; String volumeName;
if ("primary".equalsIgnoreCase(volumeId)) if ("primary".equalsIgnoreCase(volumeId))
volumeName = context.getString(R.string.maps_storage_shared); volumeName = context.getString(app.organicmaps.sdk.R.string.maps_storage_shared);
else else
volumeName = context.getString(R.string.maps_storage_removable); volumeName = context.getString(app.organicmaps.sdk.R.string.maps_storage_removable);
SpannableStringBuilder sb = new SpannableStringBuilder(); SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append(volumeName + ": \n", new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_3)), sb.append(volumeName + ": \n", new AbsoluteSizeSpan(dimen(context, R.dimen.text_size_body_3)),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sb.append("/" + subPath, new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_4)), sb.append("/" + subPath, new AbsoluteSizeSpan(dimen(context, R.dimen.text_size_body_4)),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb; return sb;
} }

View File

@@ -62,39 +62,39 @@ public class LocalBackupManager implements BookmarkManager.BookmarksSharingListe
ErrorCode errorCode = null; ErrorCode errorCode = null;
switch (result.getCode()) switch (result.getCode())
{ {
case BookmarkSharingResult.SUCCESS -> case BookmarkSharingResult.SUCCESS ->
{ {
if (!saveBackup(result)) if (!saveBackup(result))
{
Logger.e(TAG, "Failed to save backup. See system log above");
errorCode = ErrorCode.FILE_ERROR;
}
else
{
Logger.i(TAG, "Backup was created and saved successfully");
}
}
case BookmarkSharingResult.EMPTY_CATEGORY ->
{
errorCode = ErrorCode.EMPTY_CATEGORY;
Logger.e(TAG, "Failed to create backup. Category is empty");
}
case BookmarkSharingResult.ARCHIVE_ERROR ->
{
errorCode = ErrorCode.ARCHIVE_ERROR;
Logger.e(TAG, "Failed to create archive of bookmarks");
}
case BookmarkSharingResult.FILE_ERROR ->
{ {
Logger.e(TAG, "Failed to save backup. See system log above");
errorCode = ErrorCode.FILE_ERROR; errorCode = ErrorCode.FILE_ERROR;
Logger.e(TAG, "Failed create file for archive");
} }
default -> else
{ {
errorCode = ErrorCode.UNSUPPORTED; Logger.i(TAG, "Backup was created and saved successfully");
Logger.e(TAG, "Failed to create backup. Unknown error");
} }
} }
case BookmarkSharingResult.EMPTY_CATEGORY ->
{
errorCode = ErrorCode.EMPTY_CATEGORY;
Logger.e(TAG, "Failed to create backup. Category is empty");
}
case BookmarkSharingResult.ARCHIVE_ERROR ->
{
errorCode = ErrorCode.ARCHIVE_ERROR;
Logger.e(TAG, "Failed to create archive of bookmarks");
}
case BookmarkSharingResult.FILE_ERROR ->
{
errorCode = ErrorCode.FILE_ERROR;
Logger.e(TAG, "Failed create file for archive");
}
default ->
{
errorCode = ErrorCode.UNSUPPORTED;
Logger.e(TAG, "Failed to create backup. Unknown error");
}
}
ErrorCode finalErrorCode = errorCode; ErrorCode finalErrorCode = errorCode;
UiThread.run(() -> { UiThread.run(() -> {

View File

@@ -15,7 +15,7 @@ public class BaseMwmDialogFragment extends DialogFragment
@StyleRes @StyleRes
protected final int getFullscreenTheme() protected final int getFullscreenTheme()
{ {
return ThemeUtils.isNightTheme(requireContext()) ? getFullscreenDarkTheme() : getFullscreenLightTheme(); return ThemeUtils.isNightTheme() ? getFullscreenDarkTheme() : getFullscreenLightTheme();
} }
protected int getStyle() protected int getStyle()

View File

@@ -1,7 +1,6 @@
package app.organicmaps.base; package app.organicmaps.base;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.media.AudioManager; import android.media.AudioManager;
@@ -24,7 +23,6 @@ import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.concurrency.UiThread; 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 app.organicmaps.util.ThemeUtils;
import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.appbar.MaterialToolbar;
import java.util.Objects; import java.util.Objects;
@@ -40,12 +38,10 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
@StyleRes @StyleRes
protected int getThemeResourceId(@NonNull String theme) protected int getThemeResourceId(@NonNull String theme)
{ {
Context context = getApplicationContext(); if (Config.UiTheme.isDefault(theme))
if (ThemeUtils.isDefaultTheme(context, theme))
return R.style.MwmTheme; return R.style.MwmTheme;
if (ThemeUtils.isNightTheme(context, theme)) if (Config.UiTheme.isNight(theme))
return R.style.MwmTheme_Night; return R.style.MwmTheme_Night;
throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme); throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme);
@@ -62,7 +58,7 @@ 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.getCurrentUiTheme(getApplicationContext()); mThemeName = Config.UiTheme.getCurrent();
setTheme(getThemeResourceId(mThemeName)); setTheme(getThemeResourceId(mThemeName));
EdgeToEdge.enable(this, SystemBarStyle.dark(Color.TRANSPARENT)); EdgeToEdge.enable(this, SystemBarStyle.dark(Color.TRANSPARENT));
RtlUtils.manageRtl(this); RtlUtils.manageRtl(this);
@@ -122,7 +118,7 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
public void onPostResume() public void onPostResume()
{ {
super.onPostResume(); super.onPostResume();
if (!mThemeName.equals(Config.getCurrentUiTheme(getApplicationContext()))) if (!mThemeName.equals(Config.UiTheme.getCurrent()))
{ {
// Workaround described in https://code.google.com/p/android/issues/detail?id=93731 // Workaround described in https://code.google.com/p/android/issues/detail?id=93731
UiThread.runLater(this::recreate); UiThread.runLater(this::recreate);

View File

@@ -14,7 +14,7 @@ import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import app.organicmaps.util.WindowInsetUtils.ScrollableContentInsetsListener; import app.organicmaps.util.WindowInsetUtils.ScrollableContentInsetsListener;
import app.organicmaps.widget.PlaceholderView; import app.organicmaps.widget.PlaceholderView;

View File

@@ -10,7 +10,7 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentFactory; import androidx.fragment.app.FragmentFactory;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener; import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener;
import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.appbar.MaterialToolbar;

View File

@@ -42,7 +42,7 @@ public class BookmarkCategoriesActivity extends BaseToolbarActivity
@StyleRes @StyleRes
public int getThemeResourceId(@NonNull String theme) public int getThemeResourceId(@NonNull String theme)
{ {
return ThemeUtils.getWindowBgThemeResourceId(getApplicationContext(), theme); return ThemeUtils.getWindowBgThemeResourceId(theme);
} }
@Override @Override

View File

@@ -66,47 +66,47 @@ public class BookmarkCategoriesAdapter extends BaseBookmarkCategoryAdapter<Recyc
LayoutInflater inflater = LayoutInflater.from(parent.getContext()); LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) switch (viewType)
{ {
case TYPE_ACTION_HEADER -> case TYPE_ACTION_HEADER ->
{ {
View header = inflater.inflate(R.layout.item_bookmark_group_list_header, parent, false); View header = inflater.inflate(R.layout.item_bookmark_group_list_header, parent, false);
return new HeaderViewHolder(header); return new HeaderViewHolder(header);
} }
case TYPE_CATEGORY_ITEM -> case TYPE_CATEGORY_ITEM ->
{ {
View view = inflater.inflate(R.layout.item_bookmark_category, parent, false); View view = inflater.inflate(R.layout.item_bookmark_category, parent, false);
final CategoryViewHolder holder = new CategoryViewHolder(view); final CategoryViewHolder holder = new CategoryViewHolder(view);
view.setOnClickListener(new CategoryItemClickListener(holder)); view.setOnClickListener(new CategoryItemClickListener(holder));
view.setOnLongClickListener(new LongClickListener(holder)); view.setOnLongClickListener(new LongClickListener(holder));
return holder; return holder;
} }
case TYPE_ACTION_ADD -> case TYPE_ACTION_ADD ->
{ {
View item = inflater.inflate(R.layout.item_bookmark_button, parent, false); View item = inflater.inflate(R.layout.item_bookmark_button, parent, false);
item.setOnClickListener(v -> { item.setOnClickListener(v -> {
if (mCategoryListCallback != null) if (mCategoryListCallback != null)
mCategoryListCallback.onAddButtonClick(); mCategoryListCallback.onAddButtonClick();
}); });
return new Holders.GeneralViewHolder(item); return new Holders.GeneralViewHolder(item);
} }
case TYPE_ACTION_IMPORT -> case TYPE_ACTION_IMPORT ->
{ {
View item = inflater.inflate(R.layout.item_bookmark_button, parent, false); View item = inflater.inflate(R.layout.item_bookmark_button, parent, false);
item.setOnClickListener(v -> { item.setOnClickListener(v -> {
if (mCategoryListCallback != null) if (mCategoryListCallback != null)
mCategoryListCallback.onImportButtonClick(); mCategoryListCallback.onImportButtonClick();
}); });
return new Holders.GeneralViewHolder(item); return new Holders.GeneralViewHolder(item);
} }
case TYPE_ACTION_EXPORT_ALL_AS_KMZ -> case TYPE_ACTION_EXPORT_ALL_AS_KMZ ->
{ {
View item = inflater.inflate(R.layout.item_bookmark_button, parent, false); View item = inflater.inflate(R.layout.item_bookmark_button, parent, false);
item.setOnClickListener(v -> { item.setOnClickListener(v -> {
if (mCategoryListCallback != null) if (mCategoryListCallback != null)
mCategoryListCallback.onExportButtonClick(); mCategoryListCallback.onExportButtonClick();
}); });
return new Holders.GeneralViewHolder(item); return new Holders.GeneralViewHolder(item);
} }
default -> throw new AssertionError("Invalid item type: " + viewType); default -> throw new AssertionError("Invalid item type: " + viewType);
} }
} }
@@ -116,44 +116,44 @@ public class BookmarkCategoriesAdapter extends BaseBookmarkCategoryAdapter<Recyc
int type = getItemViewType(position); int type = getItemViewType(position);
switch (type) switch (type)
{ {
case TYPE_ACTION_HEADER -> case TYPE_ACTION_HEADER ->
{ {
HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder; HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
headerViewHolder.setAction(mMassOperationAction, BookmarkManager.INSTANCE.areAllCategoriesInvisible()); headerViewHolder.setAction(mMassOperationAction, BookmarkManager.INSTANCE.areAllCategoriesInvisible());
headerViewHolder.getText().setText(R.string.bookmark_lists); headerViewHolder.getText().setText(R.string.bookmark_lists);
} }
case TYPE_CATEGORY_ITEM -> case TYPE_CATEGORY_ITEM ->
{ {
final BookmarkCategory category = getCategoryByPosition(toCategoryPosition(position)); final BookmarkCategory category = getCategoryByPosition(toCategoryPosition(position));
CategoryViewHolder categoryHolder = (CategoryViewHolder) holder; CategoryViewHolder categoryHolder = (CategoryViewHolder) holder;
categoryHolder.setEntity(category); categoryHolder.setEntity(category);
categoryHolder.setName(category.getName()); categoryHolder.setName(category.getName());
categoryHolder.setSize(); categoryHolder.setSize();
categoryHolder.setVisibilityState(category.isVisible()); categoryHolder.setVisibilityState(category.isVisible());
ToggleVisibilityClickListener visibilityListener = new ToggleVisibilityClickListener(categoryHolder); ToggleVisibilityClickListener visibilityListener = new ToggleVisibilityClickListener(categoryHolder);
categoryHolder.setVisibilityListener(visibilityListener); categoryHolder.setVisibilityListener(visibilityListener);
CategoryItemMoreClickListener moreClickListener = new CategoryItemMoreClickListener(categoryHolder); CategoryItemMoreClickListener moreClickListener = new CategoryItemMoreClickListener(categoryHolder);
categoryHolder.setMoreButtonClickListener(moreClickListener); categoryHolder.setMoreButtonClickListener(moreClickListener);
} }
case TYPE_ACTION_ADD -> case TYPE_ACTION_ADD ->
{ {
Holders.GeneralViewHolder generalViewHolder = (Holders.GeneralViewHolder) holder; Holders.GeneralViewHolder generalViewHolder = (Holders.GeneralViewHolder) holder;
generalViewHolder.getImage().setImageResource(R.drawable.ic_add_list); generalViewHolder.getImage().setImageResource(R.drawable.ic_add_list);
generalViewHolder.getText().setText(R.string.bookmarks_create_new_group); generalViewHolder.getText().setText(R.string.bookmarks_create_new_group);
} }
case TYPE_ACTION_IMPORT -> case TYPE_ACTION_IMPORT ->
{ {
Holders.GeneralViewHolder generalViewHolder = (Holders.GeneralViewHolder) holder; Holders.GeneralViewHolder generalViewHolder = (Holders.GeneralViewHolder) holder;
generalViewHolder.getImage().setImageResource(R.drawable.ic_import); generalViewHolder.getImage().setImageResource(R.drawable.ic_import);
generalViewHolder.getText().setText(R.string.bookmarks_import); generalViewHolder.getText().setText(R.string.bookmarks_import);
} }
case TYPE_ACTION_EXPORT_ALL_AS_KMZ -> case TYPE_ACTION_EXPORT_ALL_AS_KMZ ->
{ {
Holders.GeneralViewHolder generalViewHolder = (Holders.GeneralViewHolder) holder; Holders.GeneralViewHolder generalViewHolder = (Holders.GeneralViewHolder) holder;
generalViewHolder.getImage().setImageResource(R.drawable.ic_export); generalViewHolder.getImage().setImageResource(R.drawable.ic_export);
generalViewHolder.getText().setText(R.string.bookmarks_export); generalViewHolder.getText().setText(R.string.bookmarks_export);
} }
default -> throw new AssertionError("Invalid item type: " + type); default -> throw new AssertionError("Invalid item type: " + type);
} }
} }

View File

@@ -11,7 +11,7 @@ import app.organicmaps.R;
import app.organicmaps.adapter.OnItemClickListener; import app.organicmaps.adapter.OnItemClickListener;
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.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.List; import java.util.List;

View File

@@ -41,7 +41,7 @@ public class BookmarkListActivity extends BaseToolbarActivity
@StyleRes @StyleRes
public int getThemeResourceId(@NonNull String theme) public int getThemeResourceId(@NonNull String theme)
{ {
return ThemeUtils.getCardBgThemeResourceId(getApplicationContext(), theme); return ThemeUtils.getCardBgThemeResourceId(theme);
} }
@Override @Override

View File

@@ -442,37 +442,37 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
Holders.BaseBookmarkHolder holder = null; Holders.BaseBookmarkHolder holder = null;
switch (viewType) switch (viewType)
{ {
case TYPE_TRACK: case TYPE_TRACK:
Holders.TrackViewHolder trackHolder = Holders.TrackViewHolder trackHolder =
new Holders.TrackViewHolder(inflater.inflate(R.layout.item_track, parent, false)); new Holders.TrackViewHolder(inflater.inflate(R.layout.item_track, parent, false));
trackHolder.setOnClickListener(mClickListener); trackHolder.setOnClickListener(mClickListener);
trackHolder.setOnLongClickListener(mLongClickListener); trackHolder.setOnLongClickListener(mLongClickListener);
trackHolder.setTrackIconClickListener(mIconClickListener); trackHolder.setTrackIconClickListener(mIconClickListener);
trackHolder.setMoreButtonClickListener(mMoreClickListener); trackHolder.setMoreButtonClickListener(mMoreClickListener);
holder = trackHolder; holder = trackHolder;
break; break;
case TYPE_BOOKMARK: case TYPE_BOOKMARK:
Holders.BookmarkViewHolder bookmarkHolder = Holders.BookmarkViewHolder bookmarkHolder =
new Holders.BookmarkViewHolder(inflater.inflate(R.layout.item_bookmark, parent, false)); new Holders.BookmarkViewHolder(inflater.inflate(R.layout.item_bookmark, parent, false));
bookmarkHolder.setOnClickListener(mClickListener); bookmarkHolder.setOnClickListener(mClickListener);
bookmarkHolder.setOnLongClickListener(mLongClickListener); bookmarkHolder.setOnLongClickListener(mLongClickListener);
holder = bookmarkHolder; holder = bookmarkHolder;
break; break;
case TYPE_SECTION: case TYPE_SECTION:
MaterialTextView tv = (MaterialTextView) inflater.inflate(R.layout.item_category_title, parent, false); MaterialTextView tv = (MaterialTextView) inflater.inflate(R.layout.item_category_title, parent, false);
holder = new Holders.SectionViewHolder(tv); holder = new Holders.SectionViewHolder(tv);
break; break;
case TYPE_DESC: case TYPE_DESC:
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); 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)); title.setOnClickListener(v -> onMoreButtonClicked(text, moreBtn));
break; break;
} }
if (holder == null) if (holder == null)

View File

@@ -33,15 +33,15 @@ import app.organicmaps.sdk.bookmarks.data.BookmarkInfo;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager; import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.BookmarkSharingResult; import app.organicmaps.sdk.bookmarks.data.BookmarkSharingResult;
import app.organicmaps.sdk.bookmarks.data.CategoryDataSource; import app.organicmaps.sdk.bookmarks.data.CategoryDataSource;
import app.organicmaps.sdk.bookmarks.data.Icon;
import app.organicmaps.sdk.bookmarks.data.KmlFileType; import app.organicmaps.sdk.bookmarks.data.KmlFileType;
import app.organicmaps.sdk.bookmarks.data.PredefinedColors;
import app.organicmaps.sdk.bookmarks.data.SortedBlock; import app.organicmaps.sdk.bookmarks.data.SortedBlock;
import app.organicmaps.sdk.bookmarks.data.Track; import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.search.BookmarkSearchListener; import app.organicmaps.sdk.search.BookmarkSearchListener;
import app.organicmaps.sdk.search.SearchEngine; import app.organicmaps.sdk.search.SearchEngine;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.Graphics; import app.organicmaps.util.Graphics;
import app.organicmaps.util.SharingUtils; import app.organicmaps.util.SharingUtils;
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.util.bottomsheet.MenuBottomSheetFragment; import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
@@ -551,12 +551,12 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
switch (adapter.getItemViewType(position)) switch (adapter.getItemViewType(position))
{ {
case BookmarkListAdapter.TYPE_SECTION, BookmarkListAdapter.TYPE_DESC -> case BookmarkListAdapter.TYPE_SECTION, BookmarkListAdapter.TYPE_DESC ->
{ {
return; return;
} }
case BookmarkListAdapter.TYPE_BOOKMARK -> onBookmarkClicked(position, intent, adapter); case BookmarkListAdapter.TYPE_BOOKMARK -> onBookmarkClicked(position, intent, adapter);
case BookmarkListAdapter.TYPE_TRACK -> onTrackClicked(position, intent, adapter); case BookmarkListAdapter.TYPE_TRACK -> onTrackClicked(position, intent, adapter);
} }
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -592,7 +592,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
if (mTrack == null) if (mTrack == null)
return; return;
final Bundle args = new Bundle(); final Bundle args = new Bundle();
args.putInt(BookmarkColorDialogFragment.ICON_TYPE, Icon.getColorPosition(mTrack.getColor())); args.putInt(BookmarkColorDialogFragment.ICON_COLOR, PredefinedColors.getPredefinedColorIndex(mTrack.getColor()));
final FragmentManager manager = getChildFragmentManager(); final FragmentManager manager = getChildFragmentManager();
String className = BookmarkColorDialogFragment.class.getName(); String className = BookmarkColorDialogFragment.class.getName();
final FragmentFactory factory = manager.getFragmentFactory(); final FragmentFactory factory = manager.getFragmentFactory();
@@ -601,7 +601,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
dialogFragment.setArguments(args); dialogFragment.setArguments(args);
dialogFragment.setOnColorSetListener((colorPos) -> { dialogFragment.setOnColorSetListener((colorPos) -> {
int from = mTrack.getColor(); int from = mTrack.getColor();
int to = BookmarkManager.ICONS.get(colorPos).argb(); int to = PredefinedColors.getColor(colorPos);
if (from == to) if (from == to)
return; return;
BookmarkManager.INSTANCE.changeTrackColor(mTrack.getTrackId(), to); BookmarkManager.INSTANCE.changeTrackColor(mTrack.getTrackId(), to);
@@ -621,22 +621,22 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
switch (type) switch (type)
{ {
case BookmarkListAdapter.TYPE_SECTION: case BookmarkListAdapter.TYPE_SECTION:
case BookmarkListAdapter.TYPE_DESC: case BookmarkListAdapter.TYPE_DESC:
// Do nothing here? // Do nothing here?
break; break;
case BookmarkListAdapter.TYPE_BOOKMARK: case BookmarkListAdapter.TYPE_BOOKMARK:
final BookmarkInfo bookmark = (BookmarkInfo) adapter.getItem(mSelectedPosition); final BookmarkInfo bookmark = (BookmarkInfo) adapter.getItem(mSelectedPosition);
MenuBottomSheetFragment.newInstance(BOOKMARKS_MENU_ID, bookmark.getName()) MenuBottomSheetFragment.newInstance(BOOKMARKS_MENU_ID, bookmark.getName())
.show(getChildFragmentManager(), BOOKMARKS_MENU_ID); .show(getChildFragmentManager(), BOOKMARKS_MENU_ID);
break; break;
case BookmarkListAdapter.TYPE_TRACK: case BookmarkListAdapter.TYPE_TRACK:
final Track track = (Track) adapter.getItem(mSelectedPosition); final Track track = (Track) adapter.getItem(mSelectedPosition);
MenuBottomSheetFragment.newInstance(TRACK_MENU_ID, track.getName()) MenuBottomSheetFragment.newInstance(TRACK_MENU_ID, track.getName())
.show(getChildFragmentManager(), TRACK_MENU_ID); .show(getChildFragmentManager(), TRACK_MENU_ID);
break; break;
} }
} }
@@ -843,19 +843,19 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
{ {
switch (id) switch (id)
{ {
case BOOKMARKS_MENU_ID -> case BOOKMARKS_MENU_ID ->
{ {
return getBookmarkMenuItems(); return getBookmarkMenuItems();
} }
case TRACK_MENU_ID -> case TRACK_MENU_ID ->
{ {
final Track track = (Track) getBookmarkListAdapter().getItem(mSelectedPosition); final Track track = (Track) getBookmarkListAdapter().getItem(mSelectedPosition);
return getTrackMenuItems(track); return getTrackMenuItems(track);
} }
case OPTIONS_MENU_ID -> case OPTIONS_MENU_ID ->
{ {
return getOptionsMenuItems(); return getOptionsMenuItems();
} }
} }
return null; return null;
} }

View File

@@ -57,27 +57,27 @@ public enum BookmarksSharingHelper
switch (result.getCode()) switch (result.getCode())
{ {
case BookmarkSharingResult.SUCCESS -> case BookmarkSharingResult.SUCCESS ->
SharingUtils.shareBookmarkFile(context, launcher, result.getSharingPath(), result.getMimeType()); SharingUtils.shareBookmarkFile(context, launcher, result.getSharingPath(), result.getMimeType());
case BookmarkSharingResult.EMPTY_CATEGORY -> case BookmarkSharingResult.EMPTY_CATEGORY ->
new MaterialAlertDialogBuilder(context, R.style.MwmTheme_AlertDialog) new MaterialAlertDialogBuilder(context, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.bookmarks_error_title_share_empty) .setTitle(R.string.bookmarks_error_title_share_empty)
.setMessage(R.string.bookmarks_error_message_share_empty) .setMessage(R.string.bookmarks_error_message_share_empty)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show(); .show();
case BookmarkSharingResult.ARCHIVE_ERROR, BookmarkSharingResult.FILE_ERROR -> case BookmarkSharingResult.ARCHIVE_ERROR, BookmarkSharingResult.FILE_ERROR ->
{ {
new MaterialAlertDialogBuilder(context, R.style.MwmTheme_AlertDialog) new MaterialAlertDialogBuilder(context, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.dialog_routing_system_error) .setTitle(R.string.dialog_routing_system_error)
.setMessage(R.string.bookmarks_error_message_share_general) .setMessage(R.string.bookmarks_error_message_share_general)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show(); .show();
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
for (long categoryId : result.getCategoriesIds()) for (long categoryId : result.getCategoriesIds())
names.add(BookmarkManager.INSTANCE.getCategoryById(categoryId).getName()); names.add(BookmarkManager.INSTANCE.getCategoryById(categoryId).getName());
Logger.e(TAG, "Failed to share bookmark categories " + names + ", error code: " + result.getCode()); Logger.e(TAG, "Failed to share bookmark categories " + names + ", error code: " + result.getCode());
} }
default -> throw new AssertionError("Unsupported bookmark sharing code: " + result.getCode()); default -> throw new AssertionError("Unsupported bookmark sharing code: " + result.getCode());
} }
} }

View File

@@ -13,7 +13,7 @@ import androidx.fragment.app.FragmentManager;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.base.BaseMwmDialogFragment; import app.organicmaps.base.BaseMwmDialogFragment;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager; import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
public class ChooseBookmarksSortingTypeFragment public class ChooseBookmarksSortingTypeFragment
extends BaseMwmDialogFragment implements RadioGroup.OnCheckedChangeListener extends BaseMwmDialogFragment implements RadioGroup.OnCheckedChangeListener
@@ -64,10 +64,10 @@ public class ChooseBookmarksSortingTypeFragment
{ {
switch (sortingType) switch (sortingType)
{ {
case BookmarkManager.SORT_BY_TYPE: return R.id.sort_by_type; case BookmarkManager.SORT_BY_TYPE: return R.id.sort_by_type;
case BookmarkManager.SORT_BY_DISTANCE: return R.id.sort_by_distance; case BookmarkManager.SORT_BY_DISTANCE: return R.id.sort_by_distance;
case BookmarkManager.SORT_BY_TIME: return R.id.sort_by_time; case BookmarkManager.SORT_BY_TIME: return R.id.sort_by_time;
case BookmarkManager.SORT_BY_NAME: return R.id.sort_by_name; case BookmarkManager.SORT_BY_NAME: return R.id.sort_by_name;
} }
} }
return R.id.sort_by_default; return R.id.sort_by_default;

View File

@@ -6,19 +6,26 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import androidx.annotation.DrawableRes;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.sdk.bookmarks.data.Icon; import app.organicmaps.sdk.bookmarks.data.PredefinedColors;
import app.organicmaps.util.Graphics; import app.organicmaps.util.Graphics;
import com.google.android.material.imageview.ShapeableImageView; import com.google.android.material.imageview.ShapeableImageView;
import java.util.List; import java.util.List;
import java.util.Objects;
public class IconsAdapter extends ArrayAdapter<Icon> public class ColorsAdapter extends ArrayAdapter<Integer>
{ {
@PredefinedColors.Color
private int mCheckedIconColor; private int mCheckedIconColor;
public IconsAdapter(Context context, List<Icon> list) @DrawableRes
private final int mIconResId;
public ColorsAdapter(Context context, List<Integer> list, @DrawableRes int iconResId)
{ {
super(context, 0, 0, list); super(context, 0, 0, list);
mIconResId = iconResId;
} }
@Override @Override
@@ -35,19 +42,19 @@ public class IconsAdapter extends ArrayAdapter<Icon>
else else
holder = (SpinnerViewHolder) convertView.getTag(); holder = (SpinnerViewHolder) convertView.getTag();
final Icon icon = getItem(position); @PredefinedColors.Color
final int color = Objects.requireNonNull(getItem(position));
Drawable circle; Drawable circle;
if (icon.getColor() == mCheckedIconColor) if (color == mCheckedIconColor)
{ {
circle = Graphics.drawCircleAndImage(getItem(position).argb(), R.dimen.track_circle_size, circle = Graphics.drawCircleAndImage(PredefinedColors.getColor(mCheckedIconColor), R.dimen.track_circle_size,
app.organicmaps.sdk.R.drawable.ic_bookmark_none, R.dimen.bookmark_icon_size, mIconResId, R.dimen.bookmark_icon_size, getContext());
getContext());
} }
else else
{ {
circle = circle = Graphics.drawCircle(PredefinedColors.getColor(color), R.dimen.select_color_circle_size,
Graphics.drawCircle(getItem(position).argb(), R.dimen.select_color_circle_size, getContext().getResources()); getContext().getResources());
} }
holder.icon.setImageDrawable(circle); holder.icon.setImageDrawable(circle);
return convertView; return convertView;

View File

@@ -18,8 +18,8 @@ import app.organicmaps.sdk.bookmarks.data.BookmarkInfo;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager; import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.IconClickListener; import app.organicmaps.sdk.bookmarks.data.IconClickListener;
import app.organicmaps.sdk.bookmarks.data.Track; import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.Graphics; import app.organicmaps.util.Graphics;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import app.organicmaps.widget.recycler.RecyclerClickListener; import app.organicmaps.widget.recycler.RecyclerClickListener;
import app.organicmaps.widget.recycler.RecyclerLongClickListener; import app.organicmaps.widget.recycler.RecyclerLongClickListener;

View File

@@ -26,7 +26,6 @@ import app.organicmaps.car.util.CurrentCountryChangedListener;
import app.organicmaps.car.util.IntentUtils; import app.organicmaps.car.util.IntentUtils;
import app.organicmaps.car.util.ThemeUtils; import app.organicmaps.car.util.ThemeUtils;
import app.organicmaps.car.util.UserActionRequired; import app.organicmaps.car.util.UserActionRequired;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.PlacePageActivationListener; import app.organicmaps.sdk.PlacePageActivationListener;
import app.organicmaps.sdk.bookmarks.data.MapObject; import app.organicmaps.sdk.bookmarks.data.MapObject;
@@ -34,6 +33,7 @@ import app.organicmaps.sdk.display.DisplayChangedListener;
import app.organicmaps.sdk.display.DisplayManager; import app.organicmaps.sdk.display.DisplayManager;
import app.organicmaps.sdk.display.DisplayType; import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.location.LocationState; import app.organicmaps.sdk.location.LocationState;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config; import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.LocationUtils; import app.organicmaps.sdk.util.LocationUtils;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;

View File

@@ -27,7 +27,10 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
{ {
private static final String TAG = SurfaceRenderer.class.getSimpleName(); private static final String TAG = SurfaceRenderer.class.getSimpleName();
@NonNull
private final CarContext mCarContext; private final CarContext mCarContext;
@NonNull
private final Map mMap = new Map(Car); private final Map mMap = new Map(Car);
@NonNull @NonNull
@@ -56,6 +59,7 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
mSurface.release(); mSurface.release();
mSurface = surfaceContainer.getSurface(); mSurface = surfaceContainer.getSurface();
mMap.setLocationHelper(MwmApplication.from(mCarContext).getLocationHelper());
mMap.onSurfaceCreated(mCarContext, mSurface, mMap.onSurfaceCreated(mCarContext, mSurface,
new Rect(0, 0, surfaceContainer.getWidth(), surfaceContainer.getHeight()), new Rect(0, 0, surfaceContainer.getWidth(), surfaceContainer.getHeight()),
surfaceContainer.getDpi()); surfaceContainer.getDpi());

View File

@@ -28,11 +28,11 @@ import app.organicmaps.car.util.RoutingUtils;
import app.organicmaps.car.util.ThemeUtils; import app.organicmaps.car.util.ThemeUtils;
import app.organicmaps.car.util.UiHelpers; import app.organicmaps.car.util.UiHelpers;
import app.organicmaps.routing.NavigationService; import app.organicmaps.routing.NavigationService;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.location.LocationHelper; import app.organicmaps.sdk.location.LocationHelper;
import app.organicmaps.sdk.location.LocationListener; import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.routing.JunctionInfo; import app.organicmaps.sdk.routing.JunctionInfo;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo; import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.sound.TtsPlayer; import app.organicmaps.sdk.sound.TtsPlayer;
import app.organicmaps.sdk.util.LocationUtils; import app.organicmaps.sdk.util.LocationUtils;
@@ -73,8 +73,7 @@ public class NavigationScreen extends BaseMapScreen implements RoutingController
public Template onGetTemplate() public Template onGetTemplate()
{ {
final NavigationTemplate.Builder builder = new NavigationTemplate.Builder(); final NavigationTemplate.Builder builder = new NavigationTemplate.Builder();
builder.setBackgroundColor(ThemeUtils.isNightMode(getCarContext()) ? Colors.NAVIGATION_TEMPLATE_BACKGROUND_NIGHT builder.setBackgroundColor(Colors.NAVIGATION_TEMPLATE_BACKGROUND);
: Colors.NAVIGATION_TEMPLATE_BACKGROUND_DAY);
builder.setActionStrip(createActionStrip()); builder.setActionStrip(createActionStrip());
builder.setMapActionStrip(UiHelpers.createMapActionStrip(getCarContext(), getSurfaceRenderer())); builder.setMapActionStrip(UiHelpers.createMapActionStrip(getCarContext(), getSurfaceRenderer()));

View File

@@ -35,11 +35,11 @@ import app.organicmaps.car.util.OnBackPressedCallback;
import app.organicmaps.car.util.RoutingHelpers; import app.organicmaps.car.util.RoutingHelpers;
import app.organicmaps.car.util.UiHelpers; import app.organicmaps.car.util.UiHelpers;
import app.organicmaps.routing.ResultCodesHelper; import app.organicmaps.routing.ResultCodesHelper;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Router; import app.organicmaps.sdk.Router;
import app.organicmaps.sdk.bookmarks.data.MapObject; import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.Metadata; import app.organicmaps.sdk.bookmarks.data.Metadata;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo; import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.util.Config; import app.organicmaps.sdk.util.Config;
import java.util.Objects; import java.util.Objects;

View File

@@ -12,6 +12,7 @@ import androidx.lifecycle.LifecycleOwner;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.car.screens.ErrorScreen; import app.organicmaps.car.screens.ErrorScreen;
import app.organicmaps.car.screens.base.BaseScreen; import app.organicmaps.car.screens.base.BaseScreen;
import app.organicmaps.downloader.MapManagerHelper;
import app.organicmaps.sdk.downloader.CountryItem; import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.util.StringUtils; import app.organicmaps.sdk.util.StringUtils;
@@ -169,7 +170,7 @@ class DownloaderScreen extends BaseScreen
mIsDownloadFailed = true; mIsDownloadFailed = true;
final ErrorScreen.Builder builder = new ErrorScreen.Builder(getCarContext()) final ErrorScreen.Builder builder = new ErrorScreen.Builder(getCarContext())
.setTitle(R.string.country_status_download_failed) .setTitle(R.string.country_status_download_failed)
.setErrorMessage(MapManager.getErrorCodeStrRes(data.errorCode)) .setErrorMessage(MapManagerHelper.getErrorCodeStrRes(data.errorCode))
.setPositiveButton(R.string.downloader_retry, null); .setPositiveButton(R.string.downloader_retry, null);
if (!mIsCancelActionDisabled) if (!mIsCancelActionDisabled)
builder.setNegativeButton(R.string.cancel, this::finish); builder.setNegativeButton(R.string.cancel, this::finish);

View File

@@ -62,29 +62,29 @@ public final class SearchUiHelpers
CarColor color = Colors.DEFAULT; CarColor color = Colors.DEFAULT;
switch (searchResult.description.openNow) switch (searchResult.description.openNow)
{ {
case SearchResult.OPEN_NOW_YES: case SearchResult.OPEN_NOW_YES:
if (searchResult.description.minutesUntilClosed < 60) // less than 1 hour if (searchResult.description.minutesUntilClosed < 60) // less than 1 hour
{ {
final String time = searchResult.description.minutesUntilClosed + " " + carContext.getString(R.string.minute); final String time = searchResult.description.minutesUntilClosed + " " + carContext.getString(R.string.minute);
text = carContext.getString(R.string.closes_in, time); text = carContext.getString(R.string.closes_in, time);
color = Colors.OPENING_HOURS_CLOSES_SOON; color = Colors.OPENING_HOURS_CLOSES_SOON;
} }
else else
{ {
text = carContext.getString(R.string.editor_time_open); text = carContext.getString(R.string.editor_time_open);
color = Colors.OPENING_HOURS_OPEN; color = Colors.OPENING_HOURS_OPEN;
} }
break; break;
case SearchResult.OPEN_NOW_NO: case SearchResult.OPEN_NOW_NO:
if (searchResult.description.minutesUntilOpen < 60) // less than 1 hour if (searchResult.description.minutesUntilOpen < 60) // less than 1 hour
{ {
final String time = searchResult.description.minutesUntilOpen + " " + carContext.getString(R.string.minute); final String time = searchResult.description.minutesUntilOpen + " " + carContext.getString(R.string.minute);
text = carContext.getString(R.string.opens_in, time); text = carContext.getString(R.string.opens_in, time);
} }
else else
text = carContext.getString(R.string.closed); text = carContext.getString(R.string.closed);
color = Colors.OPENING_HOURS_CLOSED; color = Colors.OPENING_HOURS_CLOSED;
break; break;
} }
result.append(text); result.append(text);

View File

@@ -11,8 +11,7 @@ public final class Colors
public static final CarColor OPENING_HOURS_CLOSES_SOON = CarColor.YELLOW; public static final CarColor OPENING_HOURS_CLOSES_SOON = CarColor.YELLOW;
public static final CarColor OPENING_HOURS_CLOSED = CarColor.RED; public static final CarColor OPENING_HOURS_CLOSED = CarColor.RED;
public static final CarColor START_NAVIGATION = CarColor.GREEN; public static final CarColor START_NAVIGATION = CarColor.GREEN;
public static final CarColor NAVIGATION_TEMPLATE_BACKGROUND_DAY = CarColor.GREEN; public static final CarColor NAVIGATION_TEMPLATE_BACKGROUND = CarColor.GREEN;
public static final CarColor NAVIGATION_TEMPLATE_BACKGROUND_NIGHT = CarColor.DEFAULT;
public static final CarColor BUTTON_ACCEPT = CarColor.GREEN; public static final CarColor BUTTON_ACCEPT = CarColor.GREEN;
private Colors() {} private Colors() {}

View File

@@ -7,9 +7,9 @@ import androidx.car.app.CarContext;
import androidx.car.app.ScreenManager; import androidx.car.app.ScreenManager;
import app.organicmaps.car.screens.download.DownloadMapsScreen; import app.organicmaps.car.screens.download.DownloadMapsScreen;
import app.organicmaps.car.screens.download.DownloadMapsScreenBuilder; import app.organicmaps.car.screens.download.DownloadMapsScreenBuilder;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.downloader.CountryItem; import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.routing.RoutingController;
public class CurrentCountryChangedListener implements MapManager.CurrentCountryChangedListener public class CurrentCountryChangedListener implements MapManager.CurrentCountryChangedListener
{ {

View File

@@ -15,13 +15,13 @@ import app.organicmaps.car.CarAppService;
import app.organicmaps.car.SurfaceRenderer; 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.routing.RoutingController;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Map; import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.api.ParsedSearchRequest; import app.organicmaps.sdk.api.ParsedSearchRequest;
import app.organicmaps.sdk.api.RequestType; import app.organicmaps.sdk.api.RequestType;
import app.organicmaps.sdk.display.DisplayManager; import app.organicmaps.sdk.display.DisplayManager;
import app.organicmaps.sdk.display.DisplayType; import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
public final class IntentUtils public final class IntentUtils
@@ -65,36 +65,36 @@ public final class IntentUtils
final ScreenManager screenManager = carContext.getCarService(ScreenManager.class); final ScreenManager screenManager = carContext.getCarService(ScreenManager.class);
switch (Framework.nativeParseAndSetApiUrl(uri.toString())) switch (Framework.nativeParseAndSetApiUrl(uri.toString()))
{ {
case RequestType.INCORRECT: return; case RequestType.INCORRECT: return;
case RequestType.MAP: case RequestType.MAP:
screenManager.popToRoot(); screenManager.popToRoot();
Map.executeMapApiRequest(); Map.executeMapApiRequest();
return; return;
case RequestType.SEARCH: case RequestType.SEARCH:
screenManager.popToRoot(); screenManager.popToRoot();
final ParsedSearchRequest request = Framework.nativeGetParsedSearchRequest(); final ParsedSearchRequest request = Framework.nativeGetParsedSearchRequest();
final double[] latlon = Framework.nativeGetParsedCenterLatLon(); final double[] latlon = Framework.nativeGetParsedCenterLatLon();
if (latlon != null) if (latlon != null)
{ {
Framework.nativeStopLocationFollow(); Framework.nativeStopLocationFollow();
Framework.nativeSetViewportCenter(latlon[0], latlon[1], SEARCH_IN_VIEWPORT_ZOOM); Framework.nativeSetViewportCenter(latlon[0], latlon[1], SEARCH_IN_VIEWPORT_ZOOM);
// We need to update viewport for search api manually because of drape engine // We need to update viewport for search api manually because of drape engine
// will not notify subscribers when search activity is shown. // will not notify subscribers when search activity is shown.
if (!request.mIsSearchOnMap) if (!request.mIsSearchOnMap)
Framework.nativeSetSearchViewport(latlon[0], latlon[1], SEARCH_IN_VIEWPORT_ZOOM); Framework.nativeSetSearchViewport(latlon[0], latlon[1], SEARCH_IN_VIEWPORT_ZOOM);
} }
final SearchScreen.Builder builder = new SearchScreen.Builder(carContext, surfaceRenderer); final SearchScreen.Builder builder = new SearchScreen.Builder(carContext, surfaceRenderer);
builder.setQuery(request.mQuery); builder.setQuery(request.mQuery);
if (request.mLocale != null) if (request.mLocale != null)
builder.setLocale(request.mLocale); builder.setLocale(request.mLocale);
screenManager.popToRoot(); screenManager.popToRoot();
screenManager.push(builder.build()); screenManager.push(builder.build());
return; return;
case RequestType.ROUTE: Logger.e(TAG, "Route API is not supported by Android Auto: " + uri); return; case RequestType.ROUTE: Logger.e(TAG, "Route API is not supported by Android Auto: " + uri); return;
case RequestType.CROSSHAIR: Logger.e(TAG, "Crosshair API is not supported by Android Auto: " + uri); return; case RequestType.CROSSHAIR: Logger.e(TAG, "Crosshair API is not supported by Android Auto: " + uri); return;
case RequestType.MENU: Logger.e(TAG, "Menu API is not supported by Android Auto: " + uri); return; case RequestType.MENU: Logger.e(TAG, "Menu API is not supported by Android Auto: " + uri); return;
case RequestType.SETTINGS: Logger.e(TAG, "Settings API is not supported by Android Auto: " + uri); case RequestType.SETTINGS: Logger.e(TAG, "Settings API is not supported by Android Auto: " + uri);
} }
} }

View File

@@ -8,21 +8,22 @@ import androidx.annotation.StringRes;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.car.app.CarContext; import androidx.car.app.CarContext;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.MapStyle; import app.organicmaps.sdk.MapStyle;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config;
public final class ThemeUtils public final class ThemeUtils
{ {
public enum ThemeMode public enum ThemeMode
{ {
AUTO(R.string.auto, R.string.theme_auto), AUTO(R.string.auto, Config.UiTheme.AUTO),
LIGHT(R.string.off, R.string.theme_default), LIGHT(R.string.off, Config.UiTheme.DEFAULT),
NIGHT(R.string.on, R.string.theme_night); NIGHT(R.string.on, Config.UiTheme.NIGHT);
ThemeMode(@StringRes int titleId, @StringRes int prefsKeyId) ThemeMode(@StringRes int titleId, @NonNull String config)
{ {
mTitleId = titleId; mTitleId = titleId;
mPrefsKeyId = prefsKeyId; mConfig = config;
} }
@StringRes @StringRes
@@ -31,16 +32,16 @@ public final class ThemeUtils
return mTitleId; return mTitleId;
} }
@StringRes @NonNull
public int getPrefsKeyId() public String getConfig()
{ {
return mPrefsKeyId; return mConfig;
} }
@StringRes @StringRes
private final int mTitleId; private final int mTitleId;
@StringRes @NonNull
private final int mPrefsKeyId; private final String mConfig;
} }
private static final String ANDROID_AUTO_PREFERENCES_FILE_KEY = "ANDROID_AUTO_PREFERENCES_FILE_KEY"; private static final String ANDROID_AUTO_PREFERENCES_FILE_KEY = "ANDROID_AUTO_PREFERENCES_FILE_KEY";
@@ -79,23 +80,20 @@ public final class ThemeUtils
@UiThread @UiThread
public static void setThemeMode(@NonNull CarContext context, @NonNull ThemeMode themeMode) public static void setThemeMode(@NonNull CarContext context, @NonNull ThemeMode themeMode)
{ {
getSharedPreferences(context).edit().putString(THEME_KEY, context.getString(themeMode.getPrefsKeyId())).commit(); getSharedPreferences(context).edit().putString(THEME_KEY, themeMode.getConfig()).commit();
update(context, themeMode); update(context, themeMode);
} }
@NonNull @NonNull
public static ThemeMode getThemeMode(@NonNull CarContext context) public static ThemeMode getThemeMode(@NonNull CarContext context)
{ {
final String autoTheme = context.getString(R.string.theme_auto); final String themeMode = getSharedPreferences(context).getString(THEME_KEY, ThemeMode.AUTO.getConfig());
final String lightTheme = context.getString(R.string.theme_default);
final String nightTheme = context.getString(R.string.theme_night);
final String themeMode = getSharedPreferences(context).getString(THEME_KEY, autoTheme);
if (themeMode.equals(autoTheme)) if (themeMode.equals(ThemeMode.AUTO.getConfig()))
return ThemeMode.AUTO; return ThemeMode.AUTO;
else if (themeMode.equals(lightTheme)) else if (themeMode.equals(ThemeMode.LIGHT.getConfig()))
return ThemeMode.LIGHT; return ThemeMode.LIGHT;
else if (themeMode.equals(nightTheme)) else if (themeMode.equals(ThemeMode.NIGHT.getConfig()))
return ThemeMode.NIGHT; return ThemeMode.NIGHT;
else else
throw new IllegalArgumentException("Unsupported value"); throw new IllegalArgumentException("Unsupported value");

View File

@@ -171,20 +171,20 @@ public final class UiHelpers
int drawableRes; int drawableRes;
switch (locationMode) switch (locationMode)
{ {
case LocationState.PENDING_POSITION, LocationState.NOT_FOLLOW_NO_POSITION -> case LocationState.PENDING_POSITION, LocationState.NOT_FOLLOW_NO_POSITION ->
drawableRes = R.drawable.ic_location_off; drawableRes = R.drawable.ic_location_off;
case LocationState.NOT_FOLLOW -> drawableRes = R.drawable.ic_not_follow; case LocationState.NOT_FOLLOW -> drawableRes = R.drawable.ic_not_follow;
case LocationState.FOLLOW -> case LocationState.FOLLOW ->
{ {
drawableRes = R.drawable.ic_follow; drawableRes = R.drawable.ic_follow;
tintColor = Colors.LOCATION_TINT; tintColor = Colors.LOCATION_TINT;
} }
case LocationState.FOLLOW_AND_ROTATE -> case LocationState.FOLLOW_AND_ROTATE ->
{ {
drawableRes = R.drawable.ic_follow_and_rotate; drawableRes = R.drawable.ic_follow_and_rotate;
tintColor = Colors.LOCATION_TINT; tintColor = Colors.LOCATION_TINT;
} }
default -> throw new IllegalArgumentException("Invalid button mode: " + locationMode); default -> throw new IllegalArgumentException("Invalid button mode: " + locationMode);
} }
final CarIcon icon = final CarIcon icon =

View File

@@ -15,7 +15,7 @@ import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.downloader.UpdateInfo; import app.organicmaps.sdk.downloader.UpdateInfo;
import app.organicmaps.sdk.util.StringUtils; import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.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.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -29,7 +29,7 @@ class BottomPanel
@Override @Override
public void onClick(View v) public void onClick(View v)
{ {
MapManager.warn3gAndDownload(mFragment.requireActivity(), mFragment.getCurrentRoot(), null); MapManagerHelper.warn3gAndDownload(mFragment.requireActivity(), mFragment.getCurrentRoot(), null);
} }
}; };
@@ -38,7 +38,10 @@ class BottomPanel
public void onClick(View v) public void onClick(View v)
{ {
final String country = mFragment.getCurrentRoot(); final String country = mFragment.getCurrentRoot();
MapManager.warnOn3gUpdate(mFragment.requireActivity(), country, () -> MapManager.startUpdate(country)); MapManagerHelper.warnOn3gUpdate(mFragment.requireActivity(), country, () -> {
DownloaderService.startForegroundService();
MapManagerHelper.startUpdate(country);
});
} }
}; };
@@ -55,7 +58,7 @@ class BottomPanel
@Override @Override
public void onClick(View v) public void onClick(View v)
{ {
MapManager.warn3gAndRetry(mFragment.requireActivity(), mFragment.getCurrentRoot(), null); MapManagerHelper.warn3gAndRetry(mFragment.requireActivity(), mFragment.getCurrentRoot(), null);
} }
}; };
@@ -115,15 +118,15 @@ class BottomPanel
{ {
switch (status) switch (status)
{ {
case STATUS_UPDATABLE -> case STATUS_UPDATABLE ->
{ {
UpdateInfo info = MapManager.nativeGetUpdateInfo(root); UpdateInfo info = MapManager.nativeGetUpdateInfo(root);
setUpdateAllState(info); setUpdateAllState(info);
} // Special case for "Countries" node when no maps currently downloaded. } // Special case for "Countries" node when no maps currently downloaded.
case STATUS_DOWNLOADABLE, STATUS_DONE, STATUS_PARTLY -> show = false; case STATUS_DOWNLOADABLE, STATUS_DONE, STATUS_PARTLY -> show = false;
case STATUS_PROGRESS, STATUS_APPLYING, STATUS_ENQUEUED -> setCancelState(); case STATUS_PROGRESS, STATUS_APPLYING, STATUS_ENQUEUED -> setCancelState();
case STATUS_FAILED -> setRetryFailedStates(); case STATUS_FAILED -> setRetryFailedStates();
default -> throw new IllegalArgumentException("Inappropriate status for \"" + root + "\": " + status); default -> throw new IllegalArgumentException("Inappropriate status for \"" + root + "\": " + status);
} }
} }
else else
@@ -133,15 +136,15 @@ class BottomPanel
{ {
switch (status) switch (status)
{ {
case STATUS_UPDATABLE -> case STATUS_UPDATABLE ->
{ {
UpdateInfo info = MapManager.nativeGetUpdateInfo(root); UpdateInfo info = MapManager.nativeGetUpdateInfo(root);
setUpdateAllState(info); setUpdateAllState(info);
} }
case STATUS_DONE -> show = false; case STATUS_DONE -> show = false;
case STATUS_PROGRESS, STATUS_APPLYING, STATUS_ENQUEUED -> setCancelState(); case STATUS_PROGRESS, STATUS_APPLYING, STATUS_ENQUEUED -> setCancelState();
case STATUS_FAILED -> setRetryFailedStates(); case STATUS_FAILED -> setRetryFailedStates();
default -> setDownloadAllState(); default -> setDownloadAllState();
} }
} }
} }

View File

@@ -16,7 +16,7 @@ import app.organicmaps.base.BaseMwmFragmentActivity;
import app.organicmaps.sdk.downloader.CountryItem; import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.util.StringUtils; import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
import app.organicmaps.widget.WheelProgressView; import app.organicmaps.widget.WheelProgressView;
import com.google.android.material.button.MaterialButton; import com.google.android.material.button.MaterialButton;
import com.google.android.material.textview.MaterialTextView; import com.google.android.material.textview.MaterialTextView;
@@ -70,9 +70,9 @@ public class CountrySuggestFragment extends BaseMwmFragment implements View.OnCl
switch (item.newStatus) switch (item.newStatus)
{ {
case CountryItem.STATUS_FAILED: updateViews(); return; case CountryItem.STATUS_FAILED: updateViews(); return;
case CountryItem.STATUS_DONE: exitFragment(); return; case CountryItem.STATUS_DONE: exitFragment(); return;
} }
break; break;
@@ -198,7 +198,8 @@ public class CountrySuggestFragment extends BaseMwmFragment implements View.OnCl
final int id = v.getId(); final int id = v.getId();
if (id == R.id.btn__download_map) if (id == R.id.btn__download_map)
{ {
MapManager.warn3gAndDownload(requireActivity(), mCurrentCountry.id, () -> mDownloadingCountry = mCurrentCountry); MapManagerHelper.warn3gAndDownload(requireActivity(), mCurrentCountry.id,
() -> mDownloadingCountry = mCurrentCountry);
} }
else if (id == R.id.btn__select_map) else if (id == R.id.btn__select_map)
{ {

View File

@@ -20,11 +20,11 @@ import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.MwmActivity; import app.organicmaps.MwmActivity;
import app.organicmaps.MwmApplication; import app.organicmaps.MwmApplication;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.downloader.CountryItem; import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.StringUtils; import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.util.UiUtils;
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment; import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem; import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
@@ -93,7 +93,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
private void onDownloadActionSelected(final CountryItem item, DownloaderAdapter adapter) private void onDownloadActionSelected(final CountryItem item, DownloaderAdapter adapter)
{ {
MapManager.warn3gAndDownload(adapter.mActivity, item.id, null); MapManagerHelper.warn3gAndDownload(adapter.mActivity, item.id, null);
} }
private void onUpdateActionSelected(final CountryItem item, DownloaderAdapter adapter) private void onUpdateActionSelected(final CountryItem item, DownloaderAdapter adapter)
@@ -101,7 +101,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
item.update(); item.update();
if (item.status != CountryItem.STATUS_UPDATABLE) if (item.status != CountryItem.STATUS_UPDATABLE)
return; return;
MapManager.warnOn3gUpdate(adapter.mActivity, item.id, () -> MapManager.startUpdate(item.id)); MapManagerHelper.warnOn3gUpdate(adapter.mActivity, item.id, () -> MapManagerHelper.startUpdate(item.id));
} }
private void onExploreActionSelected(CountryItem item, DownloaderAdapter adapter) private void onExploreActionSelected(CountryItem item, DownloaderAdapter adapter)
@@ -206,7 +206,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
{ {
if (item.isLeafNode && item.newStatus == CountryItem.STATUS_FAILED) if (item.isLeafNode && item.newStatus == CountryItem.STATUS_FAILED)
{ {
MapManager.showError(mActivity, item, null); MapManagerHelper.showError(mActivity, item, null);
break; break;
} }
} }
@@ -287,41 +287,41 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
ArrayList<MenuBottomSheetItem> items = new ArrayList<>(); ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
switch (mSelectedItem.status) switch (mSelectedItem.status)
{ {
case CountryItem.STATUS_DOWNLOADABLE: items.add(getDownloadMenuItem()); break; case CountryItem.STATUS_DOWNLOADABLE: items.add(getDownloadMenuItem()); break;
case CountryItem.STATUS_UPDATABLE: case CountryItem.STATUS_UPDATABLE:
items.add(getUpdateMenuItem()); items.add(getUpdateMenuItem());
// Fallthrough // Fallthrough
case CountryItem.STATUS_DONE: case CountryItem.STATUS_DONE:
if (!mSelectedItem.isExpandable()) if (!mSelectedItem.isExpandable())
items.add(getExploreMenuItem()); items.add(getExploreMenuItem());
appendDeleteMenuItem(items);
break;
case CountryItem.STATUS_FAILED:
items.add(getCancelMenuItem());
if (mSelectedItem.present)
{
appendDeleteMenuItem(items); appendDeleteMenuItem(items);
break; items.add(getExploreMenuItem());
}
break;
case CountryItem.STATUS_FAILED: case CountryItem.STATUS_PROGRESS:
items.add(getCancelMenuItem()); case CountryItem.STATUS_APPLYING:
case CountryItem.STATUS_ENQUEUED:
items.add(getCancelMenuItem());
if (mSelectedItem.present) if (mSelectedItem.present)
{ items.add(getExploreMenuItem());
appendDeleteMenuItem(items); break;
items.add(getExploreMenuItem());
}
break;
case CountryItem.STATUS_PROGRESS: case CountryItem.STATUS_PARTLY:
case CountryItem.STATUS_APPLYING: items.add(getDownloadMenuItem());
case CountryItem.STATUS_ENQUEUED: appendDeleteMenuItem(items);
items.add(getCancelMenuItem()); break;
if (mSelectedItem.present)
items.add(getExploreMenuItem());
break;
case CountryItem.STATUS_PARTLY:
items.add(getDownloadMenuItem());
appendDeleteMenuItem(items);
break;
} }
return items; return items;
} }
@@ -372,20 +372,23 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
{ {
switch (mItem.status) switch (mItem.status)
{ {
case CountryItem.STATUS_DONE, CountryItem.STATUS_PROGRESS, CountryItem.STATUS_APPLYING, case CountryItem.STATUS_DONE, CountryItem.STATUS_PROGRESS, CountryItem.STATUS_APPLYING,
CountryItem.STATUS_ENQUEUED -> CountryItem.STATUS_ENQUEUED ->
processLongClick();
case CountryItem.STATUS_DOWNLOADABLE, CountryItem.STATUS_PARTLY ->
{
if (clickOnStatus)
onDownloadActionSelected(mItem, DownloaderAdapter.this);
else
processLongClick(); processLongClick();
case CountryItem.STATUS_DOWNLOADABLE, CountryItem.STATUS_PARTLY -> }
{ case CountryItem.STATUS_FAILED ->
if (clickOnStatus) {
onDownloadActionSelected(mItem, DownloaderAdapter.this); MapManagerHelper.warn3gAndRetry(mActivity, mItem.id, null);
else }
processLongClick(); case CountryItem.STATUS_UPDATABLE ->
} MapManagerHelper.warnOn3gUpdate(mActivity, mItem.id, () -> MapManagerHelper.startUpdate(mItem.id));
case CountryItem.STATUS_FAILED -> MapManager.warn3gAndRetry(mActivity, mItem.id, null); default -> throw new IllegalArgumentException("Inappropriate item status: " + mItem.status);
case CountryItem.STATUS_UPDATABLE ->
MapManager.warnOn3gUpdate(mActivity, mItem.id, () -> MapManager.startUpdate(mItem.id));
default -> throw new IllegalArgumentException("Inappropriate item status: " + mItem.status);
} }
} }
@@ -535,33 +538,33 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
{ {
switch (ci.category) switch (ci.category)
{ {
case CountryItem.CATEGORY_NEAR_ME -> case CountryItem.CATEGORY_NEAR_ME ->
{
if (ci.category != prev)
{ {
if (ci.category != prev) headerId = CountryItem.CATEGORY_NEAR_ME;
{ mItemsAndHeader.add(new GenericItem(mActivity.getString(R.string.downloader_near_me_subtitle)));
headerId = CountryItem.CATEGORY_NEAR_ME;
mItemsAndHeader.add(new GenericItem(mActivity.getString(R.string.downloader_near_me_subtitle)));
prev = ci.category;
}
}
case CountryItem.CATEGORY_DOWNLOADED ->
{
if (ci.category != prev)
{
headerId = CountryItem.CATEGORY_DOWNLOADED;
mItemsAndHeader.add(new GenericItem(mActivity.getString(R.string.downloader_downloaded_subtitle)));
prev = ci.category;
}
}
default ->
{
int prevHeader = headerId;
headerId = CountryItem.CATEGORY_AVAILABLE + ci.name.charAt(0);
if (headerId != prevHeader)
mItemsAndHeader.add(new GenericItem(StringUtils.toUpperCase(ci.name.substring(0, 1))));
prev = ci.category; prev = ci.category;
} }
} }
case CountryItem.CATEGORY_DOWNLOADED ->
{
if (ci.category != prev)
{
headerId = CountryItem.CATEGORY_DOWNLOADED;
mItemsAndHeader.add(new GenericItem(mActivity.getString(R.string.downloader_downloaded_subtitle)));
prev = ci.category;
}
}
default ->
{
int prevHeader = headerId;
headerId = CountryItem.CATEGORY_AVAILABLE + ci.name.charAt(0);
if (headerId != prevHeader)
mItemsAndHeader.add(new GenericItem(StringUtils.toUpperCase(ci.name.substring(0, 1))));
prev = ci.category;
}
}
ci.headerId = headerId; ci.headerId = headerId;
} }
mItemsAndHeader.add(new GenericItem(ci)); mItemsAndHeader.add(new GenericItem(ci));

View File

@@ -24,8 +24,8 @@ import app.organicmaps.widget.PlaceholderView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DownloaderFragment extends BaseMwmRecyclerFragment<DownloaderAdapter> public class DownloaderFragment
implements MenuBottomSheetFragment.MenuBottomSheetInterface extends BaseMwmRecyclerFragment<DownloaderAdapter> implements MenuBottomSheetFragment.MenuBottomSheetInterface
{ {
private DownloaderToolbarController mToolbarController; private DownloaderToolbarController mToolbarController;
@@ -153,7 +153,8 @@ public class DownloaderFragment extends BaseMwmRecyclerFragment<DownloaderAdapte
mBottomPanel = new BottomPanel(this, view); mBottomPanel = new BottomPanel(this, view);
mToolbarController = new DownloaderToolbarController(view, requireActivity(), this); mToolbarController = new DownloaderToolbarController(view, requireActivity(), this);
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), mToolbarController.getBackPressedCallback()); requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
mToolbarController.getBackPressedCallback());
update(); update();
} }
@@ -195,7 +196,8 @@ public class DownloaderFragment extends BaseMwmRecyclerFragment<DownloaderAdapte
{ {
if (mAdapter == null) if (mAdapter == null)
mAdapter = new DownloaderAdapter(this); mAdapter = new DownloaderAdapter(this);
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), mAdapter.getBackPressedCallback()); requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
mAdapter.getBackPressedCallback());
return mAdapter; return mAdapter;
} }

View File

@@ -9,7 +9,8 @@ import androidx.core.view.OnApplyWindowInsetsListener;
import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.sdk.util.Utils;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.WindowInsetUtils; import app.organicmaps.util.WindowInsetUtils;
final class DownloaderInsetsListener implements OnApplyWindowInsetsListener final class DownloaderInsetsListener implements OnApplyWindowInsetsListener
@@ -55,7 +56,7 @@ final class DownloaderInsetsListener implements OnApplyWindowInsetsListener
private void applyInsetsToButtons(Insets insets) private void applyInsetsToButtons(Insets insets)
{ {
int baseMargin = UiUtils.dimen(mContext, R.dimen.margin_base); int baseMargin = Utils.dimen(mContext, R.dimen.margin_base);
ViewGroup.MarginLayoutParams fabParams = (ViewGroup.MarginLayoutParams) mFab.getLayoutParams(); ViewGroup.MarginLayoutParams fabParams = (ViewGroup.MarginLayoutParams) mFab.getLayoutParams();
ViewGroup.MarginLayoutParams buttonParams = (ViewGroup.MarginLayoutParams) mButton.getLayoutParams(); ViewGroup.MarginLayoutParams buttonParams = (ViewGroup.MarginLayoutParams) mButton.getLayoutParams();

View File

@@ -20,6 +20,7 @@ import app.organicmaps.R;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.util.StringUtils; import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
import java.util.Objects;
public class DownloaderNotifier public class DownloaderNotifier
{ {
@@ -29,7 +30,8 @@ public class DownloaderNotifier
public static final int NOTIFICATION_ID = 1; public static final int NOTIFICATION_ID = 1;
private final Context mContext; private final Context mContext;
private NotificationCompat.Builder mProgressNotificationBuilder; private NotificationCompat.Builder mProgressNotificationBuilder = null;
private String mNotificationCountryId = null;
public DownloaderNotifier(Context context) public DownloaderNotifier(Context context)
{ {
@@ -45,6 +47,7 @@ public class DownloaderNotifier
.setShowBadge(true) .setShowBadge(true)
.setVibrationEnabled(false) .setVibrationEnabled(false)
.setLightsEnabled(false) .setLightsEnabled(false)
.setSound(null, null)
.build(); .build();
notificationManager.createNotificationChannel(channel); notificationManager.createNotificationChannel(channel);
} }
@@ -62,8 +65,6 @@ public class DownloaderNotifier
final String countryName = MapManager.nativeGetName(countryId); final String countryName = MapManager.nativeGetName(countryId);
final String content = mContext.getString(R.string.download_country_failed, countryName); final String content = mContext.getString(R.string.download_country_failed, countryName);
var contentPendingIntent = getNotificationPendingIntent(countryId);
final Notification notification = new NotificationCompat.Builder(mContext, CHANNEL_ID) final Notification notification = new NotificationCompat.Builder(mContext, CHANNEL_ID)
.setAutoCancel(true) .setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_ERROR) .setCategory(NotificationCompat.CATEGORY_ERROR)
@@ -74,7 +75,7 @@ public class DownloaderNotifier
.setContentText(content) .setContentText(content)
.setShowWhen(true) .setShowWhen(true)
.setTicker(getTicker(mContext, title, content)) .setTicker(getTicker(mContext, title, content))
.setContentIntent(contentPendingIntent) .setContentIntent(getNotificationPendingIntent(countryId))
.setOnlyAlertOnce(true) .setOnlyAlertOnce(true)
.build(); .build();
@@ -110,32 +111,41 @@ public class DownloaderNotifier
@NonNull @NonNull
public Notification buildProgressNotification(@Nullable String countryId, int maxProgress, int progress) public Notification buildProgressNotification(@Nullable String countryId, int maxProgress, int progress)
{ {
var builder = startNotification(countryId); var builder = getNotificationBuilder(countryId);
/// @todo Doesn't work properly .. Bad input sizes?
builder.setProgress(maxProgress, progress, maxProgress == 0); // builder.setProgress(maxProgress, progress, maxProgress == 0);
builder.setContentText("Download in progress"); builder.setProgress(maxProgress, progress, true);
return builder.build(); return builder.build();
} }
@NonNull @NonNull
private NotificationCompat.Builder startNotification(@Nullable String countryId) private NotificationCompat.Builder getNotificationBuilder(@Nullable String countryId)
{ {
final String title = mContext.getString(R.string.app_name); if (mProgressNotificationBuilder == null || !Objects.equals(countryId, mNotificationCountryId))
{
mNotificationCountryId = countryId;
final String countryName = countryId != null ? MapManager.nativeGetName(countryId) : "";
return new NotificationCompat.Builder(mContext, CHANNEL_ID) mProgressNotificationBuilder =
.setAutoCancel(true) new NotificationCompat.Builder(mContext, CHANNEL_ID)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setAutoCancel(true)
.setSmallIcon(R.drawable.ic_logo_small) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setColor(ContextCompat.getColor(mContext, R.color.notification)) .setSmallIcon(R.drawable.ic_logo_small)
.setShowWhen(true) .setColor(ContextCompat.getColor(mContext, R.color.notification))
.setContentTitle(title) .setShowWhen(true)
.setContentIntent(getNotificationPendingIntent(countryId)); .setContentTitle(mContext.getString(R.string.app_name))
.setContentIntent(getNotificationPendingIntent(countryId))
.setContentText(mContext.getString(R.string.downloader_downloading) + " " + countryName)
.setSound(null);
}
return mProgressNotificationBuilder;
} }
@NonNull @NonNull
private PendingIntent getNotificationPendingIntent(@Nullable String countryId) private PendingIntent getNotificationPendingIntent(@Nullable String countryId)
{ {
/// @todo Zooming to the countryId when tapping on the notification?
/// Shows very low zoom level, need z=9/10, I suppose ...
final int FLAG_IMMUTABLE = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? 0 : PendingIntent.FLAG_IMMUTABLE; final int FLAG_IMMUTABLE = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? 0 : PendingIntent.FLAG_IMMUTABLE;
final Intent contentIntent = MwmActivity.createShowMapIntent(mContext, countryId); final Intent contentIntent = MwmActivity.createShowMapIntent(mContext, countryId);
contentIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); contentIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

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