Compare commits
8
Commits
master
..
ce4ce2f2ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce4ce2f2ac | ||
|
|
cb892d1bbd | ||
|
|
b2a07b80d0 | ||
|
|
ea67fbd352 | ||
|
|
38fb1500b0 | ||
|
|
881dedf050 | ||
|
|
ce13d0c8aa | ||
|
|
63d41d14d1 |
No files matched your search
@@ -1,11 +1,8 @@
|
||||
## Strike Maps
|
||||
## Strike Maps Project Android Client
|
||||
|
||||
Strike Maps is a FOSS mapping app for Android,
|
||||
focusing on customization and offline features
|
||||
<br>
|
||||
|
||||
It is developed as part of a broader project, hoping to create a multi-platform,
|
||||
user-facing, complete FOSS mapping stack
|
||||
Strike Maps is a project hoping to create a multi-platform, <br>
|
||||
user-facing, complete FOSS mapping stack, focusing on customization <br>
|
||||
and offline features.
|
||||
<br>
|
||||
|
||||
This Android app has been in development since around January 2026
|
||||
|
||||
@@ -9,8 +9,8 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "eu.konggdev.strikemaps"
|
||||
minSdk = 23
|
||||
targetSdk = 36
|
||||
minSdk = 24
|
||||
targetSdk = 35
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
@@ -28,8 +28,8 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_15
|
||||
targetCompatibility = JavaVersion.VERSION_15
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@@ -46,14 +46,12 @@ dependencies {
|
||||
implementation(libs.constraintlayout)
|
||||
implementation(libs.viewpager2)
|
||||
|
||||
implementation("androidx.core:core-ktx:1.17.0")
|
||||
implementation("org.osmdroid:osmdroid-android:6.1.20")
|
||||
implementation("org.maplibre.gl:android-sdk:11.13.0")
|
||||
implementation("com.github.mapsforge.vtm:vtm:0.27.0")
|
||||
implementation("com.github.mapsforge.vtm:vtm-android:0.27.0")
|
||||
implementation("com.github.mapsforge.vtm:vtm-http:0.27.0")
|
||||
implementation ("com.github.mapsforge.vtm:vtm-android:0.27.0@jar")
|
||||
runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-armeabi-v7a@jar")
|
||||
runtimeOnly ("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-armeabi-v7a@jar")
|
||||
runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-arm64-v8a@jar")
|
||||
runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-x86@jar")
|
||||
runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-x86_64@jar")
|
||||
@@ -61,8 +59,8 @@ dependencies {
|
||||
implementation("com.caverock:androidsvg:1.4")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.0")
|
||||
implementation("commons-codec:commons-codec:1.17.2")
|
||||
implementation("org.apache.commons:commons-lang3:3.14.0")
|
||||
implementation(libs.core.ktx)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.ext.junit)
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.StrikeMaps">
|
||||
android:theme="@style/Theme.StrikeMaps"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".activity.MainActivity"
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
File renamed without changes.
+5
-5
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"version": 8,
|
||||
"name": "Satellite",
|
||||
"icon": "assets://satellite.bmp",
|
||||
"name": "Satelite",
|
||||
"icon": "assets://satelite.bmp",
|
||||
"sources": {
|
||||
"imagery": {
|
||||
"satelite": {
|
||||
"type": "raster",
|
||||
"schema" : "raster",
|
||||
"tiles": [
|
||||
@@ -17,9 +17,9 @@
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"id": "background",
|
||||
"id": "satelite",
|
||||
"type": "raster",
|
||||
"source": "imagery"
|
||||
"source": "satelite"
|
||||
}
|
||||
],
|
||||
"id": "satellite"
|
||||
@@ -1,125 +0,0 @@
|
||||
#
|
||||
Builds included inside /dist correspond to MapLibre GL JS version 5.24.0 <br>
|
||||
The source for these builds is available on https://github.com/maplibre/maplibre-gl-js
|
||||
#
|
||||
|
||||
All files inside the /dist folder are subject to the following license
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2023, MapLibre contributors
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of MapLibre GL JS nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Contains code from mapbox-gl-js v1.13 and earlier
|
||||
|
||||
Version v1.13 of mapbox-gl-js and earlier are licensed under a BSD-3-Clause license
|
||||
|
||||
Copyright (c) 2020, Mapbox
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Mapbox GL JS nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Contains code from glfx.js
|
||||
|
||||
Copyright (C) 2011 by Evan Wallace
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Contains a portion of d3-color https://github.com/d3/d3-color
|
||||
|
||||
Copyright 2010-2016 Mike Bostock
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of contributors may be used to
|
||||
endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1 +0,0 @@
|
||||
.maplibregl-map{font:12px/20px Helvetica Neue,Arial,Helvetica,sans-serif;overflow:hidden;position:relative;-webkit-tap-highlight-color:rgb(0 0 0/0)}.maplibregl-canvas{left:0;position:absolute;top:0}.maplibregl-map:fullscreen{height:100%;width:100%}.maplibregl-ctrl-group button.maplibregl-ctrl-compass{touch-action:none}.maplibregl-canvas-container.maplibregl-interactive,.maplibregl-ctrl-group button.maplibregl-ctrl-compass{cursor:grab;-webkit-user-select:none;-moz-user-select:none;user-select:none}.maplibregl-canvas-container.maplibregl-interactive.maplibregl-track-pointer{cursor:pointer}.maplibregl-canvas-container.maplibregl-interactive:active,.maplibregl-ctrl-group button.maplibregl-ctrl-compass:active{cursor:grabbing}.maplibregl-canvas-container.maplibregl-touch-zoom-rotate,.maplibregl-canvas-container.maplibregl-touch-zoom-rotate .maplibregl-canvas{touch-action:pan-x pan-y}.maplibregl-canvas-container.maplibregl-touch-drag-pan,.maplibregl-canvas-container.maplibregl-touch-drag-pan .maplibregl-canvas{touch-action:pinch-zoom}.maplibregl-canvas-container.maplibregl-touch-zoom-rotate.maplibregl-touch-drag-pan,.maplibregl-canvas-container.maplibregl-touch-zoom-rotate.maplibregl-touch-drag-pan .maplibregl-canvas{touch-action:none}.maplibregl-canvas-container.maplibregl-touch-drag-pan.maplibregl-cooperative-gestures,.maplibregl-canvas-container.maplibregl-touch-drag-pan.maplibregl-cooperative-gestures .maplibregl-canvas{touch-action:pan-x pan-y}.maplibregl-ctrl-bottom-left,.maplibregl-ctrl-bottom-right,.maplibregl-ctrl-top-left,.maplibregl-ctrl-top-right{pointer-events:none;position:absolute;z-index:2}.maplibregl-ctrl-top-left{left:0;top:0}.maplibregl-ctrl-top-right{right:0;top:0}.maplibregl-ctrl-bottom-left{bottom:0;left:0}.maplibregl-ctrl-bottom-right{bottom:0;right:0}.maplibregl-ctrl{clear:both;pointer-events:auto;transform:translate(0)}.maplibregl-ctrl-top-left .maplibregl-ctrl{float:left;margin:10px 0 0 10px}.maplibregl-ctrl-top-right .maplibregl-ctrl{float:right;margin:10px 10px 0 0}.maplibregl-ctrl-bottom-left .maplibregl-ctrl{float:left;margin:0 0 10px 10px}.maplibregl-ctrl-bottom-right .maplibregl-ctrl{float:right;margin:0 10px 10px 0}.maplibregl-ctrl-group{background:#fff;border-radius:4px}.maplibregl-ctrl-group:not(:empty){box-shadow:0 0 0 2px rgba(0,0,0,.1)}@media (forced-colors:active){.maplibregl-ctrl-group:not(:empty){box-shadow:0 0 0 2px ButtonText}}.maplibregl-ctrl-group button{background-color:transparent;border:0;box-sizing:border-box;cursor:pointer;display:block;height:29px;outline:none;padding:0;width:29px}.maplibregl-ctrl-group button+button{border-top:1px solid #ddd}.maplibregl-ctrl button .maplibregl-ctrl-icon{background-position:50%;background-repeat:no-repeat;display:block;height:100%;width:100%}@media (forced-colors:active){.maplibregl-ctrl-icon{background-color:transparent}.maplibregl-ctrl-group button+button{border-top:1px solid ButtonText}}.maplibregl-ctrl button::-moz-focus-inner{border:0;padding:0}.maplibregl-ctrl-attrib-button:focus,.maplibregl-ctrl-group button:focus{box-shadow:0 0 2px 2px #0096ff}.maplibregl-ctrl button:disabled{cursor:not-allowed}.maplibregl-ctrl button:disabled .maplibregl-ctrl-icon{opacity:.25}@media (hover:hover){.maplibregl-ctrl button:not(:disabled):hover{background-color:rgba(0,0,0,.05)}}.maplibregl-ctrl button:not(:disabled):active{background-color:rgba(0,0,0,.05)}.maplibregl-ctrl-group button:focus:focus-visible{box-shadow:0 0 2px 2px #0096ff}.maplibregl-ctrl-group button:focus:not(:focus-visible){box-shadow:none}.maplibregl-ctrl-group button:focus:first-child{border-radius:4px 4px 0 0}.maplibregl-ctrl-group button:focus:last-child{border-radius:0 0 4px 4px}.maplibregl-ctrl-group button:focus:only-child{border-radius:inherit}.maplibregl-ctrl button.maplibregl-ctrl-zoom-out .maplibregl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='29' height='29' fill='%23333' viewBox='0 0 29 29'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13z'/%3E%3C/svg%3E")}.maplibregl-ctrl button.maplibregl-ctrl-zoom-in .maplibregl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='29' height='29' fill='%23333' viewBox='0 0 29 29'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5'/%3E%3C/svg%3E")}@media (forced-colors:active){.maplibregl-ctrl button.maplibregl-ctrl-zoom-out .maplibregl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='29' height='29' fill='%23fff' viewBox='0 0 29 29'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13z'/%3E%3C/svg%3E")}.maplibregl-ctrl button.maplibregl-ctrl-zoom-in .maplibregl-ctrl-icon{background-image:url("data:image/svLine truncated
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* MapLibre GL JS
|
||||
* @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v5.24.0/LICENSE.txt
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.maplibregl = factory());
|
||||
})(this, (function () { 'use strict';
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
var maplibregl = {};
|
||||
var modules = {};
|
||||
function define(moduleName, _dependencies, moduleFactory) {
|
||||
modules[moduleName] = moduleFactory;
|
||||
|
||||
// to get the list of modules see generated dist/maplibre-gl-dev.js file (look for `define(` calls)
|
||||
if (moduleName !== 'index') {
|
||||
return;
|
||||
}
|
||||
|
||||
// we assume that when an index module is initializing then other modules are loaded already
|
||||
var workerBundleString = 'var sharedModule = {}; (' + modules.shared + ')(sharedModule); (' + modules.worker + ')(sharedModule);'
|
||||
|
||||
var sharedModule = {};
|
||||
// the order of arguments of a module factory depends on rollup (it decides who is whose dependency)
|
||||
// to check the correct order, see dist/maplibre-gl-dev.js file (look for `define(` calls)
|
||||
// we assume that for our 3 chunks it will generate 3 modules and their order is predefined like the following
|
||||
modules.shared(sharedModule);
|
||||
modules.index(maplibregl, sharedModule);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
maplibregl.setWorkerUrl(window.URL.createObjectURL(new Blob([workerBundleString], { type: 'text/javascript' })));
|
||||
}
|
||||
|
||||
return maplibregl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
define("shared",["exports"],(function(t){"use strict";function e(t,e,n,r){return new(n||(n=Promise))((function(i,s){function o(t){try{l(r.next(t));}catch(t){s(t);}}function a(t){try{l(r.throw(t));}catch(t){s(t);}}function l(t){var e;t.done?i(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e);}))).then(o,a);}l((r=r.apply(t,e||[])).next());}))}function n(t,e){this.x=t,this.y=e;}function r(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var i,s;"function"==typeof SuppressedError&&SuppressedError,n.prototype={clone(){return new n(this.x,this.y)},add(t){return this.clone()._add(t)},sub(t){return this.clone()._sub(t)},multByPoint(t){return this.clone()._multByPoint(t)},divByPoint(t){return this.clone()._divByPoint(t)},mult(t){return this.clone()._mult(t)},div(t){return this.clone()._div(t)},rotate(t){return this.clone()._rotate(t)},rotateAround(t,e){return this.clone()._rotateAround(t,e)},matMult(t){return this.clone()._matMult(t)},unit(){return this.clone()._unit()},perp(){return this.clone()._perp()},round(){return this.clone()._round()},mag(){return Math.sqrt(this.x*this.x+this.y*this.y)},equals(t){return this.x===t.x&&this.y===t.y},dist(t){return Math.sqrt(this.distSqr(t))},distSqr(t){const e=t.x-this.x,n=t.y-this.y;return e*e+n*n},angle(){return Math.atan2(this.y,this.x)},angleTo(t){return Math.atan2(this.y-t.y,this.x-t.x)},angleWith(t){return this.angleWithSep(t.x,t.y)},angleWithSep(t,e){return Math.atan2(this.x*e-this.y*t,this.x*t+this.y*e)},_matMult(t){const e=t[2]*this.x+t[3]*this.y;return this.x=t[0]*this.x+t[1]*this.y,this.y=e,this},_add(t){return this.x+=t.x,this.y+=t.y,this},_sub(t){return this.x-=t.x,this.y-=t.y,this},_mult(t){return this.x*=t,this.y*=t,this},_div(t){return this.x/=t,this.y/=t,this},_multByPoint(t){return this.x*=t.x,this.y*=t.y,this},_divByPoint(t){return this.x/=t.x,this.y/=t.y,this},_unit(){return this._div(this.mag()),this},_perp(){const t=this.y;return this.y=this.x,this.x=-t,this},_rotate(t){const e=Math.cos(t),n=Math.sin(t),r=n*this.x+e*this.y;return this.x=e*this.x-n*this.y,this.y=r,this},_rotateAround(t,e){const n=Math.cos(t),r=Math.sin(t),i=e.y+r*(this.x-e.x)+n*(this.y-e.y);return this.x=e.x+n*(this.x-e.x)-r*(this.y-e.y),this.y=i,this},_round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},constructor:n},n.convert=function(t){if(t instanceof n)return t;if(Array.isArray(t))return new n(+t[0],+t[1]);if(void 0!==t.x&&void 0!==t.y)return new n(+t.x,+t.y);throw new Error("Expected [x, y] or {x, y} point format")};var o=function(){if(s)return i;function t(t,e,n,r){this.cx=3*t,this.bx=3*(n-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(r-e)-this.cy,this.ay=1-this.cy-this.by,this.p1x=t,this.p1y=e,this.p2x=n,this.p2y=r;}return s=1,i=t,t.prototype={sampleCurveX:function(t){return ((this.ax*t+this.bx)*t+this.cx)*t},sampleCurveY:function(t){return ((this.ay*t+this.by)*t+this.cy)*t},sampleCurveDerivativeX:function(t){return (3*this.ax*t+2*this.bx)*t+this.cx},solveCurveX:function(t,e){if(void 0===e&&(e=1e-6),t<0)return 0;if(t>1)return 1;for(var n=t,r=0;r<8;r++){var i=this.sampleCurveX(n)-t;if(Math.abs(i)<e)return n;var s=this.sampleCurveDerivativeX(n);if(Math.abs(s)<1e-6)break;n-=i/s;}var o=0,a=1;for(n=t,r=0;r<20&&(i=this.sampleCurveX(n),!(Math.abs(i-t)<e));r++)t>i?o=n:a=n,n=.5*(a-o)+o;return n},solve:function(t,e){return this.sampleCurveY(this.solveCurveX(t,e))}},i}(),a=r(o);let l,u;function c(){return null!=l||(l="undefined"!=typeof OffscreenCanvas&&new OffscreenCanvas(1,1).getContext("2d")&&"function"==typeof createImageBitmap),l}function h(){if(null==u&&(u=!1,c())){const t=5,e=new OffscreenCanvas(t,t).getContext("2d",{willReadFrequently:!0});if(e){for(let n=0;n<t*t;n++){const r=4*n;e.fillStyle=`rgb(${r},${r+1},${r+2})`,e.fillRect(n%t,Math.floor(n/t),1,1);}const n=e.getImageData(0,0,t,t).data;for(let e=0;e<t*t*4;e++)if(e%4!=3&&n[e]!==e){u=!0;break}}}return u||!1}var p=1e-6,f="undefined"!=typeof Float32Array?Float32Array:Array;function d(){var t=new f(9);return f!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function y(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function m(){var t=new f(3);return f!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function g(t){var e=t[0],n=t[1],r=t[2];return Math.sqrt(e*e+n*n+r*r)}function x(t,e,n){var r=new f(3);return r[0]=t,r[1]=e,r[2]=n,r}function v(t,e,n){return t[0]=e[0]+n[0],t[1]=e[1]+n[1],t[2]=e[2]+n[2],t}function b(t,e,n){return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t}function w(t,e,n){var r=e[0],i=e[1],s=e[2],o=n[0],a=n[1],l=n[2];return t[0]=i*l-s*a,t[1]=s*o-r*l,t[2]=r*a-i*o,t}var _,S=g;function A(t,e,n){var r=e[0],i=e[1],s=e[2],o=e[3];return t[0]=n[0]*r+n[4]*i+n[8]*s+n[12]*o,t[1]=n[1]*r+n[5]*i+n[9]*s+n[13]*o,t[2]=n[2]*r+n[6]*i+n[10]*s+n[14]*o,t[3]=n[3]*r+n[7]*i+n[11]*s+n[15]*o,t}function M(){var t=new f(4);return f!=Float32Array&&(t[0]=0,t[1]=0,t[2]Line truncated
|
||||
|
||||
define("worker",["./shared"],(function(e){"use strict";class t{constructor(e,t){this.keyCache={},e&&this.replace(e,t);}replace(e,t){this._layerConfigs={},this._layers={},this.update(e,[],t);}update(t,i,s){for(const i of t){this._layerConfigs[i.id]=i;const t=this._layers[i.id]=e.bT(i,s);t._featureFilter=e.ah(t.filter,s),this.keyCache[i.id]&&delete this.keyCache[i.id];}for(const e of i)delete this.keyCache[e],delete this._layerConfigs[e],delete this._layers[e];this.familiesBySource={};const r=e.cJ(Object.values(this._layerConfigs),this.keyCache);for(const t of r){const i=t.map((e=>this._layers[e.id])),s=i[0];if(s.isHidden())continue;const r=s.source||"";let o=this.familiesBySource[r];o||(o=this.familiesBySource[r]={});const n=s.sourceLayer||e.ag;let a=o[n];a||(a=o[n]=[]),a.push(i);}}}class i{constructor(t){const i={},s=[];for(const e in t){const r=t[e],o=i[e]={};for(const e in r){const t=r[+e];if(!t||0===t.bitmap.width||0===t.bitmap.height)continue;const i={x:0,y:0,w:t.bitmap.width+2,h:t.bitmap.height+2};s.push(i),o[e]={rect:i,metrics:t.metrics};}}const{w:r,h:o}=e.p(s),n=new e.t({width:r||1,height:o||1});for(const s in t){const r=t[s];for(const t in r){const o=r[+t];if(!o||0===o.bitmap.width||0===o.bitmap.height)continue;const a=i[s][t].rect;e.t.copy(o.bitmap,n,{x:0,y:0},{x:a.x+1,y:a.y+1},o.bitmap);}}this.image=n,this.positions=i;}}e.cK("GlyphAtlas",i);class s{constructor(t){this.tileID=new e.a3(t.tileID.overscaledZ,t.tileID.wrap,t.tileID.canonical.z,t.tileID.canonical.x,t.tileID.canonical.y),this.uid=t.uid,this.zoom=t.zoom,this.pixelRatio=t.pixelRatio,this.tileSize=t.tileSize,this.source=t.source,this.overscaling=this.tileID.overscaleFactor(),this.showCollisionBoxes=t.showCollisionBoxes,this.collectResourceTiming=!!t.collectResourceTiming,this.returnDependencies=!!t.returnDependencies,this.promoteId=t.promoteId,this.inFlightDependencies=[];}parse(t,s,o,n,a){return e._(this,void 0,void 0,(function*(){this.status="parsing",this.data=t,this.collisionBoxArray=new e.ae;const l=new e.cL(Object.keys(t.layers).sort()),c=new e.cM(this.tileID,this.promoteId);c.bucketLayerIDs=[];const h={},d={featureIndex:c,iconDependencies:{},patternDependencies:{},glyphDependencies:{},dashDependencies:{},availableImages:o,subdivisionGranularity:a},u=s.familiesBySource[this.source];for(const i in u){const s=t.layers[i];if(!s)continue;1===s.version&&e.w(`Vector tile source "${this.source}" layer "${i}" does not use vector tile spec v2 and therefore may have some rendering errors.`);const n=l.encode(i),a=[];for(let e=0;e<s.length;e++){const t=s.feature(e),r=c.getId(t,i);a.push({feature:t,id:r,index:e,sourceLayerIndex:n});}for(const t of u[i]){const i=t[0];i.source!==this.source&&e.w(`layer.source = ${i.source} does not equal this.source = ${this.source}`),i.isHidden(this.zoom,!0)||(r(t,this.zoom,o),(h[i.id]=i.createBucket({index:c.bucketLayerIDs.length,layers:t,zoom:this.zoom,pixelRatio:this.pixelRatio,overscaling:this.overscaling,collisionBoxArray:this.collisionBoxArray,sourceLayerIndex:n,sourceID:this.source})).populate(a,d,this.tileID.canonical),c.bucketLayerIDs.push(t.map((e=>e.id))));}}const g=e.bY(d.glyphDependencies,(e=>Object.keys(e).map(Number)));for(const e of this.inFlightDependencies)null==e||e.abort();this.inFlightDependencies=[];let p=Promise.resolve({});if(Object.keys(g).length){const e=new AbortController;this.inFlightDependencies.push(e),p=n.sendAsync({type:"GG",data:{stacks:g,source:this.source,tileID:this.tileID,type:"glyphs"}},e);}const f=Object.keys(d.iconDependencies);let y=Promise.resolve({});if(f.length){const e=new AbortController;this.inFlightDependencies.push(e),y=n.sendAsync({type:"GI",data:{icons:f,source:this.source,tileID:this.tileID,type:"icons"}},e);}const v=Object.keys(d.patternDependencies);let m=Promise.resolve({});if(v.length){const e=new AbortController;this.inFlightDependencies.push(e),m=n.sendAsync({type:"GI",data:{icons:v,source:this.source,tileID:this.tileID,type:"patterns"}},e);}const _=d.dashDependencies;let S=Promise.resolve({});if(Object.keys(_).length){const e=new AbortController;this.inFlightDependencies.push(e),S=n.sendAsync({type:"GDA",data:{dashes:_}},e);}const[w,b,I,T]=yield Promise.all([p,y,m,S]),k=new i(w),x=new e.cN(b,I);for(const t in h){const i=h[t];i instanceof e.af?(r(i.layers,this.zoom,o),e.cO({bucket:i,glyphMap:w,glyphPositions:k.positions,imageMap:b,imagePositions:x.iconPositions,showCollisionBoxes:this.showCollisionBoxes,canonical:this.tileID.canonical,subdivisionGranularity:d.subdivisionGranularity})):i.hasDependencies&&(i instanceof e.cP||i instanceof e.cQ||i instanceof e.cR)&&(r(i.layers,this.zoom,o),i.addFeatures(d,this.tileID.canonical,x.patternPositions,T));}return this.status="done",{buckets:Object.values(h).filter((e=>!e.isEmpty())),featureIndex:c,collisionBoxArray:this.collisionBoxArray,glyphAtlasImage:k.image,imageAtlas:x,dashPositions:T,glyphMap:this.returnDependencies?w:null,iconMap:this.returnDependencies?b:null,glyphPositions:this.returnDependencies?k.positionLine truncated
|
||||
|
||||
define("index",["exports","./shared"],(function(e,t){"use strict";var i="5.24.0";function o(){var e=new t.A(4);return t.A!=Float32Array&&(e[1]=0,e[2]=0),e[0]=1,e[3]=1,e}let a,r,s;const n={frame(e,i,o,a){const r=a||window,s=r.requestAnimationFrame((e=>{n(),i(e);})),{unsubscribe:n}=t.s(e.signal,"abort",(()=>{n(),r.cancelAnimationFrame(s),o(new t.a(e.signal.reason));}),!1);},frameAsync(e,t){return new Promise(((i,o)=>{this.frame(e,i,o,t);}))},getImageData(e,t=0){return this.getImageCanvasContext(e).getImageData(-t,-t,e.width+2*t,e.height+2*t)},getImageCanvasContext(e){const t=window.document.createElement("canvas"),i=t.getContext("2d",{willReadFrequently:!0});if(!i)throw new Error("failed to create canvas 2d context");return t.width=e.width,t.height=e.height,i.drawImage(e,0,0,e.width,e.height),i},resolveURL:e=>(a||(a=document.createElement("a")),a.href=e,a.href),hardwareConcurrency:"undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,get prefersReducedMotion(){return void 0!==s?s:!!matchMedia&&(null!=r||(r=matchMedia("(prefers-reduced-motion: reduce)")),r.matches)},set prefersReducedMotion(e){s=e;}},l=new class{constructor(){this._frozenAt=null;}getCurrentTime(){return null!==this._frozenAt?this._frozenAt:performance.now()}setNow(e){this._frozenAt=e;}restoreNow(){this._frozenAt=null;}isFrozen(){return null!==this._frozenAt}};function c(){return l.getCurrentTime()}var h,u;class d{static create(e,t,i){const o=window.document.createElement(e);return void 0!==t&&(o.className=t),i&&i.appendChild(o),o}static createNS(e,t){return window.document.createElementNS(e,t)}static disableDrag(){d.docStyle&&d.selectProp&&(d.userSelect=d.docStyle[d.selectProp],d.docStyle[d.selectProp]="none");}static enableDrag(){d.docStyle&&d.selectProp&&(d.docStyle[d.selectProp]=d.userSelect);}static suppressClickInternal(e){e.preventDefault(),e.stopPropagation(),window.removeEventListener("click",d.suppressClickInternal,!0);}static suppressClick(){window.addEventListener("click",d.suppressClickInternal,!0),window.setTimeout((()=>{window.removeEventListener("click",d.suppressClickInternal,!0);}),0);}static getScale(e){const t=e.getBoundingClientRect();return {x:t.width/e.offsetWidth||1,y:t.height/e.offsetHeight||1,boundingClientRect:t}}static getPoint(e,i,o){const a=i.boundingClientRect;return new t.P((o.clientX-a.left)/i.x-e.clientLeft,(o.clientY-a.top)/i.y-e.clientTop)}static mousePos(e,t){const i=d.getScale(e);return d.getPoint(e,i,t)}static touchPos(e,t){const i=[],o=d.getScale(e);for(const a of t)i.push(d.getPoint(e,o,a));return i}static sanitize(e){const t=(new DOMParser).parseFromString(e,"text/html").body||document.createElement("body"),i=t.querySelectorAll("script");for(const e of i)e.remove();return d.clean(t),t.innerHTML}static isPossiblyDangerous(e,t){const i=t.replace(/\s+/g,"").toLowerCase();return !(!["src","href","xlink:href"].includes(e)||!i.includes("javascript:")&&!i.includes("data:"))||!!e.startsWith("on")||void 0}static clean(e){const t=e.children;for(const e of t)d.removeAttributes(e),d.clean(e);}static removeAttributes(e){for(const{name:t,value:i}of e.attributes)d.isPossiblyDangerous(t,i)&&e.removeAttribute(t);}}d.docStyle="undefined"!=typeof window&&(null===(h=window.document)||void 0===h?void 0:h.documentElement.style),d.selectProp=!d.docStyle||"userSelect"in d.docStyle?"userSelect":"webkitUserSelect",function(e){let i,o,a,r;e.resetRequestQueue=()=>{i=[],o=0,a=0,r={};},e.addThrottleControl=e=>{const t=a++;return r[t]=e,t},e.removeThrottleControl=e=>{delete r[e],n();},e.getImage=(e,o,a=!0)=>new Promise(((r,s)=>{e.headers||(e.headers={}),e.headers.accept="image/webp,*/*",t.e(e,{type:"image"}),i.push({abortController:o,requestParameters:e,supportImageRefresh:a,state:"queued",onError:e=>{s(e);},onSuccess:e=>{r(e);}}),n();}));const s=e=>t._(this,void 0,void 0,(function*(){e.state="running";const{requestParameters:i,supportImageRefresh:a,onError:r,onSuccess:s,abortController:c}=e,h=!1===a&&!t.i(self)&&!t.g(i.url)&&(!i.headers||Object.keys(i.headers).reduce(((e,t)=>e&&"accept"===t),!0));o++;const u=h?l(i,c):t.m(i,c);try{const i=yield u;delete e.abortController,e.state="completed",i.data instanceof HTMLImageElement||t.b(i.data)?s(i):i.data&&s({data:yield(d=i.data,"function"==typeof createImageBitmap?t.h(d):t.j(d)),cacheControl:i.cacheControl,expires:i.expires});}catch(i){delete e.abortController,r(t.d(i));}finally{o--,n();}var d;})),n=()=>{const e=(()=>{for(const e of Object.keys(r))if(r[e]())return !0;return !1})()?t.c.MAX_PARALLEL_IMAGE_REQUESTS_PER_FRAME:t.c.MAX_PARALLEL_IMAGE_REQUESTS;for(let t=o;t<e&&i.length>0;t++){const e=i.shift();e.abortController.signal.aborted?t--:s(e);}},l=(e,i)=>new Promise(((o,a)=>{const r=new Image,s=e.url,n=e.credentials;n&&"include"===n?r.crossOrigin="use-credentials":(n&&"same-origin"===n||!t.f(s))&&(r.crossOrigin="anonymous"),i.signal.addEventListener("abort",(()=>{r.src="",a(new t.a(i.signal.reason));})),r.fetchPriority="high",r.onload=()=>{r.onerror=r.onload=null,o({data:r});Line truncated
|
||||
|
||||
//
|
||||
// Our custom intro provides a specialized "define()" function, called by the
|
||||
// AMD modules below, that sets up the worker blob URL and then executes the
|
||||
// main module, storing its exported value as 'maplibregl'
|
||||
|
||||
|
||||
var maplibregl$1 = maplibregl;
|
||||
|
||||
return maplibregl$1;
|
||||
|
||||
}));
|
||||
//# sourceMappingURL=maplibre-gl.js.map
|
||||
@@ -1,29 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="dist/maplibre-gl.js"></script>
|
||||
<link href="dist/maplibre-gl.css" rel="stylesheet"/>
|
||||
<style>
|
||||
html, body, #map {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="map" style="width: 100%; height: 100%"></div>
|
||||
<script>
|
||||
const map = new maplibregl.Map({
|
||||
center: [13.388, 52.517],
|
||||
zoom: 9.5,
|
||||
container: 'map',
|
||||
attributionControl: false
|
||||
})
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
package eu.konggdev.strikemaps;
|
||||
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.lineColor;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.lineWidth;
|
||||
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
AppController app;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
app = new AppController(this);
|
||||
app.init();
|
||||
}
|
||||
|
||||
public void logcat(String tag, String log) {
|
||||
Log.i(tag, log);
|
||||
}
|
||||
|
||||
public void logcat(String log) {
|
||||
Log.i("LogcatGeneric", log);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package eu.konggdev.strikemaps.activity;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import eu.konggdev.strikemaps.Component;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.element.region.UIRegion;
|
||||
import eu.konggdev.strikemaps.ui.element.region.content.MainContentRegion;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutControls;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutSearch;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentOfflineMaps;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentSettings;
|
||||
import eu.konggdev.strikemaps.ui.screen.Screen;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MainActivity extends ComponentHolderActivity {
|
||||
private List<Component> components;
|
||||
private UIComponent ui;
|
||||
|
||||
private Map<String, Screen> initScreens(UIComponent ui, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs) {
|
||||
return Map.of(
|
||||
//Main screen
|
||||
"main", new Screen(
|
||||
this,
|
||||
//Main screen init regions definition
|
||||
Map.of(
|
||||
R.id.mainContentView, new MainContentRegion(map.toFragment(), R.id.mainContentView),
|
||||
R.id.bottomUi, new UIRegion(new FragmentLayoutControls(this, ui, map, registry, userPrefs, R.id.bottomUi), R.id.bottomUi),
|
||||
R.id.topUi, new UIRegion(new FragmentLayoutSearch(this, ui, R.id.topUi), R.id.topUi)
|
||||
) //TODO: Probably stop referencing layout 3(!) times everytime
|
||||
),
|
||||
//Settings screen
|
||||
"settings", new Screen(
|
||||
this,
|
||||
//Just the settings content fragment
|
||||
Map.of(
|
||||
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentSettings(this, ui, userPrefs), R.id.mainContentView)
|
||||
)
|
||||
),
|
||||
//Offline maps screen
|
||||
"offline", new Screen(
|
||||
this,
|
||||
Map.of(
|
||||
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentOfflineMaps(this), R.id.mainContentView)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Component> initComponents() {
|
||||
SharedPreferences userPrefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
|
||||
RegistryStorageComponent registry = new RegistryStorageComponent(this, userPrefs);
|
||||
MapComponent map = new MapComponent(this, registry, userPrefs);
|
||||
UIComponent ui = new UIComponent(this, map, registry, userPrefs);
|
||||
ui.defineScreens(initScreens(ui, map, registry, userPrefs));
|
||||
this.ui = ui;
|
||||
return List.of(
|
||||
map,
|
||||
ui,
|
||||
registry
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
this.components = initComponents();
|
||||
ui.swapScreen("main");
|
||||
setContentView(R.layout.view_main);
|
||||
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
if (!ui.back()) {
|
||||
setEnabled(false);
|
||||
getOnBackPressedDispatcher().onBackPressed();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package eu.konggdev.strikemaps.app;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import eu.konggdev.strikemaps.MainActivity;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
public class AppController {
|
||||
private final MainActivity appActivity;
|
||||
|
||||
private MapComponent map;
|
||||
private UIComponent ui;
|
||||
public AppController(MainActivity refActivity) {
|
||||
appActivity = refActivity;
|
||||
}
|
||||
public void logcat(String log) {
|
||||
appActivity.logcat(log);
|
||||
}
|
||||
public UIComponent getUi() {
|
||||
if (ui == null) init();
|
||||
return ui;
|
||||
}
|
||||
public MapComponent getMap() {
|
||||
if (map == null) init();
|
||||
return map;
|
||||
}
|
||||
public SharedPreferences getPrefs() {
|
||||
return getActivity().getSharedPreferences("user_prefs", MODE_PRIVATE);
|
||||
}
|
||||
public AppCompatActivity getActivity() { return appActivity; }
|
||||
public void init() {
|
||||
if (getActivity().getSupportActionBar() != null)
|
||||
getActivity().getSupportActionBar().hide();
|
||||
|
||||
if(map == null) map = new MapComponent(this);
|
||||
if(ui == null) {
|
||||
ui = new UIComponent(this, map);
|
||||
ui.swapScreen(R.layout.screen_main); //Initial
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package eu.konggdev.strikemaps.app;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import eu.konggdev.strikemaps.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ComponentHolderActivity extends AppCompatActivity {
|
||||
private List<Component> components = new ArrayList<>();
|
||||
|
||||
public final <T extends Component> T getComponent(Class<T> type) {
|
||||
return components.stream()
|
||||
.filter(type::isInstance)
|
||||
.findFirst()
|
||||
.map(type::cast)
|
||||
.orElse(null);
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package eu.konggdev.strikemaps.data.helper;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
|
||||
//FIXME: Ugly
|
||||
public final class FileHelper {
|
||||
public static String loadStringFromAssetFile(String filePath, AppController app) {
|
||||
try (InputStream is = app.getActivity().getAssets().open(filePath)) {
|
||||
int size = is.available();
|
||||
byte[] buffer = new byte[size];
|
||||
is.read(buffer);
|
||||
return new String(buffer, StandardCharsets.UTF_8);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String loadStringFromUserFile(String filePath) {
|
||||
File file = new File(filePath);
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
int size = fis.available();
|
||||
byte[] buffer = new byte[size];
|
||||
fis.read(buffer);
|
||||
return new String(buffer, StandardCharsets.UTF_8);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getAssetFiles(String path, String fileExt, AppController app) {
|
||||
AssetManager assetManager = app.getActivity().getAssets();
|
||||
try {
|
||||
if (path != null && path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
|
||||
String fullPath = (path == null || path.isEmpty()) ? "" : path;
|
||||
|
||||
String[] files = assetManager.list(fullPath);
|
||||
|
||||
if (files == null) return new String[0];
|
||||
|
||||
if (fileExt == null || fileExt.isEmpty())
|
||||
return files;
|
||||
|
||||
List<String> filtered = new ArrayList<>();
|
||||
for (String file : files) {
|
||||
if (file.toLowerCase().endsWith(fileExt.toLowerCase())) {
|
||||
filtered.add((fullPath.isEmpty() ? "" : fullPath + "/") + file);
|
||||
}
|
||||
}
|
||||
|
||||
return filtered.toArray(new String[0]);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream openAssetStream(String path, AppController app) {
|
||||
try {
|
||||
return app.getActivity().getAssets().open(path);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getUserFiles(String path, String fileExt, AppController app) {
|
||||
String packageName = app.getActivity().getPackageName();
|
||||
File userDirectory = new File(Environment.getExternalStorageDirectory(), "Android/data/" + packageName + "/" + path);
|
||||
|
||||
if (!userDirectory.exists() || !userDirectory.isDirectory())
|
||||
return new String[0];
|
||||
|
||||
File[] files = userDirectory.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String filename) {
|
||||
if (fileExt == null || fileExt.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return filename.toLowerCase().endsWith(fileExt.toLowerCase());
|
||||
}
|
||||
});
|
||||
|
||||
if (files == null || files.length == 0) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
List<String> fileList = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
fileList.add(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
return fileList.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package eu.konggdev.strikemaps.data.helper;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public final class UserPrefsHelper {
|
||||
private UserPrefsHelper() {} // prevent instantiation
|
||||
|
||||
//Keys
|
||||
private static final String KEY_STARTUP_MAP_STYLE = "startupMapStyle";
|
||||
private static final String KEY_MAP_RENDERER = "mapRenderer";
|
||||
private static final String KEY_PERSIST_LOCATION_ENABLED = "persistLocationEnabled";
|
||||
private static final String KEY_LAST_LOCATION_ENABLED = "lastLocationEnabled";
|
||||
|
||||
//Defaults
|
||||
private static final String DEFAULT_MAP_STYLE = "bundled/style/classic.style.json";
|
||||
private static final String DEFAULT_MAP_RENDERER = "mapLibre";
|
||||
private static final boolean DEFAULT_PERSIST_LOCATION_ENABLED = true;
|
||||
private static final boolean DEFAULT_LAST_LOCATION_ENABLED = false;
|
||||
|
||||
|
||||
public static String startupMapStyle(SharedPreferences prefs) {
|
||||
return prefs.getString(KEY_STARTUP_MAP_STYLE, DEFAULT_MAP_STYLE);
|
||||
}
|
||||
|
||||
public static String mapRenderer(SharedPreferences prefs) {
|
||||
return prefs.getString(KEY_MAP_RENDERER, DEFAULT_MAP_RENDERER);
|
||||
}
|
||||
|
||||
public static boolean persistLocationEnabled(SharedPreferences prefs) {
|
||||
return prefs.getBoolean(KEY_PERSIST_LOCATION_ENABLED, DEFAULT_PERSIST_LOCATION_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean lastLocationEnabled(SharedPreferences prefs) {
|
||||
return prefs.getBoolean(KEY_LAST_LOCATION_ENABLED, DEFAULT_LAST_LOCATION_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean lastLocationEnabled(SharedPreferences prefs, boolean status) {
|
||||
return prefs.edit().putBoolean(KEY_LAST_LOCATION_ENABLED, status).commit();
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package eu.konggdev.strikemaps.helper;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
import eu.konggdev.strikemaps.map.source.tiles.SourceTiles;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
|
||||
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
|
||||
import eu.konggdev.strikemaps.util.file.FileTools;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class UserPrefsHelper {
|
||||
private UserPrefsHelper() {} // prevent instantiation
|
||||
|
||||
//Keys
|
||||
private static final String KEY_STARTUP_MAP_STYLE = "startupMapStyle";
|
||||
private static final String KEY_MAP_RENDERER = "mapRenderer";
|
||||
private static final String KEY_PERSIST_LOCATION_ENABLED = "persistLocationEnabled";
|
||||
private static final String KEY_LAST_LOCATION_ENABLED = "lastLocationEnabled";
|
||||
private static final String KEY_STYLES = "styles";
|
||||
private static final String KEY_SOURCES = "sources";
|
||||
|
||||
//Defaults
|
||||
private static final Integer DEFAULT_MAP_STYLE = 0;
|
||||
private static final Integer DEFAULT_MAP_RENDERER = 0;
|
||||
private static final boolean DEFAULT_PERSIST_LOCATION_ENABLED = true;
|
||||
private static final boolean DEFAULT_LAST_LOCATION_ENABLED = false;
|
||||
|
||||
public static Map<Integer, MapStyle> DEFAULT_STYLES(ComponentHolderActivity app) {
|
||||
Map<Integer, MapStyle> styles = new HashMap<>();
|
||||
String[] styleAssets = FileTools.getAssetFiles("bundled/style", ".style.json", app);
|
||||
for (int i = 0; i < styleAssets.length; i++) {
|
||||
String styleContents = FileTools.loadStringFromAssetFile(styleAssets[i], app);
|
||||
styles.put( i,
|
||||
new MapStyle(
|
||||
styleContents,
|
||||
new StyleOptions(),
|
||||
new StyleManagementMetadata( //Set the style to automatically update from assets
|
||||
false, true, true,
|
||||
"assets://" + styleAssets[i], DigestUtils.sha256Hex(styleContents))
|
||||
));
|
||||
}
|
||||
return styles;
|
||||
} //Built-in Styles
|
||||
|
||||
private static final Map<Integer, MapSource> DEFAULT_SOURCES = Map.of(
|
||||
0, new MapSource(
|
||||
"Strike Maps Planet",
|
||||
new SourceTiles("https://tiles.strikemaps.eu/planet"),
|
||||
"vector",
|
||||
"smts"
|
||||
),
|
||||
1, new MapSource(
|
||||
"ArcGIS Imagery",
|
||||
new SourceTiles(new String[]{"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}),
|
||||
"raster",
|
||||
"raster"
|
||||
)
|
||||
); //Built-in Sources
|
||||
|
||||
public static Integer startupMapStyle(SharedPreferences prefs) {
|
||||
return prefs.getInt(KEY_STARTUP_MAP_STYLE, DEFAULT_MAP_STYLE);
|
||||
}
|
||||
|
||||
public static boolean startupMapStyle(SharedPreferences prefs, Integer updated) {
|
||||
return prefs.edit().putInt(KEY_STARTUP_MAP_STYLE, updated).commit();
|
||||
}
|
||||
|
||||
public static Integer mapRenderer(SharedPreferences prefs) {
|
||||
return prefs.getInt(KEY_MAP_RENDERER, DEFAULT_MAP_RENDERER);
|
||||
}
|
||||
|
||||
public static boolean mapRenderer(SharedPreferences prefs, Integer updated) {
|
||||
return prefs.edit().putInt(KEY_MAP_RENDERER, updated).commit();
|
||||
}
|
||||
|
||||
public static boolean persistLocationEnabled(SharedPreferences prefs) {
|
||||
return prefs.getBoolean(KEY_PERSIST_LOCATION_ENABLED, DEFAULT_PERSIST_LOCATION_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean lastLocationEnabled(SharedPreferences prefs) {
|
||||
return prefs.getBoolean(KEY_LAST_LOCATION_ENABLED, DEFAULT_LAST_LOCATION_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean lastLocationEnabled(SharedPreferences prefs, boolean status) {
|
||||
return prefs.edit().putBoolean(KEY_LAST_LOCATION_ENABLED, status).commit();
|
||||
}
|
||||
|
||||
public static Map<Integer, MapStyle> styles(SharedPreferences prefs, ComponentHolderActivity app) {
|
||||
String json = prefs.getString(KEY_STYLES, null);
|
||||
if (json == null) return DEFAULT_STYLES(app);
|
||||
Type type = new TypeToken<Map<Integer, MapStyle.StoredRepresentation>>() {}.getType();
|
||||
Map<Integer, MapStyle.StoredRepresentation> stored =
|
||||
new Gson().fromJson(json, type);
|
||||
Map<Integer, MapStyle> result = new HashMap<>();
|
||||
for (var entry : stored.entrySet())
|
||||
result.put(entry.getKey(), entry.getValue().restore());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean styles(SharedPreferences prefs, Map<Integer, MapStyle> updated) {
|
||||
Map<Integer, MapStyle.StoredRepresentation> stored = new HashMap<>();
|
||||
for (var entry : updated.entrySet())
|
||||
stored.put(entry.getKey(), entry.getValue().makeStoredRepresentation());
|
||||
return prefs.edit()
|
||||
.putString(KEY_STYLES, new Gson().toJson(stored))
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static Map<Integer, MapSource> sources(SharedPreferences prefs) {
|
||||
String json = prefs.getString(KEY_SOURCES, null);
|
||||
if (json == null) return DEFAULT_SOURCES;
|
||||
Type type = new TypeToken<Map<Integer, MapSource>>() {}.getType();
|
||||
return new Gson().fromJson(json, type);
|
||||
}
|
||||
|
||||
public static boolean sources(SharedPreferences prefs, Map<Integer, MapSource> updated) {
|
||||
return prefs.edit()
|
||||
.putString(KEY_SOURCES, new Gson().toJson(updated))
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,35 @@
|
||||
package eu.konggdev.strikemaps.map;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
import eu.konggdev.strikemaps.Component;
|
||||
import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreGLJSRenderer;
|
||||
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
|
||||
import eu.konggdev.strikemaps.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.data.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.map.renderer.implementation.VtmRenderer;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreNativeRenderer;
|
||||
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentMap;
|
||||
|
||||
public class MapComponent implements Component {
|
||||
private final String TAG = "MapComponent";
|
||||
|
||||
private final MapRenderer mapRenderer;
|
||||
|
||||
private final ComponentHolderActivity activity;
|
||||
|
||||
private final RegistryStorageComponent registry;
|
||||
|
||||
private final SharedPreferences userPrefs;
|
||||
|
||||
//Current style
|
||||
public Integer styleId;
|
||||
public class MapComponent implements Component {
|
||||
MapRenderer mapRenderer;
|
||||
AppController app;
|
||||
|
||||
public MapStyle style;
|
||||
public Map<Class<? extends MapOverlay>, MapOverlay> overlays = new HashMap<>();
|
||||
|
||||
public MapComponent(ComponentHolderActivity activity, RegistryStorageComponent registry, SharedPreferences userPrefs) {
|
||||
this.activity = activity;
|
||||
this.registry = registry;
|
||||
this.userPrefs = userPrefs;
|
||||
switch(UserPrefsHelper.mapRenderer(userPrefs)) {
|
||||
case 0:
|
||||
this.mapRenderer = new MapLibreGLJSRenderer(activity, this);
|
||||
break;
|
||||
case 1:
|
||||
this.mapRenderer = new MapLibreNativeRenderer(activity, this);
|
||||
break;
|
||||
case 2:
|
||||
this.mapRenderer = new VtmRenderer(activity, this);
|
||||
public MapComponent(AppController ref) {
|
||||
this.app = ref;
|
||||
switch(UserPrefsHelper.mapRenderer(app.getPrefs())) {
|
||||
case "vtm":
|
||||
this.mapRenderer = new VtmRenderer(app, this);
|
||||
break;
|
||||
case "mapLibre":
|
||||
default: //This shouldn't happen
|
||||
Toast.makeText(activity, "Invalid renderer value in preferences\nFalling back to MapLibre GL JS", Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "Invalid renderer value in preferences\nFalling back to MapLibre GL JS");
|
||||
this.mapRenderer = new MapLibreGLJSRenderer(activity, this);
|
||||
this.mapRenderer = new MapLibreNativeRenderer(app, this);
|
||||
break;
|
||||
};
|
||||
}
|
||||
@@ -64,22 +38,15 @@ public class MapComponent implements Component {
|
||||
return new FragmentLayoutContentMap(mapRenderer.getView());
|
||||
}
|
||||
|
||||
public void setStyle(Integer id) {
|
||||
styleId = id;
|
||||
//Pass to renderer
|
||||
StyleDocument document = registry.getStyle(styleId)
|
||||
.effectiveDocument(registry);
|
||||
if (document == null) {
|
||||
Log.e(TAG, "Received null style from registry");
|
||||
return;
|
||||
}
|
||||
mapRenderer.styleUpdate(document);
|
||||
public void setStyle(MapStyle style) {
|
||||
this.style = style;
|
||||
mapRenderer.reload();
|
||||
}
|
||||
|
||||
public void switchOverlay(MapOverlay overlay) {
|
||||
if (hasOverlay(overlay)) overlays.remove(overlay.getClass());
|
||||
else overlays.put(overlay.getClass(), overlay);
|
||||
overlayUpdate(overlay);
|
||||
update();
|
||||
}
|
||||
|
||||
public boolean hasOverlay(MapOverlay overlay) {
|
||||
@@ -90,14 +57,18 @@ public class MapComponent implements Component {
|
||||
return overlays.containsKey(overlay);
|
||||
}
|
||||
|
||||
public void overlayUpdate(MapOverlay in) {
|
||||
mapRenderer.overlayUpdate(in);
|
||||
}
|
||||
|
||||
public void selectPoint(Feature selection) {
|
||||
//FIXME: Put back FragmentPointPreviewPopup (private code atm)
|
||||
}
|
||||
|
||||
public void onOverlayUpdate() {
|
||||
update();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(mapRenderer != null && style != null) mapRenderer.reload();
|
||||
}
|
||||
|
||||
public boolean onMapClick(LatLng point) {
|
||||
List<Feature> features = mapRenderer.featuresAtPoint(point);
|
||||
|
||||
@@ -110,12 +81,10 @@ public class MapComponent implements Component {
|
||||
selectPoint(features.get(0));
|
||||
break;
|
||||
default:
|
||||
UIComponent ui = activity.getComponent(UIComponent.class);
|
||||
if (ui != null) {
|
||||
ui.alert(
|
||||
AlertDialogFactory.pointSelector(activity, ui, features, this::selectPoint)
|
||||
);
|
||||
}
|
||||
app.getUi().alert(
|
||||
AlertDialogFactory.pointSelector(app, features, selectedItem -> {
|
||||
selectPoint(selectedItem);
|
||||
}));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -124,10 +93,4 @@ public class MapComponent implements Component {
|
||||
//TODO: Likely Nonfeature(?) point selection
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onMapInit() {
|
||||
setStyle(
|
||||
UserPrefsHelper.startupMapStyle(userPrefs)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package eu.konggdev.strikemaps.map.layer;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class MapLayer {
|
||||
public JsonNode layer;
|
||||
|
||||
public MapLayer(JsonNode layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package eu.konggdev.strikemaps.map.layer;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
|
||||
public class SourcedMapLayer {
|
||||
public String key;
|
||||
public MapSource source;
|
||||
public JsonNode layer;
|
||||
|
||||
public SourcedMapLayer(String key, MapSource source, JsonNode layer) {
|
||||
this.key = key;
|
||||
this.source = source;
|
||||
this.layer = layer;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.offline;
|
||||
|
||||
import okhttp3.*;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class OfflineTileResolver {
|
||||
|
||||
public static byte[] resolve(String url) throws IOException {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.offline.download;
|
||||
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public final class OfflineDownloader {
|
||||
|
||||
public static String[] fetchAvailableExports(MapSource source) {
|
||||
//URI uri = URI.create(source.url);
|
||||
//String host = uri.getHost();
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
public static void download(MapSource source, String export) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
public static void download(MapSource source, int[] bounds) {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package eu.konggdev.strikemaps.map.overlay;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import eu.konggdev.strikemaps.map.layer.SourcedMapLayer;
|
||||
|
||||
/* More or less a data-driven layer factory */
|
||||
public interface MapOverlay {
|
||||
public JsonNode makePatch();
|
||||
public SourcedMapLayer makeLayer();
|
||||
}
|
||||
+58
-52
@@ -1,15 +1,19 @@
|
||||
package eu.konggdev.strikemaps.map.overlay.implementation;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.layer.SourcedMapLayer;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
|
||||
import eu.konggdev.strikemaps.data.provider.LocationDataProvider;
|
||||
import org.maplibre.geojson.Feature;
|
||||
import org.maplibre.geojson.FeatureCollection;
|
||||
import org.maplibre.geojson.Point;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
@@ -17,70 +21,72 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
public class LocationOverlay implements MapOverlay, LocationListener {
|
||||
LocationDataProvider locationDataProvider;
|
||||
AppController app;
|
||||
MapComponent map;
|
||||
|
||||
public Location currentLocation = null;
|
||||
|
||||
public LocationOverlay(MapComponent map, AppCompatActivity activity) {
|
||||
this.map = map;
|
||||
this.locationDataProvider = new LocationDataProvider(activity, this);
|
||||
public LocationOverlay(AppController app) {
|
||||
this.app = app;
|
||||
this.map = app.getMap();
|
||||
this.locationDataProvider = new LocationDataProvider(app.getActivity(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode makePatch() {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
@Override
|
||||
public SourcedMapLayer makeLayer() {
|
||||
MapSource source = new MapSource();
|
||||
|
||||
ObjectNode root = mapper.createObjectNode();
|
||||
source.type = "geojson";
|
||||
|
||||
ObjectNode sources = mapper.createObjectNode();
|
||||
ObjectNode location = mapper.createObjectNode();
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
ObjectNode geometry = mapper.createObjectNode();
|
||||
ObjectNode properties = mapper.createObjectNode();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
data.put("type", "Feature");
|
||||
|
||||
ArrayNode coordinates = mapper.createArrayNode();
|
||||
coordinates.add(currentLocation.getLongitude());
|
||||
coordinates.add(currentLocation.getLatitude());
|
||||
if(currentLocation != null) {
|
||||
ObjectNode geometry = mapper.createObjectNode();
|
||||
geometry.put("type", "Point");
|
||||
|
||||
geometry.put("type", "Point");
|
||||
geometry.set("coordinates", coordinates);
|
||||
ArrayNode coordinates = mapper.createArrayNode();
|
||||
coordinates.add(currentLocation.getLongitude());
|
||||
coordinates.add(currentLocation.getLatitude());
|
||||
|
||||
data.put("type", "Feature");
|
||||
data.set("geometry", geometry);
|
||||
data.set("properties", properties);
|
||||
|
||||
location.put("type", "geojson");
|
||||
location.set("data", data);
|
||||
|
||||
sources.set("location", location);
|
||||
root.set("sources", sources);
|
||||
|
||||
// layers
|
||||
ArrayNode layers = mapper.createArrayNode();
|
||||
ObjectNode layer = mapper.createObjectNode();
|
||||
|
||||
layer.put("id", "location");
|
||||
layer.put("type", "circle");
|
||||
layer.put("source", "location");
|
||||
|
||||
ObjectNode paint = mapper.createObjectNode();
|
||||
paint.put("circle-radius", 5);
|
||||
paint.put("circle-color", "#1E88E5");
|
||||
|
||||
paint.put("circle-stroke-color", "#FFFFFF");
|
||||
paint.put("circle-stroke-width", 1.5);
|
||||
|
||||
layer.set("paint", paint);
|
||||
|
||||
layers.add(layer);
|
||||
root.set("layers", layers);
|
||||
|
||||
return root;
|
||||
geometry.set("coordinates", coordinates);
|
||||
data.set("geometry", geometry);
|
||||
data.set("properties", mapper.createObjectNode());
|
||||
}
|
||||
source.data = data;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ObjectNode layer = mapper.createObjectNode();
|
||||
layer.put("id", "location");
|
||||
layer.put("type", "circle");
|
||||
layer.put("source", "location");
|
||||
|
||||
ObjectNode paint = mapper.createObjectNode();
|
||||
paint.put("circle-radius", 5);
|
||||
paint.put("circle-color", "#1E88E5");
|
||||
paint.put("circle-stroke-color", "#FFFFFF");
|
||||
paint.put("circle-stroke-width", 1.5);
|
||||
|
||||
layer.set("paint", paint);
|
||||
|
||||
ObjectNode layout = mapper.createObjectNode();
|
||||
layout.put("circle-pitch-alignment", "map");
|
||||
|
||||
layer.set("layout", layout);
|
||||
|
||||
ArrayNode layers = mapper.createArrayNode();
|
||||
layers.add(layer);
|
||||
|
||||
return new SourcedMapLayer("location", source, layers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(@NonNull Location location) {
|
||||
this.currentLocation = location;
|
||||
map.overlayUpdate(this);
|
||||
map.onOverlayUpdate();
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -1,15 +1,12 @@
|
||||
package eu.konggdev.strikemaps.map.overlay.implementation;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.layer.MapLayer;
|
||||
import eu.konggdev.strikemaps.map.layer.SourcedMapLayer;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
|
||||
public class PointSelectionOverlay implements MapOverlay {
|
||||
ComponentHolderActivity app;
|
||||
MapComponent map;
|
||||
@Override
|
||||
public JsonNode makePatch() {
|
||||
public SourcedMapLayer makeLayer() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
package eu.konggdev.strikemaps.map.renderer;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
|
||||
import eu.konggdev.strikemaps.map.layer.MapLayer;
|
||||
import org.maplibre.android.style.layers.Layer;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MapRenderer {
|
||||
void styleUpdate(StyleDocument style);
|
||||
|
||||
void overlayUpdate(MapOverlay overlay);
|
||||
void reload();
|
||||
|
||||
View getView();
|
||||
|
||||
|
||||
-152
@@ -1,152 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.renderer.implementation;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.util.json.JsonPatcher;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
|
||||
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
|
||||
import eu.konggdev.strikemaps.map.style.source.StyleSource;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
//Stub for now
|
||||
public class MapLibreGLJSRenderer implements MapRenderer {
|
||||
private final static String TAG = "MapLibreGLJSRenderer";
|
||||
private final AppCompatActivity activity;
|
||||
|
||||
private final MapComponent controller;
|
||||
|
||||
final WebView webView;
|
||||
|
||||
private JsonNode origin;
|
||||
|
||||
@SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"})
|
||||
public MapLibreGLJSRenderer(ComponentHolderActivity activity, MapComponent controller) {
|
||||
this.activity = activity;
|
||||
this.controller = controller;
|
||||
webView = new WebView(activity);
|
||||
webView.setLayoutParams(
|
||||
new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
);
|
||||
|
||||
WebSettings settings = webView.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setDomStorageEnabled(true);
|
||||
settings.setAllowFileAccess(true);
|
||||
|
||||
webView.setWebChromeClient(new WebChromeClient());
|
||||
|
||||
webView.addJavascriptInterface(new Bridge(), "AndroidBridge");
|
||||
|
||||
webView.loadUrl("file:///android_asset/library/maplibre/gl-js/index.html");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void styleUpdate(StyleDocument style) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
|
||||
|
||||
//Thanks to this, styleUpdate(null) can be used as an origin reload
|
||||
if (style != null) {
|
||||
try {
|
||||
ObjectNode root = style.metadata.deepCopy();
|
||||
|
||||
//Sources
|
||||
ObjectNode sources = mapper.createObjectNode();
|
||||
if (style.sources != null)
|
||||
for (StyleSource source : style.sources)
|
||||
sources.set(source.key,
|
||||
source.current.makeJson());
|
||||
|
||||
//Layers
|
||||
ArrayNode layers = mapper.createArrayNode();
|
||||
if (style.layerDefinitions != null)
|
||||
layers.addAll((ArrayNode) style.layerDefinitions);
|
||||
|
||||
//Set all to root
|
||||
root.set("sources", sources);
|
||||
root.set("layers", layers);
|
||||
this.origin = root;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to parse style: " + style.name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final String mapped = mapper.writeValueAsString(origin);
|
||||
webView.evaluateJavascript("map.setStyle(" + mapped + ", { diff: false });", null);
|
||||
webView.evaluateJavascript("map.redraw()", null); //Force redraw to make the style change visible
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to set style: " + style.name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//Since we just annihilated all overlays from the face of the earth, lets repatch them
|
||||
if (controller.overlays != null) {
|
||||
for(MapOverlay overlay : controller.overlays.values())
|
||||
overlayUpdate(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void overlayUpdate(MapOverlay overlay) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
webView.evaluateJavascript(
|
||||
"JSON.stringify(map.getStyle())",
|
||||
style -> {
|
||||
try {
|
||||
JsonNode current = mapper.readTree(style);
|
||||
|
||||
JsonNode merged;
|
||||
if (controller.hasOverlay(overlay)) {
|
||||
merged = JsonPatcher.patch(current, overlay.makePatch());
|
||||
} else {
|
||||
merged = JsonPatcher.unpatch(origin, current, overlay.makePatch());
|
||||
}
|
||||
|
||||
final String mapped = mapper.writeValueAsString(merged);
|
||||
webView.evaluateJavascript("map.setStyle(" + mapped + ", { diff: false });", null);
|
||||
webView.evaluateJavascript("map.redraw()", null); //Force redraw to make the style change visible
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to patch overlay: " + overlay.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View getView() {
|
||||
return webView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Feature> featuresAtPoint(LatLng point) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
static class Bridge { }
|
||||
}
|
||||
+38
-81
@@ -1,21 +1,18 @@
|
||||
package eu.konggdev.strikemaps.map.renderer.implementation;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import eu.konggdev.strikemaps.util.json.JsonPatcher;
|
||||
import eu.konggdev.strikemaps.data.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.layer.SourcedMapLayer;
|
||||
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
|
||||
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
|
||||
import eu.konggdev.strikemaps.map.style.source.StyleSource;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import org.maplibre.android.MapLibre;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
@@ -26,96 +23,56 @@ import org.maplibre.geojson.Feature;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
|
||||
public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
|
||||
private final static String TAG = "MapLibreNativeRenderer";
|
||||
private final AppCompatActivity activity;
|
||||
private final MapComponent controller;
|
||||
AppController app;
|
||||
MapComponent controller;
|
||||
MapLibreMap map;
|
||||
final MapView mapView;
|
||||
private JsonNode origin;
|
||||
|
||||
public MapLibreNativeRenderer(ComponentHolderActivity activity, MapComponent controller) {
|
||||
this.activity = activity;
|
||||
public MapLibreNativeRenderer(AppController app, MapComponent controller) {
|
||||
this.app = app;
|
||||
this.controller = controller;
|
||||
MapLibre.getInstance(activity);
|
||||
this.mapView = new MapView(activity);
|
||||
//TODO: Investigate if we might want to restore any savedInstanceState for MapLibre
|
||||
MapLibre.getInstance(app.getActivity());
|
||||
this.mapView = new MapView(app.getActivity());
|
||||
mapView.onCreate(null);
|
||||
//We need this to get the onMapReady callback
|
||||
mapView.getMapAsync(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void styleUpdate(StyleDocument style) {
|
||||
public void reload() {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
|
||||
|
||||
//Thanks to this, styleUpdate(null) can be used as an origin reload
|
||||
if (style != null) {
|
||||
try {
|
||||
ObjectNode root = style.metadata.deepCopy();
|
||||
|
||||
//Sources
|
||||
ObjectNode sources = mapper.createObjectNode();
|
||||
if (style.sources != null)
|
||||
for (StyleSource source : style.sources)
|
||||
sources.set(source.key,
|
||||
source.current.makeJson());
|
||||
|
||||
//Layers
|
||||
ArrayNode layers = mapper.createArrayNode();
|
||||
if (style.layerDefinitions != null)
|
||||
layers.addAll((ArrayNode) style.layerDefinitions);
|
||||
|
||||
//Set all to root
|
||||
root.set("sources", sources);
|
||||
root.set("layers", layers);
|
||||
this.origin = root;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to parse style: " + style.name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
MapStyle style = controller.style;
|
||||
try {
|
||||
map.setStyle(new Style.Builder().fromJson(mapper.writeValueAsString(origin)));
|
||||
/* Take metadata from MapStyle
|
||||
everything outside sources, layers */
|
||||
ObjectNode root = style.metadata.deepCopy();
|
||||
|
||||
//Sources
|
||||
ObjectNode sources = mapper.createObjectNode();
|
||||
style.sources.forEach((k, v) -> sources.set(k, mapper.valueToTree(v)));
|
||||
|
||||
//Layers
|
||||
ArrayNode layers = mapper.createArrayNode();
|
||||
layers.addAll((ArrayNode) style.layerDefinitions);
|
||||
|
||||
//Overlays
|
||||
for (MapOverlay overlay : controller.overlays.values()) {
|
||||
SourcedMapLayer overlayLayer = overlay.makeLayer();
|
||||
sources.set(overlayLayer.key, mapper.valueToTree(overlayLayer.source));
|
||||
layers.addAll((ArrayNode) overlayLayer.layer);
|
||||
}
|
||||
|
||||
//Set all to root
|
||||
root.set("sources", sources);
|
||||
root.set("layers", layers);
|
||||
|
||||
map.setStyle(new Style.Builder().fromJson(mapper.writeValueAsString(root)));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to set style: " + style.name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//Since we just annihilated all overlays from the face of the earth, lets repatch them
|
||||
if (controller.overlays != null) {
|
||||
for(MapOverlay overlay : controller.overlays.values())
|
||||
overlayUpdate(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void overlayUpdate(MapOverlay overlay) {
|
||||
if(map == null) return;
|
||||
|
||||
Style style = map.getStyle();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
if(style == null) return;
|
||||
|
||||
try {
|
||||
JsonNode current = mapper.readTree(style.getJson());
|
||||
|
||||
JsonNode merged;
|
||||
if (controller.hasOverlay(overlay)) {
|
||||
merged = JsonPatcher.patch(current, overlay.makePatch());
|
||||
} else {
|
||||
merged = JsonPatcher.unpatch(origin, current, overlay.makePatch());
|
||||
}
|
||||
|
||||
map.setStyle(new Style.Builder().fromJson(mapper.writeValueAsString(merged)));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to patch overlay: " + overlay.toString());
|
||||
app.logcat("Failed to reload Map");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -134,7 +91,7 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
|
||||
public void onMapReady(@NonNull MapLibreMap maplibreMap) {
|
||||
this.map = maplibreMap;
|
||||
|
||||
controller.onMapInit();
|
||||
controller.setStyle(MapStyle.fromMapLibreJsonFile(UserPrefsHelper.startupMapStyle(app.getPrefs()), app));
|
||||
|
||||
//I have my own implementation of attribution that credits MapLibre among others, it's not as bad as it looks :)
|
||||
map.getUiSettings().setLogoEnabled(false);
|
||||
|
||||
+6
-14
@@ -1,11 +1,9 @@
|
||||
package eu.konggdev.strikemaps.map.renderer.implementation;
|
||||
|
||||
import android.view.View;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
|
||||
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.geojson.Feature;
|
||||
@@ -18,27 +16,21 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class VtmRenderer implements MapRenderer {
|
||||
|
||||
ComponentHolderActivity activity;
|
||||
AppController app;
|
||||
MapComponent controller;
|
||||
|
||||
Map map;
|
||||
final MapView mapView;
|
||||
|
||||
public VtmRenderer(ComponentHolderActivity activity, MapComponent controller) {
|
||||
this.activity = activity;
|
||||
public VtmRenderer(AppController app, MapComponent controller) {
|
||||
this.app = app;
|
||||
this.controller = controller;
|
||||
this.mapView = new MapView(activity);
|
||||
this.mapView = new MapView(app.getActivity());
|
||||
this.map = mapView.map();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void overlayUpdate(MapOverlay overlay) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void styleUpdate(StyleDocument style) {
|
||||
public void reload() {
|
||||
//TODO
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
OSciMap4TileSource tileSource = OSciMap4TileSource.builder().httpFactory(new OkHttpEngine.OkHttpFactory(builder)).build();
|
||||
|
||||
@@ -1,90 +1,21 @@
|
||||
package eu.konggdev.strikemaps.map.source;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import eu.konggdev.strikemaps.map.source.tiles.SourceTiles;
|
||||
|
||||
public class MapSource {
|
||||
public String name;
|
||||
|
||||
public SourceTiles tileSource;
|
||||
|
||||
public String url;
|
||||
public JsonNode data;
|
||||
public String type;
|
||||
public String schema;
|
||||
|
||||
public JsonNode tiles;
|
||||
public int minzoom;
|
||||
public int maxzoom;
|
||||
|
||||
public String scheme;
|
||||
public int tileSize;
|
||||
|
||||
public String attribution;
|
||||
|
||||
public String encoding;
|
||||
|
||||
public MapSource(String name, SourceTiles tileSource, String type, String schema) {
|
||||
this.name = name;
|
||||
this.tileSource = tileSource;
|
||||
this.type = type;
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public MapSource(String key, JsonNode sourceNode) {
|
||||
this.name = key;
|
||||
|
||||
this.type = sourceNode.path("type").asText(null);
|
||||
this.schema = sourceNode.path("schema").asText(null);
|
||||
this.scheme = sourceNode.path("scheme").asText(null);
|
||||
this.encoding = sourceNode.path("encoding").asText(null);
|
||||
|
||||
this.minzoom = sourceNode.path("minZoom").asInt(0);
|
||||
this.maxzoom = sourceNode.path("maxZoom").asInt(24);
|
||||
this.tileSize = sourceNode.path("tileSize").asInt(256);
|
||||
|
||||
this.tileSource = handleJsonTileSource(sourceNode);
|
||||
}
|
||||
|
||||
private static SourceTiles handleJsonTileSource(JsonNode sourceNode) {
|
||||
// By design, a source must use either "url" or "tiles", never both
|
||||
// In case both are present, we prefer URL over tiles... because I don't know, we just do, m'kay?
|
||||
if (sourceNode.has("url"))
|
||||
return new SourceTiles(sourceNode.get("url").asText());
|
||||
|
||||
if (sourceNode.has("tiles")) {
|
||||
String[] tiles = new String[0];
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
try {
|
||||
tiles = mapper.treeToValue(sourceNode.get("tiles"), String[].class);
|
||||
} catch (Exception e) { // If we can't parse it, lets just keep it an empty array
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new SourceTiles(tiles);
|
||||
}
|
||||
|
||||
|
||||
//TODO: Decide what to do when we have a definition that doesn't define the most important part - the tile source
|
||||
//Maybe throwing some custom exception and propagating it back to the user would be appropriate
|
||||
return null;
|
||||
}
|
||||
|
||||
public ObjectNode makeJson() {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
ObjectNode node = mapper.createObjectNode();
|
||||
|
||||
try {
|
||||
if (type != null) node.put("type", type);
|
||||
if (schema != null) node.put("schema", schema);
|
||||
if (minzoom != 0) node.put("minzoom", minzoom);
|
||||
if (maxzoom != 24) node.put("maxzoom", maxzoom);
|
||||
if (scheme != null) node.put("scheme", scheme);
|
||||
if (tileSize != 256) node.put("tileSize", tileSize);
|
||||
if (encoding != null) node.put("encoding", encoding);
|
||||
if (tileSource != null) tileSource.makeJson(mapper, node);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
public MapSource() { }
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.source.properties;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class SourceProperties {
|
||||
public String type;
|
||||
public String schema;
|
||||
|
||||
// Json constructor
|
||||
public SourceProperties(JsonNode sourceNode) {
|
||||
this.type = sourceNode.path("type").asText(null);
|
||||
this.schema = sourceNode.path("schema").asText(null);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.source.tiles;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
public class SourceTiles {
|
||||
public enum TilesType {
|
||||
URL,
|
||||
TILES,
|
||||
DATA
|
||||
}
|
||||
|
||||
private final TilesType type;
|
||||
private String url;
|
||||
private String[] tiles;
|
||||
|
||||
private JsonNode data;
|
||||
|
||||
public SourceTiles(String url) {
|
||||
this.url = url;
|
||||
this.type = TilesType.URL;
|
||||
}
|
||||
|
||||
public SourceTiles(String[] tiles) {
|
||||
this.tiles = tiles;
|
||||
this.type = TilesType.TILES;
|
||||
}
|
||||
|
||||
public SourceTiles(JsonNode data) {
|
||||
this.data = data;
|
||||
this.type = TilesType.DATA;
|
||||
}
|
||||
|
||||
public void makeJson(ObjectMapper mapper, ObjectNode node) {
|
||||
switch (type) {
|
||||
case URL -> node.put("url", url);
|
||||
|
||||
case TILES -> {
|
||||
ArrayNode tilesNode = mapper.createArrayNode();
|
||||
|
||||
for (String tile : tiles)
|
||||
tilesNode.add(tile);
|
||||
|
||||
node.set("tiles", tilesNode);
|
||||
}
|
||||
|
||||
case DATA -> node.set("data", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,68 @@
|
||||
package eu.konggdev.strikemaps.map.style;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
|
||||
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
|
||||
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.data.helper.FileHelper;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MapStyle {
|
||||
public static final class StoredRepresentation {
|
||||
public final String json;
|
||||
public final StyleOptions options;
|
||||
//Only local data
|
||||
public String name;
|
||||
public Bitmap icon;
|
||||
|
||||
public final StyleManagementMetadata managementMetadata;
|
||||
public JsonNode metadata; // everything except layers + sources
|
||||
public Map<String, MapSource> sources;
|
||||
public ArrayNode layerDefinitions; // the "layers" array
|
||||
|
||||
public StoredRepresentation(String json, StyleOptions options, StyleManagementMetadata managementMetadata) {
|
||||
this.json = json;
|
||||
this.options = options;
|
||||
this.managementMetadata = managementMetadata;
|
||||
}
|
||||
//FIXME
|
||||
public static MapStyle fromMapLibreJsonFile(String filename, AppController app) {
|
||||
String styleContents;
|
||||
if (filename.startsWith("/storage")) styleContents = FileHelper.loadStringFromUserFile(filename);
|
||||
else styleContents = FileHelper.loadStringFromAssetFile(filename, app);
|
||||
|
||||
public MapStyle restore() {
|
||||
return new MapStyle(
|
||||
json,
|
||||
options,
|
||||
managementMetadata
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
JsonNode root = mapper.readTree(styleContents);
|
||||
|
||||
MapStyle style = new MapStyle();
|
||||
style.name = root.path("name").asText();
|
||||
style.icon = getIcon(root.path("icon").asText(), app);
|
||||
|
||||
style.sources = mapper.convertValue(
|
||||
root.path("sources"),
|
||||
new TypeReference<Map<String, MapSource>>() {}
|
||||
);
|
||||
|
||||
style.layerDefinitions = root.withArray("layers");
|
||||
|
||||
ObjectNode metadata = root.deepCopy();
|
||||
metadata.remove("layers");
|
||||
metadata.remove("sources");
|
||||
style.metadata = metadata;
|
||||
|
||||
return style;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull public final StyleDocument document;
|
||||
@NonNull public final StyleOptions options;
|
||||
|
||||
// Null when the style is not managed
|
||||
@Nullable public StyleManagementMetadata managementMetadata;
|
||||
|
||||
// Original json representation of the style document, as we got it
|
||||
@NonNull public final String json;
|
||||
|
||||
public MapStyle(@NonNull String json, @NonNull StyleOptions styleOptions, @Nullable StyleManagementMetadata managementMetadata) {
|
||||
this.json = json;
|
||||
this.document = new StyleDocument(json);
|
||||
this.options = styleOptions;
|
||||
this.managementMetadata = managementMetadata;
|
||||
}
|
||||
|
||||
public MapStyle(@NonNull String json, @NonNull StyleDocument style, @NonNull StyleOptions styleOptions, @Nullable StyleManagementMetadata managementMetadata) {
|
||||
this.json = json;
|
||||
this.document = style;
|
||||
this.options = styleOptions;
|
||||
this.managementMetadata = managementMetadata;
|
||||
}
|
||||
|
||||
public StoredRepresentation makeStoredRepresentation() {
|
||||
return new StoredRepresentation(json, options, managementMetadata);
|
||||
}
|
||||
|
||||
public StyleDocument effectiveDocument(RegistryStorageComponent registry) {
|
||||
return document.effectiveDocument(options, registry);
|
||||
public static Bitmap getIcon(String iconLocator, AppController app) {
|
||||
switch(iconLocator.split("//")[0]) {
|
||||
//TODO: https
|
||||
case "assets:":
|
||||
return BitmapFactory.decodeStream(FileHelper.openAssetStream("bundled/icon/" + iconLocator.split("//")[1], app));
|
||||
default:
|
||||
app.logcat("Unimplemented icon locator space: " + iconLocator);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.style.document;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
|
||||
import eu.konggdev.strikemaps.map.style.source.StyleSource;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class StyleDocument {
|
||||
//Only local data
|
||||
public String name;
|
||||
public String icon;
|
||||
|
||||
public JsonNode metadata; // everything except layers + sources
|
||||
public List<StyleSource> sources;
|
||||
public ArrayNode layerDefinitions; // "layers" array
|
||||
|
||||
// Json constructor
|
||||
public StyleDocument(String json) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
try {
|
||||
JsonNode root = mapper.readTree(json);
|
||||
|
||||
this.name = root.path("name").asText();
|
||||
this.icon = root.path("icon").asText();
|
||||
|
||||
JsonNode jsonSources = root.path("sources");
|
||||
List<StyleSource> sources = new ArrayList<>();
|
||||
jsonSources.fields().forEachRemaining(entry -> {
|
||||
sources.add(new StyleSource(entry.getKey(), entry.getValue()));
|
||||
});
|
||||
this.sources = sources;
|
||||
|
||||
this.layerDefinitions = root.withArray("layers");
|
||||
|
||||
ObjectNode metadata = root.deepCopy();
|
||||
metadata.remove("layers");
|
||||
metadata.remove("sources");
|
||||
this.metadata = metadata;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalArgumentException("Invalid style document", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
public StyleDocument(StyleDocument other) {
|
||||
this.name = other.name;
|
||||
this.icon = other.icon;
|
||||
this.metadata = other.metadata.deepCopy();
|
||||
this.sources = new ArrayList<>(other.sources);
|
||||
this.layerDefinitions = other.layerDefinitions.deepCopy();
|
||||
}
|
||||
|
||||
// The style that is presented to the renderer, with its options applied
|
||||
public StyleDocument effectiveDocument(StyleOptions options, RegistryStorageComponent registry) {
|
||||
StyleDocument result = new StyleDocument(this); //Copy
|
||||
for (int i = 0; i < sources.size(); i++) {
|
||||
StyleSource source = sources.get(i);
|
||||
MapSource effectiveSource = registry.getSource(
|
||||
options.getInteger(source.key, 0)
|
||||
);
|
||||
if (effectiveSource != null) source.current = effectiveSource;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.style.management;
|
||||
|
||||
public class StyleManagementMetadata {
|
||||
public boolean modified;
|
||||
public boolean doUpdates;
|
||||
public boolean autoUpdate;
|
||||
|
||||
public String source;
|
||||
public String sourceHash;
|
||||
|
||||
public StyleManagementMetadata() { }
|
||||
|
||||
public StyleManagementMetadata(boolean modified, boolean doUpdates, boolean autoUpdate, String source, String sourceHash) {
|
||||
this.modified = modified;
|
||||
this.doUpdates = doUpdates;
|
||||
this.autoUpdate = autoUpdate;
|
||||
this.source = source;
|
||||
this.sourceHash = sourceHash;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.style.options;
|
||||
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class StyleOptions {
|
||||
private Map<String, Object> values;
|
||||
|
||||
public StyleOptions() {
|
||||
this.values = new HashMap<>();
|
||||
}
|
||||
|
||||
public StyleOptions(Map<String, Object> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public boolean getBoolean(String id, boolean defaultValue) {
|
||||
Object value = values.get(id);
|
||||
return value instanceof Boolean ? (Boolean) value : defaultValue;
|
||||
}
|
||||
|
||||
public int getInteger(String id, int defaultValue) {
|
||||
Object value = values.get(id);
|
||||
return value instanceof Number
|
||||
? ((Number) value).intValue()
|
||||
: defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package eu.konggdev.strikemaps.map.style.source;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
import eu.konggdev.strikemaps.map.source.properties.SourceProperties;
|
||||
|
||||
// Stores a source currently used by a style
|
||||
// Along with requirements of what source the style needs here
|
||||
public class StyleSource {
|
||||
public String key;
|
||||
|
||||
// Requirement properties
|
||||
public SourceProperties properties;
|
||||
|
||||
// In an effective style, this is the actual source matched to the
|
||||
// style's requirements according to user's preferences (StyleOptions).
|
||||
// Otherwise, this is the fallback source.
|
||||
// It also preserves the default source defined by the JSON for non-effective style documents
|
||||
@NonNull public MapSource current;
|
||||
|
||||
// Json constructor
|
||||
public StyleSource(String key, JsonNode sourceNode) {
|
||||
this.key = key;
|
||||
this.properties = new SourceProperties(sourceNode);
|
||||
this.current = new MapSource(key, sourceNode);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package eu.konggdev.strikemaps.storage;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import androidx.annotation.Nullable;
|
||||
import eu.konggdev.strikemaps.Component;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.helper.UserPrefsHelper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class RegistryStorageComponent implements Component {
|
||||
private final ComponentHolderActivity activity;
|
||||
|
||||
private final SharedPreferences userPrefs;
|
||||
|
||||
private Map<Integer, MapStyle> styles;
|
||||
|
||||
private Map<Integer, MapSource> sources;
|
||||
|
||||
public RegistryStorageComponent(ComponentHolderActivity activity, SharedPreferences userPrefs) {
|
||||
this.activity = activity;
|
||||
this.userPrefs = userPrefs;
|
||||
initAll();
|
||||
}
|
||||
|
||||
private Map<Integer, MapSource> sources() {
|
||||
if (sources == null) sources = UserPrefsHelper.sources(userPrefs);
|
||||
return sources;
|
||||
}
|
||||
|
||||
public Map<Integer, MapSource> getSources() {
|
||||
return sources();
|
||||
}
|
||||
|
||||
@Nullable public MapSource getSource(Integer id) {
|
||||
return sources().get(id);
|
||||
}
|
||||
|
||||
private Map<Integer, MapStyle> styles() {
|
||||
if (styles == null) styles = UserPrefsHelper.styles(userPrefs, activity);
|
||||
return styles;
|
||||
}
|
||||
|
||||
public Map<Integer, MapStyle> getStyles() {
|
||||
return styles();
|
||||
}
|
||||
|
||||
@Nullable public MapStyle getStyle(Integer id) {
|
||||
return styles().get(id);
|
||||
}
|
||||
|
||||
public int addStyle(MapStyle style) {
|
||||
Map<Integer, MapStyle> styles = styles();
|
||||
int id = styles.keySet().stream()
|
||||
.mapToInt(Integer::intValue)
|
||||
.max()
|
||||
.orElse(-1) + 1;
|
||||
|
||||
styles.put(id, style);
|
||||
save();
|
||||
return id;
|
||||
}
|
||||
|
||||
public void updateStyle(int id, MapStyle style) {
|
||||
styles().put(id, style);
|
||||
save();
|
||||
}
|
||||
|
||||
public void deleteStyle(int id) {
|
||||
styles().remove(id);
|
||||
save();
|
||||
}
|
||||
|
||||
private void save() {
|
||||
UserPrefsHelper.styles(userPrefs, styles);
|
||||
}
|
||||
|
||||
public void checkForUpdates() {
|
||||
//
|
||||
}
|
||||
|
||||
private void initAll() {
|
||||
styles(); sources();
|
||||
}
|
||||
}
|
||||
@@ -1,80 +1,77 @@
|
||||
package eu.konggdev.strikemaps.ui;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.google.common.collect.BiMap;
|
||||
import eu.konggdev.strikemaps.Component;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.ui.element.region.content.MainContentRegion;
|
||||
import eu.konggdev.strikemaps.ui.element.region.UIRegion;
|
||||
import eu.konggdev.strikemaps.ui.element.UIRegion;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutControls;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutSearch;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentOfflineMaps;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentSettings;
|
||||
import eu.konggdev.strikemaps.ui.screen.Screen;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class UIComponent implements Component {
|
||||
private final String TAG = "UIComponent";
|
||||
@NonNull AppController app;
|
||||
private Map<Integer, Screen> screens;
|
||||
private Integer currentScreen;
|
||||
|
||||
private final ComponentHolderActivity activity;
|
||||
private final MapComponent map;
|
||||
|
||||
private final RegistryStorageComponent registry;
|
||||
|
||||
private final SharedPreferences userPrefs;
|
||||
|
||||
private final ArrayDeque<Screen> screenStack = new ArrayDeque<>();
|
||||
|
||||
private Map<String, Screen> screens;
|
||||
|
||||
public UIComponent(ComponentHolderActivity activity, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs) {
|
||||
this.activity = activity;
|
||||
this.map = map;
|
||||
this.registry = registry;
|
||||
this.userPrefs = userPrefs;
|
||||
public UIComponent(AppController app, MapComponent map) {
|
||||
this.app = app;
|
||||
this.screens = Map.of(
|
||||
//Main screen
|
||||
R.layout.screen_main, new Screen(
|
||||
//App reference
|
||||
app,
|
||||
//Map view
|
||||
map.toFragment(), //FragmentLayoutContentMap
|
||||
//Main screen init regions definition
|
||||
Map.of(R.id.bottomUi, new UIRegion(new FragmentLayoutControls(app, R.id.bottomUi), R.id.bottomUi)), //TODO: Probably stop referencing layout 3(!) times everytime
|
||||
//Layout
|
||||
R.layout.screen_main //TODO: Define this for the Screen without duplicating the reference
|
||||
),
|
||||
//Settings screen
|
||||
R.layout.screen_settings, new Screen(
|
||||
app,
|
||||
//Settings
|
||||
new FragmentLayoutContentSettings(),
|
||||
/* No regions defined in settings
|
||||
Entire screen is just the main view */
|
||||
new HashMap<>(),
|
||||
//Layout
|
||||
R.layout.screen_settings
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public void defineScreens(Map<String, Screen> screens) {
|
||||
this.screens = screens;
|
||||
}
|
||||
|
||||
public void swapScreen(String screenKey) {
|
||||
if (screens == null) return;
|
||||
Screen newScreen = screens.get(screenKey);
|
||||
if (newScreen == null) {
|
||||
Log.e(TAG, "Invalid screen " + screenKey + " invoked");
|
||||
return;
|
||||
}
|
||||
if (!screenStack.isEmpty()) getCurrentScreen().detachAll();
|
||||
screenStack.add(newScreen);
|
||||
public void swapScreen(Integer screen) {
|
||||
currentScreen = screen;
|
||||
getCurrentScreen().attachAll();
|
||||
}
|
||||
|
||||
public boolean back() {
|
||||
if (screenStack.size() <= 1) return false;
|
||||
getCurrentScreen().detachAll();
|
||||
|
||||
screenStack.removeLast();
|
||||
getCurrentScreen().attachAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Screen getCurrentScreen() {
|
||||
return screenStack.getLast();
|
||||
return getScreen(currentScreen);
|
||||
}
|
||||
|
||||
public Screen getScreen(Integer screen) {
|
||||
return screens.get(screen);
|
||||
}
|
||||
|
||||
public void alert(AlertDialog dialog) {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public View inflateUi(int layout) {
|
||||
return activity.getLayoutInflater().inflate(layout, null);
|
||||
public <T> void alert(AlertDialog dialog, Consumer<T> callback) {
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
public View inflateUi(int layout) {
|
||||
return app.getActivity().getLayoutInflater().inflate(layout, null);
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package eu.konggdev.strikemaps.ui.element.region;
|
||||
package eu.konggdev.strikemaps.ui.element;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
@@ -40,4 +40,5 @@ public class UIRegion {
|
||||
currentFragment = stockFragment;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,82 +5,51 @@ import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.annotation.NonNull;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.util.icon.IconResolver;
|
||||
|
||||
public class GenericItem implements UIItem {
|
||||
public String name;
|
||||
|
||||
@NonNull public String name;
|
||||
public Bitmap image;
|
||||
public Runnable onClick;
|
||||
public Runnable onLongClick;
|
||||
boolean hasImage;
|
||||
|
||||
public GenericItem(String name) {
|
||||
this.name = name;
|
||||
public GenericItem(String refName) {
|
||||
this.name = refName;
|
||||
hasImage = false;
|
||||
}
|
||||
|
||||
public GenericItem(String name, Runnable onClick) {
|
||||
this.name = name;
|
||||
public GenericItem(String refName, Runnable onClick) {
|
||||
this.name = refName;
|
||||
this.onClick = onClick;
|
||||
hasImage = false;
|
||||
}
|
||||
|
||||
public GenericItem(String name, Runnable onClick, Runnable onLongClick) {
|
||||
this.name = name;
|
||||
this.onClick = onClick;
|
||||
this.onLongClick = onLongClick;
|
||||
hasImage = false;
|
||||
}
|
||||
|
||||
public GenericItem(String name, Bitmap Image) {
|
||||
this.name = name;
|
||||
this.image = Image;
|
||||
public GenericItem(String refName, Bitmap refImage) {
|
||||
this.name = refName;
|
||||
this.image = refImage;
|
||||
hasImage = true;
|
||||
}
|
||||
|
||||
public GenericItem(String name, Bitmap Image, Runnable onClick) {
|
||||
this.name = name;
|
||||
this.image = Image;
|
||||
public GenericItem(String refName, Bitmap refImage, Runnable onClick) {
|
||||
this.name = refName;
|
||||
this.image = refImage;
|
||||
this.onClick = onClick;
|
||||
hasImage = true;
|
||||
}
|
||||
|
||||
public GenericItem(String name, Bitmap Image, Runnable onClick, Runnable onLongClick) {
|
||||
this.name = name;
|
||||
this.image = Image;
|
||||
this.onClick = onClick;
|
||||
this.onLongClick = onLongClick;
|
||||
hasImage = true;
|
||||
public final static GenericItem fromStyle(MapStyle style, MapComponent map) {
|
||||
if(style == null) return new GenericItem("Unknown");
|
||||
if(style.icon != null)
|
||||
return new GenericItem(style.name, style.icon, () -> map.setStyle(style));
|
||||
return new GenericItem(style.name, () -> map.setStyle(style));
|
||||
}
|
||||
|
||||
public GenericItem(StyleDocument style, Runnable onClick, AppCompatActivity activity) {
|
||||
if (style == null) return;
|
||||
this.name = style.name;
|
||||
this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null;
|
||||
this.onClick = onClick;
|
||||
}
|
||||
|
||||
public GenericItem(StyleDocument style, Runnable onClick, Runnable onLongClick, AppCompatActivity activity) {
|
||||
if (style == null) return;
|
||||
this.name = style.name;
|
||||
this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null;
|
||||
this.onClick = onClick;
|
||||
this.onLongClick = onLongClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View makeView(UIComponent spawner) {
|
||||
View v = spawner.inflateUi(R.layout.item_generic);
|
||||
//FIXME: These shouldn't be casted like that!
|
||||
((TextView) v.findViewById(R.id.name)).setText(name);
|
||||
if(image != null) ((ImageButton) v.findViewById(R.id.image)).setImageBitmap(image);
|
||||
if(onClick != null) v.findViewById(R.id.image).setOnClickListener(click(onClick));
|
||||
if(onLongClick != null) v.findViewById(R.id.image).setOnLongClickListener(longClick(onLongClick));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package eu.konggdev.strikemaps.ui.element.item;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.map.source.MapSource;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
|
||||
public class InlineItem implements UIItem {
|
||||
public String text;
|
||||
public Runnable onClick;
|
||||
|
||||
public InlineItem(String refText) {
|
||||
this.text = refText;
|
||||
}
|
||||
|
||||
public InlineItem(String refText, Runnable onClick) {
|
||||
this.text = refText;
|
||||
this.onClick = onClick;
|
||||
}
|
||||
|
||||
public static InlineItem fromSource(MapSource source) {
|
||||
return new InlineItem(source.name);
|
||||
}
|
||||
|
||||
public static InlineItem fromSource(MapSource source, Runnable onClick) {
|
||||
return new InlineItem(source.name, onClick);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View makeView(UIComponent spawner) {
|
||||
View view = spawner.inflateUi(R.layout.item_inline);
|
||||
((TextView) view.findViewById(R.id.inline)).setText(text);
|
||||
if(onClick != null) view.findViewById(R.id.inline).setOnClickListener(click(onClick));
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -4,41 +4,35 @@ import android.graphics.Bitmap;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import eu.konggdev.strikemaps.R;
|
||||
public class PreviewItem implements UIItem {
|
||||
@NonNull public String name;
|
||||
public String details;
|
||||
public String name;
|
||||
public String type;
|
||||
public Bitmap image;
|
||||
boolean hasImage;
|
||||
public PreviewItem(String refName, String refType) {
|
||||
this.name = refName;
|
||||
this.details = refType;
|
||||
this.type = refType;
|
||||
hasImage = false;
|
||||
}
|
||||
public PreviewItem(String refName, String refType, Bitmap refImage) {
|
||||
this.name = refName;
|
||||
this.details = refType;
|
||||
this.type = refType;
|
||||
this.image = refImage;
|
||||
hasImage = true;
|
||||
}
|
||||
|
||||
public static PreviewItem fromFeature(Feature feature) {
|
||||
return new PreviewItem(feature.getStringProperty("name"), feature.getStringProperty("class"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View makeView(UIComponent spawner) {
|
||||
View view = spawner.inflateUi(R.layout.item_preview);
|
||||
((TextView) view.findViewById(R.id.choiceName)).setText(name);
|
||||
if (details != null)
|
||||
((TextView) view.findViewById(R.id.details)).setText(details);
|
||||
((TextView) view.findViewById(R.id.type)).setText(type);
|
||||
return view;
|
||||
}
|
||||
|
||||
public View makeView(UIComponent spawner, View.OnClickListener onClick) {
|
||||
View view = makeView(spawner);
|
||||
view.setOnClickListener(onClick);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package eu.konggdev.strikemaps.ui.element.item;
|
||||
|
||||
import android.view.View;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
|
||||
public class SelectionItem implements UIItem {
|
||||
|
||||
@Override
|
||||
public View makeView(UIComponent spawner) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -12,4 +12,5 @@ public interface UIItem {
|
||||
}
|
||||
|
||||
default View.OnLongClickListener longClick(Runnable action) { return v -> { action.run(); return true; };}
|
||||
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package eu.konggdev.strikemaps.ui.element.region.content;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import eu.konggdev.strikemaps.ui.element.region.UIRegion;
|
||||
|
||||
public class MainContentRegion extends UIRegion {
|
||||
public Fragment fragment;
|
||||
public Integer layoutId;
|
||||
|
||||
public MainContentRegion(@NonNull Fragment initFragment, Integer refLayoutId) {
|
||||
super(initFragment, refLayoutId);
|
||||
this.fragment = initFragment;
|
||||
this.layoutId = refLayoutId;
|
||||
}
|
||||
|
||||
public Fragment getFragment() {
|
||||
return this.fragment;
|
||||
}
|
||||
|
||||
public void setFragment(Fragment fragment) {
|
||||
this.fragment = fragment;
|
||||
}
|
||||
}
|
||||
@@ -1,178 +1,36 @@
|
||||
package eu.konggdev.strikemaps.ui.factory;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
import android.widget.*;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.util.json.JsonPatcher;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
|
||||
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.ui.element.item.PreviewItem;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
//FIXME: Cleaner architecture would be having a class for each AlertDialog type
|
||||
//FIXME: Move Item functions into specific classes for specific types - e.g. StyleItem
|
||||
public final class AlertDialogFactory {
|
||||
public static AlertDialog styleManagementOptions(AppCompatActivity activity, StyleManagementMetadata metadata) {
|
||||
String[] options = {
|
||||
"Update style",
|
||||
"Update automatically"
|
||||
};
|
||||
|
||||
boolean[] checked = {
|
||||
metadata.doUpdates,
|
||||
metadata.autoUpdate
|
||||
};
|
||||
|
||||
return new AlertDialog.Builder(activity)
|
||||
.setTitle("Built-in Style")
|
||||
.setMultiChoiceItems(options, checked, (dialog, which, isChecked) -> {
|
||||
if (which == 0) {
|
||||
metadata.doUpdates = isChecked;
|
||||
} else if (which == 1) {
|
||||
metadata.autoUpdate = isChecked;
|
||||
}
|
||||
})
|
||||
.setNegativeButton("Cancel", null)
|
||||
.setPositiveButton("OK", null)
|
||||
.create();
|
||||
}
|
||||
|
||||
public static AlertDialog copyBuiltInStyle(AppCompatActivity activity, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) {
|
||||
//TODO: Use an UI element that's supposed to be vertical, instead of GenericItem
|
||||
|
||||
LinearLayout container = new LinearLayout(activity);
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
ScrollView scrollView = new ScrollView(activity);
|
||||
scrollView.addView(container);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
||||
.setTitle("Copy from")
|
||||
.setView(scrollView)
|
||||
.setNegativeButton("Cancel", null)
|
||||
.create();
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static AlertDialog createStyle(AppCompatActivity activity, RegistryStorageComponent registry, String baseStyleContents, FragmentMapChangePopup mapChangePopup) {
|
||||
final EditText nameInput = new EditText(activity);
|
||||
nameInput.setHint("Name");
|
||||
|
||||
LinearLayout container = new LinearLayout(activity);
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
int padding = (int) (20 * activity.getResources().getDisplayMetrics().density);
|
||||
container.setPadding(padding, padding, padding, 0);
|
||||
|
||||
container.addView(nameInput);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
||||
.setTitle("Create")
|
||||
.setView(container)
|
||||
.setPositiveButton("Create", null)
|
||||
.setNegativeButton("Cancel", (d, w) -> d.dismiss())
|
||||
.create();
|
||||
|
||||
dialog.setOnShowListener(d -> {
|
||||
Button createButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
|
||||
createButton.setOnClickListener(v -> {
|
||||
ObjectMapper mactivityer = new ObjectMapper();
|
||||
boolean nameEntryRequired = true;
|
||||
String styleContentName = "";
|
||||
if (baseStyleContents != null) {
|
||||
try {
|
||||
JsonNode root = mactivityer.readTree(baseStyleContents);
|
||||
if (!root.path("name").asText().isEmpty()) {
|
||||
nameEntryRequired = false; //We can take the name from the style
|
||||
styleContentName = root.path("name").asText();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
String name = nameInput.getText().toString().trim();
|
||||
|
||||
if (name.isEmpty() && nameEntryRequired) {
|
||||
nameInput.setError("Name required");
|
||||
return;
|
||||
} else if (name.isEmpty() && !nameEntryRequired) {
|
||||
name = styleContentName;
|
||||
}
|
||||
|
||||
assert !name.isEmpty();
|
||||
|
||||
|
||||
try {
|
||||
JsonNode root;
|
||||
if(baseStyleContents != null) {
|
||||
if(!baseStyleContents.isEmpty()) {
|
||||
root = mactivityer.readTree(baseStyleContents);
|
||||
} else {
|
||||
root = mactivityer.createObjectNode();
|
||||
}
|
||||
} else {
|
||||
root = mactivityer.createObjectNode();
|
||||
}
|
||||
|
||||
if (!root.path("name").asText().isEmpty()) {
|
||||
ObjectNode node = mactivityer.createObjectNode();
|
||||
node.put("name", name);
|
||||
root = JsonPatcher.patch(root, node);
|
||||
}
|
||||
|
||||
registry.addStyle(new MapStyle(
|
||||
mactivityer.writeValueAsString(root),
|
||||
new StyleOptions(),
|
||||
null
|
||||
));
|
||||
dialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(activity, "Failed to create", Toast.LENGTH_SHORT).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
mapChangePopup.reloadStyles();
|
||||
});
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static AlertDialog pointSelector(ComponentHolderActivity activity, UIComponent ui, List<Feature> features, Consumer<Feature> callback) {
|
||||
LinearLayout layout = new LinearLayout(activity);
|
||||
public static AlertDialog pointSelector(AppController app, List<Feature> features, Consumer<Feature> callback) {
|
||||
LinearLayout layout = new LinearLayout(app.getActivity());
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
ScrollView scrollView = new ScrollView(activity);
|
||||
ScrollView scrollView = new ScrollView(app.getActivity());
|
||||
scrollView.addView(layout);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
||||
AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
|
||||
.setView(scrollView)
|
||||
.create();
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#000000")));
|
||||
|
||||
for (Feature feature : features) {
|
||||
View itemView = PreviewItem.fromFeature(feature).makeView(ui, v -> {
|
||||
View itemView = PreviewItem.fromFeature(feature).makeView(app.getUi(), v -> {
|
||||
dialog.dismiss();
|
||||
new Handler(Looper.getMainLooper())
|
||||
new android.os.Handler(android.os.Looper.getMainLooper())
|
||||
.post(() -> callback.accept(feature));
|
||||
});
|
||||
layout.addView(itemView);
|
||||
@@ -180,34 +38,4 @@ public final class AlertDialogFactory {
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static AlertDialog searchSettings(AppCompatActivity activity) {
|
||||
return new AlertDialog.Builder(activity)
|
||||
.setTitle("Configure Search")
|
||||
.setPositiveButton("OK", null)
|
||||
.create();
|
||||
}
|
||||
|
||||
public static AlertDialog restartDialog(AppCompatActivity activity) {
|
||||
return new AlertDialog.Builder(activity)
|
||||
.setTitle("Restart required")
|
||||
.setMessage("Restart the activity to activityly changes.")
|
||||
.setCancelable(false)
|
||||
.setNegativeButton("Cancel", (d, w) -> {
|
||||
Toast.makeText(activity,
|
||||
"Changes will be activitylied on next restart",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
d.dismiss();
|
||||
})
|
||||
.setPositiveButton("Restart", (d, w) -> {
|
||||
Intent i = activity.getPackageManager()
|
||||
.getLaunchIntentForPackage(activity.getPackageName());
|
||||
if (i != null) {
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
activity.startActivity(i);
|
||||
}
|
||||
Runtime.getRuntime().exit(0);
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import eu.konggdev.strikemaps.ui.element.UIRegion;
|
||||
|
||||
public interface ContainerFragment {
|
||||
abstract public Integer getRegion();
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.dialog;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class NewStyleBottomSheet extends BottomSheetDialogFragment {
|
||||
private final String styleBase = "{\"name\":\"None\"}";
|
||||
|
||||
private AppCompatActivity activity;
|
||||
|
||||
private MapComponent map;
|
||||
|
||||
private UIComponent ui;
|
||||
|
||||
private RegistryStorageComponent registry;
|
||||
|
||||
private FragmentMapChangePopup mapChangePopup;
|
||||
|
||||
private final ActivityResultLauncher<Intent> importLauncher =
|
||||
registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == android.app.Activity.RESULT_OK
|
||||
&& result.getData() != null) {
|
||||
|
||||
Uri uri = result.getData().getData();
|
||||
|
||||
try (InputStream in = requireContext()
|
||||
.getContentResolver()
|
||||
.openInputStream(uri)) {
|
||||
|
||||
try (Cursor cursor = requireContext()
|
||||
.getContentResolver()
|
||||
.query(uri, null, null, null, null)) {
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
if (nameIndex >= 0) {
|
||||
String fileName = cursor.getString(nameIndex);
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(in)
|
||||
);
|
||||
|
||||
StringBuilder contentBuilder = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
contentBuilder.append(line).append(System.lineSeparator());
|
||||
}
|
||||
reader.close();
|
||||
String content = contentBuilder.toString();
|
||||
|
||||
if (fileName != null && !fileName.endsWith(".style.json")) {
|
||||
ui.alert(
|
||||
AlertDialogFactory.createStyle(
|
||||
activity,
|
||||
registry,
|
||||
content,
|
||||
mapChangePopup
|
||||
)
|
||||
);
|
||||
} else {
|
||||
registry.addStyle(
|
||||
new MapStyle(
|
||||
content,
|
||||
new StyleOptions(),
|
||||
null
|
||||
)
|
||||
);
|
||||
mapChangePopup.reloadStyles();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private void showImportDialog() {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.setType("application/json");
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
||||
importLauncher.launch(intent);
|
||||
}
|
||||
|
||||
public NewStyleBottomSheet(AppCompatActivity activity, MapComponent map, UIComponent ui, RegistryStorageComponent registry, FragmentMapChangePopup mapChangePopup) {
|
||||
this.activity = activity;
|
||||
this.map = map;
|
||||
this.ui = ui;
|
||||
this.registry = registry;
|
||||
this.mapChangePopup = mapChangePopup;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.dialog_new_style, container, false);
|
||||
|
||||
MaterialCardView builtInBtn = view.findViewById(R.id.buttonFromBuiltInStyle);
|
||||
MaterialCardView fileBtn = view.findViewById(R.id.buttonFromFile);
|
||||
MaterialCardView emptyBtn = view.findViewById(R.id.buttonCreateEmpty);
|
||||
|
||||
builtInBtn.setOnClickListener(v -> {
|
||||
ui.alert(AlertDialogFactory.copyBuiltInStyle(activity, map, ui, mapChangePopup));
|
||||
});
|
||||
|
||||
fileBtn.setOnClickListener(v -> {
|
||||
showImportDialog();
|
||||
});
|
||||
|
||||
emptyBtn.setOnClickListener(v -> {
|
||||
ui.alert(AlertDialogFactory.createStyle(activity, registry, styleBase, mapChangePopup));
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.dialog;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
|
||||
private final AppCompatActivity activity;
|
||||
|
||||
private final MapComponent map;
|
||||
|
||||
private final UIComponent ui;
|
||||
|
||||
private final RegistryStorageComponent registry;
|
||||
|
||||
private final FragmentMapChangePopup mapChangePopup;
|
||||
|
||||
private final Integer styleId;
|
||||
|
||||
private ActivityResultLauncher<Intent> exportLauncher;
|
||||
|
||||
void deleteStyle() {
|
||||
registry.deleteStyle(styleId);
|
||||
|
||||
mapChangePopup.reloadStyles();
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private void showExportDialog() {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.setType("application/json");
|
||||
|
||||
exportLauncher.launch(intent);
|
||||
}
|
||||
|
||||
public StyleDetailsBottomSheet(AppCompatActivity activity, MapComponent map, UIComponent ui, RegistryStorageComponent registry, FragmentMapChangePopup mapChangePopup, Integer styleId) {
|
||||
this.activity = activity;
|
||||
this.map = map;
|
||||
this.ui = ui;
|
||||
this.registry = registry;
|
||||
this.mapChangePopup = mapChangePopup;
|
||||
this.styleId = styleId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
exportLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == android.app.Activity.RESULT_OK
|
||||
&& result.getData() != null) {
|
||||
|
||||
Uri uri = result.getData().getData();
|
||||
|
||||
try (OutputStream out =
|
||||
requireContext()
|
||||
.getContentResolver()
|
||||
.openOutputStream(uri)) {
|
||||
|
||||
if (out != null) {
|
||||
String styleJson = registry.getStyle(styleId).json;
|
||||
if (styleJson != null) out.write(styleJson.getBytes());
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.dialog_style_details, container, false);
|
||||
|
||||
MapStyle style = registry.getStyle(styleId);
|
||||
TextView styleNameView = view.findViewById(R.id.styleName);
|
||||
LinearLayout styleManagementInfo = view.findViewById(R.id.styleManagementInfo);
|
||||
TextView styleTypeView = view.findViewById(R.id.styleType);
|
||||
ImageView managedStyleIndicator = view.findViewById(R.id.managedStyleIndicator);
|
||||
|
||||
MaterialCardView editButtonLayout = view.findViewById(R.id.editButton);
|
||||
MaterialCardView copyButtonLayout = view.findViewById(R.id.copyButton);
|
||||
MaterialCardView exportButtonLayout = view.findViewById(R.id.exportButton);
|
||||
MaterialCardView deleteButtonLayout = view.findViewById(R.id.deleteButton);
|
||||
styleNameView.setText(style.document.name);
|
||||
|
||||
if (style.managementMetadata != null) {
|
||||
styleTypeView.setText("Built-In Style");
|
||||
managedStyleIndicator.setVisibility(View.VISIBLE);
|
||||
styleManagementInfo.setOnClickListener(v ->
|
||||
ui.alert(
|
||||
AlertDialogFactory.styleManagementOptions(activity, style.managementMetadata)
|
||||
)
|
||||
);
|
||||
|
||||
} else {
|
||||
styleTypeView.setText("User Style");
|
||||
}
|
||||
|
||||
editButtonLayout.setOnClickListener(v -> Toast.makeText(requireContext(), "Editor not implemented yet\nWait for release", Toast.LENGTH_SHORT).show());
|
||||
copyButtonLayout.setOnClickListener(v -> ui.alert(AlertDialogFactory.createStyle(activity, registry, style.json, mapChangePopup)));
|
||||
exportButtonLayout.setOnClickListener(v -> showExportDialog());
|
||||
deleteButtonLayout.setOnClickListener(v -> deleteStyle());
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
+18
-32
@@ -2,42 +2,31 @@ package eu.konggdev.strikemaps.ui.fragment.layout;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.data.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.map.overlay.implementation.LocationOverlay;
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
|
||||
|
||||
public class FragmentLayoutControls extends Fragment implements Layout {
|
||||
private final AppCompatActivity activity;
|
||||
|
||||
private final UIComponent ui;
|
||||
|
||||
private final MapComponent map;
|
||||
|
||||
private final RegistryStorageComponent registry;
|
||||
|
||||
private final SharedPreferences userPrefs;
|
||||
AppController app;
|
||||
View rootView;
|
||||
|
||||
private final Integer region;
|
||||
|
||||
// Action definitions
|
||||
//*//
|
||||
public void notImplemented() { //Should never be called in release
|
||||
Toast.makeText(requireContext(), "Not implemented yet\nWait for release", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
@@ -46,32 +35,29 @@ public class FragmentLayoutControls extends Fragment implements Layout {
|
||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
|
||||
} else {
|
||||
map.switchOverlay(new LocationOverlay(map, activity));
|
||||
app.getMap().switchOverlay(new LocationOverlay(app));
|
||||
setupView();
|
||||
}
|
||||
}
|
||||
|
||||
public void zoomToLocation() {
|
||||
if(map.hasOverlay(LocationOverlay.class)) {
|
||||
if(!app.getMap().hasOverlay(LocationOverlay.class)) {
|
||||
Toast.makeText(requireContext(), "Hold to enable location", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void attributtionDialog() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
||||
.setTitle(activity.getString(R.string.attribution_title))
|
||||
.setMessage(activity.getString(R.string.shipped_attribution))
|
||||
AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
|
||||
.setTitle(app.getActivity().getString(R.string.attribution_title))
|
||||
.setMessage(app.getActivity().getString(R.string.shipped_attribution))
|
||||
.setPositiveButton("OK", null).show();
|
||||
}
|
||||
//*//
|
||||
|
||||
public FragmentLayoutControls(AppCompatActivity activity, UIComponent ui, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs, Integer region) {
|
||||
public FragmentLayoutControls(AppController app, Integer region) {
|
||||
super(R.layout.fragment_controls);
|
||||
this.activity = activity;
|
||||
this.ui = ui;
|
||||
this.map = map;
|
||||
this.registry = registry;
|
||||
this.userPrefs = userPrefs;
|
||||
this.app = app;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@@ -92,7 +78,7 @@ public class FragmentLayoutControls extends Fragment implements Layout {
|
||||
|
||||
/* Restores location enabled status from user prefs,
|
||||
TODO: Should be moved out of UI code in the future */
|
||||
if(UserPrefsHelper.persistLocationEnabled(userPrefs) && UserPrefsHelper.lastLocationEnabled(userPrefs) && !map.hasOverlay(LocationOverlay.class))
|
||||
if(UserPrefsHelper.persistLocationEnabled(app.getPrefs()) && UserPrefsHelper.lastLocationEnabled(app.getPrefs()) && !app.getMap().hasOverlay(LocationOverlay.class))
|
||||
toggleLocationService();
|
||||
|
||||
this.setupView();
|
||||
@@ -100,7 +86,7 @@ public class FragmentLayoutControls extends Fragment implements Layout {
|
||||
|
||||
public void setupView() {
|
||||
if (rootView == null) return;
|
||||
setupButton(rootView, R.id.layersButton, click(() -> ui.getCurrentScreen().open(new FragmentMapChangePopup(activity, ui, map, registry, R.id.bottomUi))));
|
||||
setupButton(rootView, R.id.layersButton, click(() -> app.getUi().getCurrentScreen().open(new FragmentMapChangePopup(app, R.id.bottomUi))));
|
||||
setupButton(rootView, R.id.attributionButton, click(this::attributtionDialog));
|
||||
setupButton(rootView, R.id.locationButton, click(this::zoomToLocation), longClick(this::toggleLocationService));
|
||||
|
||||
@@ -111,14 +97,14 @@ public class FragmentLayoutControls extends Fragment implements Layout {
|
||||
setupButton(rootView, R.id.modeButton, click(this::notImplemented));
|
||||
|
||||
TextView locationServiceStatusIndicator = rootView.findViewById(R.id.locationServiceStatusIndicator);
|
||||
if (map.hasOverlay(LocationOverlay.class)) {
|
||||
if (app.getMap().hasOverlay(LocationOverlay.class)) {
|
||||
locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#00FF00")); //green
|
||||
} else {
|
||||
locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#FB0303")); //red
|
||||
}
|
||||
|
||||
if(UserPrefsHelper.persistLocationEnabled(userPrefs))
|
||||
UserPrefsHelper.lastLocationEnabled(userPrefs, map.hasOverlay(LocationOverlay.class));
|
||||
if(UserPrefsHelper.persistLocationEnabled(app.getPrefs()))
|
||||
UserPrefsHelper.lastLocationEnabled(app.getPrefs(), app.getMap().hasOverlay(LocationOverlay.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.layout;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.PopupWindow;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
|
||||
|
||||
public class FragmentLayoutSearch extends Fragment implements Layout {
|
||||
private final AppCompatActivity activity;
|
||||
private final UIComponent ui;
|
||||
private final Integer region;
|
||||
|
||||
public FragmentLayoutSearch(AppCompatActivity activity, UIComponent ui, Integer region) {
|
||||
super(R.layout.fragment_search);
|
||||
this.activity = activity;
|
||||
this.ui = ui;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment toFragment() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
setupButton(view, R.id.hamburgerButton, click(() -> {
|
||||
|
||||
View menuView = getLayoutInflater().inflate(R.layout.dropdown_main, null);
|
||||
|
||||
PopupWindow popupWindow = new PopupWindow(
|
||||
menuView,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
true
|
||||
);
|
||||
|
||||
popupWindow.setOutsideTouchable(true);
|
||||
popupWindow.setFocusable(true);
|
||||
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
|
||||
setupButton(menuView, R.id.menuSearchSettings, click(() -> {
|
||||
ui.alert(AlertDialogFactory.searchSettings(activity));
|
||||
}));
|
||||
|
||||
setupButton(menuView, R.id.menuSettings, click(() -> {
|
||||
popupWindow.dismiss();
|
||||
ui.swapScreen("settings");
|
||||
}));
|
||||
|
||||
menuView.findViewById(R.id.menuSearchSettings).setOnClickListener(v -> popupWindow.dismiss());
|
||||
menuView.findViewById(R.id.menuAbout).setOnClickListener(v -> popupWindow.dismiss());
|
||||
|
||||
View anchor = view.findViewById(R.id.searchContainer);
|
||||
|
||||
anchor.post(() -> {
|
||||
|
||||
menuView.measure(
|
||||
View.MeasureSpec.UNSPECIFIED,
|
||||
View.MeasureSpec.UNSPECIFIED
|
||||
);
|
||||
|
||||
int popupWidth = menuView.getMeasuredWidth();
|
||||
int containerWidth = anchor.getWidth();
|
||||
|
||||
int xOffset = containerWidth - popupWidth;
|
||||
popupWindow.showAsDropDown(anchor, xOffset, 1);
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -2,11 +2,13 @@ package eu.konggdev.strikemaps.ui.fragment.layout.content.main;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import eu.konggdev.strikemaps.ui.element.UIRegion;
|
||||
|
||||
import eu.konggdev.strikemaps.R;
|
||||
|
||||
public class FragmentLayoutContentMap extends Fragment implements MainContentLayout {
|
||||
@@ -26,7 +28,6 @@ public class FragmentLayoutContentMap extends Fragment implements MainContentLay
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
LinearLayout layout = (LinearLayout) view;
|
||||
if(mapView.getParent() != null) ((ViewGroup) mapView.getParent()).removeView(mapView);
|
||||
layout.addView(mapView);
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.layout.content.main;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
|
||||
public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout {
|
||||
private final ComponentHolderActivity activity;
|
||||
|
||||
public FragmentLayoutContentOfflineMaps(ComponentHolderActivity activity) {
|
||||
super(R.layout.fragment_offline_maps);
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment toFragment() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
|
||||
// LinearLayout sourcesLayout = view.findViewById(R.id.llDownloadContainer);
|
||||
// for (MapSource source : sources)
|
||||
// sourcesLayout.addView(new InlineItem(source.name, () -> Toast.makeText(activity.getActivity(), "Work in progress", Toast.LENGTH_SHORT).show()).makeView(app.getUi()));
|
||||
}
|
||||
}
|
||||
+2
-60
@@ -1,68 +1,10 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.layout.content.main;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
|
||||
|
||||
|
||||
public class FragmentLayoutContentSettings extends Fragment implements MainContentLayout {
|
||||
private final AppCompatActivity activity;
|
||||
private final UIComponent ui;
|
||||
|
||||
private final SharedPreferences userPrefs;
|
||||
|
||||
public FragmentLayoutContentSettings(AppCompatActivity activity, UIComponent ui, SharedPreferences userPrefs) {
|
||||
super(R.layout.fragment_settings);
|
||||
this.activity = activity;
|
||||
this.ui = ui;
|
||||
this.userPrefs = userPrefs;
|
||||
}
|
||||
|
||||
public class FragmentLayoutContentSettings implements MainContentLayout {
|
||||
@Override
|
||||
public Fragment toFragment() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
Spinner mapRendererSelector = view.findViewById(R.id.mapRendererSelector);
|
||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
|
||||
view.getContext(),
|
||||
R.array.map_renderers,
|
||||
android.R.layout.simple_spinner_item
|
||||
);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
mapRendererSelector.setAdapter(adapter);
|
||||
mapRendererSelector.setSelection(UserPrefsHelper.mapRenderer(userPrefs));
|
||||
final boolean[] ignoreFirst = {true};
|
||||
mapRendererSelector.setOnItemSelectedListener(
|
||||
new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (ignoreFirst[0]) {
|
||||
ignoreFirst[0] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
UserPrefsHelper.mapRenderer(userPrefs, position);
|
||||
ui.alert(AlertDialogFactory.restartDialog(activity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {}
|
||||
}
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+20
-113
@@ -1,117 +1,38 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.popup;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.data.helper.FileHelper;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
|
||||
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.fragment.dialog.NewStyleBottomSheet;
|
||||
import eu.konggdev.strikemaps.ui.fragment.dialog.StyleDetailsBottomSheet;
|
||||
import eu.konggdev.strikemaps.ui.element.item.GenericItem;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class FragmentMapChangePopup extends Fragment implements Popup {
|
||||
private final AppCompatActivity activity;
|
||||
private final MapComponent map;
|
||||
private final UIComponent ui;
|
||||
private final RegistryStorageComponent registry;
|
||||
@NonNull AppController app;
|
||||
@NonNull MapComponent map;
|
||||
@NonNull UIComponent ui;
|
||||
|
||||
private final Integer region;
|
||||
|
||||
private View view;
|
||||
|
||||
Map<Integer, Integer> tabs = Map.of(
|
||||
R.id.stylesTab, R.id.styles,
|
||||
R.id.optionsTab, R.id.options,
|
||||
R.id.overlaysTab, R.id.overlays
|
||||
);
|
||||
|
||||
Map<Integer, Runnable> tabLoadActions = Map.of(
|
||||
R.id.stylesTab, this::reloadStyles,
|
||||
R.id.optionsTab, this::loadStyleOptions,
|
||||
R.id.overlaysTab, this::reloadOverlays
|
||||
);
|
||||
|
||||
public void reloadStyles() {
|
||||
LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout);
|
||||
stylesLayout.removeAllViews();
|
||||
registry.getStyles().forEach((id, style) -> {
|
||||
View item = new GenericItem(
|
||||
style.document,
|
||||
() -> this.setStyle(id),
|
||||
() -> this.styleDetails(id), activity).makeView(ui);
|
||||
if (Objects.equals(map.styleId, id)) item.findViewById(R.id.indicator)
|
||||
.setVisibility(View.VISIBLE);
|
||||
stylesLayout.addView(item);
|
||||
});
|
||||
Bitmap addNewIcon = BitmapFactory.decodeResource(activity.getResources(), android.R.drawable.ic_menu_add);
|
||||
stylesLayout.addView(new GenericItem("",
|
||||
addNewIcon,
|
||||
this::newStyleFlow).makeView(ui));
|
||||
}
|
||||
|
||||
public void loadStyleOptions() {
|
||||
LinearLayout optionsLayout = view.findViewById(R.id.optionsLayout);
|
||||
// optionsLayout.removeAllViews();
|
||||
// TextView sources = new AppCompatTextView(requireContext()) {{
|
||||
// setText("Sources");
|
||||
// setTextSize(16);
|
||||
// setLayoutParams(new ViewGroup.MarginLayoutParams(
|
||||
// ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
// ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
// ) {{ leftMargin = 16; }});
|
||||
// }};
|
||||
// optionsLayout.addView(sources);
|
||||
|
||||
// for (MapSource source : map.style.sources) {
|
||||
// LinearLayout sourceSelectionLayout = new LinearLayout(requireContext());
|
||||
// TextView sourceName = new TextView(requireContext());
|
||||
// sourceName.setText(source.name);
|
||||
// sourceSelectionLayout.addView(sourceName);
|
||||
// optionsLayout.addView(sourceSelectionLayout);
|
||||
// }
|
||||
}
|
||||
|
||||
public void reloadOverlays() {
|
||||
|
||||
}
|
||||
|
||||
void newStyleFlow() {
|
||||
new NewStyleBottomSheet(activity, map, ui, registry, this).show(activity.getSupportFragmentManager(), "NewStyleBottomSheet");
|
||||
}
|
||||
|
||||
void styleDetails(Integer id) {
|
||||
new StyleDetailsBottomSheet(activity, map, ui, registry, this, id).show(activity.getSupportFragmentManager(), "StyleDetailsBottomSheet");
|
||||
}
|
||||
|
||||
void setStyle(Integer id) {
|
||||
map.setStyle(id);
|
||||
reloadStyles();
|
||||
}
|
||||
|
||||
public FragmentMapChangePopup(AppCompatActivity activity, UIComponent ui, MapComponent map, RegistryStorageComponent registry, Integer region) {
|
||||
public FragmentMapChangePopup(AppController app, Integer region) {
|
||||
super(R.layout.popup_map_change);
|
||||
this.activity = activity;
|
||||
this.ui = ui;
|
||||
this.map = map;
|
||||
this.registry = registry;
|
||||
this.app = app;
|
||||
this.map = app.getMap();
|
||||
this.ui = app.getUi();
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@@ -125,30 +46,16 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatTextViewDrawableApis")
|
||||
void switchTab(int target) {
|
||||
tabs.forEach((button, content) -> {
|
||||
view.findViewById(content).setVisibility(button == target ? View.VISIBLE : View.GONE);
|
||||
int color = (button == target
|
||||
? Color.WHITE
|
||||
: Color.parseColor("#888888"));
|
||||
((TextView) view.findViewById(button)).setTextColor(color);
|
||||
((TextView) view.findViewById(button)).setCompoundDrawableTintList(ColorStateList.valueOf(color));
|
||||
});
|
||||
tabLoadActions.get(target).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
//FIXME
|
||||
this.view = view;
|
||||
|
||||
tabs.keySet().forEach(button -> {
|
||||
view.findViewById(button).setOnClickListener(v -> switchTab(button));
|
||||
});
|
||||
|
||||
switchTab(R.id.stylesTab); // Show styles
|
||||
setupButton(view, R.id.closeButton, click(() -> ui.getCurrentScreen().closePopup()));
|
||||
setupDragHandle(view, view, () -> ui.getCurrentScreen().closePopup());
|
||||
List<String> stylePaths = new ArrayList<>();
|
||||
stylePaths.addAll(Arrays.asList(FileHelper.getAssetFiles("bundled/style", ".style.json", app)));
|
||||
stylePaths.addAll(Arrays.asList(FileHelper.getUserFiles("style", ".style.json", app)));
|
||||
LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout);
|
||||
for (String style : stylePaths)
|
||||
stylesLayout.addView(GenericItem.fromStyle(MapStyle.fromMapLibreJsonFile(style, app), map).makeView(ui));
|
||||
}
|
||||
}
|
||||
@@ -2,23 +2,30 @@ package eu.konggdev.strikemaps.ui.screen;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.ui.fragment.ContainerFragment;
|
||||
import eu.konggdev.strikemaps.ui.fragment.FragmentEmptyPlaceholder;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.MainContentLayout;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.Popup;
|
||||
import eu.konggdev.strikemaps.ui.element.region.UIRegion;
|
||||
import eu.konggdev.strikemaps.ui.element.UIRegion;
|
||||
|
||||
public class Screen {
|
||||
private final ComponentHolderActivity activity;
|
||||
|
||||
public Screen(ComponentHolderActivity activity, Map<Integer, UIRegion> regions) {
|
||||
this.activity = activity;
|
||||
@NonNull AppController app;
|
||||
public Screen(AppController app, MainContentLayout mainContent, Map<Integer, UIRegion> regions, Integer layout) {
|
||||
this.app = app;
|
||||
this.layout = layout;
|
||||
this.mainContent = mainContent;
|
||||
this.uiRegions = regions;
|
||||
}
|
||||
|
||||
private final Integer layout;
|
||||
|
||||
private MainContentLayout mainContent;
|
||||
|
||||
Map<Integer, UIRegion> uiRegions;
|
||||
public Integer popup;
|
||||
|
||||
@@ -54,17 +61,17 @@ public class Screen {
|
||||
}
|
||||
|
||||
public void fragmentTransaction(int layoutId, Fragment fragment) {
|
||||
activity.getSupportFragmentManager()
|
||||
app.getActivity().getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(layoutId, fragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void attachAll() {
|
||||
for (UIRegion region : uiRegions.values()) setFragment(region, region.getFragment());
|
||||
}
|
||||
|
||||
public void detachAll() {
|
||||
for (UIRegion region : uiRegions.values()) fragmentTransaction(region.layoutId, new FragmentEmptyPlaceholder());
|
||||
app.getActivity().setContentView(layout);
|
||||
fragmentTransaction(R.id.mainContentView, mainContent.toFragment());
|
||||
for (UIRegion region : uiRegions.values()) {
|
||||
setFragment(region, region.getFragment());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package eu.konggdev.strikemaps.util.file;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
//FIXME: Ugly
|
||||
public final class FileTools {
|
||||
private static final String TAG = "FileTools";
|
||||
|
||||
public static String loadStringFromAssetFile(String filePath, AppCompatActivity activity) {
|
||||
try (InputStream is = activity.getAssets().open(filePath)) {
|
||||
int size = is.available();
|
||||
byte[] buffer = new byte[size];
|
||||
is.read(buffer);
|
||||
return new String(buffer, StandardCharsets.UTF_8);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getAssetFiles(String path, String fileExt, AppCompatActivity activity) {
|
||||
AssetManager assetManager = activity.getAssets();
|
||||
try {
|
||||
if (path != null && path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
|
||||
String fullPath = (path == null || path.isEmpty()) ? "" : path;
|
||||
|
||||
String[] files = assetManager.list(fullPath);
|
||||
|
||||
if (files == null) return new String[0];
|
||||
|
||||
if (fileExt == null || fileExt.isEmpty())
|
||||
return files;
|
||||
|
||||
List<String> filtered = new ArrayList<>();
|
||||
for (String file : files) {
|
||||
if (file.toLowerCase().endsWith(fileExt.toLowerCase())) {
|
||||
filtered.add((fullPath.isEmpty() ? "" : fullPath + "/") + file);
|
||||
}
|
||||
}
|
||||
|
||||
return filtered.toArray(new String[0]);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream openAssetStream(String path, AppCompatActivity activity) {
|
||||
try {
|
||||
return activity.getAssets().open(path);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package eu.konggdev.strikemaps.util.icon;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.util.Log;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import eu.konggdev.strikemaps.util.file.FileTools;
|
||||
|
||||
public final class IconResolver {
|
||||
private static final String TAG = "IconResolver";
|
||||
|
||||
public static Bitmap getIcon(String iconLocator, AppCompatActivity activity) {
|
||||
switch (iconLocator.split("//")[0]) {
|
||||
//TODO: https
|
||||
case "assets:":
|
||||
return BitmapFactory.decodeStream(FileTools.openAssetStream("bundled/icon/" + iconLocator.split("//")[1], activity));
|
||||
default:
|
||||
Log.e(TAG, "Unimplemented icon locator space: " + iconLocator);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package eu.konggdev.strikemaps.util.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public final class JsonPatcher {
|
||||
//Takes a json and a patch and applies it
|
||||
public static JsonNode patch(JsonNode current, JsonNode patch) throws Exception {
|
||||
if (current.isObject()) {
|
||||
ObjectNode result = current.deepCopy();
|
||||
|
||||
patch.fields().forEachRemaining(entry -> { //For each
|
||||
String key = entry.getKey();
|
||||
JsonNode patchValue = entry.getValue();
|
||||
if(!result.has(key)) { //Not at all in current
|
||||
result.set(key, patchValue); //Just append it to result
|
||||
} else if (result.has(key) && !patchValue.isEmpty()) { //Deeper depth possible
|
||||
try {
|
||||
result.set(key, patch(result.get(key), patchValue)); //Patch iteration with patch's value (traverse deeper)
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else if (result.has(key) && patchValue.isEmpty() && result.get(key).isEmpty()) { //Max depth match
|
||||
result.set(key, patchValue); //Replace with patch's value
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (current.isArray()) {
|
||||
ArrayNode result = current.deepCopy();
|
||||
for (JsonNode entry : patch) {
|
||||
if (StreamSupport.stream(result.spliterator(), false)
|
||||
.noneMatch(node -> node.equals(entry))) { //If no exact entry, add entry (prevents duplicates)
|
||||
result.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
//Takes an original json, a patched json and a patch and removes that specific patch's changes from it
|
||||
public static JsonNode unpatch(JsonNode original, JsonNode current, JsonNode patch) throws Exception {
|
||||
if (current.isObject()) {
|
||||
ObjectNode result = current.deepCopy(); //Current contains the patch, deepcopy it and operate on the copy
|
||||
|
||||
current.fields().forEachRemaining(entry -> {
|
||||
String key = entry.getKey();
|
||||
JsonNode value = entry.getValue();
|
||||
|
||||
if (!original.has(key) && patch.has(key)) { //Value is in patch and current but was not at all in the original
|
||||
result.remove(key); //Just remove the value
|
||||
} else if (!value.isEmpty() && patch.has(key)) { //Depper depth possible
|
||||
try {
|
||||
result.set(key, unpatch(original.get(key), result.get(key), patch.get(key))); //Replace with further unpatch of deeper level
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else if (value.isEmpty() && patch.has(key)) { //Max depth match
|
||||
result.set(key, original.get(key)); //Replace with original unpatched value
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (current.isArray()) {
|
||||
ArrayNode result = current.deepCopy();
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
JsonNode entry = result.get(i);
|
||||
if (StreamSupport.stream(original.spliterator(), false)
|
||||
.noneMatch(on -> on.equals(entry)) //If not in original
|
||||
&&
|
||||
StreamSupport.stream(patch.spliterator(), false)
|
||||
.noneMatch(rn -> rn.equals(entry))) { //But also in patch
|
||||
|
||||
result.remove(i); //Remove from result
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
The following files included inside the /res/drawable folder are derived from Google Material Icons and are subject to the Apache License, Version 2.0:
|
||||
|
||||
* `ic_sliders.xml`
|
||||
* `ic_bubble.xml`
|
||||
* `ic_stack.xml`
|
||||
* `ic_clarify.xml`
|
||||
* `ic_file.xml`
|
||||
* `ic_offline.xml`
|
||||
* `ic_arrow_forward.xml`
|
||||
* `ic_hide.bmp`
|
||||
* `ic_dropdown.xml`
|
||||
|
||||
|
||||
Unless otherwise noted in this file, all other files included in the `res` folder are subject to the standard license of this project
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#2A2100" />
|
||||
<corners android:radius="10dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="#4D3D00" />
|
||||
</shape>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:insetLeft="4dp"
|
||||
android:insetTop="4dp"
|
||||
android:insetRight="4dp"
|
||||
android:insetBottom="4dp">
|
||||
|
||||
<ripple android:color="#33FFFFFF">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#000000" />
|
||||
<corners android:radius="3dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
|
||||
</inset>
|
||||
@@ -1,5 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M400,680L400,280L600,480L400,680Z"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,5 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="18dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="18dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M619.5,148.5Q685,177 734,226Q783,275 811.5,340.5Q840,406 840,480Q840,554 811.5,619.5Q783,685 734,734Q685,783 619.5,811.5Q554,840 480,840Q439,840 401,831Q363,822 325,805L386,744Q409,752 432.5,756Q456,760 480,760Q596,760 678,678Q760,596 760,480Q760,364 678,282Q596,200 480,200Q364,200 282,282Q200,364 200,480Q200,504 204,527.5Q208,551 216,574L156,634Q138,598 129,559.5Q120,521 120,480Q120,406 148.5,340.5Q177,275 226,226Q275,177 340.5,148.5Q406,120 480,120Q554,120 619.5,148.5ZM520,640L520,496L176,840L120,784L464,440L320,440L320,360L600,360L600,640L520,640Z"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,17 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:tint="#000000"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
|
||||
<group
|
||||
android:translateY="-40">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M240,680L520,680L520,600L240,600L240,680ZM640,680L720,680L720,280L640,280L640,680ZM240,520L520,520L520,440L240,440L240,520ZM240,360L520,360L520,280L240,280L240,360ZM160,840Q127,840 103.5,816.5Q80,793 80,760L80,200Q80,167 103.5,143.5Q127,120 160,120L800,120Q833,120 856.5,143.5Q880,167 880,200L880,760Q880,793 856.5,816.5Q833,840 800,840L160,840ZM160,760L800,760Q800,760 800,760Q800,760 800,760L800,200Q800,200 800,200Q800,200 800,200L160,200Q160,200 160,200Q160,200 160,200L160,760Q160,760 160,760Q160,760 160,760ZM160,760L160,760Q160,760 160,760Q160,760 160,760L160,200Q160,200 160,200Q160,200 160,200L160,200Q160,200 160,200Q160,200 160,200L160,760Q160,760 160,760Q160,760 160,760Z" />
|
||||
|
||||
</group>
|
||||
|
||||
</vector>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -1,5 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M360,720Q327,720 303.5,696.5Q280,673 280,640L280,160Q280,127 303.5,103.5Q327,80 360,80L720,80Q753,80 776.5,103.5Q800,127 800,160L800,640Q800,673 776.5,696.5Q753,720 720,720L360,720ZM360,640L720,640Q720,640 720,640Q720,640 720,640L720,160Q720,160 720,160Q720,160 720,160L360,160Q360,160 360,160Q360,160 360,160L360,640Q360,640 360,640Q360,640 360,640ZM200,880Q167,880 143.5,856.5Q120,833 120,800L120,240L200,240L200,800Q200,800 200,800Q200,800 200,800L640,800L640,880L200,880ZM360,640Q360,640 360,640Q360,640 360,640L360,160Q360,160 360,160Q360,160 360,160L360,160Q360,160 360,160Q360,160 360,160L360,640Q360,640 360,640Q360,640 360,640Z"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,5 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,600L280,400L680,400L480,600Z"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,5 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M720,630Q720,734 647,807Q574,880 470,880Q366,880 293,807Q220,734 220,630L220,260Q220,185 272.5,132.5Q325,80 400,80Q475,80 527.5,132.5Q580,185 580,260L580,610Q580,656 548,688Q516,720 470,720Q424,720 392,688Q360,656 360,610L360,240L440,240L440,610Q440,623 448.5,631.5Q457,640 470,640Q483,640 491.5,631.5Q500,623 500,610L500,260Q499,218 470.5,189Q442,160 400,160Q358,160 329,189Q300,218 300,260L300,630Q299,701 349,750.5Q399,800 470,800Q540,800 589,750.5Q638,701 640,630L640,240L720,240L720,630Z"/>
|
||||
|
||||
</vector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 177 B After Width: | Height: | Size: 214 B |
@@ -1,5 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10s10,-4.49 10,-10S17.51,2 12,2zM11,10V6h2v4h3l-4,4l-4,-4H11zM17,17H7v-2h10V17z"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,24 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="#000000">
|
||||
|
||||
<group
|
||||
android:pivotX="480"
|
||||
android:pivotY="480"
|
||||
android:scaleX="1.15"
|
||||
android:scaleY="1.15"
|
||||
android:translateX="-80"
|
||||
android:translateY="40">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M300,600L360,600L360,440L300,440L300,490L240,490L240,550L300,550L300,600Z
|
||||
M400,550L720,550L720,490L400,490L400,550Z
|
||||
M600,440L660,440L660,390L720,390L660,330L660,280L600,280L600,440Z
|
||||
M240,390L560,390L560,330L240,330L240,390Z" />
|
||||
</group>
|
||||
|
||||
</vector>
|
||||
@@ -1,17 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:tint="#000000"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
|
||||
<group
|
||||
android:translateY="-40">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M80,880L80,800L880,800L880,880L80,880ZM280,440L280,320L680,320L680,440L280,440ZM280,680L280,560L680,560L680,680L280,680Z" />
|
||||
|
||||
</group>
|
||||
|
||||
</vector>
|
||||
@@ -1,7 +0,0 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<corners android:radius="2dp" />
|
||||
|
||||
<solid android:color="#FFFFFF" />
|
||||
</shape>
|
||||
@@ -1,173 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#000000"
|
||||
android:padding="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="34dp"
|
||||
android:gravity="center"
|
||||
android:text="New style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/buttonFromBuiltInStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/builtInStyleIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_edit"
|
||||
app:tint="#A4A3A3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/builtInStyleText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="From built-In style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/buttonFromFile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/buttonFromBuiltInStyle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fileIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/ic_file"
|
||||
app:tint="#6d6c6c"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="From file"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/buttonCreateEmpty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/buttonFromFile"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/emptyIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/ic_create"
|
||||
app:tint="#6d6c6c"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/emptyBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Create empty"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,303 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#000000"
|
||||
android:padding="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/styleName"
|
||||
android:layout_width="164dp"
|
||||
android:layout_height="34dp"
|
||||
android:gravity="center"
|
||||
android:text="Style Name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/styleManagementInfo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
app:layout_constraintTop_toBottomOf="@id/styleName"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/styleType"
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="27dp"
|
||||
android:gravity="center"
|
||||
android:text="Style Type?"
|
||||
android:textColor="#A4A3A3"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/managedStyleIndicator"
|
||||
android:layout_width="27dp"
|
||||
android:layout_height="27dp"
|
||||
android:layout_marginStart="-8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:visibility="gone"
|
||||
android:background="@android:color/transparent"
|
||||
android:src="@drawable/ic_arrow_forward"
|
||||
app:tint="#FFFFFF"
|
||||
android:contentDescription="Manage updates" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/optionsButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/styleManagementInfo"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/optionsIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/ic_sliders"
|
||||
app:tint="#A4A3A3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/optionsBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Options"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/editButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/optionsButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/hideIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_edit"
|
||||
app:tint="#A4A3A3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/hideBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Edit style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/copyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/editButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/copyIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/ic_copy"
|
||||
app:tint="#6d6c6c"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/copyBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Copy style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/exportButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/copyButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/exportIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_save"
|
||||
app:tint="#A4A3A3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exportBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Export style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/deleteButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="#1B1A1A"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="#292828"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/exportButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/deleteIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_delete"
|
||||
app:tint="#A4A3A3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deleteText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Delete style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="12dp"
|
||||
app:cardBackgroundColor="#000000">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/menuSearchSettings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:text="Configure Search"
|
||||
android:textColor="#FFFFFF"
|
||||
android:background="?android:attr/selectableItemBackground"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/menuSettings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:text="Settings"
|
||||
android:textColor="#FFFFFF"
|
||||
android:background="?android:attr/selectableItemBackground"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/menuAbout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:text="About"
|
||||
android:textColor="#FFFFFF"
|
||||
android:background="?android:attr/selectableItemBackground"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,91 +1,85 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/routeButton"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="34dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:background="@drawable/bg_map_button"
|
||||
android:src="@android:drawable/ic_menu_directions"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/placesButton"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
android:id="@+id/routeButton"
|
||||
android:layout_width="65dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="36dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:src="@android:drawable/ic_menu_directions"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/placesButton"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/placesButton"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="34dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:background="@drawable/bg_map_button"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/layersButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:srcCompat="@android:drawable/ic_menu_myplaces" />
|
||||
android:id="@+id/placesButton"
|
||||
android:layout_width="65dp"
|
||||
android:layout_height="43dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="36dp"
|
||||
android:backgroundTint="#000000"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/layersButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:srcCompat="@android:drawable/ic_menu_myplaces" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/layersButton"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:background="@drawable/bg_map_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:srcCompat="@drawable/ic_styles_menu" />
|
||||
android:id="@+id/layersButton"
|
||||
android:layout_width="65dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:backgroundTint="#000000"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:srcCompat="@drawable/ic_styles_menu" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/modeButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="34dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="44dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:background="@drawable/bg_map_button"
|
||||
android:src="@android:drawable/ic_menu_manage"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/locationButtonContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0" />
|
||||
android:id="@+id/modeButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="44dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:src="@android:drawable/ic_menu_manage"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/locationButtonContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/attributionButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="272dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:background="@drawable/bg_map_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.375"
|
||||
app:srcCompat="@android:drawable/ic_menu_info_details" />
|
||||
android:id="@+id/attributionButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="31dp"
|
||||
android:layout_marginStart="272dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:backgroundTint="#000000"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.375"
|
||||
app:srcCompat="@android:drawable/ic_menu_info_details" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/locationButtonContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="21dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/attributionButton"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
android:id="@+id/locationButtonContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/attributionButton"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/locationButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="47dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:background="@drawable/bg_map_button"
|
||||
android:contentDescription="Location"
|
||||
app:srcCompat="@android:drawable/ic_menu_mylocation" />
|
||||
android:id="@+id/locationButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="47dp"
|
||||
android:backgroundTint="#000000"
|
||||
android:contentDescription="Location"
|
||||
app:srcCompat="@android:drawable/ic_menu_mylocation" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/locationServiceStatusIndicator"
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
<android.widget.LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</android.widget.LinearLayout>
|
||||
@@ -1,41 +0,0 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#000000">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDownloadLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Download for source:"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"
|
||||
android:includeFontPadding="true"
|
||||
android:paddingBottom="4dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scrollDownloadContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvDownloadLabel"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llDownloadContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="6dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/searchContainer"
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="35dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="#000000"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<SearchView
|
||||
android:id="@+id/searchView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:iconifiedByDefault="false"
|
||||
android:queryHint="Search..."
|
||||
android:background="@android:color/transparent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/hamburgerButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="Menu"
|
||||
android:src="@drawable/ic_hamburger_menu" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp"
|
||||
android:background="@android:color/background_dark">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mapRendererLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Map Renderer:"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/mapRendererSelector"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/mapRendererSelector"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
app:layout_constraintStart_toEndOf="@id/mapRendererLabel"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,35 +1,27 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="8dp">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="8dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/image"
|
||||
android:layout_width="54dp"
|
||||
android:layout_height="46dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="Image"
|
||||
android:src="@android:drawable/ic_menu_gallery"
|
||||
android:padding="0dp" />
|
||||
android:id="@+id/image"
|
||||
android:layout_width="54dp"
|
||||
android:layout_height="47dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="Style Image"
|
||||
android:src="@android:drawable/ic_menu_gallery" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:text="Name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="14sp" />
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:text="Item Name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<View
|
||||
android:id="@+id/indicator"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="3dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:visibility="gone"
|
||||
android:background="@drawable/indicator"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#000000"
|
||||
android:foregroundTint="#FFFFFF">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/inline"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:paddingVertical="12dp"
|
||||
android:text=""
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="16sp"
|
||||
android:drawableEnd="@drawable/ic_arrow_forward"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,9 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#000000"
|
||||
android:background="#0E0000"
|
||||
android:foregroundTint="#FFFFFF">
|
||||
|
||||
<TextView
|
||||
@@ -15,7 +16,7 @@
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="Choice Item"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
android:textSize="24sp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:scrollHorizontally="false"
|
||||
@@ -23,12 +24,12 @@
|
||||
android:autoSizeMinTextSize="12sp"
|
||||
android:autoSizeMaxTextSize="24sp"
|
||||
android:autoSizeStepGranularity="1sp"
|
||||
app:layout_constraintStart_toEndOf="@+id/icon"
|
||||
app:layout_constraintStart_toEndOf="@+id/poiIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:id="@+id/poiIcon"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginStart="7dp"
|
||||
@@ -38,20 +39,20 @@
|
||||
app:srcCompat="@drawable/maplibre_info_bg_selector" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/details"
|
||||
android:id="@+id/type"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="7dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:text="Type"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
app:layout_constraintStart_toEndOf="@id/icon"
|
||||
app:layout_constraintStart_toEndOf="@id/poiIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/choiceName"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/selectionName"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/currentSelection"
|
||||
android:drawableEnd="@drawable/ic_dropdown"
|
||||
android:drawablePadding="4dp"
|
||||
android:drawableTint="@android:color/white"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -2,7 +2,6 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#000000"
|
||||
@@ -20,183 +19,41 @@
|
||||
<ImageButton
|
||||
android:id="@+id/closeButton"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="27dp"
|
||||
android:layout_height="30dp"
|
||||
android:backgroundTint="#000000"
|
||||
app:srcCompat="@android:drawable/ic_menu_close_clear_cancel"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="28dp"
|
||||
<TextView
|
||||
android:id="@+id/stylesLabel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Styles"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/dragHandle"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stylesTab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Style"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@android:color/white"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableStart="@drawable/ic_bubble"
|
||||
android:drawablePadding="6dp"
|
||||
android:drawableTint="@android:color/white"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/optionsTab"
|
||||
app:layout_constraintHorizontal_chainStyle="packed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/optionsTab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Options"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#888888"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableStart="@drawable/ic_sliders"
|
||||
android:drawablePadding="2dp"
|
||||
android:drawableTint="#888888"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/stylesTab"
|
||||
app:layout_constraintEnd_toStartOf="@id/overlaysTab" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overlaysTab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Overlays"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#888888"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableStart="@drawable/ic_stack"
|
||||
android:drawablePadding="4dp"
|
||||
android:drawableTint="#888888"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/optionsTab"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/tabContent"
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/styles"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tabs"
|
||||
app:layout_constraintTop_toBottomOf="@id/stylesLabel"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" >
|
||||
|
||||
<!-- Styles tab -->
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/styles"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/stylesLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="horizontal" />
|
||||
</HorizontalScrollView>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/stylesScrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:fillViewport="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/stylesLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Options tab -->
|
||||
<ScrollView
|
||||
android:id="@+id/options"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/optionsLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sources"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginStart="12dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sourcesLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<!-- Overlays tab -->
|
||||
<ScrollView
|
||||
android:id="@+id/overlays"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/overlaysLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</FrameLayout>
|
||||
<!-- Sources selection to be implemented here -->
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/constraintLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" >
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/popupHolder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/mainContentView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" >
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottomUi"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/devIndicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="DEVELOPMENT BUILD!"
|
||||
android:textColor="#000000"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/searchContainer"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="33dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="#000000"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<SearchView
|
||||
android:id="@+id/searchView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:iconifiedByDefault="false"
|
||||
android:queryHint="Search..."
|
||||
android:background="@android:color/transparent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/hamburgerButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="Menu"
|
||||
android:src="@drawable/ic_hamburger_menu" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/constraintLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" >
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/mainContentView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottomUi"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/topUi"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,6 +1,6 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.StrikeMaps" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<style name="Theme.StrikeMaps" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_200</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
@@ -11,5 +11,6 @@
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="21">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,11 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">Strike Maps</string>
|
||||
<string name="settings_title">Settings</string>
|
||||
<string name="attribution_title"> Attribution </string>
|
||||
<string name="shipped_attribution">Map Rendering libraries Included;\n - MapLibre developed by MapLibre Organization\n - Vtm developed by Mapsforge\nStrike Maps made with <3 by konggdev</string>
|
||||
<string-array name="map_renderers">
|
||||
<item>MapLibre GL JS</item>
|
||||
<item>MapLibre Native</item>
|
||||
<item>VTM</item>
|
||||
</string-array>
|
||||
<string name="shipped_attribution">Earth map data Included;\n - © OpenStreetMap Contributors\nMap Rendering libraries Included;\n - MapLibre developed by MapLibre Organization\n - Vtm developed by Mapsforge\nStrike Maps made with <3 by konggdev</string>
|
||||
</resources>
|
||||
@@ -1,6 +1,6 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.StrikeMaps" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<style name="Theme.StrikeMaps" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/black</item>
|
||||
<item name="colorPrimaryVariant">@color/black</item>
|
||||
@@ -11,5 +11,6 @@
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="21">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ constraintlayout = "2.1.4"
|
||||
playServicesMaps = "19.0.0"
|
||||
viewpager2 = "1.1.0"
|
||||
kotlin = "2.3.10"
|
||||
coreKtx = "1.18.0"
|
||||
|
||||
[libraries]
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
@@ -19,7 +20,9 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a
|
||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||
activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||
play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
|
||||
viewpager2 = { group = "androidx.viewpager2", name = "viewpager2", version.ref = "viewpager2" }
|
||||
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
||||
Reference in new issue
Block a user