Android: get polyfills for geolocation working, some steps for logging in
This commit is contained in:
parent
76e9381650
commit
14e5f1efb3
5 changed files with 52 additions and 28 deletions
|
@ -4,6 +4,7 @@ We are using capacitor. This is a tool which packages some files into an Android
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
|
0. `nvm use` to make sure your using the correct android version
|
||||||
1. Build all the necessary files.
|
1. Build all the necessary files.
|
||||||
a. If no layer/theme changes were made, `npm run build` is sufficient
|
a. If no layer/theme changes were made, `npm run build` is sufficient
|
||||||
b. Otherwise, run `npm run prepare-deploy`.
|
b. Otherwise, run `npm run prepare-deploy`.
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { Utils } from "../../Utils"
|
||||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||||
import { AuthConfig } from "./AuthConfig"
|
import { AuthConfig } from "./AuthConfig"
|
||||||
import Constants from "../../Models/Constants"
|
import Constants from "../../Models/Constants"
|
||||||
|
import { AndroidPolyfill } from "../Web/AndroidPolyfill"
|
||||||
|
|
||||||
interface OsmUserInfo {
|
interface OsmUserInfo {
|
||||||
id: number
|
id: number
|
||||||
|
@ -520,6 +521,7 @@ export class OsmConnection {
|
||||||
* To be called by land.html
|
* To be called by land.html
|
||||||
*/
|
*/
|
||||||
public finishLogin(callback: (previousURL: string) => void) {
|
public finishLogin(callback: (previousURL: string) => void) {
|
||||||
|
console.log(">>> authenticating")
|
||||||
this.auth.authenticate(function () {
|
this.auth.authenticate(function () {
|
||||||
// Fully authed at this point
|
// Fully authed at this point
|
||||||
console.log("Authentication successful!")
|
console.log("Authentication successful!")
|
||||||
|
@ -529,17 +531,22 @@ export class OsmConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateAuthObject() {
|
private updateAuthObject() {
|
||||||
|
let redirect_uri = Utils.runningFromConsole
|
||||||
|
? "https://mapcomplete.org/land.html"
|
||||||
|
: window.location.protocol + "//" + window.location.host + "/land.html"
|
||||||
|
if(AndroidPolyfill.inAndroid.data){
|
||||||
|
redirect_uri = "https://app.mapcomplete.org/land.html"
|
||||||
|
AndroidPolyfill.requestLoginCodes(this)
|
||||||
|
}
|
||||||
this.auth = new osmAuth({
|
this.auth = new osmAuth({
|
||||||
client_id: this._oauth_config.oauth_client_id,
|
client_id: this._oauth_config.oauth_client_id,
|
||||||
url: this._oauth_config.url,
|
url: this._oauth_config.url,
|
||||||
scope: "read_prefs write_prefs write_api write_gpx write_notes",
|
scope: "read_prefs write_prefs write_api write_gpx write_notes",
|
||||||
redirect_uri: Utils.runningFromConsole
|
redirect_uri,
|
||||||
? "https://mapcomplete.org/land.html"
|
|
||||||
: window.location.protocol + "//" + window.location.host + "/land.html",
|
|
||||||
/* We use 'singlePage' as much as possible, it is the most stable - including in PWA.
|
/* We use 'singlePage' as much as possible, it is the most stable - including in PWA.
|
||||||
* However, this breaks in iframes so we open a popup in that case
|
* However, this breaks in iframes so we open a popup in that case
|
||||||
*/
|
*/
|
||||||
singlepage: !this._iframeMode,
|
singlepage: !this._iframeMode && !AndroidPolyfill.inAndroid.data,
|
||||||
auto: true,
|
auto: true,
|
||||||
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url,
|
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url,
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||||
import { QueryParameters } from "../Web/QueryParameters"
|
import { QueryParameters } from "../Web/QueryParameters"
|
||||||
import { Translation } from "../../UI/i18n/Translation"
|
import { Translation } from "../../UI/i18n/Translation"
|
||||||
import Translations from "../../UI/i18n/Translations"
|
import Translations from "../../UI/i18n/Translations"
|
||||||
|
import { AndroidPolyfill } from "../Web/AndroidPolyfill"
|
||||||
|
|
||||||
export type GeolocationPermissionState = "prompt" | "requested" | "granted" | "denied"
|
export type GeolocationPermissionState = "prompt" | "requested" | "granted" | "denied"
|
||||||
|
|
||||||
|
@ -157,12 +158,20 @@ export class GeoLocationState {
|
||||||
this.permission.setData("denied")
|
this.permission.setData("denied")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.permission.data !== "prompt" && this.permission.data !== "requested") {
|
if (this.permission.data !== "prompt" && this.permission.data !== "requested") {
|
||||||
// If the user denies the first prompt, revokes the deny and then tries again, we have to run the flow as well
|
// If the user denies the first prompt, revokes the deny and then tries again, we have to run the flow as well
|
||||||
// Hence that we continue the flow if it is "requested"
|
// Hence that we continue the flow if it is "requested"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(AndroidPolyfill.inAndroid.data){
|
||||||
|
this.permission.setData("requested")
|
||||||
|
AndroidPolyfill.geolocationPermission.addCallbackAndRunD(state => this.permission.set(state))
|
||||||
|
this.startWatching()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (GeoLocationState.isSafari()) {
|
if (GeoLocationState.isSafari()) {
|
||||||
/*
|
/*
|
||||||
This is probably safari
|
This is probably safari
|
||||||
|
|
|
@ -3,16 +3,17 @@
|
||||||
* If this is successful, it will patch some webAPIs
|
* If this is successful, it will patch some webAPIs
|
||||||
*/
|
*/
|
||||||
import { registerPlugin } from "@capacitor/core"
|
import { registerPlugin } from "@capacitor/core"
|
||||||
import { UIEventSource } from "../UIEventSource"
|
import { Store, UIEventSource } from "../UIEventSource"
|
||||||
|
import { OsmConnection } from "../Osm/OsmConnection"
|
||||||
|
|
||||||
export interface DatabridgePlugin {
|
export interface DatabridgePlugin {
|
||||||
request(options: { key: string }): Promise<{ value: string }>;
|
request(options: { key: string }): Promise<{ value: string | object }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge", {
|
const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge", {
|
||||||
web: () => {
|
web: () => {
|
||||||
return <DatabridgePlugin>{
|
return <DatabridgePlugin>{
|
||||||
async request(options: { key: string }): Promise<{ value: string }> {
|
async request(options: { key: string }): Promise<{ value: string | object }> {
|
||||||
return { value: "web" }
|
return { value: "web" }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -21,6 +22,10 @@ const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge",
|
||||||
|
|
||||||
export class AndroidPolyfill {
|
export class AndroidPolyfill {
|
||||||
private readonly databridgePlugin: DatabridgePlugin = DatabridgePluginSingleton
|
private readonly databridgePlugin: DatabridgePlugin = DatabridgePluginSingleton
|
||||||
|
private static readonly _inAndroid: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||||
|
public static readonly inAndroid: Store<boolean> = AndroidPolyfill._inAndroid
|
||||||
|
private static readonly _geolocationPermission: UIEventSource<"granted" | "denied" | "prompt"> = new UIEventSource("prompt")
|
||||||
|
public static readonly geolocationPermission: Store<"granted" | "denied" | "prompt"> = this._geolocationPermission
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers 'navigator.'
|
* Registers 'navigator.'
|
||||||
|
@ -28,26 +33,10 @@ export class AndroidPolyfill {
|
||||||
*/
|
*/
|
||||||
private backfillGeolocation(databridgePlugin: DatabridgePlugin) {
|
private backfillGeolocation(databridgePlugin: DatabridgePlugin) {
|
||||||
const origQueryFunc = navigator?.permissions?.query
|
const origQueryFunc = navigator?.permissions?.query
|
||||||
navigator.permissions.query = async (descr: PermissionDescriptor) => {
|
const src = UIEventSource.FromPromise(databridgePlugin.request({ key: "location:request-permission" }))
|
||||||
if (descr.name === "geolocation") {
|
src.addCallbackAndRunD(permission => {
|
||||||
console.log("Got a geolocation permission request")
|
AndroidPolyfill._geolocationPermission.set(<"granted" | "denied">permission.value)
|
||||||
const src = UIEventSource.FromPromise(databridgePlugin.request({ key: "location:request-permission" }))
|
})
|
||||||
|
|
||||||
return <PermissionStatus>{
|
|
||||||
state: undefined,
|
|
||||||
addEventListener(key: "change", f: (value: "granted" | "denied") => void) {
|
|
||||||
src.addCallbackAndRunD(v => {
|
|
||||||
const content = <"granted" | "denied">v.value
|
|
||||||
f(content)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (origQueryFunc) {
|
|
||||||
return await origQueryFunc(descr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async init() {
|
public async init() {
|
||||||
|
@ -57,8 +46,20 @@ export class AndroidPolyfill {
|
||||||
console.log("Not initing Android polyfill as not in a shell; web detected")
|
console.log("Not initing Android polyfill as not in a shell; web detected")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
AndroidPolyfill._inAndroid.set(true)
|
||||||
console.log("Detected shell:", shell.value)
|
console.log("Detected shell:", shell.value)
|
||||||
this.backfillGeolocation(this.databridgePlugin)
|
this.backfillGeolocation(this.databridgePlugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async requestLoginCodes(osmConnection: OsmConnection) {
|
||||||
|
const result = await DatabridgePluginSingleton.request({ key: "request:login" })
|
||||||
|
const code: string = result["code"]
|
||||||
|
const state: string = result["state"]
|
||||||
|
console.log("AndroidPolyfill: received code and state; trying to pass them to the oauth lib")
|
||||||
|
window.location.search = "?code=" + code + "&state=" + state
|
||||||
|
osmConnection.finishLogin((oldLocation) => {
|
||||||
|
console.log("Login should be completed, oldLocation is", oldLocation)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
import PanoramaxLink from "./PanoramaxLink.svelte"
|
import PanoramaxLink from "./PanoramaxLink.svelte"
|
||||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import MagnifyingGlassCircle from "@babeard/svelte-heroicons/mini/MagnifyingGlassCircle"
|
import MagnifyingGlassCircle from "@babeard/svelte-heroicons/mini/MagnifyingGlassCircle"
|
||||||
|
import { AndroidPolyfill } from "../../Logic/Web/AndroidPolyfill"
|
||||||
|
|
||||||
export let state: ThemeViewState
|
export let state: ThemeViewState
|
||||||
let userdetails = state.osmConnection.userDetails
|
let userdetails = state.osmConnection.userDetails
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
let isAndroid = AndroidPolyfill.inAndroid
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -255,7 +257,8 @@
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<a class="sidebar-button flex" href="geo:{$location.lat},{$location.lon}">
|
<a class="sidebar-button flex" href="geo:{$location.lat},{$location.lon}">
|
||||||
<ShareIcon /><Tr t={t.openHereDifferentApp} />
|
<ShareIcon />
|
||||||
|
<Tr t={t.openHereDifferentApp} />
|
||||||
</a>
|
</a>
|
||||||
</SidebarUnit>
|
</SidebarUnit>
|
||||||
|
|
||||||
|
@ -343,6 +346,9 @@
|
||||||
|
|
||||||
<div class="subtle self-end">
|
<div class="subtle self-end">
|
||||||
{Constants.vNumber}
|
{Constants.vNumber}
|
||||||
|
{#if $isAndroid}
|
||||||
|
Android
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</SidebarUnit>
|
</SidebarUnit>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue