Android: More work to attempt to get login working

This commit is contained in:
Pieter Vander Vennet 2024-12-19 13:49:14 +01:00
parent fcf8416b5a
commit 969ad74bd9
9 changed files with 99 additions and 61 deletions

1
.gitignore vendored
View file

@ -52,3 +52,4 @@ android/
dist-full/ dist-full/
public/assets/icons/*.webp public/assets/icons/*.webp
uploaded_images.json uploaded_images.json
/app/dist/

View file

@ -6,6 +6,14 @@ hosted.mapcomplete.org {
} }
} }
app.mapcomplete.org {
root * app/
file_server
header {
+Permissions-Policy "interest-cohort=()"
}
}
countrycoder.mapcomplete.org { countrycoder.mapcomplete.org {
root * tiles/ root * tiles/
file_server file_server

14
app/passthrough.html Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MapComplete Login</title>
</head>
<body>
Hey!
Open this page with the app. (Press the menu, "open in app")
</body>
</html>

View file

@ -83,18 +83,19 @@
"strt": "vite --host | sed 's/localhost:/127.0.0.1:/g'", "strt": "vite --host | sed 's/localhost:/127.0.0.1:/g'",
"build": "./scripts/build.sh", "build": "./scripts/build.sh",
"build:single": "./scripts/single_build.sh", "build:single": "./scripts/single_build.sh",
"build:vite:app-landing": "export NODE_OPTIONS=\"--max-old-space-size=12192\" && vite build --sourcemap --config app/app.vite.config.js",
"build:dbscript": "vite-node ./scripts/osm2pgsql/generateBuildDbScript.ts", "build:dbscript": "vite-node ./scripts/osm2pgsql/generateBuildDbScript.ts",
"prepare-deploy": "npm run generate:service-worker && ./scripts/prepare-build.sh && npm run build", "prepare-deploy": "npm run generate:service-worker && ./scripts/prepare-build.sh && npm run build",
"watch:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css --watch", "watch:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css --watch",
"generate:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css", "generate:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css",
"generate:doctests": "doctest-ts-improved . --ignore .*.spec.ts --ignore .*ConfigJson.ts", "generate:doctests": "doctest-ts-improved . --ignore .*.spec.ts --ignore .*ConfigJson.ts",
"test:run-only": "vitest --run test", "test:run-only": "vitest --run test",
"test": " export NODE_OPTIONS=\"--max-old-space-size=8192\" && npm run clean:tests && (npm run generate:doctests 2>&1 | grep -v \"No doctests found in\") && npm run test:run-only && npm run clean:tests", "test": "NODE_OPTIONS=\"--max-old-space-size=8192\" && npm run clean:tests && (npm run generate:doctests 2>&1 | grep -v \"No doctests found in\") && npm run test:run-only && npm run clean:tests",
"generate:polygon-features": "vite-node scripts/downloadFile.ts -- https://raw.githubusercontent.com/tyrasd/osm-polygon-features/master/polygon-features.json assets/polygon-features.json", "generate:polygon-features": "vite-node scripts/downloadFile.ts -- https://raw.githubusercontent.com/tyrasd/osm-polygon-features/master/polygon-features.json assets/polygon-features.json",
"generate:images": "vite-node scripts/generateIncludedImages.ts", "generate:images": "vite-node scripts/generateIncludedImages.ts",
"generate:translations": "vite-node scripts/generateTranslations.ts", "generate:translations": "vite-node scripts/generateTranslations.ts",
"reset:translations": "vite-node scripts/generateTranslations.ts -- --ignore-weblate", "reset:translations": "vite-node scripts/generateTranslations.ts -- --ignore-weblate",
"generate:layouts": "vite-node scripts/generateLayouts.ts", "generate:layouts": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayouts.ts",
"generate:docs": "rm -rf Docs/Themes/* && rm -rf Docs/Layers/* && rm -rf Docs/TagInfo && mkdir Docs/TagInfo && export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateDocs.ts && vite-node scripts/generateTaginfoProjectFiles.ts", "generate:docs": "rm -rf Docs/Themes/* && rm -rf Docs/Layers/* && rm -rf Docs/TagInfo && mkdir Docs/TagInfo && export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateDocs.ts && vite-node scripts/generateTaginfoProjectFiles.ts",
"generate:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts", "generate:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts",
"generate:mapcomplete-changes-theme": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --generate-change-map", "generate:mapcomplete-changes-theme": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --generate-change-map",

View file

@ -2,6 +2,14 @@
# Copy all necessary files from the 'dist' directory into dist full # Copy all necessary files from the 'dist' directory into dist full
# To be executed from the `MapComplete` repo root # To be executed from the `MapComplete` repo root
nvm use
if [[ ! -f bookcases.html ]]
then
npm run generate:layeroverview
npm run generate:layouts
fi
npm run build
echo ''' echo '''
import type { CapacitorConfig } from "@capacitor/cli"; import type { CapacitorConfig } from "@capacitor/cli";
@ -47,3 +55,5 @@ cp -r dist/assets/themes dist-full/assets
npx capacitor-assets generate npx capacitor-assets generate
npx cap sync npx cap sync
echo "All done! Don't forget to click 'gradly sync files' in Android Studio"

View file

@ -46,14 +46,14 @@ export class OsmConnection {
public userDetails: UIEventSource<UserDetails> public userDetails: UIEventSource<UserDetails>
public isLoggedIn: Store<boolean> public isLoggedIn: Store<boolean>
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>( public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
"unknown" "unknown",
) )
public apiIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>( public apiIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
"unknown" "unknown",
) )
public loadingStatus = new UIEventSource<"not-attempted" | "loading" | "error" | "logged-in">( public loadingStatus = new UIEventSource<"not-attempted" | "loading" | "error" | "logged-in">(
"not-attempted" "not-attempted",
) )
public preferencesHandler: OsmPreferences public preferencesHandler: OsmPreferences
public readonly _oauth_config: AuthConfig public readonly _oauth_config: AuthConfig
@ -97,7 +97,7 @@ export class OsmConnection {
this.userDetails = new UIEventSource<UserDetails>( this.userDetails = new UIEventSource<UserDetails>(
new UserDetails(this._oauth_config.url), new UserDetails(this._oauth_config.url),
"userDetails" "userDetails",
) )
if (options.fakeUser) { if (options.fakeUser) {
const ud = this.userDetails.data const ud = this.userDetails.data
@ -118,7 +118,7 @@ export class OsmConnection {
(user) => (user) =>
user.loggedIn && user.loggedIn &&
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"), (this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
[this.apiIsOnline] [this.apiIsOnline],
) )
this.isLoggedIn.addCallback((isLoggedIn) => { this.isLoggedIn.addCallback((isLoggedIn) => {
if (this.userDetails.data.loggedIn == false && isLoggedIn == true) { if (this.userDetails.data.loggedIn == false && isLoggedIn == true) {
@ -161,7 +161,7 @@ export class OsmConnection {
defaultValue: string = undefined, defaultValue: string = undefined,
options?: { options?: {
prefix?: string prefix?: string
} },
): UIEventSource<T | undefined> { ): UIEventSource<T | undefined> {
const prefix = options?.prefix ?? "mapcomplete-" const prefix = options?.prefix ?? "mapcomplete-"
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix) return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
@ -170,7 +170,7 @@ export class OsmConnection {
public getPreference<T extends string = string>( public getPreference<T extends string = string>(
key: string, key: string,
defaultValue: string = undefined, defaultValue: string = undefined,
prefix: string = "mapcomplete-" prefix: string = "mapcomplete-",
): UIEventSource<T | undefined> { ): UIEventSource<T | undefined> {
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix) return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
} }
@ -214,7 +214,7 @@ export class OsmConnection {
this.updateAuthObject() this.updateAuthObject()
LocalStorageSource.get("location_before_login").setData( LocalStorageSource.get("location_before_login").setData(
Utils.runningFromConsole ? undefined : window.location.href Utils.runningFromConsole ? undefined : window.location.href,
) )
this.auth.xhr( this.auth.xhr(
{ {
@ -252,13 +252,13 @@ export class OsmConnection {
data.account_created = userInfo.getAttribute("account_created") data.account_created = userInfo.getAttribute("account_created")
data.uid = Number(userInfo.getAttribute("id")) data.uid = Number(userInfo.getAttribute("id"))
data.languages = Array.from( data.languages = Array.from(
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang") userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang"),
).map((l) => l.textContent) ).map((l) => l.textContent)
data.csCount = Number.parseInt( data.csCount = Number.parseInt(
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0" userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0",
) )
data.tracesCount = Number.parseInt( data.tracesCount = Number.parseInt(
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0" userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0",
) )
data.img = undefined data.img = undefined
@ -290,7 +290,7 @@ export class OsmConnection {
action(this.userDetails.data) action(this.userDetails.data)
} }
this._onLoggedIn = [] this._onLoggedIn = []
} },
) )
} }
@ -308,7 +308,7 @@ export class OsmConnection {
method: "GET" | "POST" | "PUT" | "DELETE", method: "GET" | "POST" | "PUT" | "DELETE",
header?: Record<string, string>, header?: Record<string, string>,
content?: string, content?: string,
allowAnonymous: boolean = false allowAnonymous: boolean = false,
): Promise<string> { ): Promise<string> {
const connection: osmAuth = this.auth const connection: osmAuth = this.auth
if (allowAnonymous && !this.auth.authenticated()) { if (allowAnonymous && !this.auth.authenticated()) {
@ -316,7 +316,7 @@ export class OsmConnection {
`${this.Backend()}/api/0.6/${path}`, `${this.Backend()}/api/0.6/${path}`,
header, header,
method, method,
content content,
) )
if (possibleResult["content"]) { if (possibleResult["content"]) {
return possibleResult["content"] return possibleResult["content"]
@ -333,13 +333,13 @@ export class OsmConnection {
content, content,
path: `/api/0.6/${path}`, path: `/api/0.6/${path}`,
}, },
function (err, response) { function(err, response) {
if (err !== null) { if (err !== null) {
error(err) error(err)
} else { } else {
ok(response) ok(response)
} }
} },
) )
}) })
} }
@ -348,7 +348,7 @@ export class OsmConnection {
path: string, path: string,
content?: string, content?: string,
header?: Record<string, string>, header?: Record<string, string>,
allowAnonymous: boolean = false allowAnonymous: boolean = false,
): Promise<T> { ): Promise<T> {
return <T>await this.interact(path, "POST", header, content, allowAnonymous) return <T>await this.interact(path, "POST", header, content, allowAnonymous)
} }
@ -356,7 +356,7 @@ export class OsmConnection {
public async put<T extends string>( public async put<T extends string>(
path: string, path: string,
content?: string, content?: string,
header?: Record<string, string> header?: Record<string, string>,
): Promise<T> { ): Promise<T> {
return <T>await this.interact(path, "PUT", header, content) return <T>await this.interact(path, "PUT", header, content)
} }
@ -364,7 +364,7 @@ export class OsmConnection {
public async get( public async get(
path: string, path: string,
header?: Record<string, string>, header?: Record<string, string>,
allowAnonymous: boolean = false allowAnonymous: boolean = false,
): Promise<string> { ): Promise<string> {
return await this.interact(path, "GET", header, undefined, allowAnonymous) return await this.interact(path, "GET", header, undefined, allowAnonymous)
} }
@ -403,7 +403,7 @@ export class OsmConnection {
return new Promise<{ id: number }>((ok) => { return new Promise<{ id: number }>((ok) => {
window.setTimeout( window.setTimeout(
() => ok({ id: Math.floor(Math.random() * 1000) }), () => ok({ id: Math.floor(Math.random() * 1000) }),
Math.random() * 5000 Math.random() * 5000,
) )
}) })
} }
@ -415,7 +415,7 @@ export class OsmConnection {
{ {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
}, },
true true,
) )
const parsed = JSON.parse(response) const parsed = JSON.parse(response)
console.log("Got result:", parsed) console.log("Got result:", parsed)
@ -438,14 +438,14 @@ export class OsmConnection {
* Note: these are called 'tags' on the wiki, but I opted to name them 'labels' instead as they aren't "key=value" tags, but just words. * Note: these are called 'tags' on the wiki, but I opted to name them 'labels' instead as they aren't "key=value" tags, but just words.
*/ */
labels: string[] labels: string[]
} },
): Promise<{ id: number }> { ): Promise<{ id: number }> {
if (this._dryRun.data) { if (this._dryRun.data) {
console.warn("Dryrun enabled - not actually uploading GPX ", gpx) console.warn("Dryrun enabled - not actually uploading GPX ", gpx)
return new Promise<{ id: number }>((ok) => { return new Promise<{ id: number }>((ok) => {
window.setTimeout( window.setTimeout(
() => ok({ id: Math.floor(Math.random() * 1000) }), () => ok({ id: Math.floor(Math.random() * 1000) }),
Math.random() * 5000 Math.random() * 5000,
) )
}) })
} }
@ -462,9 +462,9 @@ export class OsmConnection {
} }
const extras = { const extras = {
file: file:
'; filename="' + "; filename=\"" +
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) + (options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
'"\r\nContent-Type: application/gpx+xml', "\"\r\nContent-Type: application/gpx+xml",
} }
const boundary = "987654" const boundary = "987654"
@ -472,7 +472,7 @@ export class OsmConnection {
let body = "" let body = ""
for (const key in contents) { for (const key in contents) {
body += "--" + boundary + "\r\n" body += "--" + boundary + "\r\n"
body += 'Content-Disposition: form-data; name="' + key + '"' body += "Content-Disposition: form-data; name=\"" + key + "\""
if (extras[key] !== undefined) { if (extras[key] !== undefined) {
body += extras[key] body += extras[key]
} }
@ -506,13 +506,13 @@ export class OsmConnection {
path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`, path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`,
}, },
function (err) { function(err) {
if (err !== null) { if (err !== null) {
error(err) error(err)
} else { } else {
ok() ok()
} }
} },
) )
}) })
} }
@ -520,13 +520,14 @@ 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, oauth_token: string) => void) {
console.log(">>> authenticating") console.log(">>> authenticating")
this.auth.authenticate(function () { this.auth.authenticate(() => {
// Fully authed at this point // Fully authed at this point
console.log("Authentication successful!") console.log("Authentication successful!")
const oauth_token = window.localStorage.getItem(this._oauth_config.url + "oauth2_access_token")
const previousLocation = LocalStorageSource.get("location_before_login") const previousLocation = LocalStorageSource.get("location_before_login")
callback(previousLocation.data) callback(previousLocation.data, oauth_token)
}) })
} }
@ -534,7 +535,7 @@ export class OsmConnection {
let redirect_uri = Utils.runningFromConsole let redirect_uri = Utils.runningFromConsole
? "https://mapcomplete.org/land.html" ? "https://mapcomplete.org/land.html"
: window.location.protocol + "//" + window.location.host + "/land.html" : window.location.protocol + "//" + window.location.host + "/land.html"
if(AndroidPolyfill.inAndroid.data){ if (AndroidPolyfill.inAndroid.data) {
redirect_uri = "https://app.mapcomplete.org/land.html" redirect_uri = "https://app.mapcomplete.org/land.html"
AndroidPolyfill.requestLoginCodes(this) AndroidPolyfill.requestLoginCodes(this)
} }

View file

@ -7,7 +7,7 @@ import { Store, UIEventSource } from "../UIEventSource"
import { OsmConnection } from "../Osm/OsmConnection" import { OsmConnection } from "../Osm/OsmConnection"
export interface DatabridgePlugin { export interface DatabridgePlugin {
request(options: { key: string }): Promise<{ value: string | object }>; request<T extends (string | object) = string | object>(options: { key: string }): Promise<{ value: T }>;
} }
const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge", { const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge", {
@ -52,14 +52,12 @@ export class AndroidPolyfill {
} }
public static async requestLoginCodes(osmConnection: OsmConnection) { public static async requestLoginCodes(osmConnection: OsmConnection) {
const result = await DatabridgePluginSingleton.request({ key: "request:login" }) const result = await DatabridgePluginSingleton.request<{oauth_token: string}>({ key: "request:login" })
const code: string = result["code"] const token: string = result.value.oauth_token
const state: string = result["state"] console.log("AndroidPolyfill: received code and state; trying to pass them to the oauth lib",token)
console.log("AndroidPolyfill: received code and state; trying to pass them to the oauth lib") const auth = osmConnection.auth.bootstrapToken(token, (err, result) => {
window.location.search = "?code=" + code + "&state=" + state console.log("AndroidPolyFill: bootstraptoken returned", JSON.stringify({err, result}))
osmConnection.finishLogin((oldLocation) => {
console.log("Login should be completed, oldLocation is", oldLocation)
}) })
} }
} }

View file

@ -39,7 +39,7 @@
let maplibremap: MapLibreAdaptor = new MapLibreAdaptor(map, { let maplibremap: MapLibreAdaptor = new MapLibreAdaptor(map, {
zoom, zoom,
location: new UIEventSource<{ lon: number; lat: number }>({ lat: lat.data, lon: lon.data }) location: new UIEventSource<{ lon: number; lat: number }>({ lat: lat.data, lon: lon.data }),
}) })
maplibremap.location.stabilized(500).addCallbackAndRunD(l => { maplibremap.location.stabilized(500).addCallbackAndRunD(l => {
lat.set(l.lat) lat.set(l.lat)
@ -47,18 +47,18 @@
}) })
let allLayers = HistoryUtils.personalTheme.layers let allLayers = HistoryUtils.personalTheme.layers
let layersNoFixme = allLayers.filter(l => l.id !== "fixme") let layersNoFixme = allLayers.filter(l => l.id !== "fixme")
let fixme = allLayers.find(l => l.id === "fixme") let fixme = allLayers.find(l => l.id === "fixme")
let featuresStore = new UIEventSource<Feature[]>([]) let featuresStore = new UIEventSource<Feature[]>([])
let features = new StaticFeatureSource(featuresStore) let features = new StaticFeatureSource(featuresStore)
ShowDataLayer.showMultipleLayers(map, features, [...layersNoFixme, fixme] , { ShowDataLayer.showMultipleLayers(map, features, [...layersNoFixme, fixme], {
zoomToFeatures: true, zoomToFeatures: true,
onClick: (f: Feature) => { onClick: (f: Feature) => {
selectedElement.set(undefined) selectedElement.set(undefined)
Utils.waitFor(200).then(() => { Utils.waitFor(200).then(() => {
selectedElement.set(f) selectedElement.set(f)
}) })
} },
}) })
let osmConnection = new OsmConnection() let osmConnection = new OsmConnection()
@ -71,7 +71,7 @@ let fixme = allLayers.find(l => l.id === "fixme")
async function load() { async function load() {
const user = username.data const user = username.data
if(user.indexOf(";")<0){ if (user.indexOf(";") < 0) {
const inspectedData = inspectedContributors.data const inspectedData = inspectedContributors.data
const previousEntry = inspectedData.find(e => e.name === user) const previousEntry = inspectedData.find(e => e.name === user)
@ -81,7 +81,7 @@ let fixme = allLayers.find(l => l.id === "fixme")
inspectedData.push({ inspectedData.push({
label: undefined, label: undefined,
visitedTime: new Date().toISOString(), visitedTime: new Date().toISOString(),
name: user name: user,
}) })
} }
inspectedContributors.ping() inspectedContributors.ping()
@ -114,44 +114,44 @@ let fixme = allLayers.find(l => l.id === "fixme")
let mode: "map" | "table" | "aggregate" | "images" = "map" let mode: "map" | "table" | "aggregate" | "images" = "map"
let showPreviouslyVisited = new UIEventSource(true) let showPreviouslyVisited = new UIEventSource(true)
const t = Translations.t.inspector const t = Translations.t.inspector
</script> </script>
<div class="flex flex-col w-full h-full"> <div class="flex flex-col w-full h-full">
<div class="flex gap-x-2 items-center low-interaction p-2"> <div class="flex gap-x-2 items-center low-interaction p-2">
<MagnifyingGlassCircle class="w-12 h-12"/> <MagnifyingGlassCircle class="w-12 h-12" />
<h1 class="flex-shrink-0 m-0 mx-2"> <h1 class="flex-shrink-0 m-0 mx-2">
<Tr t={t.title}/> <Tr t={t.title} />
</h1> </h1>
<ValidatedInput type="string" value={username} on:submit={() => load()} /> <ValidatedInput type="string" value={username} on:submit={() => load()} />
{#if loadingData} {#if loadingData}
<Loading /> <Loading />
{:else} {:else}
<button class="primary" on:click={() => load()}> <button class="primary" on:click={() => load()}>
<Tr t={t.load}/> <Tr t={t.load} />
</button> </button>
{/if} {/if}
<button on:click={() => showPreviouslyVisited.setData(true)}> <button on:click={() => showPreviouslyVisited.setData(true)}>
<Tr t={t.earlierInspected}/> <Tr t={t.earlierInspected} />
</button> </button>
<a href="./index.html" class="button"> <a href="./index.html" class="button">
<Tr t={t.backToIndex}/> <Tr t={t.backToIndex} />
</a> </a>
</div> </div>
<div class="flex"> <div class="flex">
<button class:primary={mode === "map"} on:click={() => mode = "map"}> <button class:primary={mode === "map"} on:click={() => mode = "map"}>
<Tr t={t.mapView}/> <Tr t={t.mapView} />
</button> </button>
<button class:primary={mode === "table"} on:click={() => mode = "table"}> <button class:primary={mode === "table"} on:click={() => mode = "table"}>
<Tr t={t.tableView}/> <Tr t={t.tableView} />
</button> </button>
<button class:primary={mode === "aggregate"} on:click={() => mode = "aggregate"}> <button class:primary={mode === "aggregate"} on:click={() => mode = "aggregate"}>
<Tr t={t.aggregateView}/> <Tr t={t.aggregateView} />
</button> </button>
<button class:primary={mode === "images"} on:click={() => mode = "images"}> <button class:primary={mode === "images"} on:click={() => mode = "images"}>
<Tr t={t.images}/> <Tr t={t.images} />
</button> </button>
</div> </div>
@ -215,5 +215,5 @@ const t = Translations.t.inspector
<div slot="header">Earlier inspected constributors</div> <div slot="header">Earlier inspected constributors</div>
<PreviouslySpiedUsers {osmConnection} {inspectedContributors} on:selectUser={(e) => { <PreviouslySpiedUsers {osmConnection} {inspectedContributors} on:selectUser={(e) => {
username.set(e.detail); load();showPreviouslyVisited.set(false) username.set(e.detail); load();showPreviouslyVisited.set(false)
}} /> }} />
</Page> </Page>

View file

@ -1,7 +1,12 @@
import { OsmConnection } from "./Logic/Osm/OsmConnection" import { OsmConnection } from "./Logic/Osm/OsmConnection"
import Constants from "./Models/Constants"
console.log("Authorizing...") console.log("Authorizing...")
const key = Constants.osmAuthConfig.url + "oauth2_state"
const st =window.localStorage.getItem(key )
console.log("Prev state is",key, st)
new OsmConnection().finishLogin((previousURL) => { new OsmConnection().finishLogin((previousURL) => {
const fallback = window.location.protocol + "//" + window.location.host + "/index.html" const fallback = window.location.protocol + "//" + window.location.host + "/index.html"
previousURL ??= fallback previousURL ??= fallback
if (previousURL.indexOf("/land") > 0) { if (previousURL.indexOf("/land") > 0) {