geo-activity-playground 0.38.2__py3-none-any.whl → 0.39.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. geo_activity_playground/__main__.py +5 -47
  2. geo_activity_playground/alembic/README +1 -0
  3. geo_activity_playground/alembic/env.py +76 -0
  4. geo_activity_playground/alembic/script.py.mako +26 -0
  5. geo_activity_playground/alembic/versions/451e7836b53d_add_square_planner_bookmark.py +33 -0
  6. geo_activity_playground/alembic/versions/63d3b7f6f93c_initial_version.py +73 -0
  7. geo_activity_playground/alembic/versions/ab83b9d23127_add_upstream_id.py +28 -0
  8. geo_activity_playground/alembic/versions/b03491c593f6_add_crop_indices.py +30 -0
  9. geo_activity_playground/alembic/versions/e02e27876deb_add_square_planner_bookmark_name.py +28 -0
  10. geo_activity_playground/alembic/versions/script.py.mako +28 -0
  11. geo_activity_playground/core/activities.py +53 -136
  12. geo_activity_playground/core/config.py +3 -3
  13. geo_activity_playground/core/datamodel.py +257 -0
  14. geo_activity_playground/core/enrichment.py +90 -92
  15. geo_activity_playground/core/heart_rate.py +1 -2
  16. geo_activity_playground/core/parametric_plot.py +101 -0
  17. geo_activity_playground/core/paths.py +6 -7
  18. geo_activity_playground/core/raster_map.py +43 -4
  19. geo_activity_playground/core/similarity.py +1 -2
  20. geo_activity_playground/core/tasks.py +2 -2
  21. geo_activity_playground/core/test_meta_search.py +3 -3
  22. geo_activity_playground/core/test_summary_stats.py +1 -1
  23. geo_activity_playground/explorer/grid_file.py +2 -2
  24. geo_activity_playground/explorer/tile_visits.py +8 -10
  25. geo_activity_playground/heatmap_video.py +7 -8
  26. geo_activity_playground/importers/activity_parsers.py +2 -2
  27. geo_activity_playground/importers/directory.py +9 -10
  28. geo_activity_playground/importers/strava_api.py +9 -9
  29. geo_activity_playground/importers/strava_checkout.py +12 -13
  30. geo_activity_playground/importers/test_csv_parser.py +3 -3
  31. geo_activity_playground/importers/test_directory.py +1 -1
  32. geo_activity_playground/importers/test_strava_api.py +1 -1
  33. geo_activity_playground/webui/app.py +96 -86
  34. geo_activity_playground/webui/authenticator.py +1 -1
  35. geo_activity_playground/webui/{activity/controller.py → blueprints/activity_blueprint.py} +246 -108
  36. geo_activity_playground/webui/{auth_blueprint.py → blueprints/auth_blueprint.py} +1 -1
  37. geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +61 -0
  38. geo_activity_playground/webui/{calendar/controller.py → blueprints/calendar_blueprint.py} +19 -19
  39. geo_activity_playground/webui/{eddington_blueprint.py → blueprints/eddington_blueprint.py} +5 -5
  40. geo_activity_playground/webui/blueprints/entry_views.py +68 -0
  41. geo_activity_playground/webui/{equipment_blueprint.py → blueprints/equipment_blueprint.py} +37 -4
  42. geo_activity_playground/webui/{explorer/controller.py → blueprints/explorer_blueprint.py} +88 -54
  43. geo_activity_playground/webui/blueprints/heatmap_blueprint.py +233 -0
  44. geo_activity_playground/webui/blueprints/plot_builder_blueprint.py +43 -0
  45. geo_activity_playground/webui/{search_blueprint.py → blueprints/search_blueprint.py} +7 -11
  46. geo_activity_playground/webui/blueprints/settings_blueprint.py +446 -0
  47. geo_activity_playground/webui/{square_planner_blueprint.py → blueprints/square_planner_blueprint.py} +31 -6
  48. geo_activity_playground/webui/{summary_blueprint.py → blueprints/summary_blueprint.py} +11 -23
  49. geo_activity_playground/webui/blueprints/tile_blueprint.py +27 -0
  50. geo_activity_playground/webui/{upload_blueprint.py → blueprints/upload_blueprint.py} +13 -18
  51. geo_activity_playground/webui/flasher.py +26 -0
  52. geo_activity_playground/webui/plot_util.py +1 -1
  53. geo_activity_playground/webui/search_util.py +4 -6
  54. geo_activity_playground/webui/static/images/layers-2x.png +0 -0
  55. geo_activity_playground/webui/static/images/layers.png +0 -0
  56. geo_activity_playground/webui/static/images/marker-icon-2x.png +0 -0
  57. geo_activity_playground/webui/static/images/marker-icon.png +0 -0
  58. geo_activity_playground/webui/static/images/marker-shadow.png +0 -0
  59. geo_activity_playground/webui/templates/activity/day.html.j2 +81 -0
  60. geo_activity_playground/webui/templates/activity/edit.html.j2 +38 -0
  61. geo_activity_playground/webui/{activity/templates → templates}/activity/name.html.j2 +29 -27
  62. geo_activity_playground/webui/{activity/templates → templates}/activity/show.html.j2 +57 -33
  63. geo_activity_playground/webui/templates/activity/trim.html.j2 +68 -0
  64. geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +26 -0
  65. geo_activity_playground/webui/templates/calendar/index.html.j2 +48 -0
  66. geo_activity_playground/webui/templates/calendar/month.html.j2 +57 -0
  67. geo_activity_playground/webui/templates/equipment/index.html.j2 +7 -0
  68. geo_activity_playground/webui/templates/home.html.j2 +6 -6
  69. geo_activity_playground/webui/templates/page.html.j2 +2 -1
  70. geo_activity_playground/webui/templates/plot_builder/index.html.j2 +44 -0
  71. geo_activity_playground/webui/{settings/templates → templates}/settings/index.html.j2 +9 -20
  72. geo_activity_playground/webui/templates/settings/manage-equipments.html.j2 +49 -0
  73. geo_activity_playground/webui/templates/settings/manage-kinds.html.j2 +48 -0
  74. geo_activity_playground/webui/{settings/templates → templates}/settings/privacy-zones.html.j2 +2 -0
  75. geo_activity_playground/webui/{settings/templates → templates}/settings/strava.html.j2 +2 -0
  76. geo_activity_playground/webui/templates/square_planner/index.html.j2 +63 -13
  77. {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/METADATA +5 -1
  78. geo_activity_playground-0.39.1.dist-info/RECORD +136 -0
  79. geo_activity_playground/__init__.py +0 -0
  80. geo_activity_playground/core/__init__.py +0 -0
  81. geo_activity_playground/explorer/__init__.py +0 -0
  82. geo_activity_playground/importers/__init__.py +0 -0
  83. geo_activity_playground/webui/__init__.py +0 -0
  84. geo_activity_playground/webui/activity/__init__.py +0 -0
  85. geo_activity_playground/webui/activity/blueprint.py +0 -109
  86. geo_activity_playground/webui/activity/templates/activity/day.html.j2 +0 -80
  87. geo_activity_playground/webui/activity/templates/activity/edit.html.j2 +0 -42
  88. geo_activity_playground/webui/calendar/__init__.py +0 -0
  89. geo_activity_playground/webui/calendar/blueprint.py +0 -23
  90. geo_activity_playground/webui/calendar/templates/calendar/index.html.j2 +0 -46
  91. geo_activity_playground/webui/calendar/templates/calendar/month.html.j2 +0 -55
  92. geo_activity_playground/webui/entry_controller.py +0 -63
  93. geo_activity_playground/webui/explorer/__init__.py +0 -0
  94. geo_activity_playground/webui/explorer/blueprint.py +0 -62
  95. geo_activity_playground/webui/heatmap/__init__.py +0 -0
  96. geo_activity_playground/webui/heatmap/blueprint.py +0 -51
  97. geo_activity_playground/webui/heatmap/heatmap_controller.py +0 -216
  98. geo_activity_playground/webui/settings/blueprint.py +0 -262
  99. geo_activity_playground/webui/settings/controller.py +0 -272
  100. geo_activity_playground/webui/settings/templates/settings/equipment-offsets.html.j2 +0 -44
  101. geo_activity_playground/webui/settings/templates/settings/kind-renames.html.j2 +0 -25
  102. geo_activity_playground/webui/settings/templates/settings/kinds-without-achievements.html.j2 +0 -30
  103. geo_activity_playground/webui/tile_blueprint.py +0 -42
  104. geo_activity_playground-0.38.2.dist-info/RECORD +0 -129
  105. /geo_activity_playground/webui/{activity/templates → templates}/activity/lines.html.j2 +0 -0
  106. /geo_activity_playground/webui/{explorer/templates → templates}/explorer/index.html.j2 +0 -0
  107. /geo_activity_playground/webui/{heatmap/templates → templates}/heatmap/index.html.j2 +0 -0
  108. /geo_activity_playground/webui/{settings/templates → templates}/settings/admin-password.html.j2 +0 -0
  109. /geo_activity_playground/webui/{settings/templates → templates}/settings/color-schemes.html.j2 +0 -0
  110. /geo_activity_playground/webui/{settings/templates → templates}/settings/heart-rate.html.j2 +0 -0
  111. /geo_activity_playground/webui/{settings/templates → templates}/settings/metadata-extraction.html.j2 +0 -0
  112. /geo_activity_playground/webui/{settings/templates → templates}/settings/segmentation.html.j2 +0 -0
  113. /geo_activity_playground/webui/{settings/templates → templates}/settings/sharepic.html.j2 +0 -0
  114. {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/LICENSE +0 -0
  115. {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/WHEEL +0 -0
  116. {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/entry_points.txt +0 -0
@@ -1,11 +1,9 @@
1
- from typing import Optional
2
-
3
1
  from werkzeug.datastructures import MultiDict
4
2
 
5
- from geo_activity_playground.core.config import ConfigAccessor
6
- from geo_activity_playground.core.meta_search import _parse_date_or_none
7
- from geo_activity_playground.core.meta_search import SearchQuery
8
- from geo_activity_playground.webui.authenticator import Authenticator
3
+ from ..core.config import ConfigAccessor
4
+ from ..core.meta_search import _parse_date_or_none
5
+ from ..core.meta_search import SearchQuery
6
+ from .authenticator import Authenticator
9
7
 
10
8
 
11
9
  def search_query_from_form(args: MultiDict) -> SearchQuery:
@@ -0,0 +1,81 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+ <div class="row mb-3">
5
+ <div class="col">
6
+ <h1>{{ date }}</h1>
7
+ </div>
8
+ </div>
9
+
10
+
11
+ <div class="row mb-3">
12
+ <div class="col-12">
13
+ <div id="activity-map" style="height: 500px;"></div>
14
+ <script>
15
+ var map = L.map('activity-map', {
16
+ fullscreenControl: true
17
+ });
18
+ L.tileLayer('/tile/grayscale/{z}/{x}/{y}.png', {
19
+ maxZoom: 19,
20
+ attribution: '{{ map_tile_attribution|safe }}'
21
+ }).addTo(map);
22
+
23
+ let geojson = L.geoJSON({{ geojson| safe }}, {
24
+ style: function (feature) { return { color: feature.properties.color } }
25
+ }).addTo(map)
26
+ map.fitBounds(geojson.getBounds());
27
+ </script>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="row mb-3">
32
+ <div class="col">
33
+ <h2>Activities</h2>
34
+ <div class="table-responsive">
35
+ <table class="table table-sort table-arrows">
36
+ <thead>
37
+ <tr>
38
+ <th>Name</th>
39
+ <th>Date</th>
40
+ <th>Distance / km</th>
41
+ <th>Elapsed time</th>
42
+ <th>Speed / km/h</th>
43
+ <th>Equipment</th>
44
+ <th>Kind</th>
45
+ </tr>
46
+ </thead>
47
+ <tbody>
48
+ {% for activity in activities %}
49
+ <tr>
50
+ <td><span style="color: {{ activity['color'] }};">█</span> <a
51
+ href="{{ url_for('activity.show', id=activity.id) }}">{{
52
+ activity.name }}</a></td>
53
+ <td>{{ activity.start|dt }}</td>
54
+ <td>{{ activity.distance_km | round(1) }}</td>
55
+ <td>{{ activity.elapsed_time|td }}</td>
56
+ <td>{{ activity.average_speed_moving_kmh|round(1) }}</td>
57
+ <td>{{ activity["equipment"] }}</td>
58
+ <td>{{ activity["kind"] }}</td>
59
+ </tr>
60
+ {% endfor %}
61
+ {% if activities|length > 1 %}
62
+ <tr>
63
+ <td><b>Total</b></td>
64
+ <td></td>
65
+ <td><b>{{ total_distance | round(1) }}</b></td>
66
+ <td><b>{{ total_elapsed_time|td }}</b></td>
67
+ <td></td>
68
+ <td></td>
69
+ </tr>
70
+ {% endif %}
71
+ </tbody>
72
+ </table>
73
+ </div>
74
+ </div>
75
+ </div>
76
+
77
+ <h2>Share picture</h2>
78
+
79
+ <p><img class="img-fluid" src="{{ url_for('.day_sharepic', year=year, month=month, day=day) }}" /></p>
80
+
81
+ {% endblock %}
@@ -0,0 +1,38 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+
5
+ <h1 class="mb-3">Edit Activity</h1>
6
+
7
+ <form method="POST">
8
+ <div class="mb-3">
9
+ <label for="name" class="form-label">Name</label>
10
+ <input type="text" class="form-control" id="name" name="name" value="{{ activity.name }}" />
11
+ </div>
12
+
13
+ <div class="mb-3">
14
+ <label for="kind" class="form-label">Kind</label>
15
+ <select class="form-control" id="kind" name="kind">
16
+ <option value="null" {% if activity.kind==None %} selected {% endif %}>None</option>
17
+ {% for kind in kinds %}
18
+ <option value="{{ kind.id }}" {% if activity.kind==kind %} selected {% endif %}>{{ kind.name }}</option>
19
+ {% endfor %}
20
+ </select>
21
+ </div>
22
+
23
+ <div class="mb-3">
24
+ <label for="equipment" class="form-label">Equipment</label>
25
+ <select class="form-control" id="equipment" name="equipment">
26
+ <option value="null" {% if activity.equipment==None %} selected {% endif %}>None</option>
27
+ {% for equipment in equipments %}
28
+ <option value="{{ equipment.id }}" {% if activity.equipment==equipment %} selected {% endif %}>
29
+ {{ equipment.name }}
30
+ </option>
31
+ {% endfor %}
32
+ </select>
33
+ </div>
34
+
35
+ <button type="submit" class="btn btn-primary">Save</button>
36
+ </form>
37
+
38
+ {% endblock %}
@@ -50,33 +50,35 @@
50
50
  <div class="col">
51
51
  <h2>Activities</h2>
52
52
 
53
- <table class="table table-sort table-arrows">
54
- <thead>
55
- <tr>
56
- <th>Name</th>
57
- <th>Date</th>
58
- <th class="numeric-sort">Distance / km</th>
59
- <th>Elapsed time</th>
60
- <th>Speed / km/h</th>
61
- <th>Equipment</th>
62
- <th>Kind</th>
63
- </tr>
64
- </thead>
65
- <tbody>
66
- {% for activity in activities %}
67
- <tr>
68
- <td><span style="color: {{ activity['color'] }};">█</span> <a
69
- href="{{ url_for('activity.show', id=activity.id) }}">{{
70
- activity.name }}</a></td>
71
- <td>{{ activity.start|dt }}</td>
72
- <td>{{ activity.distance_km | round(1) }}</td>
73
- <td>{{ activity.elapsed_time|td }}</td>
74
- <td>{{ activity.average_speed_moving_kmh|round(1) }}</td>
75
- <td>{{ activity["equipment"] }}</td>
76
- <td>{{ activity["kind"] }}</td>
77
- </tr>
78
- {% endfor %}
79
- </tbody>
53
+ <div class="table-responsive">
54
+ <table class="table table-sort table-arrows">
55
+ <thead>
56
+ <tr>
57
+ <th>Name</th>
58
+ <th>Date</th>
59
+ <th class="numeric-sort">Distance / km</th>
60
+ <th>Elapsed time</th>
61
+ <th>Speed / km/h</th>
62
+ <th>Equipment</th>
63
+ <th>Kind</th>
64
+ </tr>
65
+ </thead>
66
+ <tbody>
67
+ {% for activity in activities %}
68
+ <tr>
69
+ <td><span style="color: {{ activity['color'] }};">█</span> <a
70
+ href="{{ url_for('activity.show', id=activity.id) }}">{{
71
+ activity.name }}</a></td>
72
+ <td>{{ activity.start|dt }}</td>
73
+ <td>{{ activity.distance_km | round(1) }}</td>
74
+ <td>{{ activity.elapsed_time|td }}</td>
75
+ <td>{{ activity.average_speed_moving_kmh|round(1) }}</td>
76
+ <td>{{ activity["equipment"] }}</td>
77
+ <td>{{ activity["kind"] }}</td>
78
+ </tr>
79
+ {% endfor %}
80
+ </tbody>
81
+ </table>
80
82
  </table>
81
83
  </div>
82
84
  </div>
@@ -12,16 +12,19 @@
12
12
  <dl>
13
13
  <dt>Name</dt>
14
14
  <dd>{{ activity["name"] }}</dd>
15
+
16
+ {% if activity.kind %}
15
17
  <dt>Kind</dt>
16
- <dd>{{ activity.kind }}</dd>
17
- <dt>Commute</dt>
18
- <dd>{{ activity.commute }}</dd>
18
+ <dd>{{ activity.kind.name }}</dd>
19
+ {% endif %}
20
+
19
21
  <dt>Distance</dt>
20
22
  <dd>{{ activity.distance_km|round(1) }} km</dd>
21
- <dt>Elapsed time</dt>
22
- <dd>{{ activity.elapsed_time|td }}</dd>
23
- <dt>Moving time</dt>
24
- <dd>{{ activity.moving_time|td }}</dd>
23
+
24
+ {% if activity.elapsed_time %}
25
+ <dt>Duration</dt>
26
+ <dd>{{ activity.elapsed_time|td }} elapsed, {{ activity.moving_time|td }} moving</dd>
27
+
25
28
  <dt>Average moving speed</dt>
26
29
  <dd>{{ activity.average_speed_moving_kmh|round(1) }} km/h = {{
27
30
  (60/activity.average_speed_moving_kmh)|round(1) }} min/km</dd>
@@ -32,27 +35,46 @@
32
35
  <dd><a href="{{ url_for('activity.day', year=date.year, month=date.month, day=date.day) }}">{{ date }}</a>
33
36
  {{ time }}
34
37
  </dd>
38
+ {% endif %}
39
+
40
+ {% if activity.calories %}
35
41
  <dt>Calories</dt>
36
42
  <dd>{{ activity.calories }}</dd>
43
+ {% endif %}
44
+
45
+ {% if activity.steps %}
37
46
  <dt>Steps</dt>
38
47
  <dd>{{ activity.steps }}</dd>
39
- {% if activity.elevation_gain is defined %}
48
+ {% endif %}
49
+
50
+ {% if activity.elevation_gain %}
40
51
  <dt>Elevation gain</dt>
41
52
  <dd>{{ activity.elevation_gain|round(0) }} m</dd>
42
53
  {% endif %}
54
+
55
+ {% if activity.equipment %}
43
56
  <dt>Equipment</dt>
44
- <dd>{{ activity['equipment'] }}</dd>
57
+ <dd>{{ activity.equipment.name }}</dd>
58
+ {% endif %}
59
+
60
+ {% if new_tiles[14] %}
45
61
  <dt>New Explorer Tiles</dt>
46
62
  <dd>{{ new_tiles[14] }}</dd>
63
+ {% endif %}
64
+
65
+ {% if new_tiles[17] %}
47
66
  <dt>New Squadratinhos</dt>
48
67
  <dd>{{ new_tiles[17] }}</dd>
68
+ {% endif %}
69
+
49
70
  <dt>ID</dt>
50
71
  <dd>{{ activity.id }}</dd>
51
72
  <dt>Source path</dt>
52
73
  <dd>{{ activity.path }}</dd>
53
74
  </dl>
54
75
 
55
- <a href="{{ url_for('.edit', id=activity['id']) }}" class="btn btn-secondary btn-small">Edit metadata</a>
76
+ <a href="{{ url_for('.edit', id=activity['id']) }}" class="btn btn-secondary btn-small">Edit</a>
77
+ <a href="{{ url_for('.trim', id=activity['id']) }}" class="btn btn-secondary btn-small">Trim</a>
56
78
  </div>
57
79
  <div class="col-sm-12 col-md-8">
58
80
  <div id="activity-map" style="height: 500px;" class="mb-3"></div>
@@ -207,29 +229,31 @@
207
229
 
208
230
  <p><a href="{{ url_for('.name', name=activity['name']) }}">Overview over these activities</a></p>
209
231
 
210
- <table class="table table-sort table-arrows">
211
- <thead>
212
- <tr>
213
- <th>Date</th>
214
- <th class="numeric-sort">Distance / km</th>
215
- <th>Elapsed time</th>
216
- <th>Equipment</th>
217
- <th>Kind</th>
218
- </tr>
219
- </thead>
220
- <tbody>
221
- {% for other_activity in similar_activites %}
222
- <tr>
223
- <td><a href="{{ url_for('.show', id=other_activity.id) }}">{{ other_activity.start|dt
224
- }}</a></td>
225
- <td>{{ other_activity.distance_km | round(1) }}</td>
226
- <td>{{ other_activity.elapsed_time|td }}</td>
227
- <td>{{ other_activity["equipment"] }}</td>
228
- <td>{{ other_activity["kind"] }}</td>
229
- </tr>
230
- {% endfor %}
231
- </tbody>
232
- </table>
232
+ <div class="table-responsive">
233
+ <table class="table table-sort table-arrows">
234
+ <thead>
235
+ <tr>
236
+ <th>Date</th>
237
+ <th class="numeric-sort">Distance / km</th>
238
+ <th>Elapsed time</th>
239
+ <th>Equipment</th>
240
+ <th>Kind</th>
241
+ </tr>
242
+ </thead>
243
+ <tbody>
244
+ {% for other_activity in similar_activites %}
245
+ <tr>
246
+ <td><a href="{{ url_for('.show', id=other_activity.id) }}">{{ other_activity.start|dt
247
+ }}</a></td>
248
+ <td>{{ other_activity.distance_km | round(1) }}</td>
249
+ <td>{{ other_activity.elapsed_time|td }}</td>
250
+ <td>{{ other_activity["equipment"] }}</td>
251
+ <td>{{ other_activity["kind"] }}</td>
252
+ </tr>
253
+ {% endfor %}
254
+ </tbody>
255
+ </table>
256
+ </div>
233
257
  </div>
234
258
  </div>
235
259
  {% endif %}
@@ -0,0 +1,68 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+ <div class="row mb-3">
5
+ <div class="col">
6
+ <h1>{{ activity["name"] }}</h1>
7
+ </div>
8
+ </div>
9
+
10
+ <a href="{{ url_for('.show', id=activity['id']) }}" class="btn btn-primary btn-small">Back</a>
11
+
12
+
13
+ <div id="activity-map" style="height: 600px;" class="mb-3"></div>
14
+ <script>
15
+ var map = L.map('activity-map', {
16
+ fullscreenControl: true
17
+ });
18
+ L.tileLayer('/tile/pastel/{z}/{x}/{y}.png', {
19
+ maxZoom: 19,
20
+ attribution: '{{ map_tile_attribution|safe }}'
21
+ }).addTo(map);
22
+
23
+
24
+ let layer = L.geoJSON({{ color_line_geojson| safe }}, {
25
+ pointToLayer: function (feature, lat_lon) {
26
+ let p = feature.properties
27
+
28
+ let marker = null
29
+ if (p.markerType == "circle") {
30
+ marker = L.circleMarker(lat_lon, p.markerStyle)
31
+ } else {
32
+ marker = L.marker(lat_lon)
33
+ }
34
+
35
+ let text = ''
36
+ if (p.name) {
37
+ text += `<p><b>${p.name}</b></p>`
38
+ }
39
+ if (p.description) {
40
+ text += p.description
41
+ }
42
+ if (text) {
43
+ marker = marker.bindPopup(text)
44
+ }
45
+
46
+ return marker
47
+ }
48
+ })
49
+
50
+ layer.addTo(map)
51
+ map.fitBounds(layer.getBounds());
52
+ </script>
53
+
54
+ <form method="POST">
55
+ <div class="mb-3">
56
+ <label for="begin" class="form-label">Begin</label>
57
+ <input type="number" class="form-control" id="begin" name="begin" value="{{ activity.index_begin }}" />
58
+ </div>
59
+
60
+ <div class="mb-3">
61
+ <label for="end" class="form-label">End</label>
62
+ <input type="number" class="form-control" id="end" name="end" value="{{ activity.index_end }}" />
63
+ </div>
64
+
65
+ <button type="submit" class="btn btn-primary">Save</button>
66
+ </form>
67
+
68
+ {% endblock %}
@@ -0,0 +1,26 @@
1
+ <!-- filepath: /home/michael/Nextcloud/Python/Geoactivity-Fork/geo-activity-playground/geo_activity_playground/webui/templates/bubble_chart/index.html.j2 -->
2
+ {% extends "page.html.j2" %}
3
+
4
+ {% block container %}
5
+ <div class="row mb-3">
6
+ <div class="col">
7
+ <h1>Bubble Chart</h1>
8
+ <div id="bubble-chart"></div>
9
+ <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
12
+ <script>
13
+ const chartSpec = {{ bubble_chart | safe }};
14
+ vegaEmbed('#bubble-chart', chartSpec).then((result) => {
15
+ // Add a click event listener to the chart
16
+ result.view.addEventListener('click', (event, item) => {
17
+ if (item && item.datum && item.datum.activity_url) {
18
+ // Redirect to the activity URL
19
+ window.location.href = item.datum.activity_url;
20
+ }
21
+ });
22
+ }).catch(console.error);
23
+ </script>
24
+ </div>
25
+ </div>
26
+ {% endblock %}
@@ -0,0 +1,48 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+ <div class="row mb-1">
5
+ <div class="col">
6
+ <h1>Calendar</h1>
7
+ </div>
8
+ </div>
9
+
10
+ <div class="row mb-1">
11
+ <div class="col">
12
+ <div class="table-responsive">
13
+ <table class="table">
14
+ <thead>
15
+ <tr>
16
+ <th>Year</th>
17
+ {% for i in range(1, 13) %}
18
+ <th style="text-align: right;">{{ i }}</th>
19
+ {% endfor %}
20
+ <th style="text-align: right;">Total</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ {% for year, month_data in monthly_distances.items() %}
25
+ {% set year_int = year|round(0)|int %}
26
+ <tr>
27
+ <td>{{ year_int }}</td>
28
+ {% for month in range(1, 13) %}
29
+ <td align="right">
30
+ {% set distance = month_data[month] %}
31
+ {% if distance %}
32
+ <a href="{{ url_for(".month", year=year_int, month=month) }}">{{ distance|int() }} km</a>
33
+ {% else %}
34
+ 0 km
35
+ {% endif %}
36
+ </td>
37
+ {% endfor %}
38
+ <td align="right">{{ yearly_distances[year]|int() }} km</td>
39
+ </tr>
40
+ {% endfor %}
41
+ </tbody>
42
+ </table>
43
+ </div>
44
+ </div>
45
+ </div>
46
+
47
+
48
+ {% endblock %}
@@ -0,0 +1,57 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+ <div class="row mb-1">
5
+ <div class="col">
6
+ <h1>Calendar {{ year }}-{{ "{0:02d}".format(month) }}</h1>
7
+ </div>
8
+ </div>
9
+
10
+ <div class="row mb-1">
11
+ <div class="col">
12
+ <div class="table-responsive">
13
+ <table class="table">
14
+ <thead>
15
+ <tr>
16
+ <th>Week</th>
17
+ <th>Monday</th>
18
+ <th>Tuesday</th>
19
+ <th>Wednesday</th>
20
+ <th>Thursday</th>
21
+ <th>Friday</th>
22
+ <th>Saturday</th>
23
+ <th>Sunday</th>
24
+ </tr>
25
+ </thead>
26
+ <tbody>
27
+ {% for week, week_data in weeks.items() %}
28
+ <tr>
29
+ <td>{{ week }}</td>
30
+ {% for day in range(1, 8) %}
31
+ <td>
32
+ {% if weeks[week][day] %}
33
+ <a href="{{ url_for('activity.day', year=year, month=month, day=day_of_month[week][day]) }}"><b>{{
34
+ day_of_month[week][day] }}.</b></a>
35
+ {% elif day_of_month[week][day] %}
36
+ <b>{{ day_of_month[week][day] }}.</b>
37
+ {% endif %}
38
+
39
+ {% if weeks[week][day] %}
40
+ <ul>
41
+ {% for activity in weeks[week][day] %}
42
+ <li><a href="{{ url_for('activity.show', id=activity.id) }}">{{ activity.name }}</a></li>
43
+ {% endfor %}
44
+ </ul>
45
+ {% endif %}
46
+ </td>
47
+ {% endfor %}
48
+ </tr>
49
+ {% endfor %}
50
+ </tbody>
51
+ </table>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+
57
+ {% endblock %}
@@ -32,6 +32,13 @@
32
32
  </div>
33
33
  </div>
34
34
 
35
+ <div class="row mb-3">
36
+ <div class="col">
37
+ <h2>Monthly Equipment Usage</h2>
38
+ {{ vega_direct("stacked_area_chart", stacked_area_chart) }}
39
+ </div>
40
+ </div>
41
+
35
42
  <div class="row mb-3">
36
43
  <div class="col">
37
44
  <h2>Details for each equipment</h2>
@@ -13,11 +13,6 @@
13
13
  </div>
14
14
 
15
15
 
16
- <div class="row mb-3">
17
- <div class="col">
18
- <h2>Latest activities</h2>
19
- </div>
20
- </div>
21
16
 
22
17
  <script>
23
18
  function add_map(id, geojson) {
@@ -35,7 +30,11 @@
35
30
  }
36
31
  </script>
37
32
 
38
- {% for activity_batch in latest_activities|batch(3) %}
33
+ <h2>Latest activities</h2>
34
+
35
+ {% for date, date_data in latest_activities.items() %}
36
+ <h3>{{ date }}</h3>
37
+ {% for activity_batch in date_data|batch(3) %}
39
38
  <div class="row row-cols-1 row-cols-md-3 g-4 mb-3">
40
39
  {% for elem in activity_batch %}
41
40
  <div class="col">
@@ -57,6 +56,7 @@
57
56
  {% endfor %}
58
57
  </div>
59
58
  {% endfor %}
59
+ {% endfor %}
60
60
  {% else %}
61
61
  <p>You don't have activities yet. Either put some files into a directory <tt>Activities</tt>, <a
62
62
  href="{{ url_for('upload.index') }}">upload activities</a> or <a href="{{ url_for('settings.strava') }}">set up
@@ -64,6 +64,7 @@
64
64
  <ul class="dropdown-menu">
65
65
  <li><a class="dropdown-item" href="{{ url_for('calendar.index') }}">Calendar</a></li>
66
66
  <li><a class="dropdown-item" href="{{ url_for('search.index') }}">Overview & Search</a>
67
+ <li><a class="dropdown-item" href="{{ url_for('bubble_chart.index') }}">Bubble Chart</a>
67
68
  </li>
68
69
  </ul>
69
70
  </li>
@@ -195,7 +196,7 @@
195
196
 
196
197
  <div class="row border-top py-3 my-4">
197
198
  <ul class="nav col-4">
198
- <li class="nav-item text-muted px-2 nav-link">Version {{ version }}</li>
199
+ <li class="nav-item px-2 nav-link"><a href="https://github.com/martin-ueding/geo-activity-playground/blob/main/docs/changelog.md" class="nav-link px-2 text-muted" target="_blank">Version {{ version }}</a></li>
199
200
  </ul>
200
201
  <ul class="nav col-8 justify-content-end">
201
202
  <li class="nav-item"><a href="https://github.com/martin-ueding/geo-activity-playground"