Compare commits
84 Commits
hb0nd-url-
...
hb0nd-laye
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00e77cd745 | ||
|
|
ae0ef4d3f8 | ||
|
|
68d1ead44c | ||
|
|
09de87fd29 | ||
|
|
1a241121c4 | ||
|
|
fdeeb1ae34 | ||
|
|
c2bd2b897a | ||
|
|
e39b5eb507 | ||
|
|
96ef33a401 | ||
|
|
c6dcfc71bf | ||
|
|
053fe3c143 | ||
|
|
c6439aaa82 | ||
|
|
e50a668feb | ||
|
|
5ce753bd5c | ||
|
|
8058183f72 | ||
|
|
07f745411f | ||
|
|
2004c9bfc1 | ||
|
|
1e7715d10f | ||
|
|
e884e32bb6 | ||
|
|
660694aee0 | ||
|
|
99fa3ec551 | ||
|
|
f26db1a79b | ||
|
|
1151f0fb75 | ||
|
|
bbb28107b8 | ||
|
|
9c7b39fd5b | ||
|
|
0d9514bee9 | ||
|
|
a036edc9c5 | ||
|
|
90492e95e6 | ||
|
|
fc199252eb | ||
|
|
327d302aae | ||
|
|
0b8bd42cb0 | ||
|
|
962ee67833 | ||
|
|
69e3fdca90 | ||
|
|
ac8f945455 | ||
|
|
c8a4726500 | ||
|
|
40adb0f860 | ||
|
|
c600a4fd5d | ||
|
|
07420a3f19 | ||
|
|
3920988ef4 | ||
|
|
6136abb33a | ||
|
|
a0e40c98d7 | ||
|
|
3bdaa44c3a | ||
|
|
945c6205a0 | ||
|
|
ef4fd85883 | ||
|
|
83db427c40 | ||
|
|
946fea1e07 | ||
|
|
bd80e9160d | ||
|
|
5333ad3597 | ||
|
|
65b5234396 | ||
|
|
969c805182 | ||
|
|
8b03e99035 | ||
|
|
3aabde338a | ||
|
|
d5d86ffd36 | ||
|
|
d4cef9385b | ||
|
|
9c495ca616 | ||
|
|
a08f3df3e6 | ||
|
|
bb5da20fec | ||
|
|
e112dc2ac4 | ||
|
|
3e2e6cb487 | ||
|
|
21020429cb | ||
|
|
07025ff696 | ||
|
|
c13da0f0a2 | ||
|
|
dd023b65c7 | ||
|
|
0c8648d1e3 | ||
|
|
760e050110 | ||
|
|
db4b46f8ad | ||
|
|
29ebd8b725 | ||
|
|
6b53d1fb91 | ||
|
|
d1da6c197e | ||
|
|
0dc8d69375 | ||
|
|
3352279d9d | ||
|
|
6da8b69a1b | ||
|
|
fe1c371b5f | ||
|
|
309eed2365 | ||
|
|
979c713436 | ||
|
|
5e8a8de646 | ||
|
|
b0bdd2c665 | ||
|
|
dd949925f6 | ||
|
|
b37572000f | ||
|
|
332ab819b2 | ||
|
|
860f58e60e | ||
|
|
0e7d8a65cc | ||
|
|
4c6207a8ce | ||
|
|
b96afc6fbb |
@@ -1,48 +1,59 @@
|
||||
# Configuration file for clang-format, based on docs/CPP_STYLE.md.
|
||||
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: Right
|
||||
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||
AlignEscapedNewlines: LeftWithLastLine
|
||||
AlignOperands: AlignAfterOperator
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterExternBlock: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: true
|
||||
BeforeWhile: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
SplitEmptyRecord: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakAfterJavaFieldAnnotations: true
|
||||
BreakBeforeBraces: Custom
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
ColumnLimit: 120
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
ContinuationIndentWidth: 4
|
||||
DerivePointerAlignment: false
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: false
|
||||
IndentAccessModifiers: false
|
||||
IndentExternBlock: NoIndent
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: true
|
||||
PackConstructorInitializers: Never
|
||||
LambdaBodyIndentation: OuterScope
|
||||
PackConstructorInitializers: CurrentLine
|
||||
PointerAlignment: Middle
|
||||
RemoveBracesLLVM: true
|
||||
QualifierAlignment: Right
|
||||
SpacesInContainerLiterals: false
|
||||
Standard: Latest
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
|
||||
---
|
||||
Language: Java
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
name: 🐞 Bug Report
|
||||
description: Report a problem you've encountered
|
||||
title: "bug: "
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
name: "💡 Feature Request"
|
||||
description: "Suggest an idea or improvement for CoMaps"
|
||||
title: "feat: "
|
||||
labels:
|
||||
- "enhancement"
|
||||
body:
|
||||
|
||||
@@ -32,13 +32,12 @@ on:
|
||||
- track_generator/**
|
||||
- xcode/**
|
||||
|
||||
env:
|
||||
JAVA_HOME: /usr/lib/jvm/temurin-17-jdk-amd64 # Java 17 is required for Android Gradle 8 plugin
|
||||
|
||||
jobs:
|
||||
android-google-beta:
|
||||
name: Android Google Beta
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: runmymind/docker-android-sdk:latest
|
||||
environment: beta
|
||||
steps:
|
||||
- name: Install build tools and dependencies
|
||||
@@ -71,10 +70,6 @@ jobs:
|
||||
SECURE_PROPERTIES: ${{ secrets.SECURE_PROPERTIES }}
|
||||
RELEASE_KEYSTORE: ${{ secrets.RELEASE_KEYSTORE }}
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Compile
|
||||
shell: bash
|
||||
working-directory: android
|
||||
|
||||
@@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
android-check-metadata:
|
||||
name: Check app metadata
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: codeberg-tiny
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -34,13 +34,12 @@ on:
|
||||
- track_generator/**
|
||||
- xcode/**
|
||||
|
||||
env:
|
||||
JAVA_HOME: /usr/lib/jvm/temurin-17-jdk-amd64 # Java 17 is required for Android Gradle 8 plugin
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Android Lint
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: codeberg-tiny
|
||||
container:
|
||||
image: runmymind/docker-android-sdk:latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
@@ -51,10 +50,6 @@ jobs:
|
||||
shell: bash
|
||||
run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20))
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Lint
|
||||
shell: bash
|
||||
working-directory: android
|
||||
@@ -63,6 +58,8 @@ jobs:
|
||||
android-check:
|
||||
name: Build Android Debug
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: runmymind/docker-android-sdk:latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -93,10 +90,6 @@ jobs:
|
||||
shell: bash
|
||||
run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20))
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Configure ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
|
||||
@@ -4,12 +4,9 @@ on:
|
||||
schedule:
|
||||
- cron: '0 5 * * 0' # Once per week at 05:00 UTC
|
||||
|
||||
env:
|
||||
JAVA_HOME: /usr/lib/jvm/temurin-17-jdk-amd64 # Java 17 is required for Android Gradle 8 plugin
|
||||
|
||||
jobs:
|
||||
precondition:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: codeberg-tiny
|
||||
name: Check preconditions
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
@@ -34,6 +31,8 @@ jobs:
|
||||
android-google-beta:
|
||||
name: Android Google Beta
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: runmymind/docker-android-sdk:latest
|
||||
needs: precondition
|
||||
if: ${{ needs.precondition.outputs.updated != '' }}
|
||||
environment: beta
|
||||
@@ -73,10 +72,6 @@ jobs:
|
||||
SECURE_PROPERTIES: ${{ secrets.SECURE_PROPERTIES }}
|
||||
RELEASE_KEYSTORE: ${{ secrets.RELEASE_KEYSTORE }}
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Compile
|
||||
shell: bash
|
||||
working-directory: android
|
||||
|
||||
@@ -2,13 +2,12 @@ name: Android Release Metadata
|
||||
on:
|
||||
workflow_dispatch: # Manual trigger
|
||||
|
||||
env:
|
||||
JAVA_HOME: /usr/lib/jvm/temurin-17-jdk-amd64 # Java 17 is required for Android Gradle 8 plugin
|
||||
|
||||
jobs:
|
||||
android-release-metadata:
|
||||
name: Upload Google Play metadata
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: codeberg-tiny
|
||||
container:
|
||||
image: runmymind/docker-android-sdk:latest
|
||||
environment: production
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
|
||||
@@ -5,12 +5,13 @@ on:
|
||||
env:
|
||||
RELEASE_NOTES: android/app/src/google/play/release-notes/en-US/default.txt
|
||||
FDROID_VERSION: android/app/src/fdroid/play/version.yaml
|
||||
JAVA_HOME: /usr/lib/jvm/temurin-17-jdk-amd64 # Java 17 is required for Android Gradle 8 plugin
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
name: Tag
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: runmymind/docker-android-sdk:latest
|
||||
environment: production
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
@@ -117,10 +118,6 @@ jobs:
|
||||
SECURE_PROPERTIES: ${{ secrets.SECURE_PROPERTIES }}
|
||||
RELEASE_KEYSTORE: ${{ secrets.RELEASE_KEYSTORE }}
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Set up SDK
|
||||
shell: bash
|
||||
run: echo "sdk.dir=$ANDROID_SDK_ROOT" > android/local.properties
|
||||
|
||||
@@ -3,20 +3,20 @@ on:
|
||||
workflow_dispatch: # Manual trigger
|
||||
pull_request:
|
||||
paths:
|
||||
- packaging/app.organicmaps.desktop.metainfo.xml
|
||||
- packaging/app.comaps.desktop.metainfo.xml
|
||||
- .forgejo/workflows/appstream-check.yaml # Run check on self change
|
||||
|
||||
jobs:
|
||||
validate-appstream:
|
||||
name: Validate appstream metadata xml
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: codeberg-tiny
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
sparse-checkout: |
|
||||
packaging/app.organicmaps.desktop.metainfo.xml
|
||||
packaging/app.comaps.desktop.metainfo.xml
|
||||
|
||||
- name: Install appstream validator and flatpak Builder
|
||||
shell: bash
|
||||
@@ -29,8 +29,8 @@ jobs:
|
||||
|
||||
- name: Lint appstream data with flatpak Builder
|
||||
shell: bash
|
||||
run: flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream packaging/app.organicmaps.desktop.metainfo.xml
|
||||
run: flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream packaging/app.comaps.desktop.metainfo.xml
|
||||
|
||||
- name: Run appstreamcli in pedantic mode
|
||||
shell: bash
|
||||
run: flatpak run --command=appstreamcli org.flatpak.Builder validate --pedantic packaging/app.organicmaps.desktop.metainfo.xml
|
||||
run: flatpak run --command=appstreamcli org.flatpak.Builder validate --pedantic packaging/app.comaps.desktop.metainfo.xml
|
||||
|
||||
@@ -33,7 +33,7 @@ concurrency:
|
||||
jobs:
|
||||
should-run-check:
|
||||
name: Should run coverage
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: codeberg-tiny
|
||||
outputs:
|
||||
run-from-pr: ${{ steps.run-from-pr.outputs.run-from-pr }}
|
||||
manually-triggered: ${{ steps.manually-triggered.outputs.manually-triggered }}
|
||||
@@ -59,14 +59,9 @@ jobs:
|
||||
coverage:
|
||||
needs: should-run-check
|
||||
name: Generate coverage report
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ needs.should-run-check.outputs.run-from-pr == 'true' || needs.should-run-check.outputs.manually-triggered == 'true'}}
|
||||
steps:
|
||||
- name: Free disk space by removing .NET, Android and Haskell
|
||||
shell: bash
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
|
||||
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -94,10 +89,6 @@ jobs:
|
||||
llvm \
|
||||
gcovr
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Configure ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
|
||||
@@ -3,20 +3,20 @@ on:
|
||||
workflow_dispatch: # Manual trigger
|
||||
pull_request:
|
||||
paths:
|
||||
- qt/res/app.organicmaps.desktop.desktop
|
||||
- qt/res/app.comaps.desktop.desktop
|
||||
- .forgejo/workflows/desktop-file-check.yaml # Run check on self change
|
||||
|
||||
jobs:
|
||||
validate-desktop-file:
|
||||
name: Validate .desktop file
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: codeberg-tiny
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
sparse-checkout: |
|
||||
qt/res/app.organicmaps.desktop.desktop
|
||||
qt/res/app.comaps.desktop.desktop
|
||||
|
||||
- name: Install desktop-file-validate tool
|
||||
shell: bash
|
||||
@@ -27,4 +27,4 @@ jobs:
|
||||
|
||||
- name: Validate desktop file
|
||||
shell: bash
|
||||
run: desktop-file-validate qt/res/app.organicmaps.desktop.desktop && echo "Successfully validated .desktop file"
|
||||
run: desktop-file-validate qt/res/app.comaps.desktop.desktop && echo "Successfully validated .desktop file"
|
||||
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
jobs:
|
||||
ios-check-metadata:
|
||||
name: Check app metadata
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: codeberg-tiny
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -31,18 +31,13 @@ on:
|
||||
jobs:
|
||||
linux-no-unity:
|
||||
name: Linux no unity build
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
# Cancels previous jobs if the same branch or PR was updated again.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-no-unity-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- name: Free disk space by removing .NET, Android and Haskell
|
||||
shell: bash
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
|
||||
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -71,10 +66,6 @@ jobs:
|
||||
libqt6positioning6-plugins \
|
||||
libqt6positioning6
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Configure ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
@@ -99,7 +90,7 @@ jobs:
|
||||
|
||||
linux-matrix:
|
||||
name: Linux builds and tests
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -111,11 +102,6 @@ jobs:
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- name: Free disk space by removing .NET, Android and Haskell
|
||||
shell: bash
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
|
||||
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -142,10 +128,6 @@ jobs:
|
||||
libqt6positioning6-plugins \
|
||||
libqt6positioning6
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Configure ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
|
||||
@@ -57,10 +57,6 @@ jobs:
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install ninja qt@6
|
||||
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
- name: Configure ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
|
||||
9
.github/workflows/android-check.yaml
vendored
@@ -7,6 +7,7 @@ on:
|
||||
|
||||
env:
|
||||
JAVA_HOME: /usr/lib/jvm/temurin-17-jdk-amd64 # Java 17 is required for Android Gradle 8 plugin
|
||||
SKIP_MAP_DOWNLOAD: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
@@ -22,10 +23,6 @@ jobs:
|
||||
shell: bash
|
||||
run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20))
|
||||
|
||||
- name: Init boost, generate textures
|
||||
shell: bash
|
||||
run: ./configure.sh --skip-map-download
|
||||
|
||||
- name: Lint
|
||||
shell: bash
|
||||
working-directory: android
|
||||
@@ -76,10 +73,6 @@ jobs:
|
||||
shell: bash
|
||||
run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20))
|
||||
|
||||
- name: Init boost, generate textures
|
||||
shell: bash
|
||||
run: ./configure.sh --skip-map-download
|
||||
|
||||
- name: Configure ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
|
||||
43
.github/workflows/clang-format.yaml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
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
|
||||
2
.github/workflows/ios-check.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
shell: bash
|
||||
run: git submodule update --depth 1 --init --recursive --jobs=$(($(sysctl -n hw.logicalcpu) * 20))
|
||||
|
||||
- name: Init boost, download World map, generate textures
|
||||
- name: Configure repository
|
||||
shell: bash
|
||||
run: ./configure.sh
|
||||
|
||||
|
||||
6
.gitignore
vendored
@@ -26,10 +26,8 @@ data/bookmarks
|
||||
data/edits.xml
|
||||
data/World.mwm
|
||||
data/WorldCoasts.mwm
|
||||
|
||||
# generated when running tests. NOT the lowercase 'testing' which should be kept.
|
||||
Testing
|
||||
!testing
|
||||
data/world_mwm/*
|
||||
data/*_hash
|
||||
|
||||
# Compiled Python
|
||||
*.pyc
|
||||
|
||||
@@ -48,6 +48,8 @@ if (APPLE AND NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL Android))
|
||||
set(CMAKE_OBJCXX_VISIBILITY_PRESET hidden)
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "./configure.sh" WORKING_DIRECTORY ${OMIM_ROOT})
|
||||
|
||||
message(STATUS "Using compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
|
||||
|
||||
if (CMAKE_UNITY_BUILD)
|
||||
@@ -269,5 +271,5 @@ endif()
|
||||
omim_add_test_subdirectory(qt_tstfrm)
|
||||
|
||||
if (PLATFORM_ANDROID)
|
||||
add_subdirectory(android/app/src/main/cpp)
|
||||
add_subdirectory(android/sdk/src/main/cpp)
|
||||
endif()
|
||||
|
||||
@@ -53,6 +53,9 @@ A community-led free & open source maps app based on [OpenStreetMap](https://www
|
||||
<a href="https://f-droid.org/en/packages/app.comaps.fdroid/">
|
||||
<img src="docs/badges/fdroid.png" alt="F-Droid" width="160"/>
|
||||
</a>
|
||||
<a href="https://apps.obtainium.imranr.dev/redirect?r=obtainium://add/https://codeberg.org/comaps/comaps">
|
||||
<img src="docs/badges/obtainium.png" alt="Obtainium" width="160"/>
|
||||
</a>
|
||||
<a href="https://codeberg.org/comaps/comaps/releases">
|
||||
<img src="docs/badges/codeberg.png" alt="Codeberg" width="160"/>
|
||||
</a>
|
||||
|
||||
@@ -18,5 +18,4 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libxi-dev \
|
||||
optipng
|
||||
WORKDIR /root/comaps
|
||||
RUN ./configure.sh
|
||||
CMD ./gradlew -Parm64 assembleFdroidDebug
|
||||
|
||||
@@ -15,43 +15,17 @@ buildscript {
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://www.jitpack.io' } // MPAndroidChart
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
apply plugin: 'ru.cian.huawei-publish-gradle-plugin'
|
||||
|
||||
def run(cmd) {
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = cmd
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString()
|
||||
}
|
||||
|
||||
|
||||
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
|
||||
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||
|
||||
def getVersion() {
|
||||
def isWindows = DefaultNativePlatform.getCurrentOperatingSystem().isWindows()
|
||||
def bash = isWindows ? 'C:\\Program Files\\Git\\bin\\bash.exe' : 'bash'
|
||||
def versionCode = Integer.parseInt(run([bash, '../../tools/unix/version.sh', 'android_code']).trim())
|
||||
def versionName = run([bash, '../../tools/unix/version.sh', 'android_name']).trim()
|
||||
return new Tuple2(versionCode, versionName)
|
||||
}
|
||||
|
||||
def getCommitMessage() {
|
||||
return run(['git', '--no-pager', 'show', '-s', '--format=%s%n%n%b', 'HEAD']).trim()
|
||||
}
|
||||
|
||||
def osName = System.properties['os.name'].toLowerCase()
|
||||
|
||||
project.ext.appId = 'app.comaps'
|
||||
project.ext.appName = 'CoMaps'
|
||||
|
||||
@@ -63,7 +37,10 @@ project.ext.appName = 'CoMaps'
|
||||
//}
|
||||
|
||||
android {
|
||||
namespace 'app.organicmaps'
|
||||
namespace = 'app.organicmaps'
|
||||
|
||||
// TODO: it should not be here, but in sdk/build.gradle. But for some reason it should be specified here as well.
|
||||
ndkVersion = '28.2.13676358'
|
||||
|
||||
dependenciesInfo {
|
||||
// Disables dependency metadata when building APKs (for IzzyOnDroid/F-Droid)
|
||||
@@ -85,79 +62,23 @@ android {
|
||||
}
|
||||
|
||||
// All properties are read from gradle.properties file
|
||||
compileSdk propCompileSdkVersion.toInteger()
|
||||
|
||||
ndkVersion '28.2.13676358'
|
||||
compileSdk = propCompileSdkVersion.toInteger()
|
||||
|
||||
defaultConfig {
|
||||
// Default package name is taken from the manifest and should be app.comaps
|
||||
def ver = getVersion()
|
||||
versionCode = ver.V1
|
||||
versionName = ver.V2
|
||||
versionCode = rootProject.ext.versionCode
|
||||
versionName = rootProject.ext.versionName
|
||||
println('Version: ' + versionName)
|
||||
println('VersionCode: ' + versionCode)
|
||||
minSdk propMinSdkVersion.toInteger()
|
||||
targetSdk propTargetSdkVersion.toInteger()
|
||||
minSdk = propMinSdkVersion.toInteger()
|
||||
targetSdk = propTargetSdkVersion.toInteger()
|
||||
applicationId project.ext.appId
|
||||
buildConfigField 'String', 'SUPPORT_MAIL', '"android@comaps.app"'
|
||||
// Should be customized in flavors.
|
||||
buildConfigField 'String', 'REVIEW_URL', '""'
|
||||
|
||||
externalNativeBuild {
|
||||
def pchFlag = 'OFF'
|
||||
if (project.hasProperty('pch')) pchFlag = 'ON'
|
||||
base.archivesName = appName.replaceAll('\\s','') + '-' + defaultConfig.versionCode
|
||||
|
||||
def njobs = ''
|
||||
if (project.hasProperty('njobs')) njobs = project.getProperty('njobs')
|
||||
|
||||
def enableVulkanDiagnostics = 'OFF'
|
||||
if (project.hasProperty('enableVulkanDiagnostics')) {
|
||||
enableVulkanDiagnostics = project.getProperty('enableVulkanDiagnostics')
|
||||
}
|
||||
|
||||
def enableTrace = 'OFF'
|
||||
if (project.hasProperty('enableTrace')) {
|
||||
enableTrace = project.getProperty('enableTrace')
|
||||
}
|
||||
|
||||
cmake {
|
||||
cppFlags '-fexceptions', '-frtti'
|
||||
// There is no sense to enable sections without gcc's --gc-sections flag.
|
||||
cFlags '-fno-function-sections', '-fno-data-sections',
|
||||
'-Wno-extern-c-compat'
|
||||
arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static',
|
||||
"-DOS=$osName", '-DSKIP_TESTS=ON', '-DSKIP_TOOLS=ON', "-DUSE_PCH=$pchFlag",
|
||||
"-DNJOBS=$njobs", "-DENABLE_VULKAN_DIAGNOSTICS=$enableVulkanDiagnostics",
|
||||
"-DENABLE_TRACE=$enableTrace"
|
||||
targets 'organicmaps'
|
||||
}
|
||||
}
|
||||
|
||||
// Use, for example, -Parm32 gradle parameter to build only for armeabi-v7a.
|
||||
ndk {
|
||||
abiFilters = new HashSet<>()
|
||||
if (project.hasProperty('arm32') || project.hasProperty('armeabi-v7a')) {
|
||||
abiFilters.add('armeabi-v7a')
|
||||
}
|
||||
if (project.hasProperty('arm64') || project.hasProperty('arm64-v8a')) {
|
||||
abiFilters.add('arm64-v8a')
|
||||
}
|
||||
if (project.hasProperty('x86')) {
|
||||
abiFilters.add('x86')
|
||||
}
|
||||
if (project.hasProperty('x86_64') || project.hasProperty('x64')) {
|
||||
abiFilters.add('x86_64')
|
||||
}
|
||||
if (abiFilters.isEmpty()) {
|
||||
abiFilters.add('armeabi-v7a')
|
||||
abiFilters.add('arm64-v8a')
|
||||
// For the emulator, chromebooks and some Intel Atom devices.
|
||||
abiFilters.add('x86_64')
|
||||
}
|
||||
println('Building for ' + abiFilters + ' archs.')
|
||||
}
|
||||
|
||||
setProperty('archivesBaseName', appName.replaceAll('\\s','') + '-' + defaultConfig.versionCode)
|
||||
ndk.debugSymbolLevel = 'full'
|
||||
}
|
||||
|
||||
flavorDimensions += 'default'
|
||||
@@ -207,10 +128,10 @@ android {
|
||||
splits.abi {
|
||||
boolean enabled = project.hasProperty('splitApk')
|
||||
println ('Create separate apks: ' + enabled)
|
||||
enable enabled
|
||||
enable = enabled
|
||||
reset()
|
||||
include 'x86', 'armeabi-v7a', 'arm64-v8a', 'x86_64'
|
||||
universalApk true
|
||||
universalApk = true
|
||||
}
|
||||
|
||||
lint {
|
||||
@@ -223,7 +144,7 @@ android {
|
||||
disable 'CustomSplashScreen'
|
||||
// https://github.com/organicmaps/organicmaps/issues/3610
|
||||
disable 'InsecureBaseConfiguration'
|
||||
abortOnError true
|
||||
abortOnError = true
|
||||
}
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
@@ -282,33 +203,29 @@ android {
|
||||
debug {
|
||||
applicationIdSuffix '.debug' // Allows to install debug and release builds together
|
||||
versionNameSuffix '-debug'
|
||||
jniDebuggable true // Enable jni debug build
|
||||
zipAlignEnabled true
|
||||
signingConfig signingConfigs.debug
|
||||
signingConfig = signingConfigs.debug
|
||||
resValue 'string', 'app_name', 'CoMaps Debug'
|
||||
// Do not generate separate debug symbols for debug apps, because we don't distribute them.
|
||||
ndk.debugSymbolLevel = 'none'
|
||||
}
|
||||
|
||||
release {
|
||||
if (taskName.contains('release')) {
|
||||
if (secureReleasePropertiesFileExists) {
|
||||
println('Using RELEASE signing keys from secure.properties.release')
|
||||
signingConfig signingConfigs.release
|
||||
signingConfig = signingConfigs.release
|
||||
} else {
|
||||
println('NO RELEASE signing keys found')
|
||||
println('Using DEBUG signing keys')
|
||||
signingConfig signingConfigs.debug
|
||||
signingConfig = signingConfigs.debug
|
||||
}
|
||||
}
|
||||
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
shrinkResources = true
|
||||
// Includes the default ProGuard rules files that are packaged with the Android Gradle plugin.
|
||||
// To learn more, go to the documentation section about R8 configuration files.
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
resValue 'string', 'app_name', project.ext.appName
|
||||
// Full size symbols are too big for Google, 217mb aab vs 95mb.
|
||||
ndk.debugSymbolLevel = 'symbol_table'
|
||||
}
|
||||
|
||||
beta {
|
||||
@@ -317,37 +234,27 @@ android {
|
||||
if (taskName.contains('beta')) {
|
||||
if (secureTestPropertiesFileExists) {
|
||||
println('Using TEST signing keys from secure.properties.test')
|
||||
signingConfig signingConfigs.test
|
||||
signingConfig = signingConfigs.test
|
||||
} else {
|
||||
println('NO TEST signing keys found')
|
||||
println('Using DEBUG signing keys')
|
||||
signingConfig signingConfigs.debug
|
||||
signingConfig = signingConfigs.debug
|
||||
}
|
||||
}
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
shrinkResources = true
|
||||
// Includes the default ProGuard rules files that are packaged with the Android Gradle plugin.
|
||||
// To learn more, go to the documentation section about R8 configuration files.
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
matchingFallbacks = ['release'] // use dependencies of "release" build type
|
||||
resValue 'string', 'app_name', 'CoMaps Test'
|
||||
// Full size symbols are too big for Google, 217mb aab vs 95mb.
|
||||
ndk.debugSymbolLevel = 'symbol_table'
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version '3.22.1+'
|
||||
buildStagingDirectory './nativeOutputs'
|
||||
path '../../CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
|
||||
// We don't compress these extensions in assets/ because our random FileReader can't read zip-compressed files from apk.
|
||||
// TODO: Load all minor files via separate call to ReadAsString which can correctly handle compressed files in zip containers.
|
||||
androidResources {
|
||||
ignoreAssetsPattern '!.svn:!.git:!.DS_Store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
ignoreAssetsPattern = '!.svn:!.git:!.DS_Store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
noCompress = ['txt', 'bin', 'html', 'png', 'json', 'mwm', 'ttf', 'sdf', 'ui', 'config', 'csv', 'spv', 'obj']
|
||||
localeFilters += [
|
||||
"af",
|
||||
@@ -404,7 +311,7 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
coreLibraryDesugaringEnabled = true
|
||||
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
@@ -412,6 +319,8 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':sdk')
|
||||
|
||||
coreLibraryDesugaring libs.android.tools.desugar
|
||||
|
||||
// Google Play Location Services
|
||||
@@ -457,10 +366,6 @@ dependencies {
|
||||
testImplementation libs.mockito.core
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
|
||||
}
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
def authorityValue = variant.applicationId + ".provider"
|
||||
def authority = "\"" + authorityValue + "\""
|
||||
@@ -508,3 +413,7 @@ huaweiPublish {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 97 KiB |
@@ -0,0 +1 @@
|
||||
সহজ মানচিত্র নেভিগেশন - আপনার যাত্রা সম্পর্কে আরও জানুন - সম্প্রদায় কর্তৃক পরিচালিত
|
||||
1
android/app/src/fdroid/play/listings/bn/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
কোম্যাপস - অফলাইনে হাইকিং, সাইকেলিং এবং ড্রাইভিং করুন গোপনীয়তা সহ
|
||||
@@ -0,0 +1 @@
|
||||
Navegació intuïtiva - Descobreix el teu camí - El poder de la comunitat
|
||||
@@ -0,0 +1,65 @@
|
||||
Una aplicación de mapas gratuita y de código abierto liderada por la comunidad, basada en los datos de OpenStreetMap y reforzada con un compromiso con la transparencia, la privacidad y la ausencia de fines de lucro. CoMaps es un fork o derivado de Organic Maps, que a su vez es un fork de Maps.ME.
|
||||
|
||||
<br><br>
|
||||
|
||||
Lee más sobre los motivos del proyecto y su dirección en <b><i>codeberg.org/comaps</i></b>.
|
||||
|
||||
<br><br>
|
||||
|
||||
Únete allí a la comunidad y ayuda a crear la mejor app de mapas
|
||||
|
||||
• Usa la aplicación y corre la voz sobre ella
|
||||
|
||||
• Envía comentarios y reporta problemas
|
||||
|
||||
• Actualiza los datos del mapa en la app o en el sitio web de OpenStreetMap
|
||||
|
||||
<br><br>
|
||||
|
||||
‣ <b>Enfocada en el uso sin conexión</b>: Planifica y navega tus viajes sin necesidad de conexión móvil, busca puntos de paso en rutas remotas, etc. Todas las funciones están diseñadas para funcionar sin conexión.
|
||||
|
||||
‣ <b>Respeta tu Privacidad</b>: La app está diseñada pensando en tu privacidad: no identifica personas, no rastrea y no recoge datos personales. Sin publicidad.
|
||||
|
||||
‣ <b>Sencilla y Pulida</b>: funciones esenciales fáciles de usar que simplemente funcionan.
|
||||
|
||||
‣ <b>Ahorra Batería y Espacio</b>: No consume la batería como otras apps de navegación. Los mapas compactos ahorran espacio valioso en tu teléfono.
|
||||
|
||||
‣ <b>Gratuita y Creada por la Comunidad</b>: Personas como tú ayudaron a construir la app añadiendo lugares a OpenStreetMap, probando funciones, dando opiniones y contribuyendo con desarrollo o financiación.
|
||||
|
||||
‣ <b>Toma de decisiones y finanzas abiertas y transparentes, sin ánimo de lucro y completamente de código abierto.</b>
|
||||
|
||||
<br><br>
|
||||
|
||||
<b>Funciones Principales</b>:
|
||||
|
||||
• Mapas detallados descargables con lugares que no aparecen en Google Maps
|
||||
|
||||
• Modo exterior con rutas de senderismo destacadas, campings, fuentes de agua, picos, curvas de nivel, etc.
|
||||
|
||||
• Caminos peatonales y carriles bici
|
||||
|
||||
• Puntos de interés como restaurantes, gasolineras, hoteles, tiendas, lugares turísticos y muchos más
|
||||
|
||||
• Búsqueda por nombre, dirección o categoría de punto de interés
|
||||
|
||||
• Navegación con indicaciones por voz para caminar, ir en bici o conducir
|
||||
|
||||
• Guarda tus lugares favoritos con un solo toque
|
||||
|
||||
• Artículos de Wikipedia sin conexión
|
||||
|
||||
• Capa de transporte subterráneo y rutas
|
||||
|
||||
• Grabación de rutas
|
||||
|
||||
• Exporta e importa favoritos y rutas en formatos KML, KMZ y GPX
|
||||
|
||||
• Modo oscuro para usar de noche
|
||||
|
||||
• Mejora los datos del mapa para todos usando un editor básico integrado
|
||||
|
||||
<br><br>
|
||||
|
||||
<b>La Libertad Está Aquí</b>
|
||||
|
||||
Descubre tu camino, navega el mundo con privacidad y con la comunidad como prioridad.
|
||||
@@ -0,0 +1 @@
|
||||
Navegación de mapa fácil - Descubre más en tu camino - Creado por la comunidad
|
||||
1
android/app/src/fdroid/play/listings/es-ES/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps - Senderismo, ciclismo y conducción offline
|
||||
@@ -0,0 +1 @@
|
||||
Navigation facile del mappa – Discoperi tu viage – Alimentate per le communitate
|
||||
@@ -1 +1 @@
|
||||
CoMaps - Mapas com Privacidade
|
||||
CoMaps - Mapas e Navegação Offline com Privacidade
|
||||
|
||||
@@ -8,10 +8,10 @@ import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresPermission;
|
||||
|
||||
import app.organicmaps.sdk.util.LocationUtils;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
import com.google.android.gms.common.api.ApiException;
|
||||
import com.google.android.gms.common.api.ResolvableApiException;
|
||||
import com.google.android.gms.location.FusedLocationProviderClient;
|
||||
@@ -26,9 +26,6 @@ import com.google.android.gms.location.LocationSettingsStatusCodes;
|
||||
import com.google.android.gms.location.Priority;
|
||||
import com.google.android.gms.location.SettingsClient;
|
||||
|
||||
import app.organicmaps.sdk.util.LocationUtils;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
|
||||
class GoogleFusedLocationProvider extends BaseLocationProvider
|
||||
{
|
||||
private static final String TAG = GoogleFusedLocationProvider.class.getSimpleName();
|
||||
@@ -72,71 +69,75 @@ class GoogleFusedLocationProvider extends BaseLocationProvider
|
||||
{
|
||||
Logger.d(TAG);
|
||||
|
||||
final LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval)
|
||||
// Wait a few seconds for accurate locations initially, when accurate locations could not be computed on the device immediately.
|
||||
// https://github.com/organicmaps/organicmaps/issues/2149
|
||||
.setWaitForAccurateLocation(true)
|
||||
// The desired location granularity should correspond to the client permission level. The client will be
|
||||
// delivered fine locations while it has the Manifest.permission.ACCESS_FINE_LOCATION permission, coarse
|
||||
// locations while it has only the Manifest.permission.ACCESS_COARSE_LOCATION permission, and no location
|
||||
// if it lacks either.
|
||||
.setGranularity(Granularity.GRANULARITY_PERMISSION_LEVEL)
|
||||
// Sets the maximum age of an initial historical location delivered for this request.
|
||||
.setMaxUpdateAgeMillis(60 * 60 * 1000L) // 1 hour
|
||||
.build();
|
||||
final LocationRequest locationRequest =
|
||||
new LocationRequest
|
||||
.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval)
|
||||
// Wait a few seconds for accurate locations initially, when accurate locations could not be computed on the
|
||||
// device immediately. https://github.com/organicmaps/organicmaps/issues/2149
|
||||
.setWaitForAccurateLocation(true)
|
||||
// The desired location granularity should correspond to the client permission level. The client will be
|
||||
// delivered fine locations while it has the Manifest.permission.ACCESS_FINE_LOCATION permission, coarse
|
||||
// locations while it has only the Manifest.permission.ACCESS_COARSE_LOCATION permission, and no location
|
||||
// if it lacks either.
|
||||
.setGranularity(Granularity.GRANULARITY_PERMISSION_LEVEL)
|
||||
// Sets the maximum age of an initial historical location delivered for this request.
|
||||
.setMaxUpdateAgeMillis(60 * 60 * 1000L) // 1 hour
|
||||
.build();
|
||||
|
||||
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
|
||||
builder.addLocationRequest(locationRequest);
|
||||
builder.setAlwaysShow(true); // improves the wording/appearance of the dialog
|
||||
final LocationSettingsRequest locationSettingsRequest = builder.build();
|
||||
|
||||
mSettingsClient.checkLocationSettings(locationSettingsRequest).addOnSuccessListener(locationSettingsResponse -> {
|
||||
Logger.d(TAG, "Service is available");
|
||||
mFusedLocationClient.requestLocationUpdates(locationRequest, mCallback, Looper.myLooper());
|
||||
}).addOnFailureListener(e -> {
|
||||
try
|
||||
{
|
||||
int statusCode = ((ApiException) e).getStatusCode();
|
||||
if (statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED)
|
||||
{
|
||||
// This case happens if at least one of the following system settings is off:
|
||||
// 1. Location Services a.k.a GPS;
|
||||
// 2. Google Location Accuracy a.k.a High Accuracy;
|
||||
// 3. Both Wi-Fi && Mobile Data together (needed for 2).
|
||||
//
|
||||
// PendingIntent below will show a special Google "For better experience... enable (1) and/or (2) and/or (3)"
|
||||
// dialog. This system dialog can change system settings if "Yes" is pressed. We can't do it from our app.
|
||||
// However, we don't want to annoy a user who disabled (2) or (3) intentionally. GPS (1) is mandatory to
|
||||
// continue, while (2) and (3) are not dealbreakers here.
|
||||
//
|
||||
// See https://github.com/organicmaps/organicmaps/issues/3846
|
||||
//
|
||||
if (LocationUtils.areLocationServicesTurnedOn(mContext))
|
||||
mSettingsClient.checkLocationSettings(locationSettingsRequest)
|
||||
.addOnSuccessListener(locationSettingsResponse -> {
|
||||
Logger.d(TAG, "Service is available");
|
||||
mFusedLocationClient.requestLocationUpdates(locationRequest, mCallback, Looper.myLooper());
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
try
|
||||
{
|
||||
Logger.d(TAG, "Don't show 'location resolution' dialog because location services are already on");
|
||||
mFusedLocationClient.requestLocationUpdates(locationRequest, mCallback, Looper.myLooper());
|
||||
return;
|
||||
int statusCode = ((ApiException) e).getStatusCode();
|
||||
if (statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED)
|
||||
{
|
||||
// This case happens if at least one of the following system settings is off:
|
||||
// 1. Location Services a.k.a GPS;
|
||||
// 2. Google Location Accuracy a.k.a High Accuracy;
|
||||
// 3. Both Wi-Fi && Mobile Data together (needed for 2).
|
||||
//
|
||||
// PendingIntent below will show a special Google "For better experience... enable (1) and/or (2) and/or
|
||||
// (3)" dialog. This system dialog can change system settings if "Yes" is pressed. We can't do it from our
|
||||
// app. However, we don't want to annoy a user who disabled (2) or (3) intentionally. GPS (1) is mandatory
|
||||
// to continue, while (2) and (3) are not dealbreakers here.
|
||||
//
|
||||
// See https://github.com/organicmaps/organicmaps/issues/3846
|
||||
//
|
||||
if (LocationUtils.areLocationServicesTurnedOn(mContext))
|
||||
{
|
||||
Logger.d(TAG, "Don't show 'location resolution' dialog because location services are already on");
|
||||
mFusedLocationClient.requestLocationUpdates(locationRequest, mCallback, Looper.myLooper());
|
||||
return;
|
||||
}
|
||||
Logger.d(TAG, "Requesting 'location resolution' dialog");
|
||||
final ResolvableApiException resolvable = (ResolvableApiException) e;
|
||||
final PendingIntent pendingIntent = resolvable.getResolution();
|
||||
// Call this callback in the next event loop to allow LocationHelper::start() to finish.
|
||||
runLater(() -> mListener.onLocationResolutionRequired(pendingIntent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
Logger.d(TAG, "Requesting 'location resolution' dialog");
|
||||
final ResolvableApiException resolvable = (ResolvableApiException) e;
|
||||
final PendingIntent pendingIntent = resolvable.getResolution();
|
||||
catch (ClassCastException ex)
|
||||
{
|
||||
// Ignore, should be an impossible error.
|
||||
// https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
|
||||
Logger.e(TAG, "An error that should be impossible: " + ex);
|
||||
}
|
||||
// Location settings are not satisfied. However, we have no way to fix the
|
||||
// settings so we won't show the dialog.
|
||||
Logger.e(TAG, "Service is not available: " + e);
|
||||
// Call this callback in the next event loop to allow LocationHelper::start() to finish.
|
||||
runLater(() -> mListener.onLocationResolutionRequired(pendingIntent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ClassCastException ex)
|
||||
{
|
||||
// Ignore, should be an impossible error.
|
||||
// https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
|
||||
Logger.e(TAG, "An error that should be impossible: " + ex);
|
||||
}
|
||||
// Location settings are not satisfied. However, we have no way to fix the
|
||||
// settings so we won't show the dialog.
|
||||
Logger.e(TAG, "Service is not available: " + e);
|
||||
// Call this callback in the next event loop to allow LocationHelper::start() to finish.
|
||||
runLater(mListener::onFusedLocationUnsupported);
|
||||
});
|
||||
runLater(mListener::onFusedLocationUnsupported);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package app.organicmaps.sdk.location;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
|
||||
import app.organicmaps.sdk.util.Config;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
|
||||
public class LocationProviderFactory
|
||||
{
|
||||
@@ -18,7 +16,8 @@ public class LocationProviderFactory
|
||||
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static BaseLocationProvider getProvider(@NonNull Context context, @NonNull BaseLocationProvider.Listener listener)
|
||||
public static BaseLocationProvider getProvider(@NonNull Context context,
|
||||
@NonNull BaseLocationProvider.Listener listener)
|
||||
{
|
||||
if (isGoogleLocationAvailable(context) && Config.useGoogleServices())
|
||||
{
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
সহজ মানচিত্র নেভিগেশন - আপনার যাত্রা সম্পর্কে আরও জানুন - সম্প্রদায় কর্তৃক পরিচালিত
|
||||
1
android/app/src/google/play/listings/bn/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps - গোপনীয়তা সহ যাতায়াত
|
||||
36
android/app/src/google/play/listings/ca/full-description.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
CoMaps és una aplicació de mapes lliure i de codi obert a càrrec de la comunitat que es basa en les dades OpenStreetMap i es fonamenta en el compromís amb la transparència i la privadesa sense ànim de lucre.
|
||||
|
||||
Uneix-te a la comunitat i ajuda a crear la millor aplicació de mapes.
|
||||
• Fes servir l'aplicació i recomana-la.
|
||||
• Dona la teva opinió i comunica qualsevol problema.
|
||||
• Actualitza les dades de mapes a l'aplicació o al web d'OpenStreetMap.
|
||||
|
||||
<i>Els teus comentaris i les valoracions de 5 estrelles són el que més ens ajuda.</i>
|
||||
|
||||
‣ <b>Disseny senzill i polit</b>: funcions bàsiques i fàcils de fer servir que funcionen i punt.
|
||||
‣ <b>Centrada en l'ús sense connexió</b>: planifica viatges a l'estranger i navega sense haver d'accedir a les dades mòbils o cerca punts d'interès durant rutes d'excursionisme llargues. Totes les funcions de l'aplicació s'han dissenyat perquè funcionin sense connexió.
|
||||
‣ <b>Respecte per la privadesa</b>: el disseny de l'aplicació prioritza la privadesa. No t'identifica, no fa cap seguiment i no recull dades personals. A més, no té anuncis.
|
||||
‣ <b>Ús eficient de la bateria i l'espai</b>: consumeix menys bateria que altres aplicacions de navegació. Els mapes compactes ocupen molt poc espai al telèfon.
|
||||
‣ <b>Lliure gràcies a la comunitat</b>: aquesta aplicació s'ha desenvolupat gràcies a persones com tu que han afegit llocs a OpenStreetMap, han provat funcions, n'han aportat comentaris i hi han contribuït amb diners i esforç.
|
||||
‣ <b>És un projecte obert i transparent en les seves decisions i finances. No té cap ànim de lucre i és completament de codi obert.</b>
|
||||
|
||||
<b>Funcions principals</b>:
|
||||
• Mapes detallats que es poden baixar i inclouen llocs que no apareixen a Google Maps
|
||||
• Mode exterior en què es ressalten les rutes d'excursionisme, els llocs d'acampada, les fonts d'aigua, els pics i les línies de contorn, entre altres coses
|
||||
• Zones per a vianants i carrils bici
|
||||
• Punts d'interès, com ara restaurants, benzineres, hotels, botigues, atraccions turístiques i molt més
|
||||
• Cerques per nom, adreça o categoria de punt d'interès
|
||||
• Navegació amb indicacions per veu mentre camines, vas amb bicicleta o condueixes
|
||||
• Adreces d'interès perquè desis els teus llocs preferits amb un toc
|
||||
• Articles de Wikipedia sense connexió
|
||||
• Capa de línies de metro amb direccions
|
||||
• Enregistrament d'itineraris
|
||||
• Exportació i importació d'adreces d'interès i itineraris en els formats KML, KMZ i GPX
|
||||
• Mode fosc per fer servir l'aplicació a la nit
|
||||
• Millora de les dades de mapes per a tothom amb un editor integrat bàsic
|
||||
• Compatibilitat amb Android Auto
|
||||
|
||||
Pots informar de problemes a l'aplicació, suggerir idees i unir-te a la comunitat al web <b><i>comaps.app</i></b>.
|
||||
|
||||
<b>La llibertat ha arribat</b>
|
||||
Descobreix el teu camí i explora el món amb la privadesa i la comunitat com a eix central!
|
||||
@@ -0,0 +1 @@
|
||||
Navegació intuïtiva - Descobreix el teu camí - El poder de la comunitat
|
||||
1
android/app/src/google/play/listings/ca/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps – Navega amb privadesa
|
||||
@@ -0,0 +1,36 @@
|
||||
En fællesskabsdrevet gratis og open source-kortapp baseret på OpenStreetMap-data og forstærket med en forpligtelse til gennemsigtighed, privatliv og non-profit.
|
||||
|
||||
Bliv en del af fællesskabet og vær med til at skabe den bedste kortapp
|
||||
• Brug appen og fortæl andre om den
|
||||
• Giv feedback og rapporter problemer
|
||||
• Opdater kortdata i appen eller på OpenStreetMap-webstedet
|
||||
|
||||
<i>Din feedback og 5-stjernede anmeldelser er den bedste støtte for os!</i>
|
||||
|
||||
‣ <b>Enkel og poleret</b>: væsentlige, brugervenlige funktioner, der bare virker.
|
||||
‣ <b>Offline-focused</b>: Planlæg og naviger på din rejse i udlandet uden behov for mobilfordbindelse, søg efter rutepunkter, mens du er på en lang vandretur osv. Alle app-funktioner er designet til at fungere offline..
|
||||
‣ <b>Respekt for privatlivets fred</b>: Appen er designet med fokus på privatlivets fred – den identificerer ikke personer, sporer ikke og indsamler ikke personlige oplysninger. Annoncefri.
|
||||
‣ <b>Sparer på batteriet og plads</b>: Dræner ikke dit batteri som andre navigationsapps. Kompakte kort sparer værdifuld plads på din telefon.
|
||||
‣ <b>Gratis og udviklet af fællesskabet</b>: Folk som dig har været med til at udvikle appen ved at tilføje steder til OpenStreetMap, teste og give feedback på funktioner samt bidrage med deres udviklingskompetencer og penge.
|
||||
‣ <b>Åben og gennemsigtig beslutningstagning og økonomi, non-profit og fuldstændig open source.</b>
|
||||
|
||||
<b>Vigtigste funktioner</b>:
|
||||
• Detaljerede kort med steder, der ikke er tilgængelige på Google Maps, kan downloades.
|
||||
• Udendørstilstand med fremhævede vandreruter, campingpladser, vandkilder, bjergtoppe, højdekurver osv.
|
||||
• Gang- og cykelstier
|
||||
• Interessepunkter som restauranter, tankstationer, hoteller, butikker, seværdigheder og meget mere
|
||||
• Søg efter navn, adresse eller efter interessepunkt-kategori
|
||||
• Navigation med stemmevejledning til gående, cyklende eller kørende
|
||||
• Bogmærk dine yndlingssteder med ét enkelt tryk
|
||||
• Offline Wikipedia-artikler
|
||||
• Lag med metrolinjer og rutevejledning
|
||||
• Sporoptagelse
|
||||
• Eksportér og importér bogmærker og ruter i KML, KMZ, GPX-formater
|
||||
• En mørk tilstand til brug om natten
|
||||
• Forbedr kortdata for alle ved hjælp af en simpel, indbygget redigeringsfunktion
|
||||
• Android Auto-understøttelse
|
||||
|
||||
Rapportér app-problemer, kom med forslag og bliv en del af vores fællesskab på <b><i>comaps.app</i></b> webstedet.
|
||||
|
||||
<b>Nu med frihed</b>
|
||||
Udforsk din rejse, og navigér i verden med fokus på privatliv og fællesskab!
|
||||
1
android/app/src/google/play/listings/da-DK/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps - Naviger med privatliv
|
||||
@@ -0,0 +1,71 @@
|
||||
Una aplicación de mapas gratuita y de código abierto liderada por la comunidad, basada en los datos de OpenStreetMap y reforzada con un compromiso con la transparencia, la privacidad y la ausencia de fines de lucro.
|
||||
|
||||
<br><br>
|
||||
|
||||
Únete a la comunidad y ayuda a crear la mejor app de mapas
|
||||
|
||||
• Usa la aplicación y corre la voz sobre ella
|
||||
|
||||
• Envía comentarios y reporta problemas
|
||||
|
||||
• Actualiza los datos del mapa en la app o en el sitio web de OpenStreetMap
|
||||
|
||||
<br><br>
|
||||
|
||||
<i>¡Tus comentarios y valoraciones de 5 estrellas son el mejor apoyo para nosotros!</i>
|
||||
|
||||
<br><br>
|
||||
|
||||
‣ <b>Sencilla y Pulida</b>: funciones esenciales fáciles de usar que simplemente funcionan.
|
||||
|
||||
‣ <b>Enfocada en el uso sin conexión</b>: Planifica y navega tus viajes sin necesidad de conexión móvil, busca puntos de paso en rutas remotas, etc. Todas las funciones están diseñadas para funcionar sin conexión.
|
||||
|
||||
‣ <b>Respeta tu Privacidad</b>: La app está diseñada pensando en tu privacidad: no identifica personas, no rastrea y no recoge datos personales. Sin publicidad.
|
||||
|
||||
‣ <b>Ahorra Batería y Espacio</b>: No consume la batería como otras apps de navegación. Los mapas compactos ahorran espacio valioso en tu teléfono.
|
||||
|
||||
‣ <b>Gratuita y Creada por la Comunidad</b>: Personas como tú ayudaron a construir la app añadiendo lugares a OpenStreetMap, probando funciones, dando opiniones y contribuyendo con desarrollo o financiación.
|
||||
|
||||
‣ <b>Toma de decisiones y finanzas abiertas y transparentes, sin ánimo de lucro y completamente de código abierto.</b>
|
||||
|
||||
<br><br>
|
||||
|
||||
<b>Funciones Principales</b>:
|
||||
|
||||
• Mapas detallados descargables con lugares que no aparecen en Google Maps
|
||||
|
||||
• Modo exterior con rutas de senderismo destacadas, campings, fuentes de agua, picos, curvas de nivel, etc.
|
||||
|
||||
• Caminos peatonales y carriles bici
|
||||
|
||||
• Puntos de interés como restaurantes, gasolineras, hoteles, tiendas, lugares turísticos y muchos más
|
||||
|
||||
• Búsqueda por nombre, dirección o categoría de punto de interés
|
||||
|
||||
• Navegación con indicaciones por voz para caminar, ir en bici o conducir
|
||||
|
||||
• Guarda tus lugares favoritos con un solo toque
|
||||
|
||||
• Artículos de Wikipedia sin conexión
|
||||
|
||||
• Capa de transporte subterráneo y rutas
|
||||
|
||||
• Grabación de rutas
|
||||
|
||||
• Exporta e importa favoritos y rutas en formatos KML, KMZ y GPX
|
||||
|
||||
• Modo oscuro para usar de noche
|
||||
|
||||
• Mejora los datos del mapa para todos usando un editor básico integrado
|
||||
|
||||
• Compatibilidad con Android Auto
|
||||
|
||||
<br><br>
|
||||
|
||||
Por favor, informa de errores, sugiere ideas y únete a nuestra comunidad en el sitio web <b><i>comaps.app</i></b>.
|
||||
|
||||
<br><br>
|
||||
|
||||
<b>La Libertad Está Aquí</b>
|
||||
|
||||
Descubre tu camino, navega el mundo con privacidad y con la comunidad como prioridad.
|
||||
@@ -0,0 +1 @@
|
||||
Navegación de mapa fácil - Descubre más en tu camino - Creado por la comunidad
|
||||
1
android/app/src/google/play/listings/es-ES/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps - Navega con Privacidad
|
||||
@@ -1 +1 @@
|
||||
Navigation cartographique facile - Propulsé par la communauté
|
||||
Navigation cartographique facile - Découvrez davantage de votre voyage - Propulsé par la communauté
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Navigation facile del mappa – Discoperi tu viage – Alimentate per le communitate
|
||||
1
android/app/src/google/play/listings/ia/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps – Naviga private
|
||||
@@ -1 +1 @@
|
||||
CoMaps - Navegue privadamente
|
||||
CoMaps - Navegue Privadamente
|
||||
|
||||
@@ -1 +1 @@
|
||||
CoMaps - Оффлайн навигация
|
||||
CoMaps - Приватная навигация
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
android:backupInForeground="true"
|
||||
android:fullBackupContent="@xml/backup_content"
|
||||
android:dataExtractionRules="@xml/backup_content_v31"
|
||||
android:enableOnBackInvokedCallback="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
@@ -376,6 +377,7 @@
|
||||
|
||||
<activity
|
||||
android:name="app.organicmaps.downloader.DownloaderActivity"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:configChanges="orientation|screenLayout|screenSize"
|
||||
android:screenOrientation="fullUser"
|
||||
android:label="@string/download_maps"
|
||||
|
||||
@@ -5,10 +5,16 @@ import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import app.organicmaps.sdk.Framework;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
|
||||
import app.organicmaps.util.ThemeUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.widget.placepage.AxisValueFormatter;
|
||||
import app.organicmaps.widget.placepage.CurrentLocationMarkerView;
|
||||
import app.organicmaps.widget.placepage.FloatingMarkerView;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
import com.github.mikephil.charting.components.MarkerView;
|
||||
@@ -20,16 +26,6 @@ import com.github.mikephil.charting.data.LineDataSet;
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter;
|
||||
import com.github.mikephil.charting.highlight.Highlight;
|
||||
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
|
||||
|
||||
import app.organicmaps.sdk.Framework;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
|
||||
import app.organicmaps.widget.placepage.AxisValueFormatter;
|
||||
import app.organicmaps.widget.placepage.CurrentLocationMarkerView;
|
||||
import app.organicmaps.widget.placepage.FloatingMarkerView;
|
||||
import app.organicmaps.util.ThemeUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -151,7 +147,7 @@ public class ChartController implements OnChartValueSelectedListener,
|
||||
mTrackId = info.getId();
|
||||
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()));
|
||||
|
||||
LineDataSet set = new LineDataSet(values, "Elevation_profile_points");
|
||||
@@ -184,15 +180,15 @@ public class ChartController implements OnChartValueSelectedListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValueSelected(Entry e, Highlight h) {
|
||||
public void onValueSelected(Entry e, Highlight h)
|
||||
{
|
||||
mFloatingMarkerView.updateOffsets(e, h);
|
||||
Highlight curPos = getCurrentPosHighlight();
|
||||
|
||||
if (mCurrentPositionOutOfTrack)
|
||||
mChart.highlightValues(Collections.singletonList(h), Collections.singletonList(mFloatingMarkerView));
|
||||
else
|
||||
mChart.highlightValues(Arrays.asList(curPos, h), Arrays.asList(mCurrentLocationMarkerView,
|
||||
mFloatingMarkerView));
|
||||
mChart.highlightValues(Arrays.asList(curPos, h), Arrays.asList(mCurrentLocationMarkerView, mFloatingMarkerView));
|
||||
if (mTrackId == Utils.INVALID_ID)
|
||||
return;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.CallSuper;
|
||||
@@ -28,10 +27,10 @@ import androidx.annotation.StringRes;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import app.organicmaps.base.BaseMwmFragmentActivity;
|
||||
import app.organicmaps.intent.Factory;
|
||||
import app.organicmaps.sdk.Framework;
|
||||
import app.organicmaps.sdk.downloader.CountryItem;
|
||||
import app.organicmaps.sdk.downloader.MapManager;
|
||||
import app.organicmaps.intent.Factory;
|
||||
import app.organicmaps.sdk.location.LocationListener;
|
||||
import app.organicmaps.sdk.util.Config;
|
||||
import app.organicmaps.sdk.util.ConnectionState;
|
||||
@@ -39,13 +38,11 @@ import app.organicmaps.sdk.util.StringUtils;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator;
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -81,10 +78,9 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
|
||||
private int mCountryDownloadListenerSlot;
|
||||
|
||||
private final LocationListener mLocationListener = new LocationListener()
|
||||
{
|
||||
private final LocationListener mLocationListener = new LocationListener() {
|
||||
@Override
|
||||
public void onLocationUpdated(Location location)
|
||||
public void onLocationUpdated(@NonNull Location location)
|
||||
{
|
||||
if (mCurrentCountry != null)
|
||||
return;
|
||||
@@ -117,34 +113,33 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
}
|
||||
};
|
||||
|
||||
private final app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener mResourcesDownloadListener = new app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onProgress(final int percent)
|
||||
{
|
||||
if (!isFinishing())
|
||||
mProgress.setProgressCompat(percent, true);
|
||||
}
|
||||
private final app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener mResourcesDownloadListener =
|
||||
new app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener() {
|
||||
@Override
|
||||
public void onProgress(final int percent)
|
||||
{
|
||||
if (!isFinishing())
|
||||
mProgress.setProgressCompat(percent, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(final int errorCode)
|
||||
{
|
||||
if (isFinishing())
|
||||
return;
|
||||
@Override
|
||||
public void onFinish(final int errorCode)
|
||||
{
|
||||
if (isFinishing())
|
||||
return;
|
||||
|
||||
if (errorCode == ERR_DOWNLOAD_SUCCESS)
|
||||
{
|
||||
final int res = nativeStartNextFileDownload(mResourcesDownloadListener);
|
||||
if (res == ERR_NO_MORE_FILES)
|
||||
finishFilesDownload(res);
|
||||
}
|
||||
else
|
||||
finishFilesDownload(errorCode);
|
||||
}
|
||||
};
|
||||
if (errorCode == ERR_DOWNLOAD_SUCCESS)
|
||||
{
|
||||
final int res = nativeStartNextFileDownload(mResourcesDownloadListener);
|
||||
if (res == ERR_NO_MORE_FILES)
|
||||
finishFilesDownload(res);
|
||||
}
|
||||
else
|
||||
finishFilesDownload(errorCode);
|
||||
}
|
||||
};
|
||||
|
||||
private final MapManager.StorageCallback mCountryDownloadListener = new MapManager.StorageCallback()
|
||||
{
|
||||
private final MapManager.StorageCallback mCountryDownloadListener = new MapManager.StorageCallback() {
|
||||
@Override
|
||||
public void onStatusChanged(List<MapManager.StorageCallbackData> data)
|
||||
{
|
||||
@@ -155,14 +150,14 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
|
||||
switch (item.newStatus)
|
||||
{
|
||||
case CountryItem.STATUS_DONE:
|
||||
mAreResourcesDownloaded = true;
|
||||
showMap();
|
||||
return;
|
||||
case CountryItem.STATUS_DONE:
|
||||
mAreResourcesDownloaded = true;
|
||||
showMap();
|
||||
return;
|
||||
|
||||
case CountryItem.STATUS_FAILED:
|
||||
MapManager.showError(DownloadResourcesLegacyActivity.this, item, null);
|
||||
return;
|
||||
case CountryItem.STATUS_FAILED:
|
||||
MapManager.showError(DownloadResourcesLegacyActivity.this, item, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,8 +232,7 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
|
||||
private void setDownloadMessage(int bytesToDownload)
|
||||
{
|
||||
mTvMessage.setText(getString(R.string.download_resources,
|
||||
StringUtils.getFileSizeString(this, bytesToDownload)));
|
||||
mTvMessage.setText(getString(R.string.download_resources, StringUtils.getFileSizeString(this, bytesToDownload)));
|
||||
}
|
||||
|
||||
private boolean prepareFilesDownload(boolean showMap)
|
||||
@@ -375,7 +369,7 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
CountryItem item = CountryItem.fill(mCurrentCountry);
|
||||
String fileSizeString = StringUtils.getFileSizeString(this, item.totalSize);
|
||||
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);
|
||||
|
||||
mCountryDownloadListenerSlot = MapManager.nativeSubscribe(mCountryDownloadListener);
|
||||
@@ -399,8 +393,10 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
if (mAlertDialog != null && mAlertDialog.isShowing())
|
||||
return;
|
||||
|
||||
@StringRes final int titleId;
|
||||
@StringRes final int messageId = switch (result)
|
||||
@StringRes
|
||||
final int titleId;
|
||||
@StringRes
|
||||
final int messageId = switch (result)
|
||||
{
|
||||
case ERR_NOT_ENOUGH_FREE_SPACE ->
|
||||
{
|
||||
@@ -415,8 +411,8 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
case ERR_DOWNLOAD_ERROR ->
|
||||
{
|
||||
titleId = R.string.connection_failure;
|
||||
yield (ConnectionState.INSTANCE.isConnected() ? R.string.download_has_failed
|
||||
: R.string.common_check_internet_connection_dialog);
|
||||
yield(ConnectionState.INSTANCE.isConnected() ? R.string.download_has_failed
|
||||
: R.string.common_check_internet_connection_dialog);
|
||||
}
|
||||
case ERR_DISK_ERROR ->
|
||||
{
|
||||
@@ -426,17 +422,18 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
default -> throw new AssertionError("Unexpected result code = " + result);
|
||||
};
|
||||
|
||||
mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
|
||||
.setTitle(titleId)
|
||||
.setMessage(messageId)
|
||||
.setCancelable(true)
|
||||
.setOnCancelListener((dialog) -> setAction(PAUSE))
|
||||
.setPositiveButton(R.string.try_again, (dialog, which) -> {
|
||||
setAction(TRY_AGAIN);
|
||||
onTryAgainClicked();
|
||||
})
|
||||
.setOnDismissListener(dialog -> mAlertDialog = null)
|
||||
.show();
|
||||
mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
|
||||
.setTitle(titleId)
|
||||
.setMessage(messageId)
|
||||
.setCancelable(true)
|
||||
.setOnCancelListener((dialog) -> setAction(PAUSE))
|
||||
.setPositiveButton(R.string.try_again,
|
||||
(dialog, which) -> {
|
||||
setAction(TRY_AGAIN);
|
||||
onTryAgainClicked();
|
||||
})
|
||||
.setOnDismissListener(dialog -> mAlertDialog = null)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,17 +10,14 @@ import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.res.ConfigurationHelper;
|
||||
|
||||
import app.organicmaps.base.BaseMwmFragment;
|
||||
import app.organicmaps.sdk.display.DisplayType;
|
||||
import app.organicmaps.sdk.Map;
|
||||
import app.organicmaps.sdk.MapRenderingListener;
|
||||
import app.organicmaps.sdk.display.DisplayType;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
public class MapFragment extends BaseMwmFragment implements View.OnTouchListener, SurfaceHolder.Callback
|
||||
@@ -71,7 +68,8 @@ public class MapFragment extends BaseMwmFragment implements View.OnTouchListener
|
||||
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height)
|
||||
{
|
||||
Logger.d(TAG);
|
||||
mMap.onSurfaceChanged(requireContext(), surfaceHolder.getSurface(), surfaceHolder.getSurfaceFrame(), surfaceHolder.isCreating());
|
||||
mMap.onSurfaceChanged(requireContext(), surfaceHolder.getSurface(), surfaceHolder.getSurfaceFrame(),
|
||||
surfaceHolder.isCreating());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,10 +2,8 @@ package app.organicmaps;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.organicmaps.base.BaseMwmFragmentActivity;
|
||||
import app.organicmaps.sdk.display.DisplayChangedListener;
|
||||
import app.organicmaps.sdk.display.DisplayManager;
|
||||
@@ -24,7 +22,7 @@ public class MapPlaceholderActivity extends BaseMwmFragmentActivity implements D
|
||||
super.onSafeCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_map_placeholder);
|
||||
|
||||
mDisplayManager = DisplayManager.from(this);
|
||||
mDisplayManager = MwmApplication.from(this).getDisplayManager();
|
||||
mDisplayManager.addListener(DisplayType.Device, this);
|
||||
|
||||
findViewById(R.id.btn_continue).setOnClickListener((unused) -> mDisplayManager.changeDisplay(DisplayType.Device));
|
||||
@@ -34,8 +32,7 @@ public class MapPlaceholderActivity extends BaseMwmFragmentActivity implements D
|
||||
public void onDisplayChangedToDevice(@NonNull Runnable onTaskFinishedCallback)
|
||||
{
|
||||
mRemoveDisplayListener = false;
|
||||
startActivity(new Intent(this, MwmActivity.class)
|
||||
.putExtra(MwmActivity.EXTRA_UPDATE_THEME, true));
|
||||
startActivity(new Intent(this, MwmActivity.class).putExtra(MwmActivity.EXTRA_UPDATE_THEME, true));
|
||||
finish();
|
||||
onTaskFinishedCallback.run();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
@@ -15,30 +14,26 @@ import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import app.organicmaps.background.OsmUploadWork;
|
||||
import app.organicmaps.downloader.Android7RootCertificateWorkaround;
|
||||
import app.organicmaps.downloader.DownloaderNotifier;
|
||||
import app.organicmaps.sdk.display.DisplayManager;
|
||||
import app.organicmaps.location.TrackRecordingService;
|
||||
import app.organicmaps.routing.NavigationService;
|
||||
import app.organicmaps.routing.RoutingController;
|
||||
import app.organicmaps.sdk.Map;
|
||||
import app.organicmaps.sdk.OrganicMaps;
|
||||
import app.organicmaps.sdk.display.DisplayManager;
|
||||
import app.organicmaps.sdk.location.LocationHelper;
|
||||
import app.organicmaps.sdk.location.LocationState;
|
||||
import app.organicmaps.sdk.location.SensorHelper;
|
||||
import app.organicmaps.sdk.location.TrackRecorder;
|
||||
import app.organicmaps.location.TrackRecordingService;
|
||||
import app.organicmaps.sdk.maplayer.isolines.IsolinesManager;
|
||||
import app.organicmaps.sdk.maplayer.subway.SubwayManager;
|
||||
import app.organicmaps.routing.NavigationService;
|
||||
import app.organicmaps.routing.RoutingController;
|
||||
import app.organicmaps.sdk.OrganicMaps;
|
||||
import app.organicmaps.sdk.util.Config;
|
||||
import app.organicmaps.sdk.util.ConnectionState;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
import app.organicmaps.sdk.util.log.LogsManager;
|
||||
import app.organicmaps.util.Utils;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class MwmApplication extends Application implements Application.ActivityLifecycleCallbacks
|
||||
{
|
||||
@@ -56,6 +51,10 @@ public class MwmApplication extends Application implements Application.ActivityL
|
||||
@Nullable
|
||||
private WeakReference<Activity> mTopActivity;
|
||||
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
@NonNull
|
||||
public static MwmApplication sInstance;
|
||||
|
||||
@UiThread
|
||||
@Nullable
|
||||
public Activity getTopActivity()
|
||||
@@ -105,13 +104,10 @@ public class MwmApplication extends Application implements Application.ActivityL
|
||||
return (MwmApplication) context.getApplicationContext();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static MwmApplication sInstance;
|
||||
|
||||
@NonNull
|
||||
public static SharedPreferences prefs(@NonNull Context context)
|
||||
{
|
||||
return context.getSharedPreferences(context.getString(R.string.pref_file_name), MODE_PRIVATE);
|
||||
return from(context).getOrganicMaps().getPreferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,10 +120,6 @@ public class MwmApplication extends Application implements Application.ActivityL
|
||||
|
||||
mOrganicMaps = new OrganicMaps(getApplicationContext());
|
||||
|
||||
LogsManager.INSTANCE.initFileLogging(this);
|
||||
|
||||
Android7RootCertificateWorkaround.initializeIfNeeded(this);
|
||||
|
||||
ConnectionState.INSTANCE.initialize(this);
|
||||
|
||||
DownloaderNotifier.createNotificationChannel(this);
|
||||
@@ -146,8 +138,7 @@ public class MwmApplication extends Application implements Application.ActivityL
|
||||
});
|
||||
}
|
||||
|
||||
private final LifecycleObserver mProcessLifecycleObserver = new DefaultLifecycleObserver()
|
||||
{
|
||||
private final LifecycleObserver mProcessLifecycleObserver = new DefaultLifecycleObserver() {
|
||||
@Override
|
||||
public void onStart(@NonNull LifecycleOwner owner)
|
||||
{
|
||||
|
||||
@@ -5,21 +5,19 @@ import android.animation.ValueAnimator;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
|
||||
import androidx.annotation.IntegerRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import org.chromium.base.ObserverList;
|
||||
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import org.chromium.base.ObserverList;
|
||||
|
||||
class PanelAnimator
|
||||
{
|
||||
private final MwmActivity mActivity;
|
||||
private final ObserverList<MwmActivity.LeftAnimationTrackListener> mAnimationTrackListeners = new ObserverList<>();
|
||||
private final ObserverList.RewindableIterator<MwmActivity.LeftAnimationTrackListener> mAnimationTrackIterator = mAnimationTrackListeners.rewindableIterator();
|
||||
private final ObserverList.RewindableIterator<MwmActivity.LeftAnimationTrackListener> mAnimationTrackIterator =
|
||||
mAnimationTrackListeners.rewindableIterator();
|
||||
private final View mPanel;
|
||||
private final int mWidth;
|
||||
@IntegerRes
|
||||
@@ -50,7 +48,8 @@ class PanelAnimator
|
||||
}
|
||||
|
||||
/** @param completionListener will be called before the fragment becomes actually visible */
|
||||
public void show(final Class<? extends Fragment> clazz, final Bundle args, @Nullable final Runnable completionListener)
|
||||
public void show(final Class<? extends Fragment> clazz, final Bundle args,
|
||||
@Nullable final Runnable completionListener)
|
||||
{
|
||||
if (isVisible())
|
||||
{
|
||||
@@ -78,8 +77,7 @@ class PanelAnimator
|
||||
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(-mWidth, 0.0f);
|
||||
animator.addUpdateListener(this::track);
|
||||
animator.addListener(new UiUtils.SimpleAnimatorListener()
|
||||
{
|
||||
animator.addListener(new UiUtils.SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation)
|
||||
{
|
||||
@@ -109,8 +107,7 @@ class PanelAnimator
|
||||
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(0.0f, -mWidth);
|
||||
animator.addUpdateListener(this::track);
|
||||
animator.addListener(new UiUtils.SimpleAnimatorListener()
|
||||
{
|
||||
animator.addListener(new UiUtils.SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.Keep;
|
||||
@@ -21,20 +20,18 @@ import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.OnApplyWindowInsetsListener;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import app.organicmaps.sdk.display.DisplayManager;
|
||||
import app.organicmaps.downloader.DownloaderActivity;
|
||||
import app.organicmaps.intent.Factory;
|
||||
import app.organicmaps.sdk.display.DisplayManager;
|
||||
import app.organicmaps.sdk.location.LocationHelper;
|
||||
import app.organicmaps.sdk.util.Config;
|
||||
import app.organicmaps.sdk.util.LocationUtils;
|
||||
import app.organicmaps.sdk.util.concurrency.UiThread;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
import app.organicmaps.util.SharingUtils;
|
||||
import app.organicmaps.util.ThemeUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.sdk.util.concurrency.UiThread;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -86,14 +83,14 @@ public class SplashActivity extends AppCompatActivity
|
||||
}
|
||||
});
|
||||
mPermissionRequest = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(),
|
||||
result -> Config.setLocationRequested());
|
||||
result -> Config.setLocationRequested());
|
||||
mApiRequest = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
|
||||
setResult(result.getResultCode(), result.getData());
|
||||
finish();
|
||||
});
|
||||
mShareLauncher = SharingUtils.RegisterLauncher(this);
|
||||
|
||||
if (DisplayManager.from(this).isCarDisplayUsed())
|
||||
if (MwmApplication.from(this).getDisplayManager().isCarDisplayUsed())
|
||||
{
|
||||
startActivity(new Intent(this, MapPlaceholderActivity.class));
|
||||
finish();
|
||||
@@ -109,10 +106,7 @@ public class SplashActivity extends AppCompatActivity
|
||||
if (!Config.isLocationRequested() && !LocationUtils.checkLocationPermission(this))
|
||||
{
|
||||
Logger.d(TAG, "Requesting location permissions");
|
||||
mPermissionRequest.launch(new String[]{
|
||||
ACCESS_COARSE_LOCATION,
|
||||
ACCESS_FINE_LOCATION
|
||||
});
|
||||
mPermissionRequest.launch(new String[] {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,19 +134,13 @@ public class SplashActivity extends AppCompatActivity
|
||||
{
|
||||
mCanceled = true;
|
||||
new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
|
||||
.setTitle(titleId)
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(
|
||||
R.string.report_a_bug,
|
||||
(dialog, which) -> Utils.sendBugReport(
|
||||
mShareLauncher,
|
||||
this,
|
||||
"Fatal Error",
|
||||
Log.getStackTraceString(error)
|
||||
)
|
||||
)
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
.setTitle(titleId)
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(
|
||||
R.string.report_a_bug,
|
||||
(dialog, which) -> Utils.sendBugReport(mShareLauncher, this, "Fatal Error", Log.getStackTraceString(error)))
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void init()
|
||||
@@ -162,7 +150,8 @@ public class SplashActivity extends AppCompatActivity
|
||||
try
|
||||
{
|
||||
asyncContinue = app.initOrganicMaps(this::processNavigation);
|
||||
} catch (IOException error)
|
||||
}
|
||||
catch (IOException error)
|
||||
{
|
||||
showFatalErrorDialog(R.string.dialog_error_storage_title, R.string.dialog_error_storage_message, error);
|
||||
return;
|
||||
@@ -195,9 +184,12 @@ public class SplashActivity extends AppCompatActivity
|
||||
// https://github.com/organicmaps/organicmaps/issues/6944
|
||||
final Intent intent = Objects.requireNonNull(getIntent());
|
||||
|
||||
if (isManageSpaceActivity(intent)) {
|
||||
if (isManageSpaceActivity(intent))
|
||||
{
|
||||
intent.setComponent(new ComponentName(this, DownloaderActivity.class));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
intent.setComponent(new ComponentName(this, DownloadResourcesLegacyActivity.class));
|
||||
}
|
||||
|
||||
@@ -219,11 +211,14 @@ public class SplashActivity extends AppCompatActivity
|
||||
finish();
|
||||
}
|
||||
|
||||
private boolean isManageSpaceActivity(Intent intent) {
|
||||
private boolean isManageSpaceActivity(Intent intent)
|
||||
{
|
||||
var component = intent.getComponent();
|
||||
|
||||
if (!Intent.ACTION_VIEW.equals(intent.getAction())) return false;
|
||||
if (component == null) return false;
|
||||
if (!Intent.ACTION_VIEW.equals(intent.getAction()))
|
||||
return false;
|
||||
if (component == null)
|
||||
return false;
|
||||
|
||||
var manageSpaceActivityName = BuildConfig.APPLICATION_ID + ".ManageSpaceActivity";
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import app.organicmaps.base.OnBackPressListener;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
|
||||
@@ -21,8 +19,7 @@ public abstract class WebContainerDelegate implements OnBackPressListener
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
private void initWebView(String url)
|
||||
{
|
||||
mWebView.setWebViewClient(new WebViewClient()
|
||||
{
|
||||
mWebView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url)
|
||||
{
|
||||
@@ -37,7 +34,7 @@ public abstract class WebContainerDelegate implements OnBackPressListener
|
||||
{
|
||||
MailTo parser = MailTo.parse(url);
|
||||
doStartActivity(new Intent(Intent.ACTION_SEND)
|
||||
.putExtra(Intent.EXTRA_EMAIL, new String[] { parser.getTo() })
|
||||
.putExtra(Intent.EXTRA_EMAIL, new String[] {parser.getTo()})
|
||||
.putExtra(Intent.EXTRA_TEXT, parser.getBody())
|
||||
.putExtra(Intent.EXTRA_SUBJECT, parser.getSubject())
|
||||
.putExtra(Intent.EXTRA_CC, parser.getCc())
|
||||
@@ -46,8 +43,7 @@ public abstract class WebContainerDelegate implements OnBackPressListener
|
||||
return true;
|
||||
}
|
||||
|
||||
doStartActivity(new Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse(url)));
|
||||
doStartActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(url)));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,18 +4,23 @@ import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.SimpleExpandableListAdapter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Disables child selections, also fixes bug with SimpleExpandableListAdapter not switching expandedGroupLayout and collapsedGroupLayout correctly.
|
||||
* Disables child selections, also fixes bug with SimpleExpandableListAdapter not switching expandedGroupLayout and
|
||||
* collapsedGroupLayout correctly.
|
||||
*/
|
||||
public class DisabledChildSimpleExpandableListAdapter extends SimpleExpandableListAdapter
|
||||
{
|
||||
public DisabledChildSimpleExpandableListAdapter(Context context, List<? extends Map<String, ?>> groupData, int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData, int childLayout, String[] childFrom, int[] childTo)
|
||||
public DisabledChildSimpleExpandableListAdapter(Context context, List<? extends Map<String, ?>> groupData,
|
||||
int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom,
|
||||
int[] groupTo,
|
||||
List<? extends List<? extends Map<String, ?>>> childData,
|
||||
int childLayout, String[] childFrom, int[] childTo)
|
||||
{
|
||||
super(context, groupData, expandedGroupLayout, collapsedGroupLayout, groupFrom, groupTo, childData, childLayout, childFrom, childTo);
|
||||
super(context, groupData, expandedGroupLayout, collapsedGroupLayout, groupFrom, groupTo, childData, childLayout,
|
||||
childFrom, childTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -29,8 +34,7 @@ public class DisabledChildSimpleExpandableListAdapter extends SimpleExpandableLi
|
||||
* See http://stackoverflow.com/questions/19520037/simpleexpandablelistadapter-and-expandedgrouplayout for details
|
||||
*/
|
||||
@Override
|
||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
||||
ViewGroup parent)
|
||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
|
||||
{
|
||||
return super.getGroupView(groupPosition, isExpanded, null, parent);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package app.organicmaps.adapter;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public interface OnItemClickListener<T>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package app.organicmaps.background;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import androidx.work.NetworkType;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import androidx.work.WorkRequest;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import app.organicmaps.MwmApplication;
|
||||
@@ -17,7 +16,6 @@ import app.organicmaps.sdk.util.log.Logger;
|
||||
|
||||
public class OsmUploadWork extends Worker
|
||||
{
|
||||
|
||||
private static final String TAG = OsmUploadWork.class.getSimpleName();
|
||||
private final Context mContext;
|
||||
private final WorkerParameters mWorkerParameters;
|
||||
@@ -34,11 +32,11 @@ public class OsmUploadWork extends Worker
|
||||
*/
|
||||
public static void startActionUploadOsmChanges(@NonNull Context context)
|
||||
{
|
||||
if (Editor.nativeHasSomethingToUpload() && OsmOAuth.isAuthorized(context))
|
||||
if (Editor.nativeHasSomethingToUpload() && OsmOAuth.isAuthorized())
|
||||
{
|
||||
final Constraints c = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
|
||||
final WorkRequest wr = new OneTimeWorkRequest.Builder(OsmUploadWork.class).setConstraints(c).build();
|
||||
WorkManager.getInstance(context).enqueue(wr);
|
||||
final OneTimeWorkRequest wr = new OneTimeWorkRequest.Builder(OsmUploadWork.class).setConstraints(c).build();
|
||||
WorkManager.getInstance(context).beginUniqueWork("UploadOsmChanges", ExistingWorkPolicy.KEEP, wr).enqueue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,13 +44,12 @@ public class OsmUploadWork extends Worker
|
||||
@Override
|
||||
public Result doWork()
|
||||
{
|
||||
final MwmApplication app = MwmApplication.from(mContext);
|
||||
if (!app.getOrganicMaps().arePlatformAndCoreInitialized())
|
||||
if (!MwmApplication.from(mContext).getOrganicMaps().arePlatformAndCoreInitialized())
|
||||
{
|
||||
Logger.w(TAG, "Application is not initialized, ignoring " + mWorkerParameters);
|
||||
return Result.failure();
|
||||
}
|
||||
Editor.uploadChanges(mContext);
|
||||
Editor.uploadChanges();
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.sdk.util.StorageUtils.isFolderWritable;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_DEFAULT_COUNT;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_KEY;
|
||||
import static app.organicmaps.sdk.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
@@ -13,30 +12,23 @@ import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
|
||||
public class BackupUtils
|
||||
{
|
||||
private static final String BACKUP_PREFIX = "backup_";
|
||||
private static final String BACKUP_EXTENSION = ".kmz";
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").withLocale(Locale.US);
|
||||
private static final DateTimeFormatter DATE_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").withLocale(Locale.US);
|
||||
private static final String TAG = BackupUtils.class.getSimpleName();
|
||||
|
||||
public static CharSequence formatReadableFolderPath(Context context, @NonNull Uri uri)
|
||||
@@ -63,8 +55,10 @@ public class BackupUtils
|
||||
volumeName = context.getString(R.string.maps_storage_removable);
|
||||
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
sb.append(volumeName + ": \n", new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_3)), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
sb.append("/" + subPath, new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_4)), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
sb.append(volumeName + ": \n", new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_3)),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
sb.append("/" + subPath, new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_4)),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return sb;
|
||||
}
|
||||
|
||||
@@ -74,12 +68,14 @@ public class BackupUtils
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(rawValue);
|
||||
} catch (NumberFormatException e)
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to parse max backups count, raw value: " + rawValue + " set to default: " + MAX_BACKUPS_DEFAULT_COUNT, e);
|
||||
prefs.edit()
|
||||
.putString(MAX_BACKUPS_KEY, String.valueOf(MAX_BACKUPS_DEFAULT_COUNT))
|
||||
.apply();
|
||||
Logger.e(
|
||||
TAG,
|
||||
"Failed to parse max backups count, raw value: " + rawValue + " set to default: " + MAX_BACKUPS_DEFAULT_COUNT,
|
||||
e);
|
||||
prefs.edit().putString(MAX_BACKUPS_KEY, String.valueOf(MAX_BACKUPS_DEFAULT_COUNT)).apply();
|
||||
return MAX_BACKUPS_DEFAULT_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.backup.BackupUtils.getBackupName;
|
||||
import static app.organicmaps.backup.BackupUtils.getBackupFolders;
|
||||
import static app.organicmaps.backup.BackupUtils.getBackupName;
|
||||
import static app.organicmaps.sdk.util.StorageUtils.copyFileToDocumentFile;
|
||||
import static app.organicmaps.sdk.util.StorageUtils.deleteDirectoryRecursive;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkSharingResult;
|
||||
@@ -24,6 +16,11 @@ import app.organicmaps.sdk.bookmarks.data.KmlFileType;
|
||||
import app.organicmaps.sdk.util.concurrency.ThreadPool;
|
||||
import app.organicmaps.sdk.util.concurrency.UiThread;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
import java.io.File;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class LocalBackupManager implements BookmarkManager.BookmarksSharingListener
|
||||
{
|
||||
@@ -65,39 +62,39 @@ public class LocalBackupManager implements BookmarkManager.BookmarksSharingListe
|
||||
ErrorCode errorCode = null;
|
||||
switch (result.getCode())
|
||||
{
|
||||
case BookmarkSharingResult.SUCCESS ->
|
||||
{
|
||||
if (!saveBackup(result))
|
||||
case BookmarkSharingResult.SUCCESS ->
|
||||
{
|
||||
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;
|
||||
Logger.e(TAG, "Failed create file for archive");
|
||||
}
|
||||
else
|
||||
default ->
|
||||
{
|
||||
Logger.i(TAG, "Backup was created and saved successfully");
|
||||
errorCode = ErrorCode.UNSUPPORTED;
|
||||
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;
|
||||
UiThread.run(() -> {
|
||||
@@ -139,8 +136,8 @@ public class LocalBackupManager implements BookmarkManager.BookmarksSharingListe
|
||||
}
|
||||
}
|
||||
cleanOldBackups(parentFolder);
|
||||
|
||||
} catch (Exception e)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to save backup", e);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,10 @@ import static app.organicmaps.backup.BackupUtils.isBackupFolderAvailable;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.BACKUP_FOLDER_PATH_KEY;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.BACKUP_INTERVAL_KEY;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.LAST_BACKUP_TIME_KEY;
|
||||
import static app.organicmaps.sdk.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
|
||||
public class PeriodicBackupRunner
|
||||
@@ -68,7 +65,8 @@ public class PeriodicBackupRunner
|
||||
try
|
||||
{
|
||||
return Long.parseLong(prefs.getString(BACKUP_INTERVAL_KEY, defaultValue));
|
||||
} catch (NumberFormatException e)
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -77,8 +75,7 @@ public class PeriodicBackupRunner
|
||||
private void performBackup(String backupFolderPath, int maxBackups)
|
||||
{
|
||||
LocalBackupManager backupManager = new LocalBackupManager(activity, backupFolderPath, maxBackups);
|
||||
backupManager.setListener(new LocalBackupManager.Listener()
|
||||
{
|
||||
backupManager.setListener(new LocalBackupManager.Listener() {
|
||||
@Override
|
||||
public void onBackupStarted()
|
||||
{
|
||||
|
||||
@@ -3,12 +3,10 @@ package app.organicmaps.base;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.util.ThemeUtils;
|
||||
|
||||
@@ -38,7 +36,7 @@ public class BaseMwmDialogFragment extends DialogFragment
|
||||
int style = getStyle();
|
||||
int theme = getCustomTheme();
|
||||
if (style != STYLE_NORMAL || theme != 0)
|
||||
//noinspection WrongConstant
|
||||
// noinspection WrongConstant
|
||||
setStyle(style, theme);
|
||||
}
|
||||
|
||||
@@ -62,5 +60,4 @@ public class BaseMwmDialogFragment extends DialogFragment
|
||||
throw new IllegalStateException("Before call this method make sure that the context exists");
|
||||
return (Application) context.getApplicationContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package app.organicmaps.base;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import app.organicmaps.util.Utils;
|
||||
|
||||
public class BaseMwmFragment extends Fragment implements OnBackPressListener
|
||||
@@ -20,5 +18,4 @@ public class BaseMwmFragment extends Fragment implements OnBackPressListener
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import android.graphics.Color;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.activity.SystemBarStyle;
|
||||
import androidx.annotation.CallSuper;
|
||||
@@ -18,18 +17,15 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentFactory;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.SplashActivity;
|
||||
import app.organicmaps.sdk.util.Config;
|
||||
import app.organicmaps.util.RtlUtils;
|
||||
import app.organicmaps.util.ThemeUtils;
|
||||
import app.organicmaps.sdk.util.concurrency.UiThread;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
|
||||
import app.organicmaps.util.RtlUtils;
|
||||
import app.organicmaps.util.ThemeUtils;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
||||
@@ -47,7 +43,7 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
||||
Context context = getApplicationContext();
|
||||
|
||||
if (ThemeUtils.isDefaultTheme(context, theme))
|
||||
return R.style.MwmTheme;
|
||||
return R.style.MwmTheme;
|
||||
|
||||
if (ThemeUtils.isNightTheme(context, theme))
|
||||
return R.style.MwmTheme_Night;
|
||||
@@ -216,11 +212,13 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
||||
/**
|
||||
* Replace attached fragment with the new one.
|
||||
*/
|
||||
public void replaceFragment(@NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args, @Nullable Runnable completionListener)
|
||||
public void replaceFragment(@NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args,
|
||||
@Nullable Runnable completionListener)
|
||||
{
|
||||
final int resId = getFragmentContentResId();
|
||||
if (resId <= 0 || findViewById(resId) == null)
|
||||
throw new IllegalStateException("Fragment can't be added, since getFragmentContentResId() isn't implemented or returns wrong resourceId.");
|
||||
throw new IllegalStateException(
|
||||
"Fragment can't be added, since getFragmentContentResId() isn't implemented or returns wrong resourceId.");
|
||||
|
||||
String name = fragmentClass.getName();
|
||||
Fragment potentialInstance = getSupportFragmentManager().findFragmentByTag(name);
|
||||
@@ -230,9 +228,7 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
||||
final FragmentFactory factory = manager.getFragmentFactory();
|
||||
final Fragment fragment = factory.instantiate(getClassLoader(), name);
|
||||
fragment.setArguments(args);
|
||||
manager.beginTransaction()
|
||||
.replace(resId, fragment, name)
|
||||
.commitAllowingStateLoss();
|
||||
manager.beginTransaction().replace(resId, fragment, name).commitAllowingStateLoss();
|
||||
manager.executePendingTransactions();
|
||||
if (completionListener != null)
|
||||
completionListener.run();
|
||||
@@ -240,8 +236,8 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to automatically attach fragment in onCreate. Tag applied to fragment in back stack is set to fragment name, too.
|
||||
* WARNING : if custom layout for activity is set, getFragmentContentResId() must be implemented, too.
|
||||
* Override to automatically attach fragment in onCreate. Tag applied to fragment in back stack is set to fragment
|
||||
* name, too. WARNING : if custom layout for activity is set, getFragmentContentResId() must be implemented, too.
|
||||
* @return class of the fragment, eg FragmentClass.getClass()
|
||||
*/
|
||||
protected Class<? extends Fragment> getFragmentClass()
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -14,14 +13,12 @@ import androidx.core.view.ViewCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.util.WindowInsetUtils.ScrollableContentInsetsListener;
|
||||
import app.organicmaps.widget.PlaceholderView;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
|
||||
public abstract class BaseMwmRecyclerFragment<T extends RecyclerView.Adapter> extends Fragment
|
||||
{
|
||||
@@ -39,8 +36,7 @@ public abstract class BaseMwmRecyclerFragment<T extends RecyclerView.Adapter> ex
|
||||
private T mAdapter;
|
||||
|
||||
@NonNull
|
||||
private final View.OnClickListener mNavigationClickListener
|
||||
= view -> Utils.navigateToParent(requireActivity());
|
||||
private final View.OnClickListener mNavigationClickListener = view -> Utils.navigateToParent(requireActivity());
|
||||
|
||||
@NonNull
|
||||
protected abstract T createAdapter();
|
||||
|
||||
@@ -2,10 +2,8 @@ package app.organicmaps.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.organicmaps.widget.ToolbarController;
|
||||
|
||||
public class BaseMwmToolbarFragment extends BaseMwmFragment
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package app.organicmaps.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -10,12 +9,10 @@ import androidx.core.view.ViewCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentFactory;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
|
||||
public abstract class BaseToolbarActivity extends BaseMwmFragmentActivity
|
||||
{
|
||||
@@ -73,23 +70,20 @@ public abstract class BaseToolbarActivity extends BaseMwmFragmentActivity
|
||||
return R.id.fragment_container;
|
||||
}
|
||||
|
||||
public Fragment stackFragment(@NonNull Class<? extends Fragment> fragmentClass,
|
||||
@Nullable String title, @Nullable Bundle args)
|
||||
public Fragment stackFragment(@NonNull Class<? extends Fragment> fragmentClass, @Nullable String title,
|
||||
@Nullable Bundle args)
|
||||
{
|
||||
final int resId = getFragmentContentResId();
|
||||
if (resId <= 0 || findViewById(resId) == null)
|
||||
throw new IllegalStateException("Fragment can't be added, since getFragmentContentResId() " +
|
||||
"isn't implemented or returns wrong resourceId.");
|
||||
throw new IllegalStateException("Fragment can't be added, since getFragmentContentResId() "
|
||||
+ "isn't implemented or returns wrong resourceId.");
|
||||
|
||||
String name = fragmentClass.getName();
|
||||
final FragmentManager manager = getSupportFragmentManager();
|
||||
final FragmentFactory factory = manager.getFragmentFactory();
|
||||
final Fragment fragment = factory.instantiate(getClassLoader(), name);
|
||||
fragment.setArguments(args);
|
||||
manager.beginTransaction()
|
||||
.replace(resId, fragment, name)
|
||||
.addToBackStack(null)
|
||||
.commitAllowingStateLoss();
|
||||
manager.beginTransaction().replace(resId, fragment, name).addToBackStack(null).commitAllowingStateLoss();
|
||||
manager.executePendingTransactions();
|
||||
|
||||
if (title != null)
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package app.organicmaps.bookmarks;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class BaseBookmarkCategoryAdapter<V extends RecyclerView.ViewHolder>
|
||||
extends RecyclerView.Adapter<V>
|
||||
public abstract class BaseBookmarkCategoryAdapter<V extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<V>
|
||||
{
|
||||
@NonNull
|
||||
private final Context mContext;
|
||||
@@ -54,6 +50,5 @@ public abstract class BaseBookmarkCategoryAdapter<V extends RecyclerView.ViewHol
|
||||
if (position < 0 || position > categories.size() - 1)
|
||||
throw new ArrayIndexOutOfBoundsException(position);
|
||||
return categories.get(position);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@ package app.organicmaps.bookmarks;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.base.BaseToolbarActivity;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
|
||||
@@ -7,16 +7,13 @@ import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.adapter.OnItemClickListener;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BookmarkCategoriesAdapter extends BaseBookmarkCategoryAdapter<RecyclerView.ViewHolder>
|
||||
@@ -122,8 +119,7 @@ public class BookmarkCategoriesAdapter extends BaseBookmarkCategoryAdapter<Recyc
|
||||
case TYPE_ACTION_HEADER ->
|
||||
{
|
||||
HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
|
||||
headerViewHolder.setAction(mMassOperationAction,
|
||||
BookmarkManager.INSTANCE.areAllCategoriesInvisible());
|
||||
headerViewHolder.setAction(mMassOperationAction, BookmarkManager.INSTANCE.areAllCategoriesInvisible());
|
||||
headerViewHolder.getText().setText(R.string.bookmark_lists);
|
||||
}
|
||||
case TYPE_CATEGORY_ITEM ->
|
||||
@@ -191,7 +187,6 @@ public class BookmarkCategoriesAdapter extends BaseBookmarkCategoryAdapter<Recyc
|
||||
|
||||
private int toCategoryPosition(int adapterPosition)
|
||||
{
|
||||
|
||||
int type = getItemViewType(adapterPosition);
|
||||
if (type != TYPE_CATEGORY_ITEM)
|
||||
throw new AssertionError("An element at specified position is not category!");
|
||||
|
||||
@@ -12,7 +12,6 @@ import android.os.Bundle;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.CallSuper;
|
||||
@@ -20,42 +19,36 @@ import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.adapter.OnItemClickListener;
|
||||
import app.organicmaps.base.BaseMwmRecyclerFragment;
|
||||
import app.organicmaps.dialog.EditTextDialogFragment;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkSharingResult;
|
||||
import app.organicmaps.sdk.bookmarks.data.DataChangedListener;
|
||||
import app.organicmaps.sdk.bookmarks.data.KmlFileType;
|
||||
import app.organicmaps.dialog.EditTextDialogFragment;
|
||||
import app.organicmaps.util.SharingUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.widget.PlaceholderView;
|
||||
import app.organicmaps.widget.recycler.DividerItemDecorationWithPadding;
|
||||
import app.organicmaps.sdk.util.StorageUtils;
|
||||
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
|
||||
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
|
||||
import app.organicmaps.sdk.util.concurrency.ThreadPool;
|
||||
import app.organicmaps.sdk.util.concurrency.UiThread;
|
||||
import app.organicmaps.sdk.util.log.Logger;
|
||||
|
||||
import app.organicmaps.util.SharingUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
|
||||
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
|
||||
import app.organicmaps.widget.PlaceholderView;
|
||||
import app.organicmaps.widget.recycler.DividerItemDecorationWithPadding;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<BookmarkCategoriesAdapter>
|
||||
implements BookmarkManager.BookmarksLoadingListener,
|
||||
CategoryListCallback,
|
||||
OnItemClickListener<BookmarkCategory>,
|
||||
OnItemMoreClickListener<BookmarkCategory>,
|
||||
OnItemLongClickListener<BookmarkCategory>,
|
||||
BookmarkManager.BookmarksSharingListener,
|
||||
MenuBottomSheetFragment.MenuBottomSheetInterface
|
||||
implements BookmarkManager.BookmarksLoadingListener, CategoryListCallback, OnItemClickListener<BookmarkCategory>,
|
||||
OnItemMoreClickListener<BookmarkCategory>, OnItemLongClickListener<BookmarkCategory>,
|
||||
BookmarkManager.BookmarksSharingListener, MenuBottomSheetFragment.MenuBottomSheetInterface
|
||||
|
||||
{
|
||||
private static final String TAG = BookmarkCategoriesFragment.class.getSimpleName();
|
||||
@@ -75,21 +68,24 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
@NonNull
|
||||
private DataChangedListener mCategoriesAdapterObserver;
|
||||
|
||||
private final ActivityResultLauncher<Intent> startBookmarkListForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
if( activityResult.getResultCode() == Activity.RESULT_OK)
|
||||
onDeleteActionSelected(getSelectedCategory());
|
||||
});
|
||||
private final ActivityResultLauncher<Intent> startBookmarkListForResult =
|
||||
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
if (activityResult.getResultCode() == Activity.RESULT_OK)
|
||||
onDeleteActionSelected(getSelectedCategory());
|
||||
});
|
||||
|
||||
private final ActivityResultLauncher<Intent> startImportDirectoryForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult ->
|
||||
{
|
||||
if( activityResult.getResultCode() == Activity.RESULT_OK)
|
||||
onImportDirectoryResult(activityResult.getData());
|
||||
});
|
||||
|
||||
private final ActivityResultLauncher<Intent> startBookmarkSettingsForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
// not handled at the moment
|
||||
});
|
||||
private final ActivityResultLauncher<Intent> startImportDirectoryForResult =
|
||||
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
if (activityResult.getResultCode() == Activity.RESULT_OK)
|
||||
onImportDirectoryResult(activityResult.getData());
|
||||
});
|
||||
|
||||
private final ActivityResultLauncher<Intent> startBookmarkSettingsForResult =
|
||||
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
|
||||
activityResult
|
||||
-> {
|
||||
// not handled at the moment
|
||||
});
|
||||
|
||||
@Override
|
||||
@LayoutRes
|
||||
@@ -119,7 +115,8 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
getAdapter().setCategoryListCallback(this);
|
||||
|
||||
RecyclerView rw = getRecyclerView();
|
||||
if (rw == null) return;
|
||||
if (rw == null)
|
||||
return;
|
||||
|
||||
rw.setNestedScrollingEnabled(false);
|
||||
RecyclerView.ItemDecoration decor = new DividerItemDecorationWithPadding(requireContext());
|
||||
@@ -181,7 +178,7 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
{
|
||||
mSelectedCategory = item;
|
||||
MenuBottomSheetFragment.newInstance(BOOKMARKS_CATEGORIES_MENU_ID, item.getName())
|
||||
.show(getChildFragmentManager(), BOOKMARKS_CATEGORIES_MENU_ID);
|
||||
.show(getChildFragmentManager(), BOOKMARKS_CATEGORIES_MENU_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,28 +188,19 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
|
||||
if (mSelectedCategory != null)
|
||||
{
|
||||
items.add(new MenuBottomSheetItem(
|
||||
R.string.edit,
|
||||
R.drawable.ic_settings,
|
||||
() -> onSettingsActionSelected(mSelectedCategory)));
|
||||
items.add(new MenuBottomSheetItem(
|
||||
mSelectedCategory.isVisible() ? R.string.hide : R.string.show,
|
||||
mSelectedCategory.isVisible() ? R.drawable.ic_hide : R.drawable.ic_show,
|
||||
() -> onShowActionSelected(mSelectedCategory)));
|
||||
items.add(new MenuBottomSheetItem(
|
||||
R.string.export_file,
|
||||
R.drawable.ic_file_kmz,
|
||||
() -> onShareActionSelected(mSelectedCategory, KmlFileType.Text)));
|
||||
items.add(new MenuBottomSheetItem(
|
||||
R.string.export_file_gpx,
|
||||
R.drawable.ic_file_gpx,
|
||||
() -> onShareActionSelected(mSelectedCategory, KmlFileType.Gpx)));
|
||||
items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_settings,
|
||||
() -> onSettingsActionSelected(mSelectedCategory)));
|
||||
items.add(new MenuBottomSheetItem(mSelectedCategory.isVisible() ? R.string.hide : R.string.show,
|
||||
mSelectedCategory.isVisible() ? R.drawable.ic_hide : R.drawable.ic_show,
|
||||
() -> onShowActionSelected(mSelectedCategory)));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file, R.drawable.ic_file_kmz,
|
||||
() -> onShareActionSelected(mSelectedCategory, KmlFileType.Text)));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx,
|
||||
() -> onShareActionSelected(mSelectedCategory, KmlFileType.Gpx)));
|
||||
// Disallow deleting the last category
|
||||
if (getAdapter().getBookmarkCategories().size() > 1)
|
||||
items.add(new MenuBottomSheetItem(
|
||||
R.string.delete,
|
||||
R.drawable.ic_delete,
|
||||
() -> onDeleteActionSelected(mSelectedCategory)));
|
||||
items.add(new MenuBottomSheetItem(R.string.delete, R.drawable.ic_delete,
|
||||
() -> onDeleteActionSelected(mSelectedCategory)));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
@@ -245,15 +233,10 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
{
|
||||
mCategoryEditor = BookmarkManager.INSTANCE::createCategory;
|
||||
|
||||
EditTextDialogFragment dialogFragment =
|
||||
EditTextDialogFragment.show(getString(R.string.bookmarks_create_new_group),
|
||||
getString(R.string.bookmarks_new_list_hint),
|
||||
getString(R.string.bookmark_set_name),
|
||||
getString(R.string.create),
|
||||
getString(R.string.cancel),
|
||||
MAX_CATEGORY_NAME_LENGTH,
|
||||
this,
|
||||
new CategoryValidator());
|
||||
EditTextDialogFragment dialogFragment = EditTextDialogFragment.show(
|
||||
getString(R.string.bookmarks_create_new_group), getString(R.string.bookmarks_new_list_hint),
|
||||
getString(R.string.bookmark_set_name), getString(R.string.create), getString(R.string.cancel),
|
||||
MAX_CATEGORY_NAME_LENGTH, this, new CategoryValidator());
|
||||
dialogFragment.setTextSaveListener(this::onSaveText);
|
||||
}
|
||||
|
||||
@@ -280,7 +263,8 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
showNoFileManagerError();
|
||||
}
|
||||
|
||||
private void showNoFileManagerError() {
|
||||
private void showNoFileManagerError()
|
||||
{
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setMessage(R.string.error_no_file_manager_app)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
|
||||
@@ -341,17 +325,16 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
ThreadPool.getStorage().execute(() -> {
|
||||
AtomicInteger found = new AtomicInteger(0);
|
||||
StorageUtils.listContentProviderFilesRecursively(
|
||||
resolver, rootUri, uri -> {
|
||||
if (BookmarkManager.INSTANCE.importBookmarksFile(resolver, uri, tempDir))
|
||||
found.incrementAndGet();
|
||||
});
|
||||
StorageUtils.listContentProviderFilesRecursively(resolver, rootUri, uri -> {
|
||||
if (BookmarkManager.INSTANCE.importBookmarksFile(resolver, uri, tempDir))
|
||||
found.incrementAndGet();
|
||||
});
|
||||
UiThread.run(() -> {
|
||||
if (dialog.isShowing())
|
||||
dialog.dismiss();
|
||||
int found_val = found.get();
|
||||
String message = context.getResources().getQuantityString(
|
||||
R.plurals.bookmarks_detect_message, found_val, found_val);
|
||||
String message =
|
||||
context.getResources().getQuantityString(R.plurals.bookmarks_detect_message, found_val, found_val);
|
||||
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package app.organicmaps.bookmarks;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.base.BaseMwmFragmentActivity;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
@@ -32,11 +30,12 @@ public class BookmarkCategorySettingsActivity extends BaseMwmFragmentActivity
|
||||
return BookmarkCategorySettingsFragment.class;
|
||||
}
|
||||
|
||||
public static void startForResult(@NonNull Fragment fragment, ActivityResultLauncher<Intent> startBookmarkSettingsForResult,
|
||||
@NonNull BookmarkCategory category)
|
||||
public static void startForResult(@NonNull Fragment fragment,
|
||||
ActivityResultLauncher<Intent> startBookmarkSettingsForResult,
|
||||
@NonNull BookmarkCategory category)
|
||||
{
|
||||
android.content.Intent intent = new Intent(fragment.requireActivity(), BookmarkCategorySettingsActivity.class)
|
||||
.putExtra(EXTRA_BOOKMARK_CATEGORY, category);
|
||||
.putExtra(EXTRA_BOOKMARK_CATEGORY, category);
|
||||
startBookmarkSettingsForResult.launch(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,21 +11,17 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.base.BaseMwmToolbarFragment;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.util.Utils;
|
||||
|
||||
import app.organicmaps.util.InputUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class BookmarkCategorySettingsFragment extends BaseMwmToolbarFragment
|
||||
@@ -49,14 +45,13 @@ public class BookmarkCategorySettingsFragment extends BaseMwmToolbarFragment
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
final Bundle args = requireArguments();
|
||||
mCategory = Objects.requireNonNull(Utils.getParcelable(args,
|
||||
BookmarkCategorySettingsActivity.EXTRA_BOOKMARK_CATEGORY, BookmarkCategory.class));
|
||||
mCategory = Objects.requireNonNull(
|
||||
Utils.getParcelable(args, BookmarkCategorySettingsActivity.EXTRA_BOOKMARK_CATEGORY, BookmarkCategory.class));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState)
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
View root = inflater.inflate(R.layout.fragment_bookmark_category_settings, container, false);
|
||||
setHasOptionsMenu(true);
|
||||
@@ -70,13 +65,13 @@ public class BookmarkCategorySettingsFragment extends BaseMwmToolbarFragment
|
||||
TextInputLayout clearNameBtn = root.findViewById(R.id.edit_list_name_input);
|
||||
clearNameBtn.setEndIconOnClickListener(v -> clearAndFocus(mEditCategoryNameView));
|
||||
mEditCategoryNameView.setText(mCategory.getName());
|
||||
InputFilter[] f = { new InputFilter.LengthFilter(TEXT_LENGTH_LIMIT) };
|
||||
InputFilter[] f = {new InputFilter.LengthFilter(TEXT_LENGTH_LIMIT)};
|
||||
mEditCategoryNameView.setFilters(f);
|
||||
mEditCategoryNameView.requestFocus();
|
||||
mEditCategoryNameView.addTextChangedListener(new TextWatcher()
|
||||
{
|
||||
mEditCategoryNameView.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
|
||||
{}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
|
||||
@@ -85,7 +80,8 @@ public class BookmarkCategorySettingsFragment extends BaseMwmToolbarFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {}
|
||||
public void afterTextChanged(Editable editable)
|
||||
{}
|
||||
});
|
||||
mEditDescView = root.findViewById(R.id.edit_description);
|
||||
mEditDescView.setText(mCategory.getDescription());
|
||||
|
||||
@@ -3,18 +3,15 @@ package app.organicmaps.bookmarks;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.adapter.OnItemClickListener;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
@@ -22,8 +19,9 @@ import java.util.List;
|
||||
public class BookmarkCollectionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||
{
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({ TYPE_HEADER_ITEM, TYPE_CATEGORY_ITEM })
|
||||
public @interface SectionType { }
|
||||
@IntDef({TYPE_HEADER_ITEM, TYPE_CATEGORY_ITEM})
|
||||
public @interface SectionType
|
||||
{}
|
||||
|
||||
private final static int TYPE_CATEGORY_ITEM = BookmarkManager.CATEGORY;
|
||||
private final static int TYPE_HEADER_ITEM = 3;
|
||||
@@ -63,11 +61,10 @@ public class BookmarkCollectionAdapter extends RecyclerView.Adapter<RecyclerView
|
||||
}
|
||||
}
|
||||
|
||||
BookmarkCollectionAdapter(@NonNull BookmarkCategory bookmarkCategory,
|
||||
@NonNull List<BookmarkCategory> itemsCategories)
|
||||
BookmarkCollectionAdapter(@NonNull BookmarkCategory bookmarkCategory, @NonNull List<BookmarkCategory> itemsCategories)
|
||||
{
|
||||
mBookmarkCategory = bookmarkCategory;
|
||||
//noinspection AssignmentOrReturnOfFieldWithMutableType
|
||||
// noinspection AssignmentOrReturnOfFieldWithMutableType
|
||||
mItemsCategory = itemsCategories;
|
||||
|
||||
mSectionCount = 0;
|
||||
@@ -93,7 +90,7 @@ public class BookmarkCollectionAdapter extends RecyclerView.Adapter<RecyclerView
|
||||
@NonNull
|
||||
private List<BookmarkCategory> getItemsListByType(@SectionType int type)
|
||||
{
|
||||
return mItemsCategory;
|
||||
return mItemsCategory;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -129,18 +126,15 @@ public class BookmarkCollectionAdapter extends RecyclerView.Adapter<RecyclerView
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
|
||||
@SectionType int viewType)
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @SectionType int viewType)
|
||||
{
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
RecyclerView.ViewHolder holder = null;
|
||||
|
||||
if (viewType == TYPE_HEADER_ITEM)
|
||||
holder = new Holders.HeaderViewHolder(inflater.inflate(R.layout.item_bookmark_group_list_header,
|
||||
parent, false));
|
||||
holder = new Holders.HeaderViewHolder(inflater.inflate(R.layout.item_bookmark_group_list_header, parent, false));
|
||||
if (viewType == TYPE_CATEGORY_ITEM)
|
||||
holder = new Holders.CollectionViewHolder(inflater.inflate(R.layout.item_bookmark_collection,
|
||||
parent, false));
|
||||
holder = new Holders.CollectionViewHolder(inflater.inflate(R.layout.item_bookmark_collection, parent, false));
|
||||
|
||||
if (holder == null)
|
||||
throw new AssertionError("Unsupported view type: " + viewType);
|
||||
@@ -170,8 +164,7 @@ public class BookmarkCollectionAdapter extends RecyclerView.Adapter<RecyclerView
|
||||
throw new AssertionError("Position not found: " + position);
|
||||
}
|
||||
|
||||
private void bindCollectionHolder(RecyclerView.ViewHolder holder, SectionPosition position,
|
||||
@SectionType int type)
|
||||
private void bindCollectionHolder(RecyclerView.ViewHolder holder, SectionPosition position, @SectionType int type)
|
||||
{
|
||||
final BookmarkCategory category = getGroupByPosition(position, type);
|
||||
Holders.CollectionViewHolder collectionViewHolder = (Holders.CollectionViewHolder) holder;
|
||||
@@ -188,8 +181,7 @@ public class BookmarkCollectionAdapter extends RecyclerView.Adapter<RecyclerView
|
||||
private void bindHeaderHolder(@NonNull RecyclerView.ViewHolder holder, int nextSectionPosition)
|
||||
{
|
||||
Holders.HeaderViewHolder headerViewHolder = (Holders.HeaderViewHolder) holder;
|
||||
headerViewHolder.getText()
|
||||
.setText(holder.itemView.getResources().getString(R.string.bookmarks));
|
||||
headerViewHolder.getText().setText(holder.itemView.getResources().getString(R.string.bookmarks));
|
||||
final boolean visibility = !BookmarkManager.INSTANCE.areAllCategoriesVisible();
|
||||
headerViewHolder.setAction(mMassOperationAction, visibility);
|
||||
updateVisibility(headerViewHolder.itemView);
|
||||
@@ -251,4 +243,3 @@ public class BookmarkCollectionAdapter extends RecyclerView.Adapter<RecyclerView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,11 @@ package app.organicmaps.bookmarks;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.base.BaseToolbarActivity;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
@@ -58,7 +56,8 @@ public class BookmarkListActivity extends BaseToolbarActivity
|
||||
return R.layout.bookmarks_activity;
|
||||
}
|
||||
|
||||
static void startForResult(@NonNull Fragment fragment, ActivityResultLauncher<Intent> startBookmarkListForResult, @NonNull BookmarkCategory category)
|
||||
static void startForResult(@NonNull Fragment fragment, ActivityResultLauncher<Intent> startBookmarkListForResult,
|
||||
@NonNull BookmarkCategory category)
|
||||
{
|
||||
Bundle args = new Bundle();
|
||||
Intent intent = new Intent(fragment.requireActivity(), BookmarkListActivity.class);
|
||||
|
||||
@@ -4,13 +4,9 @@ import android.content.res.Resources;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.sdk.bookmarks.data.BookmarkInfo;
|
||||
@@ -20,7 +16,7 @@ import app.organicmaps.sdk.bookmarks.data.SortedBlock;
|
||||
import app.organicmaps.sdk.content.DataSource;
|
||||
import app.organicmaps.widget.recycler.RecyclerClickListener;
|
||||
import app.organicmaps.widget.recycler.RecyclerLongClickListener;
|
||||
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -62,12 +58,14 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
mDataSource = dataSource;
|
||||
}
|
||||
|
||||
public BookmarkCategory getCategory() { return mDataSource.getData(); }
|
||||
public BookmarkCategory getCategory()
|
||||
{
|
||||
return mDataSource.getData();
|
||||
}
|
||||
|
||||
boolean hasDescription()
|
||||
{
|
||||
return (!mDataSource.getData().getAnnotation().isEmpty() ||
|
||||
!mDataSource.getData().getDescription().isEmpty());
|
||||
return (!mDataSource.getData().getAnnotation().isEmpty() || !mDataSource.getData().getDescription().isEmpty());
|
||||
}
|
||||
|
||||
void invalidate()
|
||||
@@ -115,7 +113,10 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionsCount() { return mSectionsCount; }
|
||||
public int getSectionsCount()
|
||||
{
|
||||
return mSectionsCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable(int sectionIndex)
|
||||
@@ -124,7 +125,10 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTitle(int sectionIndex) { return true; }
|
||||
public boolean hasTitle(int sectionIndex)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTitle(int sectionIndex, @NonNull Resources rs)
|
||||
@@ -172,15 +176,13 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
@Override
|
||||
public long getBookmarkId(@NonNull SectionPosition pos)
|
||||
{
|
||||
return BookmarkManager.INSTANCE.getBookmarkIdByPosition(getCategory().getId(),
|
||||
pos.getItemIndex());
|
||||
return BookmarkManager.INSTANCE.getBookmarkIdByPosition(getCategory().getId(), pos.getItemIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTrackId(@NonNull SectionPosition pos)
|
||||
{
|
||||
return BookmarkManager.INSTANCE.getTrackIdByPosition(getCategory().getId(),
|
||||
pos.getItemIndex());
|
||||
return BookmarkManager.INSTANCE.getTrackIdByPosition(getCategory().getId(), pos.getItemIndex());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,30 +191,47 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
@NonNull
|
||||
private final List<Long> mSearchResults;
|
||||
|
||||
SearchResultsSectionsDataSource(@NonNull DataSource<BookmarkCategory> dataSource,
|
||||
@NonNull List<Long> searchResults)
|
||||
SearchResultsSectionsDataSource(@NonNull DataSource<BookmarkCategory> dataSource, @NonNull List<Long> searchResults)
|
||||
{
|
||||
super(dataSource);
|
||||
mSearchResults = searchResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionsCount() { return 1; }
|
||||
public int getSectionsCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable(int sectionIndex) { return true; }
|
||||
public boolean isEditable(int sectionIndex)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTitle(int sectionIndex) { return false; }
|
||||
public boolean hasTitle(int sectionIndex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTitle(int sectionIndex, @NonNull Resources rs) { return null; }
|
||||
public String getTitle(int sectionIndex, @NonNull Resources rs)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemsCount(int sectionIndex) { return mSearchResults.size(); }
|
||||
public int getItemsCount(int sectionIndex)
|
||||
{
|
||||
return mSearchResults.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemsType(int sectionIndex) { return TYPE_BOOKMARK; }
|
||||
public int getItemsType(int sectionIndex)
|
||||
{
|
||||
return TYPE_BOOKMARK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete(@NonNull SectionPosition pos)
|
||||
@@ -238,8 +257,7 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
@NonNull
|
||||
private final List<SortedBlock> mSortedBlocks;
|
||||
|
||||
SortedSectionsDataSource(@NonNull DataSource<BookmarkCategory> dataSource,
|
||||
@NonNull List<SortedBlock> sortedBlocks)
|
||||
SortedSectionsDataSource(@NonNull DataSource<BookmarkCategory> dataSource, @NonNull List<SortedBlock> sortedBlocks)
|
||||
{
|
||||
super(dataSource);
|
||||
mSortedBlocks = sortedBlocks;
|
||||
@@ -272,7 +290,10 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTitle(int sectionIndex) { return true; }
|
||||
public boolean hasTitle(int sectionIndex)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTitle(int sectionIndex, @NonNull Resources rs)
|
||||
@@ -423,8 +444,7 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
{
|
||||
case TYPE_TRACK:
|
||||
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.setOnLongClickListener(mLongClickListener);
|
||||
trackHolder.setTrackIconClickListener(mIconClickListener);
|
||||
@@ -433,8 +453,7 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
|
||||
break;
|
||||
case TYPE_BOOKMARK:
|
||||
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.setOnLongClickListener(mLongClickListener);
|
||||
holder = bookmarkHolder;
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.CallSuper;
|
||||
@@ -40,9 +39,9 @@ import app.organicmaps.sdk.bookmarks.data.SortedBlock;
|
||||
import app.organicmaps.sdk.bookmarks.data.Track;
|
||||
import app.organicmaps.sdk.search.BookmarkSearchListener;
|
||||
import app.organicmaps.sdk.search.SearchEngine;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import app.organicmaps.util.Graphics;
|
||||
import app.organicmaps.util.SharingUtils;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.util.WindowInsetUtils;
|
||||
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
|
||||
@@ -53,16 +52,13 @@ import app.organicmaps.widget.placepage.EditBookmarkFragment;
|
||||
import app.organicmaps.widget.recycler.DividerItemDecorationWithPadding;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
import com.google.android.material.imageview.ShapeableImageView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter>
|
||||
implements BookmarkManager.BookmarksSharingListener,
|
||||
BookmarkManager.BookmarksSortingListener,
|
||||
BookmarkManager.BookmarksLoadingListener,
|
||||
BookmarkSearchListener,
|
||||
implements BookmarkManager.BookmarksSharingListener, BookmarkManager.BookmarksSortingListener,
|
||||
BookmarkManager.BookmarksLoadingListener, BookmarkSearchListener,
|
||||
ChooseBookmarksSortingTypeFragment.ChooseSortingTypeListener,
|
||||
MenuBottomSheetFragment.MenuBottomSheetInterface
|
||||
{
|
||||
@@ -75,15 +71,17 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
private static final String OPTIONS_MENU_ID = "OPTIONS_MENU_BOTTOM_SHEET";
|
||||
|
||||
private ActivityResultLauncher<SharingUtils.SharingIntent> shareLauncher;
|
||||
private final ActivityResultLauncher<Intent> startBookmarkListForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
System.out.println("resultCode: " + activityResult.getResultCode());
|
||||
handleActivityResult();
|
||||
});
|
||||
private final ActivityResultLauncher<Intent> startBookmarkListForResult =
|
||||
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
System.out.println("resultCode: " + activityResult.getResultCode());
|
||||
handleActivityResult();
|
||||
});
|
||||
|
||||
private final ActivityResultLauncher<Intent> startBookmarkSettingsForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
System.out.println("resultCode: " + activityResult.getResultCode());
|
||||
handleActivityResult();
|
||||
});
|
||||
private final ActivityResultLauncher<Intent> startBookmarkSettingsForResult =
|
||||
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
System.out.println("resultCode: " + activityResult.getResultCode());
|
||||
handleActivityResult();
|
||||
});
|
||||
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
@NonNull
|
||||
@@ -104,8 +102,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
private ExtendedFloatingActionButton mFabViewOnMap;
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
@NonNull
|
||||
private final RecyclerView.OnScrollListener mRecyclerListener = new RecyclerView.OnScrollListener()
|
||||
{
|
||||
private final RecyclerView.OnScrollListener mRecyclerListener = new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
|
||||
{
|
||||
@@ -140,7 +137,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
{
|
||||
BookmarkCategory category = mCategoryDataSource.getData();
|
||||
return new ConcatAdapter(initAndGetCollectionAdapter(category.getId()),
|
||||
new BookmarkListAdapter(mCategoryDataSource));
|
||||
new BookmarkListAdapter(mCategoryDataSource));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -148,18 +145,15 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
{
|
||||
List<BookmarkCategory> mCategoryItems = BookmarkManager.INSTANCE.getChildrenCategories(categoryId);
|
||||
|
||||
BookmarkCollectionAdapter adapter = new BookmarkCollectionAdapter(getCategoryOrThrow(),
|
||||
mCategoryItems);
|
||||
adapter.setOnClickListener((v, item) -> {
|
||||
BookmarkListActivity.startForResult(this, startBookmarkListForResult, item);
|
||||
});
|
||||
BookmarkCollectionAdapter adapter = new BookmarkCollectionAdapter(getCategoryOrThrow(), mCategoryItems);
|
||||
adapter.setOnClickListener(
|
||||
(v, item) -> BookmarkListActivity.startForResult(this, startBookmarkListForResult, item));
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState)
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
return inflater.inflate(R.layout.fragment_bookmark_list, container, false);
|
||||
}
|
||||
@@ -204,8 +198,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
// recycler view already has an InsetListener in BaseMwmRecyclerFragment
|
||||
// here we must reset it, because the logic is different from a common use case
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
getRecyclerView(),
|
||||
new WindowInsetUtils.ScrollableContentInsetsListener(getRecyclerView(), mFabViewOnMap));
|
||||
getRecyclerView(), new WindowInsetUtils.ScrollableContentInsetsListener(getRecyclerView(), mFabViewOnMap));
|
||||
|
||||
updateLoadingPlaceholder(view, false);
|
||||
}
|
||||
@@ -263,8 +256,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
private void configureFab(@NonNull View view)
|
||||
{
|
||||
mFabViewOnMap = view.findViewById(R.id.show_on_map_fab);
|
||||
mFabViewOnMap.setOnClickListener(v ->
|
||||
{
|
||||
mFabViewOnMap.setOnClickListener(v -> {
|
||||
final Intent i = makeMwmActivityIntent();
|
||||
i.putExtra(MwmActivity.EXTRA_CATEGORY_ID, mCategoryDataSource.getData().getId());
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
@@ -290,13 +282,11 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
{
|
||||
if (isEmptySearchResults())
|
||||
{
|
||||
requirePlaceholder().setContent(R.string.search_not_found,
|
||||
R.string.search_not_found_query);
|
||||
requirePlaceholder().setContent(R.string.search_not_found, R.string.search_not_found_query);
|
||||
}
|
||||
else if (isEmpty())
|
||||
{
|
||||
requirePlaceholder().setContent(R.string.bookmarks_empty_list_title,
|
||||
R.string.bookmarks_empty_list_message);
|
||||
requirePlaceholder().setContent(R.string.bookmarks_empty_list_title, R.string.bookmarks_empty_list_message);
|
||||
}
|
||||
|
||||
boolean isEmptyRecycler = isEmpty() || isEmptySearchResults();
|
||||
@@ -332,9 +322,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
SearchEngine.INSTANCE.cancel();
|
||||
|
||||
mLastQueryTimestamp = System.nanoTime();
|
||||
if (SearchEngine.INSTANCE.searchInBookmarks(query,
|
||||
mCategoryDataSource.getData().getId(),
|
||||
mLastQueryTimestamp))
|
||||
if (SearchEngine.INSTANCE.searchInBookmarks(query, mCategoryDataSource.getData().getId(), mLastQueryTimestamp))
|
||||
{
|
||||
mToolbarController.showProgress(true);
|
||||
}
|
||||
@@ -433,8 +421,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
final double lon = hasMyPosition ? loc.getLongitude() : 0;
|
||||
|
||||
BookmarkManager.INSTANCE.setLastSortingType(catId, sortingType);
|
||||
BookmarkManager.INSTANCE.getSortedCategory(catId, sortingType, hasMyPosition, lat, lon,
|
||||
mLastSortTimestamp);
|
||||
BookmarkManager.INSTANCE.getSortedCategory(catId, sortingType, hasMyPosition, lat, lon, mLastSortTimestamp);
|
||||
|
||||
updateSortingProgressBar();
|
||||
}
|
||||
@@ -448,8 +435,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
@NonNull
|
||||
private BookmarkCollectionAdapter getBookmarkCollectionAdapter()
|
||||
{
|
||||
return (BookmarkCollectionAdapter) getAdapter().getAdapters()
|
||||
.get(INDEX_BOOKMARKS_COLLECTION_ADAPTER);
|
||||
return (BookmarkCollectionAdapter) getAdapter().getAdapters().get(INDEX_BOOKMARKS_COLLECTION_ADAPTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -527,7 +513,8 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
private int getLastAvailableSortingType()
|
||||
{
|
||||
int currentType = getLastSortingType();
|
||||
@BookmarkManager.SortingType int[] types = getAvailableSortingTypes();
|
||||
@BookmarkManager.SortingType
|
||||
int[] types = getAvailableSortingTypes();
|
||||
for (@BookmarkManager.SortingType int type : types)
|
||||
{
|
||||
if (type == currentType)
|
||||
@@ -538,14 +525,12 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
|
||||
private boolean isEmpty()
|
||||
{
|
||||
return !getBookmarkListAdapter().isSearchResults()
|
||||
&& getBookmarkListAdapter().getItemCount() == 0;
|
||||
return !getBookmarkListAdapter().isSearchResults() && getBookmarkListAdapter().getItemCount() == 0;
|
||||
}
|
||||
|
||||
private boolean isEmptySearchResults()
|
||||
{
|
||||
return getBookmarkListAdapter().isSearchResults()
|
||||
&& getBookmarkListAdapter().getItemCount() == 0;
|
||||
return getBookmarkListAdapter().isSearchResults() && getBookmarkListAdapter().getItemCount() == 0;
|
||||
}
|
||||
|
||||
private boolean isLastOwnedCategory()
|
||||
@@ -591,8 +576,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
i.putExtra(MwmActivity.EXTRA_TRACK_ID, track.getTrackId());
|
||||
}
|
||||
|
||||
private void onBookmarkClicked(int position, @NonNull Intent i,
|
||||
@NonNull BookmarkListAdapter adapter)
|
||||
private void onBookmarkClicked(int position, @NonNull Intent i, @NonNull BookmarkListAdapter adapter)
|
||||
{
|
||||
final BookmarkInfo bookmark = (BookmarkInfo) adapter.getItem(position);
|
||||
i.putExtra(MwmActivity.EXTRA_CATEGORY_ID, bookmark.getCategoryId());
|
||||
@@ -605,7 +589,8 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
|
||||
mSelectedPosition = position;
|
||||
final Track mTrack = (Track) adapter.getItem(mSelectedPosition);
|
||||
if (mTrack == null) return;
|
||||
if (mTrack == null)
|
||||
return;
|
||||
final Bundle args = new Bundle();
|
||||
args.putInt(BookmarkColorDialogFragment.ICON_TYPE, Icon.getColorPosition(mTrack.getColor()));
|
||||
final FragmentManager manager = getChildFragmentManager();
|
||||
@@ -620,9 +605,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
if (from == to)
|
||||
return;
|
||||
BookmarkManager.INSTANCE.changeTrackColor(mTrack.getTrackId(), to);
|
||||
Drawable circle = Graphics.drawCircle(to,
|
||||
R.dimen.track_circle_size,
|
||||
requireContext().getResources());
|
||||
Drawable circle = Graphics.drawCircle(to, R.dimen.track_circle_size, requireContext().getResources());
|
||||
v.setImageDrawable(circle);
|
||||
});
|
||||
|
||||
@@ -646,7 +629,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
case BookmarkListAdapter.TYPE_BOOKMARK:
|
||||
final BookmarkInfo bookmark = (BookmarkInfo) adapter.getItem(mSelectedPosition);
|
||||
MenuBottomSheetFragment.newInstance(BOOKMARKS_MENU_ID, bookmark.getName())
|
||||
.show(getChildFragmentManager(), BOOKMARKS_MENU_ID);
|
||||
.show(getChildFragmentManager(), BOOKMARKS_MENU_ID);
|
||||
break;
|
||||
|
||||
case BookmarkListAdapter.TYPE_TRACK:
|
||||
@@ -699,7 +682,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
if (item.getItemId() == R.id.bookmarks_more)
|
||||
{
|
||||
MenuBottomSheetFragment.newInstance(OPTIONS_MENU_ID, mCategoryDataSource.getData().getName())
|
||||
.show(getChildFragmentManager(), OPTIONS_MENU_ID);
|
||||
.show(getChildFragmentManager(), OPTIONS_MENU_ID);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -716,29 +699,25 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
{
|
||||
BookmarkListAdapter adapter = getBookmarkListAdapter();
|
||||
BookmarkInfo info = (BookmarkInfo) adapter.getItem(mSelectedPosition);
|
||||
EditBookmarkFragment.editBookmark(
|
||||
info.getCategoryId(), info.getBookmarkId(), requireActivity(), getChildFragmentManager(),
|
||||
(bookmarkId, movedFromCategory) ->
|
||||
{
|
||||
if (movedFromCategory)
|
||||
resetSearchAndSort();
|
||||
else
|
||||
adapter.notifyDataSetChanged();
|
||||
});
|
||||
EditBookmarkFragment.editBookmark(info.getCategoryId(), info.getBookmarkId(), requireActivity(),
|
||||
getChildFragmentManager(), (bookmarkId, movedFromCategory) -> {
|
||||
if (movedFromCategory)
|
||||
resetSearchAndSort();
|
||||
else
|
||||
adapter.notifyDataSetChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private void onTrackEditActionSelected()
|
||||
{
|
||||
Track track = (Track) getBookmarkListAdapter().getItem(mSelectedPosition);
|
||||
EditBookmarkFragment.editTrack(
|
||||
track.getCategoryId(), track.getTrackId(), requireActivity(), getChildFragmentManager(),
|
||||
(trackId, movedFromCategory) ->
|
||||
{
|
||||
if (movedFromCategory)
|
||||
resetSearchAndSort();
|
||||
else
|
||||
getBookmarkListAdapter().notifyDataSetChanged();
|
||||
});
|
||||
EditBookmarkFragment.editTrack(track.getCategoryId(), track.getTrackId(), requireActivity(),
|
||||
getChildFragmentManager(), (trackId, movedFromCategory) -> {
|
||||
if (movedFromCategory)
|
||||
resetSearchAndSort();
|
||||
else
|
||||
getBookmarkListAdapter().notifyDataSetChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private void onDeleteActionSelected()
|
||||
@@ -756,8 +735,8 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
|
||||
private void onSortOptionSelected()
|
||||
{
|
||||
ChooseBookmarksSortingTypeFragment.chooseSortingType(getAvailableSortingTypes(),
|
||||
getLastSortingType(), requireActivity(), getChildFragmentManager());
|
||||
ChooseBookmarksSortingTypeFragment.chooseSortingType(getAvailableSortingTypes(), getLastSortingType(),
|
||||
requireActivity(), getChildFragmentManager());
|
||||
}
|
||||
|
||||
private void onShareOptionSelected(KmlFileType kmlFileType)
|
||||
@@ -768,7 +747,8 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
|
||||
private void onSettingsOptionSelected()
|
||||
{
|
||||
BookmarkCategorySettingsActivity.startForResult(this, startBookmarkSettingsForResult, mCategoryDataSource.getData());
|
||||
BookmarkCategorySettingsActivity.startForResult(this, startBookmarkSettingsForResult,
|
||||
mCategoryDataSource.getData());
|
||||
}
|
||||
|
||||
private void onDeleteOptionSelected()
|
||||
@@ -779,14 +759,17 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
|
||||
private ArrayList<MenuBottomSheetItem> getOptionsMenuItems()
|
||||
{
|
||||
@BookmarkManager.SortingType int[] types = getAvailableSortingTypes();
|
||||
@BookmarkManager.SortingType
|
||||
int[] types = getAvailableSortingTypes();
|
||||
ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
|
||||
if (!isEmpty())
|
||||
{
|
||||
if (types.length > 0)
|
||||
items.add(new MenuBottomSheetItem(R.string.sort, R.drawable.ic_sort, this::onSortOptionSelected));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file, R.drawable.ic_file_kmz, () -> onShareOptionSelected(KmlFileType.Text)));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx, () -> onShareOptionSelected(KmlFileType.Gpx)));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file, R.drawable.ic_file_kmz,
|
||||
() -> onShareOptionSelected(KmlFileType.Text)));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx,
|
||||
() -> onShareOptionSelected(KmlFileType.Gpx)));
|
||||
}
|
||||
items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_settings, this::onSettingsOptionSelected));
|
||||
if (!isLastOwnedCategory())
|
||||
@@ -807,9 +790,12 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
{
|
||||
ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
|
||||
items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_edit, this::onTrackEditActionSelected));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file, R.drawable.ic_file_kmz, () -> onShareTrackSelected(track.getTrackId(), KmlFileType.Text)));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx, () -> onShareTrackSelected(track.getTrackId(), KmlFileType.Gpx)));
|
||||
items.add(new MenuBottomSheetItem(R.string.delete, R.drawable.ic_delete, () -> onDeleteTrackSelected(track.getTrackId())));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file, R.drawable.ic_file_kmz,
|
||||
() -> onShareTrackSelected(track.getTrackId(), KmlFileType.Text)));
|
||||
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx,
|
||||
() -> onShareTrackSelected(track.getTrackId(), KmlFileType.Gpx)));
|
||||
items.add(new MenuBottomSheetItem(R.string.delete, R.drawable.ic_delete,
|
||||
() -> onDeleteTrackSelected(track.getTrackId())));
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -855,15 +841,22 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment<ConcatAdapter
|
||||
@Nullable
|
||||
public ArrayList<MenuBottomSheetItem> getMenuBottomSheetItems(String id)
|
||||
{
|
||||
if (id.equals(BOOKMARKS_MENU_ID))
|
||||
return getBookmarkMenuItems();
|
||||
if (id.equals(TRACK_MENU_ID))
|
||||
switch (id)
|
||||
{
|
||||
final Track track = (Track) getBookmarkListAdapter().getItem(mSelectedPosition);
|
||||
return getTrackMenuItems(track);
|
||||
case BOOKMARKS_MENU_ID ->
|
||||
{
|
||||
return getBookmarkMenuItems();
|
||||
}
|
||||
case TRACK_MENU_ID ->
|
||||
{
|
||||
final Track track = (Track) getBookmarkListAdapter().getItem(mSelectedPosition);
|
||||
return getTrackMenuItems(track);
|
||||
}
|
||||
case OPTIONS_MENU_ID ->
|
||||
{
|
||||
return getOptionsMenuItems();
|
||||
}
|
||||
}
|
||||
if (id.equals(OPTIONS_MENU_ID))
|
||||
return getOptionsMenuItems();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||