Android: docs, app landing page

This commit is contained in:
Pieter Vander Vennet 2025-01-12 01:53:58 +01:00
parent 8b43c63a31
commit 15caadbd3d
5 changed files with 67 additions and 10 deletions

View file

@ -1,9 +1,12 @@
import { defineConfig } from "vite" import { defineConfig } from "vite"
import { svelte } from "@sveltejs/vite-plugin-svelte" import { svelte } from "@sveltejs/vite-plugin-svelte"
import fs from "fs"
import basicSsl from "@vitejs/plugin-basic-ssl" import basicSsl from "@vitejs/plugin-basic-ssl"
const input = { "land": "./app/land.html", passthrough: "./app/passthrough.html" } const input = {
land: "./app/land.html",
index: "./app/index.html",
passthrough: "./app/passthrough.html"
}
console.log("Args:", process.argv) console.log("Args:", process.argv)

18
app/index.html Normal file
View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MapComplete App</title>
</head>
<body>
Hi!
MapComplete will soon (TM) be available as Android App in the play store and on FDroid.
In the meantime, there isn't a lot to see here.
<a href="https://mapcomplete.org">Go back to mapcomplete</a>
</body>
</html>

View file

@ -22,6 +22,7 @@ const config: CapacitorConfig = {
export default config; export default config;
''' > capacitor.config.ts ''' > capacitor.config.ts
# copy distribution files
rm -rf dist-full rm -rf dist-full
mkdir dist-full mkdir dist-full
cp dist/*.html dist-full/ cp dist/*.html dist-full/

View file

@ -14,10 +14,12 @@ const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge",
web: () => { web: () => {
return <DatabridgePlugin>{ return <DatabridgePlugin>{
async request(options: { key: string }): Promise<{ value: string | object }> { async request(options: { key: string }): Promise<{ value: string | object }> {
return { value: "web" } if (options.key === "meta") {
}, return { value: "web" }
}
}
} }
}, }
}) })
export class AndroidPolyfill { export class AndroidPolyfill {
@ -32,7 +34,6 @@ export class AndroidPolyfill {
* @private * @private
*/ */
private backfillGeolocation(databridgePlugin: DatabridgePlugin) { private backfillGeolocation(databridgePlugin: DatabridgePlugin) {
const origQueryFunc = navigator?.permissions?.query
const src = UIEventSource.FromPromise(databridgePlugin.request({ key: "location:request-permission" })) const src = UIEventSource.FromPromise(databridgePlugin.request({ key: "location:request-permission" }))
src.addCallbackAndRunD(permission => { src.addCallbackAndRunD(permission => {
AndroidPolyfill._geolocationPermission.set(<"granted" | "denied">permission.value) AndroidPolyfill._geolocationPermission.set(<"granted" | "denied">permission.value)
@ -57,5 +58,23 @@ export class AndroidPolyfill {
console.log("AndroidPolyfill: received oauth_token; trying to pass them to the oauth lib",token) console.log("AndroidPolyfill: received oauth_token; trying to pass them to the oauth lib",token)
return token return token
} }
public static onBackButton(callback: () => boolean, options: {
returnToIndex: Store<boolean>
}) {
console.log("Registering back button callback", callback)
DatabridgePluginSingleton.request({ key: "backbutton" }).then(ev => {
console.log("AndroidPolyfill: received backbutton: ", ev)
if (callback()) {
return
}
// Nothing more to close - we return (if not a single theme) to the index
if (options.returnToIndex) {
console.log("Back to the index!")
window.location.href = "/"
}
})
}
} }

View file

@ -1,6 +1,7 @@
import ThemeViewState from "../../Models/ThemeViewState" import ThemeViewState from "../../Models/ThemeViewState"
import Hash from "./Hash" import Hash from "./Hash"
import { MenuState } from "../../Models/MenuState" import { MenuState } from "../../Models/MenuState"
import { AndroidPolyfill } from "./AndroidPolyfill"
export default class ThemeViewStateHashActor { export default class ThemeViewStateHashActor {
private readonly _state: ThemeViewState private readonly _state: ThemeViewState
@ -22,7 +23,7 @@ export default class ThemeViewStateHashActor {
/** /**
* Converts the hash to the appropriate theme-view state and, vice versa, sets the hash. * Converts the hash to the appropriate theme-view state and, vice versa, sets the hash.
* *
* As the navigator-back-button changes the hash first, this class thus also handles the 'back'-button events. * As the navigator-back-button changes the hash first, this class thus also handles the (browser) 'back'-button events.
* *
* Note that there is no "real" way to intercept the back button, we can only detect the removal of the hash. * Note that there is no "real" way to intercept the back button, we can only detect the removal of the hash.
* As such, we use a change in the hash to close the appropriate windows * As such, we use a change in the hash to close the appropriate windows
@ -30,6 +31,9 @@ export default class ThemeViewStateHashActor {
*/ */
constructor(state: ThemeViewState) { constructor(state: ThemeViewState) {
this._state = state this._state = state
AndroidPolyfill.onBackButton(() => this.back(), {
returnToIndex: state.featureSwitches.featureSwitchBackToThemeOverview
})
const hashOnLoad = Hash.hash.data const hashOnLoad = Hash.hash.data
const containsMenu = this.loadStateFromHash(hashOnLoad) const containsMenu = this.loadStateFromHash(hashOnLoad)
@ -66,6 +70,7 @@ export default class ThemeViewStateHashActor {
// When all is done, set the hash. This must happen last to give the code above correct info // When all is done, set the hash. This must happen last to give the code above correct info
this.setHash() this.setHash()
} }
/** /**
@ -137,15 +142,26 @@ export default class ThemeViewStateHashActor {
} }
} }
/**
* Returns 'true' if an action was taken
* @private
*/
private back() { private back() {
console.log("Received back!")
const state = this._state const state = this._state
if (state.previewedImage.data) { if (state.previewedImage.data) {
state.previewedImage.setData(undefined) state.previewedImage.setData(undefined)
return return true
} }
if (state.guistate.closeAll()) { if (state.guistate.closeAll()) {
return return true
} }
state.selectedElement.setData(undefined) if (state.selectedElement.data) {
state.selectedElement.setData(undefined)
return true
}
return false
} }
} }