Compare commits
5 Commits
a89ba904c8
...
b23d54d74f
| Author | SHA1 | Date | |
|---|---|---|---|
|
b23d54d74f
|
|||
|
5bd4dba907
|
|||
|
54ba99673f
|
|||
|
54445f249b
|
|||
|
9828ad2714
|
@@ -1,129 +1,25 @@
|
|||||||
import Component from '@glimmer/component';
|
|
||||||
import { on } from '@ember/modifier';
|
import { on } from '@ember/modifier';
|
||||||
import { service } from '@ember/service';
|
|
||||||
import { action } from '@ember/object';
|
|
||||||
import Icon from '#components/icon';
|
import Icon from '#components/icon';
|
||||||
import eq from 'ember-truth-helpers/helpers/eq';
|
import AppMenuSettingsMapUi from './settings/map-ui';
|
||||||
|
import AppMenuSettingsApis from './settings/apis';
|
||||||
|
import AppMenuSettingsNostr from './settings/nostr';
|
||||||
|
|
||||||
export default class AppMenuSettings extends Component {
|
<template>
|
||||||
@service settings;
|
<div class="sidebar-header">
|
||||||
|
<button type="button" class="back-btn" {{on "click" @onBack}}>
|
||||||
|
<Icon @name="arrow-left" @size={{20}} @color="#333" />
|
||||||
|
</button>
|
||||||
|
<h2>Settings</h2>
|
||||||
|
<button type="button" class="close-btn" {{on "click" @onClose}}>
|
||||||
|
<Icon @name="x" @size={{20}} @color="#333" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
@action
|
<div class="sidebar-content">
|
||||||
updateApi(event) {
|
<section class="settings-section">
|
||||||
this.settings.updateOverpassApi(event.target.value);
|
<AppMenuSettingsMapUi />
|
||||||
}
|
<AppMenuSettingsApis />
|
||||||
|
<AppMenuSettingsNostr />
|
||||||
@action
|
</section>
|
||||||
toggleKinetic(event) {
|
</div>
|
||||||
this.settings.updateMapKinetic(event.target.value === 'true');
|
</template>
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
toggleQuickSearchButtons(event) {
|
|
||||||
this.settings.updateShowQuickSearchButtons(event.target.value === 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
updatePhotonApi(event) {
|
|
||||||
this.settings.updatePhotonApi(event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="sidebar-header">
|
|
||||||
<button type="button" class="back-btn" {{on "click" @onBack}}>
|
|
||||||
<Icon @name="arrow-left" @size={{20}} @color="#333" />
|
|
||||||
</button>
|
|
||||||
<h2>Settings</h2>
|
|
||||||
<button type="button" class="close-btn" {{on "click" @onClose}}>
|
|
||||||
<Icon @name="x" @size={{20}} @color="#333" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="sidebar-content">
|
|
||||||
<section class="settings-section">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="show-quick-search">Quick search buttons visible</label>
|
|
||||||
<select
|
|
||||||
id="show-quick-search"
|
|
||||||
class="form-control"
|
|
||||||
{{on "change" this.toggleQuickSearchButtons}}
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
value="true"
|
|
||||||
selected={{if this.settings.showQuickSearchButtons "selected"}}
|
|
||||||
>
|
|
||||||
Yes
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value="false"
|
|
||||||
selected={{unless
|
|
||||||
this.settings.showQuickSearchButtons
|
|
||||||
"selected"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
No
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="map-kinetic">Map Inertia (Kinetic Panning)</label>
|
|
||||||
<select
|
|
||||||
id="map-kinetic"
|
|
||||||
class="form-control"
|
|
||||||
{{on "change" this.toggleKinetic}}
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
value="true"
|
|
||||||
selected={{if this.settings.mapKinetic "selected"}}
|
|
||||||
>
|
|
||||||
On
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value="false"
|
|
||||||
selected={{unless this.settings.mapKinetic "selected"}}
|
|
||||||
>
|
|
||||||
Off
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="overpass-api">Overpass API Provider</label>
|
|
||||||
<select
|
|
||||||
id="overpass-api"
|
|
||||||
class="form-control"
|
|
||||||
{{on "change" this.updateApi}}
|
|
||||||
>
|
|
||||||
{{#each this.settings.overpassApis as |api|}}
|
|
||||||
<option
|
|
||||||
value={{api.url}}
|
|
||||||
selected={{if
|
|
||||||
(eq api.url this.settings.overpassApi)
|
|
||||||
"selected"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{{api.name}}
|
|
||||||
</option>
|
|
||||||
{{/each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="photon-api">Photon API Provider</label>
|
|
||||||
<select
|
|
||||||
id="photon-api"
|
|
||||||
class="form-control"
|
|
||||||
{{on "change" this.updatePhotonApi}}
|
|
||||||
>
|
|
||||||
{{#each this.settings.photonApis as |api|}}
|
|
||||||
<option
|
|
||||||
value={{api.url}}
|
|
||||||
selected={{if (eq api.url this.settings.photonApi) "selected"}}
|
|
||||||
>
|
|
||||||
{{api.name}}
|
|
||||||
</option>
|
|
||||||
{{/each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
}
|
|
||||||
|
|||||||
69
app/components/app-menu/settings/apis.gjs
Normal file
69
app/components/app-menu/settings/apis.gjs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { on } from '@ember/modifier';
|
||||||
|
import { service } from '@ember/service';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
import Icon from '#components/icon';
|
||||||
|
import eq from 'ember-truth-helpers/helpers/eq';
|
||||||
|
|
||||||
|
export default class AppMenuSettingsApis extends Component {
|
||||||
|
@service settings;
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateApi(event) {
|
||||||
|
this.settings.updateOverpassApi(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
updatePhotonApi(event) {
|
||||||
|
this.settings.updatePhotonApi(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable no-nested-interactive }}
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<Icon @name="server" @size={{20}} />
|
||||||
|
<span>API Providers</span>
|
||||||
|
</summary>
|
||||||
|
<div class="details-content">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="overpass-api">Overpass API Provider</label>
|
||||||
|
<select
|
||||||
|
id="overpass-api"
|
||||||
|
class="form-control"
|
||||||
|
{{on "change" this.updateApi}}
|
||||||
|
>
|
||||||
|
{{#each this.settings.overpassApis as |api|}}
|
||||||
|
<option
|
||||||
|
value={{api.url}}
|
||||||
|
selected={{if
|
||||||
|
(eq api.url this.settings.overpassApi)
|
||||||
|
"selected"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{{api.name}}
|
||||||
|
</option>
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="photon-api">Photon API Provider</label>
|
||||||
|
<select
|
||||||
|
id="photon-api"
|
||||||
|
class="form-control"
|
||||||
|
{{on "change" this.updatePhotonApi}}
|
||||||
|
>
|
||||||
|
{{#each this.settings.photonApis as |api|}}
|
||||||
|
<option
|
||||||
|
value={{api.url}}
|
||||||
|
selected={{if (eq api.url this.settings.photonApi) "selected"}}
|
||||||
|
>
|
||||||
|
{{api.name}}
|
||||||
|
</option>
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</template>
|
||||||
|
}
|
||||||
76
app/components/app-menu/settings/map-ui.gjs
Normal file
76
app/components/app-menu/settings/map-ui.gjs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { on } from '@ember/modifier';
|
||||||
|
import { service } from '@ember/service';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
import Icon from '#components/icon';
|
||||||
|
|
||||||
|
export default class AppMenuSettingsMapUi extends Component {
|
||||||
|
@service settings;
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleKinetic(event) {
|
||||||
|
this.settings.updateMapKinetic(event.target.value === 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleQuickSearchButtons(event) {
|
||||||
|
this.settings.updateShowQuickSearchButtons(event.target.value === 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable no-nested-interactive }}
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<Icon @name="map" @size={{20}} />
|
||||||
|
<span>Map & UI</span>
|
||||||
|
</summary>
|
||||||
|
<div class="details-content">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="show-quick-search">Quick search buttons visible</label>
|
||||||
|
<select
|
||||||
|
id="show-quick-search"
|
||||||
|
class="form-control"
|
||||||
|
{{on "change" this.toggleQuickSearchButtons}}
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
value="true"
|
||||||
|
selected={{if this.settings.showQuickSearchButtons "selected"}}
|
||||||
|
>
|
||||||
|
Yes
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="false"
|
||||||
|
selected={{unless
|
||||||
|
this.settings.showQuickSearchButtons
|
||||||
|
"selected"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="map-kinetic">Map Inertia (Kinetic Panning)</label>
|
||||||
|
<select
|
||||||
|
id="map-kinetic"
|
||||||
|
class="form-control"
|
||||||
|
{{on "change" this.toggleKinetic}}
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
value="true"
|
||||||
|
selected={{if this.settings.mapKinetic "selected"}}
|
||||||
|
>
|
||||||
|
On
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="false"
|
||||||
|
selected={{unless this.settings.mapKinetic "selected"}}
|
||||||
|
>
|
||||||
|
Off
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</template>
|
||||||
|
}
|
||||||
53
app/components/app-menu/settings/nostr.gjs
Normal file
53
app/components/app-menu/settings/nostr.gjs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { on } from '@ember/modifier';
|
||||||
|
import { service } from '@ember/service';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
import Icon from '#components/icon';
|
||||||
|
|
||||||
|
export default class AppMenuSettingsNostr extends Component {
|
||||||
|
@service settings;
|
||||||
|
|
||||||
|
@action
|
||||||
|
togglePhotoFallbackUploads(event) {
|
||||||
|
this.settings.updateNostrPhotoFallbackUploads(
|
||||||
|
event.target.value === 'true'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable no-nested-interactive }}
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<Icon @name="zap" @size={{20}} />
|
||||||
|
<span>Nostr</span>
|
||||||
|
</summary>
|
||||||
|
<div class="details-content">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="nostr-photo-fallback-uploads">Upload photos to fallback
|
||||||
|
servers</label>
|
||||||
|
<select
|
||||||
|
id="nostr-photo-fallback-uploads"
|
||||||
|
class="form-control"
|
||||||
|
{{on "change" this.togglePhotoFallbackUploads}}
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
value="true"
|
||||||
|
selected={{if this.settings.nostrPhotoFallbackUploads "selected"}}
|
||||||
|
>
|
||||||
|
Yes
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="false"
|
||||||
|
selected={{unless
|
||||||
|
this.settings.nostrPhotoFallbackUploads
|
||||||
|
"selected"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</template>
|
||||||
|
}
|
||||||
@@ -551,7 +551,10 @@ export default class PlaceDetails extends Component {
|
|||||||
|
|
||||||
{{#if this.isPhotoUploadModalOpen}}
|
{{#if this.isPhotoUploadModalOpen}}
|
||||||
<Modal @onClose={{this.closePhotoUploadModal}}>
|
<Modal @onClose={{this.closePhotoUploadModal}}>
|
||||||
<PlacePhotoUpload @place={{this.saveablePlace}} />
|
<PlacePhotoUpload
|
||||||
|
@place={{this.saveablePlace}}
|
||||||
|
@onClose={{this.closePhotoUploadModal}}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|||||||
@@ -183,11 +183,16 @@ export default class PlacePhotoUpload extends Component {
|
|||||||
const event = await factory.sign(template);
|
const event = await factory.sign(template);
|
||||||
await this.nostrRelay.publish(event);
|
await this.nostrRelay.publish(event);
|
||||||
|
|
||||||
this.status = 'Published successfully!';
|
this.toast.show('Photos published successfully');
|
||||||
|
this.status = '';
|
||||||
|
|
||||||
// Clear out the files so user can upload more or be done
|
// Clear out the files so user can upload more or be done
|
||||||
this.files = [];
|
this.files = [];
|
||||||
this.uploadedPhotos = [];
|
this.uploadedPhotos = [];
|
||||||
|
|
||||||
|
if (this.args.onClose) {
|
||||||
|
this.args.onClose();
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = 'Failed to publish: ' + e.message;
|
this.error = 'Failed to publish: ' + e.message;
|
||||||
this.status = '';
|
this.status = '';
|
||||||
|
|||||||
@@ -21,10 +21,17 @@ function getBlossomUrl(serverUrl, path) {
|
|||||||
export default class BlossomService extends Service {
|
export default class BlossomService extends Service {
|
||||||
@service nostrAuth;
|
@service nostrAuth;
|
||||||
@service nostrData;
|
@service nostrData;
|
||||||
|
@service settings;
|
||||||
|
|
||||||
get servers() {
|
get servers() {
|
||||||
const servers = this.nostrData.blossomServers;
|
const servers = this.nostrData.blossomServers;
|
||||||
return servers.length ? servers : [DEFAULT_BLOSSOM_SERVER];
|
const allServers = servers.length ? servers : [DEFAULT_BLOSSOM_SERVER];
|
||||||
|
|
||||||
|
if (!this.settings.nostrPhotoFallbackUploads) {
|
||||||
|
return [allServers[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return allServers;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _getAuthHeader(action, hash, serverUrl) {
|
async _getAuthHeader(action, hash, serverUrl) {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { EventStore } from 'applesauce-core/event-store';
|
|||||||
import { ProfileModel } from 'applesauce-core/models/profile';
|
import { ProfileModel } from 'applesauce-core/models/profile';
|
||||||
import { MailboxesModel } from 'applesauce-core/models/mailboxes';
|
import { MailboxesModel } from 'applesauce-core/models/mailboxes';
|
||||||
import { npubEncode } from 'applesauce-core/helpers/pointers';
|
import { npubEncode } from 'applesauce-core/helpers/pointers';
|
||||||
|
import { persistEventsToCache } from 'applesauce-core/helpers/event-cache';
|
||||||
|
import { NostrIDB, openDB } from 'nostr-idb';
|
||||||
|
|
||||||
const BOOTSTRAP_RELAYS = [
|
const BOOTSTRAP_RELAYS = [
|
||||||
'wss://purplepag.es',
|
'wss://purplepag.es',
|
||||||
@@ -26,10 +28,40 @@ export default class NostrDataService extends Service {
|
|||||||
_blossomSub = null;
|
_blossomSub = null;
|
||||||
|
|
||||||
_requestSub = null;
|
_requestSub = null;
|
||||||
|
_cachePromise = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
|
||||||
|
// Initialize the IndexedDB cache
|
||||||
|
this._cachePromise = openDB('applesauce-events').then(async (db) => {
|
||||||
|
this.cache = new NostrIDB(db, {
|
||||||
|
cacheIndexes: 1000,
|
||||||
|
maxEvents: 10000,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.cache.start();
|
||||||
|
|
||||||
|
// Automatically persist new events to the cache
|
||||||
|
this._stopPersisting = persistEventsToCache(
|
||||||
|
this.store,
|
||||||
|
async (events) => {
|
||||||
|
// Only cache profiles, mailboxes, and blossom servers
|
||||||
|
const toCache = events.filter(
|
||||||
|
(e) => e.kind === 0 || e.kind === 10002 || e.kind === 10063
|
||||||
|
);
|
||||||
|
|
||||||
|
if (toCache.length > 0) {
|
||||||
|
await Promise.all(toCache.map((event) => this.cache.add(event)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
batchTime: 1000, // Batch writes every 1 second
|
||||||
|
maxBatchSize: 100,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Feed events from the relay pool into the event store
|
// Feed events from the relay pool into the event store
|
||||||
this.nostrRelay.pool.relays$.subscribe(() => {
|
this.nostrRelay.pool.relays$.subscribe(() => {
|
||||||
// Setup relay subscription tracking if needed, or we just rely on request()
|
// Setup relay subscription tracking if needed, or we just rely on request()
|
||||||
@@ -63,24 +95,8 @@ export default class NostrDataService extends Service {
|
|||||||
|
|
||||||
const relayList = Array.from(relays);
|
const relayList = Array.from(relays);
|
||||||
|
|
||||||
// Request events and dump them into the store
|
// Setup models to track state reactively FIRST
|
||||||
this._requestSub = this.nostrRelay.pool
|
// This way, if cached events populate the store, the UI updates instantly.
|
||||||
.request(relayList, [
|
|
||||||
{
|
|
||||||
authors: [pubkey],
|
|
||||||
kinds: [0, 10002, 10063],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.subscribe({
|
|
||||||
next: (event) => {
|
|
||||||
this.store.add(event);
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.error('Error fetching profile events:', err);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Setup models to track state reactively
|
|
||||||
this._profileSub = this.store
|
this._profileSub = this.store
|
||||||
.model(ProfileModel, pubkey)
|
.model(ProfileModel, pubkey)
|
||||||
.subscribe((profileContent) => {
|
.subscribe((profileContent) => {
|
||||||
@@ -104,6 +120,43 @@ export default class NostrDataService extends Service {
|
|||||||
this.blossomServers = [];
|
this.blossomServers = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 1. Await cache initialization and populate the EventStore with local data
|
||||||
|
try {
|
||||||
|
await this._cachePromise;
|
||||||
|
|
||||||
|
const cachedEvents = await this.cache.query([
|
||||||
|
{
|
||||||
|
authors: [pubkey],
|
||||||
|
kinds: [0, 10002, 10063],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (cachedEvents && cachedEvents.length > 0) {
|
||||||
|
for (const event of cachedEvents) {
|
||||||
|
this.store.add(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to read from local Nostr IDB cache', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Request new events from the network in the background and dump them into the store
|
||||||
|
this._requestSub = this.nostrRelay.pool
|
||||||
|
.request(relayList, [
|
||||||
|
{
|
||||||
|
authors: [pubkey],
|
||||||
|
kinds: [0, 10002, 10063],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.subscribe({
|
||||||
|
next: (event) => {
|
||||||
|
this.store.add(event);
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('Error fetching profile events:', err);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get userDisplayName() {
|
get userDisplayName() {
|
||||||
@@ -154,5 +207,13 @@ export default class NostrDataService extends Service {
|
|||||||
willDestroy() {
|
willDestroy() {
|
||||||
super.willDestroy(...arguments);
|
super.willDestroy(...arguments);
|
||||||
this._cleanupSubscriptions();
|
this._cleanupSubscriptions();
|
||||||
|
|
||||||
|
if (this._stopPersisting) {
|
||||||
|
this._stopPersisting();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.cache) {
|
||||||
|
this.cache.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export default class SettingsService extends Service {
|
|||||||
@tracked mapKinetic = true;
|
@tracked mapKinetic = true;
|
||||||
@tracked photonApi = 'https://photon.komoot.io/api/';
|
@tracked photonApi = 'https://photon.komoot.io/api/';
|
||||||
@tracked showQuickSearchButtons = true;
|
@tracked showQuickSearchButtons = true;
|
||||||
|
@tracked nostrPhotoFallbackUploads = false;
|
||||||
|
|
||||||
overpassApis = [
|
overpassApis = [
|
||||||
{
|
{
|
||||||
@@ -64,6 +65,14 @@ export default class SettingsService extends Service {
|
|||||||
if (savedShowQuickSearch !== null) {
|
if (savedShowQuickSearch !== null) {
|
||||||
this.showQuickSearchButtons = savedShowQuickSearch === 'true';
|
this.showQuickSearchButtons = savedShowQuickSearch === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const savedNostrPhotoFallbackUploads = localStorage.getItem(
|
||||||
|
'marco:nostr-photo-fallback-uploads'
|
||||||
|
);
|
||||||
|
if (savedNostrPhotoFallbackUploads !== null) {
|
||||||
|
this.nostrPhotoFallbackUploads =
|
||||||
|
savedNostrPhotoFallbackUploads === 'true';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateOverpassApi(url) {
|
updateOverpassApi(url) {
|
||||||
@@ -84,4 +93,9 @@ export default class SettingsService extends Service {
|
|||||||
updatePhotonApi(url) {
|
updatePhotonApi(url) {
|
||||||
this.photonApi = url;
|
this.photonApi = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateNostrPhotoFallbackUploads(enabled) {
|
||||||
|
this.nostrPhotoFallbackUploads = enabled;
|
||||||
|
localStorage.setItem('marco:nostr-photo-fallback-uploads', String(enabled));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -595,7 +595,7 @@ body {
|
|||||||
display: block;
|
display: block;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.form-control {
|
||||||
@@ -967,6 +967,7 @@ abbr[title] {
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
margin: -6px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-logo-icon svg {
|
.app-logo-icon svg {
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
"blurhash": "^2.0.5",
|
"blurhash": "^2.0.5",
|
||||||
"ember-concurrency": "^5.2.0",
|
"ember-concurrency": "^5.2.0",
|
||||||
"ember-lifeline": "^7.0.0",
|
"ember-lifeline": "^7.0.0",
|
||||||
|
"nostr-idb": "^5.0.0",
|
||||||
"oauth2-pkce": "^2.1.3",
|
"oauth2-pkce": "^2.1.3",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"rxjs": "^7.8.2"
|
"rxjs": "^7.8.2"
|
||||||
|
|||||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -35,6 +35,9 @@ importers:
|
|||||||
ember-lifeline:
|
ember-lifeline:
|
||||||
specifier: ^7.0.0
|
specifier: ^7.0.0
|
||||||
version: 7.0.0(@ember/test-helpers@5.4.1(@babel/core@7.28.6))
|
version: 7.0.0(@ember/test-helpers@5.4.1(@babel/core@7.28.6))
|
||||||
|
nostr-idb:
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.0
|
||||||
oauth2-pkce:
|
oauth2-pkce:
|
||||||
specifier: ^2.1.3
|
specifier: ^2.1.3
|
||||||
version: 2.1.3
|
version: 2.1.3
|
||||||
@@ -3709,6 +3712,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
|
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
idb@8.0.3:
|
||||||
|
resolution: {integrity: sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==}
|
||||||
|
|
||||||
ignore@5.3.2:
|
ignore@5.3.2:
|
||||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
@@ -4405,6 +4411,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
nostr-idb@5.0.0:
|
||||||
|
resolution: {integrity: sha512-w5y4AnHefZIwCCL11NryfM2xp3U0Ka4qVNQEYAjnQbPwyoV+bZTdwuPXHCdRDWvhOFP2bZr1WBegcsAmkBjrxQ==}
|
||||||
|
|
||||||
nostr-signer-capacitor-plugin@0.0.5:
|
nostr-signer-capacitor-plugin@0.0.5:
|
||||||
resolution: {integrity: sha512-/EvqWz71HZ5cWmzvfXWTm48AWZtbeZDbOg3vLwXyXPjnIp1DR7Wurww/Mo41ORNu1DNPlqH20l7kIXKO6vR5og==}
|
resolution: {integrity: sha512-/EvqWz71HZ5cWmzvfXWTm48AWZtbeZDbOg3vLwXyXPjnIp1DR7Wurww/Mo41ORNu1DNPlqH20l7kIXKO6vR5og==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -10286,6 +10295,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safer-buffer: 2.1.2
|
safer-buffer: 2.1.2
|
||||||
|
|
||||||
|
idb@8.0.3: {}
|
||||||
|
|
||||||
ignore@5.3.2: {}
|
ignore@5.3.2: {}
|
||||||
|
|
||||||
ignore@7.0.5: {}
|
ignore@7.0.5: {}
|
||||||
@@ -11021,6 +11032,13 @@ snapshots:
|
|||||||
|
|
||||||
normalize-path@3.0.0: {}
|
normalize-path@3.0.0: {}
|
||||||
|
|
||||||
|
nostr-idb@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
idb: 8.0.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
nostr-signer-capacitor-plugin@0.0.5(@capacitor/core@7.6.2):
|
nostr-signer-capacitor-plugin@0.0.5(@capacitor/core@7.6.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@capacitor/core': 7.6.2
|
'@capacitor/core': 7.6.2
|
||||||
|
|||||||
Reference in New Issue
Block a user