App: prepare for embedding in native app (#12490)

This commit is contained in:
Michael Geers 2024-02-26 17:39:28 +01:00 • committed by GitHub
parent d8eb167333
commit 45ac7c81d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 100 additions and 21 deletions

View file

@ -384,6 +384,10 @@ small {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>"); background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>");
} }
.dark .text-muted {
color: var(--bs-gray-medium) !important;
}
.dark .form-select:disabled { .dark .form-select:disabled {
opacity: 0.5; opacity: 0.5;
} }
@ -474,3 +478,17 @@ input[type="time"]::-webkit-calendar-picker-indicator {
width: 50% !important; width: 50% !important;
} }
} }
html.app .hide-in-app {
display: none !important;
}
.safe-area-inset {
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom)
env(safe-area-inset-left);
}
.modal-dialog {
margin-top: max(var(--bs-modal-margin), env(safe-area-inset-top));
margin-bottom: max(var(--bs-modal-margin), env(safe-area-inset-bottom));
}

View file

@ -8,6 +8,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="default" /> <meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="evcc" /> <meta name="apple-mobile-web-app-title" content="evcc" />
<meta name="application-name" content="evcc" /> <meta name="application-name" content="evcc" />
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover" />
<link rel="apple-touch-icon" sizes="180x180" href="meta/apple-touch-icon.png?[[.Version]]" /> <link rel="apple-touch-icon" sizes="180x180" href="meta/apple-touch-icon.png?[[.Version]]" />
<link rel="icon" type="image/png" sizes="32x32" href="meta/favicon-32x32.png?[[.Version]]" /> <link rel="icon" type="image/png" sizes="32x32" href="meta/favicon-32x32.png?[[.Version]]" />
@ -18,6 +19,7 @@
<meta name="msapplication-TileColor" content="#1C2445" /> <meta name="msapplication-TileColor" content="#1C2445" />
<meta name="msapplication-config" content="meta/browserconfig.xml?[[.Version]]" /> <meta name="msapplication-config" content="meta/browserconfig.xml?[[.Version]]" />
<meta name="theme-color" content="#020318" /> <meta name="theme-color" content="#020318" />
<meta name="evcc-app-compatible" content="true" />
<title>evcc</title> <title>evcc</title>
</head> </head>

View file

@ -7,6 +7,7 @@ import setupRouter from "./router";
import setupI18n from "./i18n"; import setupI18n from "./i18n";
import featureflags from "./featureflags"; import featureflags from "./featureflags";
import { watchThemeChanges } from "./theme"; import { watchThemeChanges } from "./theme";
import { appDetection, sendToApp } from "./utils/native";
// lazy load smoothscroll polyfill. mainly for safari < 15.4 // lazy load smoothscroll polyfill. mainly for safari < 15.4
if (!window.CSS.supports("scroll-behavior", "smooth")) { if (!window.CSS.supports("scroll-behavior", "smooth")) {
@ -23,6 +24,7 @@ const app = createApp({
watch: { watch: {
offline: function (value) { offline: function (value) {
console.log(`we are ${value ? "offline" : "online"}`); console.log(`we are ${value ? "offline" : "online"}`);
sendToApp({ type: value ? "offline" : "online" });
}, },
}, },
methods: { methods: {
@ -70,3 +72,4 @@ app.mixin(VueHeadMixin);
window.app = app.mount("#app"); window.app = app.mount("#app");
watchThemeChanges(); watchThemeChanges();
appDetection();

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="d-flex flex-column site"> <div class="d-flex flex-column site safe-area-inset">
<div class="container px-4 top-area"> <div class="container px-4 top-area">
<div class="d-flex justify-content-between align-items-center my-3"> <div class="d-flex justify-content-between align-items-center my-3">
<h1 class="d-block my-0"> <h1 class="d-block my-0">

View file

@ -51,16 +51,6 @@
{{ $t("batterySettings.modalTitle") }} {{ $t("batterySettings.modalTitle") }}
</button> </button>
</li> </li>
<li v-if="gridModalAvailable">
<button
type="button"
class="dropdown-item"
data-testid="topnavigation-grid"
@click="openGridSettingsModal"
>
{{ $t("gridSettings.modalTitle") }}
</button>
</li>
<li v-if="$hiddenFeatures()"> <li v-if="$hiddenFeatures()">
<router-link class="dropdown-item" to="/config"> <router-link class="dropdown-item" to="/config">
Device Configuration 🧪 Device Configuration 🧪
@ -101,6 +91,11 @@
></shopicon-regular-newtab> ></shopicon-regular-newtab>
</a> </a>
</li> </li>
<li v-if="isApp">
<button type="button" class="dropdown-item" @click="openNativeSettings">
{{ $t("header.nativeSettings") }}
</button>
</li>
</ul> </ul>
</div> </div>
</template> </template>
@ -115,6 +110,7 @@ import "@h2d2/shopicons/es/regular/newtab";
import collector from "../mixins/collector"; import collector from "../mixins/collector";
import baseAPI from "../baseapi"; import baseAPI from "../baseapi";
import { isApp, sendToApp } from "../utils/native";
export default { export default {
name: "TopNavigation", name: "TopNavigation",
@ -130,6 +126,11 @@ export default {
sponsorTokenExpires: Number, sponsorTokenExpires: Number,
batteryConfigured: Boolean, batteryConfigured: Boolean,
}, },
data() {
return {
isApp: isApp(),
};
},
computed: { computed: {
logoutCount() { logoutCount() {
return this.providerLogins.filter((login) => !login.loggedIn).length; return this.providerLogins.filter((login) => !login.loggedIn).length;
@ -186,6 +187,9 @@ export default {
); );
modal.show(); modal.show();
}, },
openNativeSettings() {
sendToApp({ type: "settings" });
},
}, },
}; };
</script> </script>

14
assets/js/utils/native.js Normal file
View file

@ -0,0 +1,14 @@
export function isApp() {
return navigator.userAgent.includes("evcc/");
}
export function appDetection() {
if (isApp()) {
const $html = document.querySelector("html");
$html.classList.add("app");
}
}
export function sendToApp(data) {
window.ReactNativeWebView?.postMessage(JSON.stringify(data));
}

View file

@ -1,9 +1,11 @@
<template> <template>
<div class="container px-4"> <div class="container px-4 safe-area-inset">
<TopHeader :title="$t('sessions.title')" /> <TopHeader :title="$t('sessions.title')" />
<div class="row"> <div class="row">
<main class="col-12"> <main class="col-12">
<div class="d-flex align-items-baseline justify-content-between my-3 my-md-5"> <div
class="d-flex align-items-baseline justify-content-between my-3 my-md-5 month-header"
>
<router-link <router-link
class="d-flex text-decoration-none align-items-center" class="d-flex text-decoration-none align-items-center"
:class="{ 'pe-none': !hasPrev, 'text-muted': !hasPrev }" :class="{ 'pe-none': !hasPrev, 'text-muted': !hasPrev }"
@ -630,6 +632,21 @@ export default {
.sticky-bottom { .sticky-bottom {
z-index: 1; z-index: 1;
} }
.sticky-top th {
padding-top: max(0.5rem, env(safe-area-inset-top));
}
.table-outer {
position: relative;
top: calc(max(0.5rem, env(safe-area-inset-top)) * -1);
}
.month-header {
position: relative;
z-index: 2;
}
.sticky-bottom th {
padding-bottom: max(0.5rem, env(safe-area-inset-bottom));
border-bottom: none;
}
@media (max-width: 576px) { @media (max-width: 576px) {
.table td, .table td,
.table th { .table th {

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="root"> <div class="root safe-area-inset">
<div class="container px-4"> <div class="container px-4">
<TopHeader title="Configuration 🧪" /> <TopHeader title="Configuration 🧪" />
<div class="wrapper"> <div class="wrapper">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

View file

@ -170,6 +170,7 @@ blog = "Blog"
docs = "Dokumentation" docs = "Dokumentation"
github = "GitHub" github = "GitHub"
login = "Fahrzeug-Logins" login = "Fahrzeug-Logins"
nativeSettings = "Server ändern"
needHelp = "Hilfe benötigt?" needHelp = "Hilfe benötigt?"
sessions = "Ladevorgänge" sessions = "Ladevorgänge"

View file

@ -167,7 +167,8 @@ blog = "Blog"
docs = "Documentation" docs = "Documentation"
github = "GitHub" github = "GitHub"
login = "Vehicle Logins" login = "Vehicle Logins"
needHelp = "Need help?" nativeSettings = "Change Server"
needHelp = "Need Help?"
sessions = "Charging Sessions" sessions = "Charging Sessions"
[help] [help]