mirror of
https://github.com/ev-map/EVMap.git
synced 2025-12-24 23:57:45 -05:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
897b439cca | ||
|
|
141b2c76b1 | ||
|
|
fc22b16111 | ||
|
|
f41ea230de | ||
|
|
ceb5081757 | ||
|
|
28bb8cef5f | ||
|
|
ba17cb989a | ||
|
|
d08aaa3325 | ||
|
|
0f24608d2a | ||
|
|
92e9539286 | ||
|
|
b373f49180 | ||
|
|
ec8728a253 | ||
|
|
9ca470cd46 | ||
|
|
38a1bf2da5 | ||
|
|
5c1dad82b1 | ||
|
|
5647820f3e | ||
|
|
092a3e50bc | ||
|
|
7b27fe2cac | ||
|
|
8991cb4e4a | ||
|
|
66d6aee97e |
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -75,8 +75,10 @@ jobs:
|
||||
run: |
|
||||
checksec --output=json --dir=lib > checksec_output.json
|
||||
jq --argjson exceptions '[
|
||||
"lib/arm64-v8a/libc++_shared.so",
|
||||
"lib/armeabi-v7a/libc++_shared.so",
|
||||
"lib/x86/libc++_shared.so"
|
||||
"lib/x86/libc++_shared.so",
|
||||
"lib/x86_64/libc++_shared.so"
|
||||
]' '
|
||||
to_entries
|
||||
| map(select(.value.fortify_source == "no" and (.key as $lib | $exceptions | index($lib) | not)))
|
||||
|
||||
36
Gemfile.lock
36
Gemfile.lock
@@ -5,23 +5,28 @@ GEM
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.354.0)
|
||||
aws-sdk-core (3.104.3)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.36.0)
|
||||
aws-sdk-core (~> 3, >= 3.99.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.78.0)
|
||||
aws-sdk-core (~> 3, >= 3.104.3)
|
||||
aws-eventstream (1.4.0)
|
||||
aws-partitions (1.1196.0)
|
||||
aws-sdk-core (3.240.0)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
bigdecimal
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
logger
|
||||
aws-sdk-kms (1.118.0)
|
||||
aws-sdk-core (~> 3, >= 3.239.1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.208.0)
|
||||
aws-sdk-core (~> 3, >= 3.234.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.12.1)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.3)
|
||||
base64 (0.3.0)
|
||||
bigdecimal (4.0.1)
|
||||
claide (1.0.3)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
@@ -113,9 +118,10 @@ GEM
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.6.1)
|
||||
jmespath (1.6.2)
|
||||
json (2.3.1)
|
||||
jwt (2.2.1)
|
||||
logger (1.7.0)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.10.1)
|
||||
mini_mime (1.0.2)
|
||||
|
||||
@@ -20,7 +20,6 @@ Features
|
||||
- Search for places
|
||||
- Advanced filtering options, including saved filter profiles
|
||||
- Favorites list, also with availability information
|
||||
- Integrated price comparison using [Chargeprice.app](https://chargeprice.app) (only in Europe)
|
||||
- Android Auto & Android Automotive OS integration
|
||||
- No ads, fully open source
|
||||
- Compatible with Android 5.0 and above
|
||||
@@ -90,9 +89,5 @@ information on the [Donate page](https://ev-map.app/donate/) on the EVMap websit
|
||||
Since May 2024, **JawgMaps** provides their OpenStreetMap vector map tiles service to EVMap for
|
||||
free, i.e. the background map displayed in the app if OpenStreetMap is selected as the data source.
|
||||
|
||||
<a href="https://chargeprice.app"><img src="https://raw.githubusercontent.com/ev-map/EVMap/master/_img/powered_by_chargeprice.svg" alt="Powered by Chargeprice" height="38"/></a><br>
|
||||
Since April 2021, **Chargeprice.app** provide their price comparison API at a greatly reduced
|
||||
price for EVMap. This data is used in EVMap's price comparison feature.
|
||||
|
||||
<a href="https://www.jetbrains.com/community/opensource/"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg" alt="JetBrains logo" height="38"/></a><br>
|
||||
As part of its support program for Open-source projects, **JetBrains** supports the development of EVMap since December 2023 with a license of their software suite.
|
||||
|
||||
@@ -8,4 +8,5 @@
|
||||
<string name="nobil_key" translatable="false">ci</string>
|
||||
<string name="fronyx_key" translatable="false">ci</string>
|
||||
<string name="acra_credentials" translatable="false">ci:ci</string>
|
||||
<string name="evmap_key" translatable="false">ci</string>
|
||||
</resources>
|
||||
|
||||
@@ -18,7 +18,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId = "net.vonforst.evmap"
|
||||
compileSdk = 36
|
||||
minSdk = 21
|
||||
minSdk = 23
|
||||
targetSdk = 36
|
||||
// NOTE: always increase versionCode by 2 since automotive flavor uses versionCode + 1
|
||||
versionCode = 268
|
||||
@@ -129,6 +129,17 @@ android {
|
||||
|
||||
// add API keys from environment variable if not set in apikeys.xml
|
||||
applicationVariants.all {
|
||||
var evmapKey =
|
||||
System.getenv("EVMAP_API_KEY") ?: project.findProperty("EVMAP_API_KEY")?.toString()
|
||||
if (evmapKey == null && project.hasProperty("EVMAP_API_KEY_ENCRYPTED")) {
|
||||
evmapKey = decode(
|
||||
project.findProperty("EVMAP_API_KEY_ENCRYPTED").toString(),
|
||||
"FmK.d,-f*p+rD+WK!eds"
|
||||
)
|
||||
}
|
||||
if (evmapKey != null) {
|
||||
resValue("string", "evmap_key", evmapKey)
|
||||
}
|
||||
val goingelectricKey =
|
||||
System.getenv("GOINGELECTRIC_API_KEY") ?: project.findProperty("GOINGELECTRIC_API_KEY")
|
||||
?.toString()
|
||||
@@ -287,7 +298,7 @@ dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion")
|
||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||
implementation("androidx.core:core-ktx:1.17.0")
|
||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||
implementation("androidx.core:core-splashscreen:1.2.0")
|
||||
implementation("androidx.activity:activity-ktx:1.11.0")
|
||||
implementation("androidx.fragment:fragment-ktx:1.8.9")
|
||||
implementation("androidx.cardview:cardview:1.0.0")
|
||||
@@ -358,13 +369,7 @@ dependencies {
|
||||
implementation("androidx.room:room-runtime:$roomVersion")
|
||||
ksp("androidx.room:room-compiler:$roomVersion")
|
||||
implementation("androidx.room:room-ktx:$roomVersion")
|
||||
implementation("com.github.anboralabs:spatia-room:0.3.0") {
|
||||
exclude("com.github.dalgarins", "android-spatialite")
|
||||
}
|
||||
// forked version with upgraded sqlite & libxml & 16 KB page size support
|
||||
// https://github.com/dalgarins/android-spatialite/pull/11
|
||||
// https://github.com/dalgarins/android-spatialite/pull/12
|
||||
implementation("io.github.ev-map:android-spatialite:2.2.1-alpha")
|
||||
implementation("com.github.anboralabs:spatia-room:1.0.1")
|
||||
|
||||
// billing library
|
||||
val billingVersion = "7.0.0"
|
||||
|
||||
938
app/schemas/net.vonforst.evmap.storage.AppDatabase/28.json
Normal file
938
app/schemas/net.vonforst.evmap.storage.AppDatabase/28.json
Normal file
@@ -0,0 +1,938 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 28,
|
||||
"identityHash": "84f71cce385c444726ba336834ddf6b4",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "ChargeLocation",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `dataSource` TEXT NOT NULL, `name` TEXT NOT NULL, `coordinates` BLOB NOT NULL, `chargepoints` TEXT NOT NULL, `network` TEXT, `dataSourceUrl` TEXT NOT NULL, `url` TEXT, `editUrl` TEXT, `verified` INTEGER NOT NULL, `barrierFree` INTEGER, `operator` TEXT, `generalInformation` TEXT, `amenities` TEXT, `locationDescription` TEXT, `photos` TEXT, `chargecards` TEXT, `accessibility` TEXT, `license` TEXT, `networkUrl` TEXT, `chargerUrl` TEXT, `timeRetrieved` INTEGER NOT NULL, `isDetailed` INTEGER NOT NULL, `coordinatesProjected` BLOB NOT NULL, `city` TEXT, `country` TEXT, `postcode` TEXT, `street` TEXT, `fault_report_created` INTEGER, `fault_report_description` TEXT, `twentyfourSeven` INTEGER, `description` TEXT, `mostart` TEXT, `moend` TEXT, `tustart` TEXT, `tuend` TEXT, `westart` TEXT, `weend` TEXT, `thstart` TEXT, `thend` TEXT, `frstart` TEXT, `frend` TEXT, `sastart` TEXT, `saend` TEXT, `sustart` TEXT, `suend` TEXT, `hostart` TEXT, `hoend` TEXT, `freecharging` INTEGER, `freeparking` INTEGER, `descriptionShort` TEXT, `descriptionLong` TEXT, `chargepricecountry` TEXT, `chargepricenetwork` TEXT, `chargepriceplugTypes` TEXT, PRIMARY KEY(`id`, `dataSource`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSource",
|
||||
"columnName": "dataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "coordinates",
|
||||
"columnName": "coordinates",
|
||||
"affinity": "BLOB",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargepoints",
|
||||
"columnName": "chargepoints",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "network",
|
||||
"columnName": "network",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSourceUrl",
|
||||
"columnName": "dataSourceUrl",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "editUrl",
|
||||
"columnName": "editUrl",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "verified",
|
||||
"columnName": "verified",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "barrierFree",
|
||||
"columnName": "barrierFree",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "operator",
|
||||
"columnName": "operator",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "generalInformation",
|
||||
"columnName": "generalInformation",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "amenities",
|
||||
"columnName": "amenities",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "locationDescription",
|
||||
"columnName": "locationDescription",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "photos",
|
||||
"columnName": "photos",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargecards",
|
||||
"columnName": "chargecards",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "accessibility",
|
||||
"columnName": "accessibility",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "license",
|
||||
"columnName": "license",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "networkUrl",
|
||||
"columnName": "networkUrl",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargerUrl",
|
||||
"columnName": "chargerUrl",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "timeRetrieved",
|
||||
"columnName": "timeRetrieved",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isDetailed",
|
||||
"columnName": "isDetailed",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "coordinatesProjected",
|
||||
"columnName": "coordinatesProjected",
|
||||
"affinity": "BLOB",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "address.city",
|
||||
"columnName": "city",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "address.country",
|
||||
"columnName": "country",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "address.postcode",
|
||||
"columnName": "postcode",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "address.street",
|
||||
"columnName": "street",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "faultReport.created",
|
||||
"columnName": "fault_report_created",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "faultReport.description",
|
||||
"columnName": "fault_report_description",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.twentyfourSeven",
|
||||
"columnName": "twentyfourSeven",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.description",
|
||||
"columnName": "description",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.monday.start",
|
||||
"columnName": "mostart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.monday.end",
|
||||
"columnName": "moend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.tuesday.start",
|
||||
"columnName": "tustart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.tuesday.end",
|
||||
"columnName": "tuend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.wednesday.start",
|
||||
"columnName": "westart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.wednesday.end",
|
||||
"columnName": "weend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.thursday.start",
|
||||
"columnName": "thstart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.thursday.end",
|
||||
"columnName": "thend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.friday.start",
|
||||
"columnName": "frstart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.friday.end",
|
||||
"columnName": "frend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.saturday.start",
|
||||
"columnName": "sastart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.saturday.end",
|
||||
"columnName": "saend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.sunday.start",
|
||||
"columnName": "sustart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.sunday.end",
|
||||
"columnName": "suend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.holiday.start",
|
||||
"columnName": "hostart",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "openinghours.days.holiday.end",
|
||||
"columnName": "hoend",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "cost.freecharging",
|
||||
"columnName": "freecharging",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "cost.freeparking",
|
||||
"columnName": "freeparking",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "cost.descriptionShort",
|
||||
"columnName": "descriptionShort",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "cost.descriptionLong",
|
||||
"columnName": "descriptionLong",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargepriceData.country",
|
||||
"columnName": "chargepricecountry",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargepriceData.network",
|
||||
"columnName": "chargepricenetwork",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargepriceData.plugTypes",
|
||||
"columnName": "chargepriceplugTypes",
|
||||
"affinity": "TEXT"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"dataSource"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "Favorite",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`favoriteId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `chargerId` INTEGER NOT NULL, `chargerDataSource` TEXT NOT NULL, FOREIGN KEY(`chargerId`, `chargerDataSource`) REFERENCES `ChargeLocation`(`id`, `dataSource`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "favoriteId",
|
||||
"columnName": "favoriteId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargerId",
|
||||
"columnName": "chargerId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargerDataSource",
|
||||
"columnName": "chargerDataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"favoriteId"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_Favorite_chargerId_chargerDataSource",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"chargerId",
|
||||
"chargerDataSource"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Favorite_chargerId_chargerDataSource` ON `${TABLE_NAME}` (`chargerId`, `chargerDataSource`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "ChargeLocation",
|
||||
"onDelete": "NO ACTION",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"chargerId",
|
||||
"chargerDataSource"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id",
|
||||
"dataSource"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "BooleanFilterValue",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `value` INTEGER NOT NULL, `dataSource` TEXT NOT NULL, `profile` INTEGER NOT NULL, PRIMARY KEY(`key`, `profile`, `dataSource`), FOREIGN KEY(`profile`, `dataSource`) REFERENCES `FilterProfile`(`id`, `dataSource`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "key",
|
||||
"columnName": "key",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "value",
|
||||
"columnName": "value",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSource",
|
||||
"columnName": "dataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "profile",
|
||||
"columnName": "profile",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"key",
|
||||
"profile",
|
||||
"dataSource"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_BooleanFilterValue_profile_dataSource",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"profile",
|
||||
"dataSource"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_BooleanFilterValue_profile_dataSource` ON `${TABLE_NAME}` (`profile`, `dataSource`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "FilterProfile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"profile",
|
||||
"dataSource"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id",
|
||||
"dataSource"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "MultipleChoiceFilterValue",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `values` TEXT NOT NULL, `all` INTEGER NOT NULL, `dataSource` TEXT NOT NULL, `profile` INTEGER NOT NULL, PRIMARY KEY(`key`, `profile`, `dataSource`), FOREIGN KEY(`profile`, `dataSource`) REFERENCES `FilterProfile`(`id`, `dataSource`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "key",
|
||||
"columnName": "key",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "values",
|
||||
"columnName": "values",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "all",
|
||||
"columnName": "all",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSource",
|
||||
"columnName": "dataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "profile",
|
||||
"columnName": "profile",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"key",
|
||||
"profile",
|
||||
"dataSource"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_MultipleChoiceFilterValue_profile_dataSource",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"profile",
|
||||
"dataSource"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_MultipleChoiceFilterValue_profile_dataSource` ON `${TABLE_NAME}` (`profile`, `dataSource`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "FilterProfile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"profile",
|
||||
"dataSource"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id",
|
||||
"dataSource"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "SliderFilterValue",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `value` INTEGER NOT NULL, `dataSource` TEXT NOT NULL, `profile` INTEGER NOT NULL, PRIMARY KEY(`key`, `profile`, `dataSource`), FOREIGN KEY(`profile`, `dataSource`) REFERENCES `FilterProfile`(`id`, `dataSource`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "key",
|
||||
"columnName": "key",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "value",
|
||||
"columnName": "value",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSource",
|
||||
"columnName": "dataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "profile",
|
||||
"columnName": "profile",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"key",
|
||||
"profile",
|
||||
"dataSource"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_SliderFilterValue_profile_dataSource",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"profile",
|
||||
"dataSource"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_SliderFilterValue_profile_dataSource` ON `${TABLE_NAME}` (`profile`, `dataSource`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "FilterProfile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"profile",
|
||||
"dataSource"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id",
|
||||
"dataSource"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "FilterProfile",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `dataSource` TEXT NOT NULL, `id` INTEGER NOT NULL, `order` INTEGER NOT NULL, PRIMARY KEY(`dataSource`, `id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSource",
|
||||
"columnName": "dataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "order",
|
||||
"columnName": "order",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"dataSource",
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_FilterProfile_dataSource_name",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"dataSource",
|
||||
"name"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_FilterProfile_dataSource_name` ON `${TABLE_NAME}` (`dataSource`, `name`)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "RecentAutocompletePlace",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `dataSource` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `primaryText` TEXT NOT NULL, `secondaryText` TEXT NOT NULL, `latLng` TEXT NOT NULL, `viewport` TEXT, `types` TEXT NOT NULL, PRIMARY KEY(`id`, `dataSource`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSource",
|
||||
"columnName": "dataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timestamp",
|
||||
"columnName": "timestamp",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "primaryText",
|
||||
"columnName": "primaryText",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "secondaryText",
|
||||
"columnName": "secondaryText",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "latLng",
|
||||
"columnName": "latLng",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "viewport",
|
||||
"columnName": "viewport",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "types",
|
||||
"columnName": "types",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"dataSource"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "GEPlug",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "GENetwork",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "GEChargeCard",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "OCMConnectionType",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `formalName` TEXT, `discontinued` INTEGER, `obsolete` INTEGER, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "formalName",
|
||||
"columnName": "formalName",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "discontinued",
|
||||
"columnName": "discontinued",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "obsolete",
|
||||
"columnName": "obsolete",
|
||||
"affinity": "INTEGER"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "OCMCountry",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `isoCode` TEXT NOT NULL, `continentCode` TEXT, `title` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isoCode",
|
||||
"columnName": "isoCode",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "continentCode",
|
||||
"columnName": "continentCode",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "OCMOperator",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `websiteUrl` TEXT, `title` TEXT NOT NULL, `contactEmail` TEXT, `contactTelephone1` TEXT, `contactTelephone2` TEXT, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "websiteUrl",
|
||||
"columnName": "websiteUrl",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "contactEmail",
|
||||
"columnName": "contactEmail",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "contactTelephone1",
|
||||
"columnName": "contactTelephone1",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "contactTelephone2",
|
||||
"columnName": "contactTelephone2",
|
||||
"affinity": "TEXT"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "OSMNetwork",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "SavedRegion",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`region` BLOB NOT NULL, `dataSource` TEXT NOT NULL, `timeRetrieved` INTEGER NOT NULL, `filters` TEXT, `isDetailed` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "region",
|
||||
"columnName": "region",
|
||||
"affinity": "BLOB",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dataSource",
|
||||
"columnName": "dataSource",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timeRetrieved",
|
||||
"columnName": "timeRetrieved",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "filters",
|
||||
"columnName": "filters",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "isDetailed",
|
||||
"columnName": "isDetailed",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_SavedRegion_filters_dataSource",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"filters",
|
||||
"dataSource"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_SavedRegion_filters_dataSource` ON `${TABLE_NAME}` (`filters`, `dataSource`)"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '84f71cce385c444726ba336834ddf6b4')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -175,6 +175,7 @@ class AvailabilityRepository(context: Context) {
|
||||
RheinenergieAvailabilityDetector(okhttp),
|
||||
teslaOwnerAvailabilityDetector,
|
||||
TeslaGuestAvailabilityDetector(okhttp),
|
||||
NobilAvailabilityDetector(okhttp, context),
|
||||
EnBwAvailabilityDetector(okhttp),
|
||||
NewMotionAvailabilityDetector(okhttp)
|
||||
)
|
||||
|
||||
@@ -61,8 +61,9 @@ interface NewMotionApi {
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NMElectricalProperties(val powerType: String, val voltage: Int, val amperage: Int) {
|
||||
data class NMElectricalProperties(val powerType: String, val voltage: Int, val amperage: Int, val maxElectricPower: Double?) {
|
||||
fun getPower(): Double {
|
||||
maxElectricPower?.let { return it }
|
||||
val phases = when (powerType) {
|
||||
"AC1Phase" -> 1
|
||||
"AC3Phase" -> 3
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package net.vonforst.evmap.api.availability
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.FromJson
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.ToJson
|
||||
import net.vonforst.evmap.R
|
||||
import net.vonforst.evmap.model.ChargeLocation
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Path
|
||||
import java.time.Instant
|
||||
|
||||
internal class InstantStringAdapter {
|
||||
@FromJson
|
||||
fun fromJson(value: String?): Instant? = value?.let {
|
||||
Instant.parse(value)
|
||||
}
|
||||
|
||||
@ToJson
|
||||
fun toJson(value: Instant?): String? = value?.toString()
|
||||
}
|
||||
|
||||
interface NobilRealtimeApi {
|
||||
@GET("{nobilId}")
|
||||
suspend fun getAvailability(
|
||||
@Path("nobilId") nobilId: String,
|
||||
@Header("X-Api-Key") apiKey: String
|
||||
): List<NobilChargepointState>
|
||||
|
||||
companion object {
|
||||
fun create(client: OkHttpClient): NobilRealtimeApi {
|
||||
val retrofit = Retrofit.Builder()
|
||||
.baseUrl("https://api.ev-map.app/nobil/api/realtime/")
|
||||
.addConverterFactory(
|
||||
MoshiConverterFactory.create(
|
||||
Moshi.Builder().add(InstantStringAdapter()).build()
|
||||
)
|
||||
)
|
||||
.client(client)
|
||||
.build()
|
||||
return retrofit.create(NobilRealtimeApi::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NobilChargepointState(
|
||||
val evseUid: String,
|
||||
val status: String,
|
||||
val timestamp: Instant
|
||||
)
|
||||
|
||||
class NobilAvailabilityDetector(client: OkHttpClient, context: Context) :
|
||||
BaseAvailabilityDetector(client) {
|
||||
val api = NobilRealtimeApi.create(client)
|
||||
val apiKey = context.getString(R.string.evmap_key)
|
||||
|
||||
override suspend fun getAvailability(location: ChargeLocation): ChargeLocationStatus {
|
||||
val nobilId = when (location.address?.country) {
|
||||
"Norway" -> "NOR"
|
||||
"Sweden" -> "SWE"
|
||||
else -> throw AvailabilityDetectorException("nobil: unsupported country")
|
||||
} + "_%05d".format(location.id)
|
||||
|
||||
val availability = api.getAvailability(nobilId, apiKey)
|
||||
if (availability.isEmpty()) {
|
||||
throw AvailabilityDetectorException("nobil: no real-time data available")
|
||||
}
|
||||
return ChargeLocationStatus(
|
||||
location.chargepointsMerged.associateWith { cp ->
|
||||
cp.evseUIds!!.map { evseUId ->
|
||||
when (availability.find { it.evseUid == evseUId }?.status) {
|
||||
"AVAILABLE" -> ChargepointStatus.AVAILABLE
|
||||
"BLOCKED" -> ChargepointStatus.OCCUPIED
|
||||
"CHARGING" -> ChargepointStatus.CHARGING
|
||||
"INOPERATIVE" -> ChargepointStatus.FAULTED
|
||||
"OUTOFORDER" -> ChargepointStatus.FAULTED
|
||||
"PLANNED" -> ChargepointStatus.FAULTED
|
||||
"REMOVED" -> ChargepointStatus.FAULTED
|
||||
"RESERVED" -> ChargepointStatus.OCCUPIED
|
||||
"UNKNOWN" -> ChargepointStatus.UNKNOWN
|
||||
else -> ChargepointStatus.UNKNOWN
|
||||
}
|
||||
}
|
||||
},
|
||||
"Nobil",
|
||||
location.chargepointsMerged.associateWith { cp ->
|
||||
if (cp.evseIds != null) cp.evseIds.map { it ?: "??" } else listOf()
|
||||
},
|
||||
lastChange = location.chargepointsMerged.associateWith { cp ->
|
||||
cp.evseUIds!!.map { evseUId ->
|
||||
availability.find { it.evseUid == evseUId }?.timestamp
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun isChargerSupported(charger: ChargeLocation): Boolean {
|
||||
return when (charger.dataSource) {
|
||||
"nobil" -> charger.chargepoints.any { it.evseUIds?.isNotEmpty() == true }
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,9 +279,10 @@ data class NobilChargerStation(
|
||||
|
||||
val connectionVoltage = if (attribs["12"]?.attrVal is String) attribs["12"]?.attrVal.toString().toDoubleOrNull() else null
|
||||
val connectionCurrent = if (attribs["31"]?.attrVal is String) attribs["31"]?.attrVal.toString().toDoubleOrNull() else null
|
||||
val evseUId = if (attribs["27"]?.attrVal is String) listOf(attribs["27"]?.attrVal.toString()) else null
|
||||
val evseId = if (attribs["28"]?.attrVal is String) listOf(attribs["28"]?.attrVal.toString()) else null
|
||||
|
||||
return Chargepoint(connectionType, connectionPower, 1, connectionCurrent, connectionVoltage, evseId)
|
||||
return Chargepoint(connectionType, connectionPower, 1, connectionCurrent, connectionVoltage, evseId, evseUId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,9 +143,9 @@ class SettingsScreen(ctx: CarContext, val session: EVMapSession) : Screen(ctx),
|
||||
).setTint(CarColor.DEFAULT).build()
|
||||
)
|
||||
.setBrowsable(true)
|
||||
.setOnClickListener {
|
||||
.setOnClickListener(ParkedOnlyOnClickListener.create {
|
||||
screenManager.push(AboutScreen(carContext, session))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
)
|
||||
}.build())
|
||||
|
||||
@@ -140,10 +140,12 @@ data class ChargeLocation(
|
||||
.filter { it.type == variant.type && it.power == variant.power }
|
||||
val count = filtered.sumOf { it.count }
|
||||
val mergedEvseIds = filtered.map { if (it.evseIds == null) List(it.count) {null} else it.evseIds }.flatten()
|
||||
val mergedEvseUIds = filtered.map { if (it.evseUIds == null) List(it.count) {null} else it.evseUIds }.flatten()
|
||||
Chargepoint(variant.type, variant.power, count,
|
||||
filtered.map { it.current }.distinct().singleOrNull(),
|
||||
filtered.map { it.voltage }.distinct().singleOrNull(),
|
||||
if (mergedEvseIds.all { it == null }) null else mergedEvseIds
|
||||
if (mergedEvseIds.all { it == null }) null else mergedEvseIds,
|
||||
if (mergedEvseUIds.all { it == null }) null else mergedEvseUIds
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -425,7 +427,9 @@ data class Chargepoint(
|
||||
// (each of the three can be separately limited)
|
||||
val voltage: Double? = null,
|
||||
// Electric Vehicle Supply Equipment Ids for this Chargepoint's plugs/sockets
|
||||
val evseIds: List<String?>? = null
|
||||
val evseIds: List<String?>? = null,
|
||||
// Electric Vehicle Supply Equipment Unique Ids for this Chargepoint's plugs/sockets
|
||||
val evseUIds: List<String?>? = null
|
||||
) : Equatable, Parcelable {
|
||||
fun hasKnownPower(): Boolean = power != null
|
||||
fun hasKnownVoltageAndCurrent(): Boolean = voltage != null && current != null
|
||||
|
||||
@@ -25,4 +25,4 @@ data class Favorite(
|
||||
data class FavoriteWithDetail(
|
||||
@Embedded val favorite: Favorite,
|
||||
@Embedded val charger: ChargeLocation
|
||||
)
|
||||
)
|
||||
@@ -37,6 +37,7 @@ class CustomNavigator(
|
||||
"goingelectric" -> "https://www.goingelectric.de/stromtankstellen/new/"
|
||||
"nobil" -> "http://nobil.no/api/chargerregistration/chargerregistration.php?action=register"
|
||||
"openchargemap" -> "https://openchargemap.org/site/poi/add"
|
||||
"openstreetmap" -> "https://www.openstreetmap.org/edit"
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
launchCustomTab(url)
|
||||
|
||||
@@ -15,7 +15,7 @@ class CleanupCacheWorker(appContext: Context, workerParams: WorkerParameters) :
|
||||
val savedRegionDao = db.savedRegionDao()
|
||||
val now = Instant.now()
|
||||
|
||||
val dataSources = listOf("openchargemap", "openstreetmap", "goingelectric")
|
||||
val dataSources = listOf("openchargemap", "openstreetmap", "goingelectric", "nobil")
|
||||
for (dataSource in dataSources) {
|
||||
val api = createApi(dataSource, applicationContext)
|
||||
val limit = now.minus(api.cacheLimit).toEpochMilli()
|
||||
|
||||
@@ -40,7 +40,7 @@ import net.vonforst.evmap.model.SliderFilterValue
|
||||
OCMOperator::class,
|
||||
OSMNetwork::class,
|
||||
SavedRegion::class
|
||||
], version = 27
|
||||
], version = 28
|
||||
)
|
||||
@TypeConverters(Converters::class, GeometryConverters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
@@ -85,7 +85,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
MIGRATION_12, MIGRATION_13, MIGRATION_14, MIGRATION_15, MIGRATION_16,
|
||||
MIGRATION_17, MIGRATION_18, MIGRATION_19, MIGRATION_20, MIGRATION_21,
|
||||
MIGRATION_22, MIGRATION_23, MIGRATION_24, MIGRATION_25, MIGRATION_26,
|
||||
MIGRATION_27
|
||||
MIGRATION_27, MIGRATION_28
|
||||
)
|
||||
.addCallback(object : Callback() {
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
@@ -547,6 +547,14 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
db.execSQL("ALTER TABLE `ChargeLocation` ADD `accessibility` TEXT")
|
||||
}
|
||||
}
|
||||
|
||||
private val MIGRATION_28 = object : Migration(27, 28) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
// Force nobil data refresh to fetch EVSE UId attributes needed for real-time data
|
||||
db.execSQL("DELETE FROM SavedRegion WHERE `dataSource` = 'nobil'")
|
||||
db.execSQL("DELETE FROM ChargeLocation WHERE `dataSource` = 'nobil'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,10 +13,10 @@ interface FavoritesDao {
|
||||
@Delete
|
||||
suspend fun delete(vararg favorites: Favorite)
|
||||
|
||||
@Query("SELECT * FROM favorite LEFT JOIN chargelocation ON favorite.chargerDataSource = chargelocation.dataSource AND favorite.chargerId = chargelocation.id")
|
||||
@Query("SELECT * FROM favorite LEFT JOIN chargelocation ON favorite.chargerDataSource = chargelocation.dataSource AND favorite.chargerId = chargelocation.id WHERE chargelocation.id is not NULL")
|
||||
fun getAllFavorites(): LiveData<List<FavoriteWithDetail>>
|
||||
|
||||
@Query("SELECT * FROM favorite LEFT JOIN chargelocation ON favorite.chargerDataSource = chargelocation.dataSource AND favorite.chargerId = chargelocation.id")
|
||||
@Query("SELECT * FROM favorite LEFT JOIN chargelocation ON favorite.chargerDataSource = chargelocation.dataSource AND favorite.chargerId = chargelocation.id WHERE chargelocation.id is not NULL")
|
||||
suspend fun getAllFavoritesAsync(): List<FavoriteWithDetail>
|
||||
|
||||
@SkipQueryVerification
|
||||
|
||||
@@ -392,4 +392,5 @@
|
||||
<string name="accessibility_residents">Obyvatelé</string>
|
||||
<string name="chargeprice_removal_2025_dialog_title">Omlouváme se!</string>
|
||||
<string name="chargeprice_removal_2025_dialog_detail">Náklady na přístup k údajům ze služby Chargeprice prudce vzrostly a nelze je pokrýt z darů, takže EVMap již nemůže tyto údaje přímo zobrazovat. Prozatím se otevře webová stránka Chargeprice. Alternativní řešení se vyvíjí, ale bude to nějakou dobu trvat a zpočátku bude mít omezené funkce. Děkujeme za trpělivost a podporu!</string>
|
||||
<string name="auto_use_new_map_screen">Nová obrazovka mapy (beta)</string>
|
||||
</resources>
|
||||
|
||||
@@ -380,7 +380,7 @@
|
||||
<string name="pref_chargeprice_native_integration_on">Preise werden direkt in EVMap angezeigt</string>
|
||||
<string name="pref_chargeprice_native_integration_off">Preisvergleich verlinkt auf die App oder Website von Chargeprice</string>
|
||||
<string name="auto_zoom_for_details">Für Details hineinzoomen</string>
|
||||
<string name="plug_type_2_tethered">Typ 2 Kabel mit Stecker</string>
|
||||
<string name="plug_type_2_tethered">Typ-2-Kabel mit Stecker</string>
|
||||
<string name="accessibility_public">Öffentlich</string>
|
||||
<string name="accessibility_visitors">Besucher</string>
|
||||
<string name="accessibility_employees">Mitarbeiter</string>
|
||||
|
||||
@@ -388,4 +388,5 @@
|
||||
<string name="accessibility_residents">Elanikele</string>
|
||||
<string name="chargeprice_removal_2025_dialog_title">Vabandust!</string>
|
||||
<string name="chargeprice_removal_2025_dialog_detail">Chargeprice\'i andmete maksumus on 2025. aastast järsult kasvanud ja rahalistest toetustest meile pole võimalik seda enam rahastada. Seega EVMap ei saa neid andmeid enam otse näidata. Asendusena on esialgu kasutusel link Chargeprice\'i veebisaiti. Oleme arendamas ka alternatiivset lahendust, aga selleks kulub aega ning ta võib kasutusele tulla piiratud funktsionaalsuses. Suur tänu teie toe eest!</string>
|
||||
<string name="auto_use_new_map_screen">Uus kaardivaade (beetaversioon)</string>
|
||||
</resources>
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<string name="operator">Opérateur</string>
|
||||
<string name="network">Réseau</string>
|
||||
<string name="hours">Heures d\'ouverture</string>
|
||||
<string name="open_247"><b>Ouvert 24h/24 et 7j/7</b></string>
|
||||
<string name="open_closesat"><b>Ouvert</b> · Ferme à %s</string>
|
||||
<string name="open_247"><![CDATA[<b>Ouvert 24h/24 et 7j/7</b>]]></string>
|
||||
<string name="open_closesat"><![CDATA[<b>Ouvert</b> · Ferme à %s]]></string>
|
||||
<string name="closed_unfmt">Fermé</string>
|
||||
<string name="cost">Coût</string>
|
||||
<string name="closed"><b>Fermé</b></string>
|
||||
<string name="closed_opensat"><b>Fermé</b> · Ouvre à %s</string>
|
||||
<string name="closed"><![CDATA[<b>Fermé</b>]]></string>
|
||||
<string name="closed_opensat"><![CDATA[<b>Fermé</b> · Ouvre à %s]]></string>
|
||||
<string name="holiday">Jour férié</string>
|
||||
<string name="cost_detail"><b>Recharge :</b> %1$s · <b>Stationnement :</b> %2$s</string>
|
||||
<string name="cost_detail"><![CDATA[<b>Recharge :</b> %1$s · <b>Stationnement :</b> %2$s]]></string>
|
||||
<string name="realtime_data_unavailable">Statut en temps réel non disponible</string>
|
||||
<string name="source">Source : %s</string>
|
||||
<string name="menu_favs">Favoris</string>
|
||||
@@ -235,17 +235,17 @@
|
||||
<string name="crash_report_text">EVMap a planté. Veuillez envoyer un rapport de plantage au développeur.</string>
|
||||
<string name="unknown_operator">Opérateur inconnu</string>
|
||||
<string name="data_source_goingelectric_desc">Idéal dans les pays germanophones. Descriptions en allemand. Maintenu par la communauté.</string>
|
||||
<string name="data_source_openchargemap_desc">Couverture mondiale avec une qualité variable. Descriptions en anglais ou dans la langue locale. Données ouvertes maintenues par la communauté et provenant de sources gouvernementales dans certains pays (par exemple, Amérique du Nord, Royaume-Uni, France, Norvège).</string>
|
||||
<string name="data_source_openchargemap_desc"><![CDATA[Couverture mondiale avec une qualité variable. Descriptions en anglais ou dans la langue locale. Données ouvertes maintenues par la communauté et provenant de sources gouvernementales dans certains pays (par exemple, Amérique du Nord, Royaume-Uni, France, Norvège).]]></string>
|
||||
<string name="faq_link">https://ev-map.app/faq/</string>
|
||||
<string name="chargeprice_faq_link">https://ev-map.app/faq/#price-comparison-feature</string>
|
||||
<string name="settings_data_sources">Sources de données</string>
|
||||
<string name="data_sources_description">Veuillez choisir une source de données pour les stations de recharge. Vous pourrez la modifier ultérieurement dans les paramètres de l\'application.</string>
|
||||
<string name="pref_search_provider_info">Les données pour la recherche de lieux, en particulier celles de Google Maps, sont relativement coûteuses à récupérer. Veuillez envisager de faire un don via \"À propos\" → \"Faire un don\".</string>
|
||||
<string name="pref_search_provider_info"><![CDATA[Les données pour la recherche de lieux, en particulier celles de Google Maps, sont relativement coûteuses à récupérer. Veuillez envisager de faire un don via "À propos" → "Faire un don".]]></string>
|
||||
<string name="help">Aide</string>
|
||||
<string name="pref_chargeprice_allow_unbalanced_load_summary">Autoriser la charge en courant alternatif monophasé de plus de 4,5 kW</string>
|
||||
<string name="pref_map_rotate_gestures_on">Utilisez deux doigts pour faire pivoter la carte</string>
|
||||
<string name="cost_detail_charging"><b>Recharge %s</b></string>
|
||||
<string name="cost_detail_parking"><b>Stationnement %s</b></string>
|
||||
<string name="cost_detail_charging"><![CDATA[<b>Recharge %s</b>]]></string>
|
||||
<string name="cost_detail_parking"><![CDATA[<b>Stationnement %s</b>]]></string>
|
||||
<string name="navigate">Naviguer vers</string>
|
||||
<string name="charge_price_format">%1$.2f %2$s</string>
|
||||
<string name="charge_price_average_format">⌀ %1$.2f %2$s/kWh</string>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<resources>
|
||||
<string name="app_name">EVMap</string>
|
||||
<string name="no_maps_app_found">Installer et navigeringsprogram først</string>
|
||||
<string name="closed"><b>Stengt</b></string>
|
||||
<string name="open_closesat"><b>Åpen</b> · Stenger %s</string>
|
||||
<string name="closed"><![CDATA[<b>Stengt</b>]]></string>
|
||||
<string name="open_closesat"><![CDATA[<b>Åpen</b> · Stenger %s]]></string>
|
||||
<string name="holiday">Ferie</string>
|
||||
<string name="cost">Kostnad</string>
|
||||
<string name="general_info">Generell info</string>
|
||||
@@ -40,18 +40,18 @@
|
||||
<string name="edit_filter_profile">Rediger «%s»</string>
|
||||
<string name="help">Hjelp</string>
|
||||
<string name="hours">Åpningstider</string>
|
||||
<string name="open_247"><b>Døgnåpen</b></string>
|
||||
<string name="open_247"><![CDATA[<b>Døgnåpen</b>]]></string>
|
||||
<string name="settings_ui">Grensesnitt</string>
|
||||
<string name="title_activity_maps">EVMap</string>
|
||||
<string name="no_browser_app_found">Installer en nettleser først</string>
|
||||
<string name="address">Adresse</string>
|
||||
<string name="network">Nettverk</string>
|
||||
<string name="closed_unfmt">Stengt</string>
|
||||
<string name="cost_detail_charging"><b>%s-lading</b></string>
|
||||
<string name="cost_detail_parking"><b>%s-parkering</b></string>
|
||||
<string name="cost_detail_charging"><![CDATA[<b>%s-lading</b>]]></string>
|
||||
<string name="cost_detail_parking"><![CDATA[<b>%s-parkering</b>]]></string>
|
||||
<string name="menu_map">Kart</string>
|
||||
<string name="category_petrol_station">Bensinstasjon</string>
|
||||
<string name="closed_opensat"><b>Stengt</b> · Åpner %s</string>
|
||||
<string name="closed_opensat"><![CDATA[<b>Stengt</b> · Åpner %s]]></string>
|
||||
<string name="retry">Prøv igjen</string>
|
||||
<string name="source">Kilde: %s</string>
|
||||
<string name="menu_favs">Favoritter</string>
|
||||
@@ -88,7 +88,7 @@
|
||||
<string name="realtime_data_source">Kilde for sanntidsstatus (beta): %s</string>
|
||||
<string name="realtime_data_unavailable">Sanntidsstatus utilgjengelig</string>
|
||||
<string name="other">Andre</string>
|
||||
<string name="cost_detail"><b>Lading:</b> %1$s · <b>Parkering:</b> %2$s</string>
|
||||
<string name="cost_detail"><![CDATA[<b>Lading:</b> %1$s · <b>Parkering:</b> %2$s]]></string>
|
||||
<string name="pref_navigate_use_maps_on">Navigasjonsnkappen starter ruteveiledning på Google Maps</string>
|
||||
<string name="filter_free_parking">Kun ladere med gratis parkering</string>
|
||||
<string name="filter_min_power">Min. effekt</string>
|
||||
@@ -239,8 +239,8 @@
|
||||
</plurals>
|
||||
<string name="data_source_goingelectric_desc">Storartet i tyskspråklige land. Beskrivelser på tysk. Gemenskapsdrevet.</string>
|
||||
<string name="powered_by_mapbox">tilbudt av Mapbox</string>
|
||||
<string name="pref_search_provider_info">Data for søk er dyre å hente, spesielt fra Google Maps. Overvei å donere gjennom «Om» → «Doner».</string>
|
||||
<string name="data_source_openchargemap_desc">Verdensomspennende, med varierende kvalitet. Beskrivelser på engelsk eller det lokale språket. Gemenskapsdrevet og åpen myndighetsdata i noen land (f.eks. Nord-Amerika, Storbritannia, Frankrike, og Norge.)</string>
|
||||
<string name="pref_search_provider_info"><![CDATA[Data for søk er dyre å hente, spesielt fra Google Maps. Overvei å donere gjennom «Om» → «Doner».]]></string>
|
||||
<string name="data_source_openchargemap_desc"><![CDATA[Verdensomspennende, med varierende kvalitet. Beskrivelser på engelsk eller det lokale språket. Gemenskapsdrevet og åpen myndighetsdata i noen land (f.eks. Nord-Amerika, Storbritannia, Frankrike, og Norge.)]]></string>
|
||||
<string name="lets_go">Begynn</string>
|
||||
<string name="crash_report_text">EVMap krasjet. Send en rapport til utvikleren.</string>
|
||||
<string name="chargeprice_all_tariffs_selected">alle planer valgt</string>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<resources>
|
||||
<string name="data_source_goingelectric_desc">Ideaal in Duitstalige landen. Beschrijvingen in het Duits. Onderhouden door de gebruikersgemeenschap.</string>
|
||||
<string name="crash_report_text">EVMap is afgebroken. Stuur een crash rapport naar de ontwikkelaar.</string>
|
||||
<string name="pref_search_provider_info">Gegevens opzoeken is duur, vooral via Google Maps. Overweeg aub om een donatie te doen via “Over” → “Doneer”.</string>
|
||||
<string name="data_source_openchargemap_desc">Werelddekkend, met variabele kwaliteit. Beschrijving in Engels of lokale taal. Onderhouden door de gebruikers. Ook open overheidswege eens in sommige landen (bv. Noord-Amerika, UK, Frankrijk, Noorwegen).</string>
|
||||
<string name="pref_search_provider_info"><![CDATA[Gegevens opzoeken is duur, vooral via Google Maps. Overweeg aub om een donatie te doen via “Over” → “Doneer”.]]></string>
|
||||
<string name="data_source_openchargemap_desc"><![CDATA[Werelddekkend, met variabele kwaliteit. Beschrijving in Engels of lokale taal. Onderhouden door de gebruikers. Ook open overheidswege eens in sommige landen (bv. Noord-Amerika, UK, Frankrijk, Noorwegen).]]></string>
|
||||
<string name="pref_darkmode_always_off">altijd uit</string>
|
||||
<string name="chargeprice_select_car_first">Kiest eerst je voertuig model in de instellingen</string>
|
||||
<string name="chargeprice_no_compatible_connectors">Geen compatibele connectoren aan dit laadstation</string>
|
||||
@@ -22,16 +22,16 @@
|
||||
<string name="address">Adres</string>
|
||||
<string name="operator">Operator</string>
|
||||
<string name="network">Netwerk</string>
|
||||
<string name="open_247"><b>24/7 open</b></string>
|
||||
<string name="closed"><b>Gesloten</b></string>
|
||||
<string name="open_closesat"><b>Open</b> · Sluit om %s</string>
|
||||
<string name="closed_opensat"><b>Gesloten</b> · Opent om %s</string>
|
||||
<string name="open_247"><![CDATA[<b>24/7 open</b>]]></string>
|
||||
<string name="closed"><![CDATA[<b>Gesloten</b>]]></string>
|
||||
<string name="open_closesat"><![CDATA[<b>Open</b> · Sluit om %s]]></string>
|
||||
<string name="closed_opensat"><![CDATA[<b>Gesloten</b> · Opent om %s]]></string>
|
||||
<string name="closed_unfmt">Gesloten</string>
|
||||
<string name="holiday">Feestdag</string>
|
||||
<string name="cost">Kostprijs</string>
|
||||
<string name="cost_detail"><b>Laden:</b> %1$s · <b>Parkeren:</b> %2$s</string>
|
||||
<string name="cost_detail_charging"><b>%s laden</b></string>
|
||||
<string name="cost_detail_parking"><b>%s parkeren</b></string>
|
||||
<string name="cost_detail"><![CDATA[<b>Laden:</b> %1$s · <b>Parkeren:</b> %2$s]]></string>
|
||||
<string name="cost_detail_charging"><![CDATA[<b>%s laden</b>]]></string>
|
||||
<string name="cost_detail_parking"><![CDATA[<b>%s parkeren</b>]]></string>
|
||||
<string name="charging_free">Gratis</string>
|
||||
<string name="parking_free">Gratis</string>
|
||||
<string name="amenities">Voorzieningen</string>
|
||||
|
||||
@@ -387,4 +387,6 @@
|
||||
<string name="accessibility_residents">Boende</string>
|
||||
<string name="chargeprice_removal_2025_dialog_detail">Kostnaderna för Chargeprice-data har stigit kraftigt och täcks inte av längre av donationer. Därför kan inte EVMap längre visa denna data direkt i appen. Tillsvidare öppnar detta Chargeprices webbsida. En alternativ lösning är under utveckling, men kommer dröja något och kan introduceras med begränsad funktionalitet. Tack för ditt tålamod och stöd!</string>
|
||||
<string name="chargeprice_removal_2025_dialog_title">Ursäkta!</string>
|
||||
<string name="auto_use_new_map_screen">Ny kartvy (beta)</string>
|
||||
<string name="welcome_2_title">Full koll på hastigheten</string>
|
||||
</resources>
|
||||
|
||||
@@ -38,6 +38,9 @@ be put into the app in the form of a resource file called `apikeys.xml` under
|
||||
<string name="nobil_key" translatable="false">
|
||||
insert your nobil key here
|
||||
</string>
|
||||
<string name="evmap_key" translatable="false">
|
||||
insert your EVMap key here
|
||||
</string>
|
||||
</resources>
|
||||
```
|
||||
|
||||
@@ -236,6 +239,13 @@ key and documentation.
|
||||
If you don't want to test this functionality, simply leave the API key blank.
|
||||
</details>
|
||||
|
||||
### EVMap
|
||||
|
||||
EVMap provides APIs to fetch Nobil real-time data.
|
||||
|
||||
Contact [EVMap](mailto:evmap@vonforst.net) to get an API key.
|
||||
|
||||
|
||||
Crash reporting
|
||||
---------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user