Skip to content

Commit

Permalink
refactoring: split all the states
Browse files Browse the repository at this point in the history
  • Loading branch information
pietervdvn committed Mar 25, 2023
1 parent 4d48b1c commit 8e2f04c
Show file tree
Hide file tree
Showing 32 changed files with 411 additions and 395 deletions.
2 changes: 1 addition & 1 deletion Logic/Actors/OverpassFeatureSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export default class OverpassFeatureSource implements FeatureSource {
if (typeof layer === "string") {
throw "A layer was not expanded!"
}
if (Constants.priviliged_layers.indexOf(layer.id) >= 0) {
if (layer.source === undefined) {
continue
}
if (this.state.locationControl.data.zoom < layer.minzoom) {
Expand Down
12 changes: 3 additions & 9 deletions Logic/Actors/TitleHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ import { ElementStorage } from "../ElementStorage"
import { Utils } from "../../Utils"

export default class TitleHandler {
constructor(state: {
selectedElement: Store<any>
layoutToUse: LayoutConfig
allElements: ElementStorage
}) {
const currentTitle: Store<string> = state.selectedElement.map(
constructor(selectedElement: Store<any>, layout: LayoutConfig, allElements: ElementStorage) {
const currentTitle: Store<string> = selectedElement.map(
(selected) => {
const layout = state.layoutToUse
const defaultTitle = layout?.title?.txt ?? "MapComplete"

if (selected === undefined) {
Expand All @@ -28,8 +23,7 @@ export default class TitleHandler {
}
if (layer.source.osmTags.matchesProperties(tags)) {
const tagsSource =
state.allElements.getEventSourceById(tags.id) ??
new UIEventSource<any>(tags)
allElements.getEventSourceById(tags.id) ?? new UIEventSource<any>(tags)
const title = new TagRenderingAnswer(tagsSource, layer.title, {})
return (
new Combine([defaultTitle, " | ", title]).ConstructElement()
Expand Down
2 changes: 1 addition & 1 deletion Logic/BBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export class BBox {
public asGeoJson<T>(properties: T): Feature<Polygon, T> {
return {
type: "Feature",
properties: properties,
properties,
geometry: this.asGeometry(),
}
}
Expand Down
40 changes: 1 addition & 39 deletions Logic/FeatureSource/FeaturePipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default class FeaturePipeline {
public readonly relationTracker: RelationsTracker
/**
* Keeps track of all raw OSM-nodes.
* Only initialized if 'type_node' is defined as layer
* Only initialized if `ReplaceGeometryAction` is needed somewhere
*/
public readonly fullNodeDatabase?: FullNodeDatabaseSource
private readonly overpassUpdater: OverpassFeatureSource
Expand Down Expand Up @@ -132,14 +132,6 @@ export default class FeaturePipeline {
// We do not mark as visited here, this is the responsability of the code near the actual loader (e.g. overpassLoader and OSMApiFeatureLoader)
}

function handlePriviligedFeatureSource(src: FeatureSourceForLayer & Tiled) {
// Passthrough to passed function, except that it registers as well
handleFeatureSource(src)
src.features.addCallbackAndRunD((fs) => {
fs.forEach((ff) => state.allElements.addOrGetElement(<any>ff))
})
}

for (const filteredLayer of state.filteredLayers.data) {
const id = filteredLayer.layerDef.id
const source = filteredLayer.layerDef.source
Expand All @@ -160,36 +152,6 @@ export default class FeaturePipeline {
continue
}

if (id === "selected_element") {
handlePriviligedFeatureSource(state.selectedElementsLayer)
continue
}

if (id === "gps_location") {
handlePriviligedFeatureSource(state.currentUserLocation)
continue
}

if (id === "gps_location_history") {
handlePriviligedFeatureSource(state.historicalUserLocations)
continue
}

if (id === "gps_track") {
handlePriviligedFeatureSource(state.historicalUserLocationsTrack)
continue
}

if (id === "home_location") {
handlePriviligedFeatureSource(state.homeLocation)
continue
}

if (id === "current_view") {
handlePriviligedFeatureSource(state.currentView)
continue
}

const localTileSaver = new SaveTileToLocalStorageActor(filteredLayer)
this.localStorageSavers.set(filteredLayer.layerDef.id, localTileSaver)

Expand Down
4 changes: 1 addition & 3 deletions Logic/State/FeaturePipelineState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import ScrollableFullScreen from "../../UI/Base/ScrollableFullScreen"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import ShowDataLayer from "../../UI/Map/ShowDataLayer"

export default class FeaturePipelineState extends MapState {
export default class FeaturePipelineState {
/**
* The piece of code which fetches data from various sources and shows it on the background map
*/
Expand All @@ -27,8 +27,6 @@ export default class FeaturePipelineState extends MapState {
>()

constructor(layoutToUse: LayoutConfig) {
super(layoutToUse)

const clustering = layoutToUse?.clustering
this.featureAggregator = TileHierarchyAggregator.createHierarchy(this)
const clusterCounter = this.featureAggregator
Expand Down
145 changes: 145 additions & 0 deletions Logic/State/LayerState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { UIEventSource } from "../UIEventSource"
import { GlobalFilter } from "../../Models/GlobalFilter"
import FilteredLayer, { FilterState } from "../../Models/FilteredLayer"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import { OsmConnection } from "../Osm/OsmConnection"
import { LocalStorageSource } from "../Web/LocalStorageSource"
import { QueryParameters } from "../Web/QueryParameters"

/**
* The layer state keeps track of:
* - Which layers are enabled
* - Which filters are used, including 'global' filters
*/
export default class LayerState {
/**
* Filters which apply onto all layers
*/
public readonly globalFilters: UIEventSource<GlobalFilter[]> = new UIEventSource(
[],
"globalFilters"
)

/**
* Which layers are enabled in the current theme and what filters are applied onto them
*/
public readonly filteredLayers: Map<string, FilteredLayer>
private readonly osmConnection: OsmConnection

/**
*
* @param osmConnection
* @param layers
* @param context: the context, probably the name of the theme. Used to disambiguate the upstream user preference
*/
constructor(osmConnection: OsmConnection, layers: LayerConfig[], context: string) {
this.osmConnection = osmConnection
this.filteredLayers = new Map()
for (const layer of layers) {
this.filteredLayers.set(layer.id, this.initFilteredLayer(layer, context))
}
layers.forEach((l) => this.linkFilterStates(l))
}

private static getPref(
osmConnection: OsmConnection,
key: string,
layer: LayerConfig
): UIEventSource<boolean> {
return osmConnection.GetPreference(key, layer.shownByDefault + "").sync(
(v) => {
if (v === undefined) {
return undefined
}
return v === "true"
},
[],
(b) => {
if (b === undefined) {
return undefined
}
return "" + b
}
)
}
/**
* INitializes a filtered layer for the given layer.
* @param layer
* @param context: probably the theme-name. This is used to disambiguate the user settings; e.g. when using the same layer in different contexts
* @private
*/
private initFilteredLayer(layer: LayerConfig, context: string): FilteredLayer | undefined {
let isDisplayed: UIEventSource<boolean>
const osmConnection = this.osmConnection
if (layer.syncSelection === "local") {
isDisplayed = LocalStorageSource.GetParsed(
context + "-layer-" + layer.id + "-enabled",
layer.shownByDefault
)
} else if (layer.syncSelection === "theme-only") {
isDisplayed = LayerState.getPref(
osmConnection,
context + "-layer-" + layer.id + "-enabled",
layer
)
} else if (layer.syncSelection === "global") {
isDisplayed = LayerState.getPref(osmConnection, "layer-" + layer.id + "-enabled", layer)
} else {
isDisplayed = QueryParameters.GetBooleanQueryParameter(
"layer-" + layer.id,
layer.shownByDefault,
"Wether or not layer " + layer.id + " is shown"
)
}

const flayer: FilteredLayer = {
isDisplayed,
layerDef: layer,
appliedFilters: new UIEventSource<Map<string, FilterState>>(
new Map<string, FilterState>()
),
}
layer.filters?.forEach((filterConfig) => {
const stateSrc = filterConfig.initState()

stateSrc.addCallbackAndRun((state) =>
flayer.appliedFilters.data.set(filterConfig.id, state)
)
flayer.appliedFilters
.map((dict) => dict.get(filterConfig.id))
.addCallback((state) => stateSrc.setData(state))
})

return flayer
}

/**
* Some layers copy the filter state of another layer - this is quite often the case for 'sibling'-layers,
* (where two variations of the same layer are used, e.g. a specific type of shop on all zoom levels and all shops on high zoom).
*
* This methods links those states for the given layer
*/
private linkFilterStates(layer: LayerConfig) {
if (layer.filterIsSameAs === undefined) {
return
}
const toReuse = this.filteredLayers.get(layer.filterIsSameAs)
if (toReuse === undefined) {
throw (
"Error in layer " +
layer.id +
": it defines that it should be use the filters of " +
layer.filterIsSameAs +
", but this layer was not loaded"
)
}
console.warn(
"Linking filter and isDisplayed-states of " + layer.id + " and " + layer.filterIsSameAs
)
this.filteredLayers.set(layer.id, {
isDisplayed: toReuse.isDisplayed,
layerDef: layer,
appliedFilters: toReuse.appliedFilters,
})
}
}
Loading

0 comments on commit 8e2f04c

Please sign in to comment.