otripy 1.0.0__tar.gz
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.
- otripy-1.0.0/PKG-INFO +151 -0
- otripy-1.0.0/README.md +119 -0
- otripy-1.0.0/pyproject.toml +53 -0
- otripy-1.0.0/setup.cfg +4 -0
- otripy-1.0.0/src/otripy/__init__.py +1 -0
- otripy-1.0.0/src/otripy/config.py +84 -0
- otripy-1.0.0/src/otripy/journey.py +58 -0
- otripy-1.0.0/src/otripy/location.py +46 -0
- otripy-1.0.0/src/otripy/main.py +898 -0
- otripy-1.0.0/src/otripy/nextcloud.py +232 -0
- otripy-1.0.0/src/otripy/nextcloud_uuid.py +34 -0
- otripy-1.0.0/src/otripy/nextcloud_with_api.py +203 -0
- otripy-1.0.0/src/otripy/note_widget.py +122 -0
- otripy-1.0.0/src/otripy/rename_popup.py +41 -0
- otripy-1.0.0/src/otripy/search_popup.py +45 -0
- otripy-1.0.0/src/otripy/toolbar.py +249 -0
- otripy-1.0.0/src/otripy.egg-info/PKG-INFO +151 -0
- otripy-1.0.0/src/otripy.egg-info/SOURCES.txt +20 -0
- otripy-1.0.0/src/otripy.egg-info/dependency_links.txt +1 -0
- otripy-1.0.0/src/otripy.egg-info/entry_points.txt +2 -0
- otripy-1.0.0/src/otripy.egg-info/requires.txt +21 -0
- otripy-1.0.0/src/otripy.egg-info/top_level.txt +1 -0
otripy-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: otripy
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A tool to plan your next trip
|
|
5
|
+
Author-email: "Gaël de Chalendar (aka Kleag)" <kleagg@gmail.com>
|
|
6
|
+
License: AGPL
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: folium>=0.19.5
|
|
15
|
+
Requires-Dist: geopy>=2.4.1
|
|
16
|
+
Requires-Dist: lxml>=5.3.1
|
|
17
|
+
Requires-Dist: markdown>=3.7
|
|
18
|
+
Requires-Dist: nc-py-api>=0.19.0
|
|
19
|
+
Requires-Dist: numpy>=2.2.3
|
|
20
|
+
Requires-Dist: pillow>=11.1.0
|
|
21
|
+
Requires-Dist: pyside6>=6.8.2.1
|
|
22
|
+
Requires-Dist: typing-extensions>=4.12.2
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest; extra == "dev"
|
|
25
|
+
Requires-Dist: black; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff; extra == "dev"
|
|
27
|
+
Requires-Dist: mypy; extra == "dev"
|
|
28
|
+
Provides-Extra: build
|
|
29
|
+
Requires-Dist: bumpver; extra == "build"
|
|
30
|
+
Provides-Extra: deploy
|
|
31
|
+
Requires-Dist: uv; extra == "deploy"
|
|
32
|
+
|
|
33
|
+
# Otripy - An open trip planning tool
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/otripy)
|
|
37
|
+
[](https://github.com/kleag/otripy/blob/main/AGPL.md)
|
|
38
|
+
[](https://pepy.tech/project/otripy)
|
|
39
|
+
[](https://pypi.org/project/otripy)
|
|
40
|
+
[](https://github.com/kleag/otripy/graphs/contributors)
|
|
41
|
+
|
|
42
|
+
<!--
|
|
43
|
+

|
|
44
|
+

|
|
45
|
+
-->
|
|
46
|
+
|
|
47
|
+
## Description
|
|
48
|
+
|
|
49
|
+
Otripy is a GUI application for trip planning, providing an intuitive user interface for organizing travel visits efficiently. Otripy allows to plan a trip by adding markers on a map (based on OpenStreetMap) associated with a note.
|
|
50
|
+
|
|
51
|
+
Otripy is developed and daily tested on Linux. It should work on any platform. It has already been tested on MacOS.
|
|
52
|
+
|
|
53
|
+
Otripy is already usable but would be better with a lot of other features. Some wanted features are listed [here](https://github.com/kleag/otripy/issues). Don't hesitate to create a new issue if you think at other features. And contribute them if you can!
|
|
54
|
+
|
|
55
|
+
### Current features:
|
|
56
|
+
|
|
57
|
+
* Display OpenStreetMap map
|
|
58
|
+
* Zoom and pan the map
|
|
59
|
+
* Adding location markers on the map
|
|
60
|
+
* List existing location on the left part of the GUI
|
|
61
|
+
* Associate a note to a location. The first line of the note is used as the title in the list
|
|
62
|
+
* Search location by name, and add a new marker when selecting an entry in the list
|
|
63
|
+
* Delete markers
|
|
64
|
+
* Open and save local files
|
|
65
|
+
* Open and save files on any Nextcloud server you have access to
|
|
66
|
+
* Note text formatting (heading, bold, …)
|
|
67
|
+
* Image insertion (copy paste only currently)
|
|
68
|
+
|
|
69
|
+
## Screenshots
|
|
70
|
+
|
|
71
|
+

|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
### For users familiar with Python
|
|
76
|
+
|
|
77
|
+
Otripy is on PyPi. To install it, run:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
pip install otripy
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### For all others
|
|
84
|
+
|
|
85
|
+
If you are not used to installing Python packages, the simplest method is probably to use [uv](https://docs.astral.sh/uv/). Please [install it](https://docs.astral.sh/uv/getting-started/installation/) first. Then, open a terminal and create an uv virtual environment and activate it:
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
uv venv otripy
|
|
90
|
+
source otripy/bin/activate
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Then install Otripy and run it:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
uv pip install otripy
|
|
97
|
+
otripy
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Usage
|
|
101
|
+
|
|
102
|
+
To launch the application:
|
|
103
|
+
```bash
|
|
104
|
+
otripy
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Building and publishing
|
|
108
|
+
|
|
109
|
+
Otripy uses [uv](https://docs.astral.sh/uv/), please [install it](https://docs.astral.sh/uv/getting-started/installation/) if not already available.
|
|
110
|
+
|
|
111
|
+
If you just cloned this repository, cd to it and then:
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
uv venv
|
|
115
|
+
uv sync --all-extras
|
|
116
|
+
uv pip install -r pyproject.toml --extra build
|
|
117
|
+
install -d dist
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Then, to build and publish:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
rm dist/otripy-*
|
|
124
|
+
bumpver update --patch # or --minor or --major
|
|
125
|
+
uv build
|
|
126
|
+
uv publish
|
|
127
|
+
uv sync --all-extras
|
|
128
|
+
git add uv.lock
|
|
129
|
+
git commit -m "Update lock to new package version"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## Contributing
|
|
134
|
+
|
|
135
|
+
Contributions are welcome! Please follow these steps:
|
|
136
|
+
1. Fork the repository.
|
|
137
|
+
2. Create a new branch (`git checkout -b feature-name`).
|
|
138
|
+
3. Commit changes (`git commit -m "Add feature"`).
|
|
139
|
+
4. Push to your branch (`git push origin feature-name`).
|
|
140
|
+
5. Open a pull request.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
This project is Free Software, licensed under the AGPL License. See the [AGPL](https://github.com/kleag/otripy/blob/main/AGPL.md) file for details. In summary: you can use it, share it, change it, redistribute your changes, but any version you offer, with or without changes must be under the same (or a compatible) license.
|
|
144
|
+
|
|
145
|
+
## Credits
|
|
146
|
+
Otripy is developed and maintained by [Kleag](https://github.com/kleag). Special thanks to all contributors!
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
For more information, visit the [GitHub repository](https://github.com/kleag/otripy) or the [PyPI page](https://pypi.org/project/otripy/).
|
|
151
|
+
|
otripy-1.0.0/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Otripy - An open trip planning tool
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
[](https://pypi.org/project/otripy)
|
|
5
|
+
[](https://github.com/kleag/otripy/blob/main/AGPL.md)
|
|
6
|
+
[](https://pepy.tech/project/otripy)
|
|
7
|
+
[](https://pypi.org/project/otripy)
|
|
8
|
+
[](https://github.com/kleag/otripy/graphs/contributors)
|
|
9
|
+
|
|
10
|
+
<!--
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
-->
|
|
14
|
+
|
|
15
|
+
## Description
|
|
16
|
+
|
|
17
|
+
Otripy is a GUI application for trip planning, providing an intuitive user interface for organizing travel visits efficiently. Otripy allows to plan a trip by adding markers on a map (based on OpenStreetMap) associated with a note.
|
|
18
|
+
|
|
19
|
+
Otripy is developed and daily tested on Linux. It should work on any platform. It has already been tested on MacOS.
|
|
20
|
+
|
|
21
|
+
Otripy is already usable but would be better with a lot of other features. Some wanted features are listed [here](https://github.com/kleag/otripy/issues). Don't hesitate to create a new issue if you think at other features. And contribute them if you can!
|
|
22
|
+
|
|
23
|
+
### Current features:
|
|
24
|
+
|
|
25
|
+
* Display OpenStreetMap map
|
|
26
|
+
* Zoom and pan the map
|
|
27
|
+
* Adding location markers on the map
|
|
28
|
+
* List existing location on the left part of the GUI
|
|
29
|
+
* Associate a note to a location. The first line of the note is used as the title in the list
|
|
30
|
+
* Search location by name, and add a new marker when selecting an entry in the list
|
|
31
|
+
* Delete markers
|
|
32
|
+
* Open and save local files
|
|
33
|
+
* Open and save files on any Nextcloud server you have access to
|
|
34
|
+
* Note text formatting (heading, bold, …)
|
|
35
|
+
* Image insertion (copy paste only currently)
|
|
36
|
+
|
|
37
|
+
## Screenshots
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
### For users familiar with Python
|
|
44
|
+
|
|
45
|
+
Otripy is on PyPi. To install it, run:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
pip install otripy
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### For all others
|
|
52
|
+
|
|
53
|
+
If you are not used to installing Python packages, the simplest method is probably to use [uv](https://docs.astral.sh/uv/). Please [install it](https://docs.astral.sh/uv/getting-started/installation/) first. Then, open a terminal and create an uv virtual environment and activate it:
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
uv venv otripy
|
|
58
|
+
source otripy/bin/activate
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then install Otripy and run it:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
uv pip install otripy
|
|
65
|
+
otripy
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
70
|
+
To launch the application:
|
|
71
|
+
```bash
|
|
72
|
+
otripy
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Building and publishing
|
|
76
|
+
|
|
77
|
+
Otripy uses [uv](https://docs.astral.sh/uv/), please [install it](https://docs.astral.sh/uv/getting-started/installation/) if not already available.
|
|
78
|
+
|
|
79
|
+
If you just cloned this repository, cd to it and then:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
uv venv
|
|
83
|
+
uv sync --all-extras
|
|
84
|
+
uv pip install -r pyproject.toml --extra build
|
|
85
|
+
install -d dist
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Then, to build and publish:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
rm dist/otripy-*
|
|
92
|
+
bumpver update --patch # or --minor or --major
|
|
93
|
+
uv build
|
|
94
|
+
uv publish
|
|
95
|
+
uv sync --all-extras
|
|
96
|
+
git add uv.lock
|
|
97
|
+
git commit -m "Update lock to new package version"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## Contributing
|
|
102
|
+
|
|
103
|
+
Contributions are welcome! Please follow these steps:
|
|
104
|
+
1. Fork the repository.
|
|
105
|
+
2. Create a new branch (`git checkout -b feature-name`).
|
|
106
|
+
3. Commit changes (`git commit -m "Add feature"`).
|
|
107
|
+
4. Push to your branch (`git push origin feature-name`).
|
|
108
|
+
5. Open a pull request.
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
This project is Free Software, licensed under the AGPL License. See the [AGPL](https://github.com/kleag/otripy/blob/main/AGPL.md) file for details. In summary: you can use it, share it, change it, redistribute your changes, but any version you offer, with or without changes must be under the same (or a compatible) license.
|
|
112
|
+
|
|
113
|
+
## Credits
|
|
114
|
+
Otripy is developed and maintained by [Kleag](https://github.com/kleag). Special thanks to all contributors!
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
For more information, visit the [GitHub repository](https://github.com/kleag/otripy) or the [PyPI page](https://pypi.org/project/otripy/).
|
|
119
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "otripy"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "A tool to plan your next trip"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"folium>=0.19.5",
|
|
9
|
+
"geopy>=2.4.1",
|
|
10
|
+
"lxml>=5.3.1",
|
|
11
|
+
"markdown>=3.7",
|
|
12
|
+
"nc-py-api>=0.19.0",
|
|
13
|
+
"numpy>=2.2.3",
|
|
14
|
+
"pillow>=11.1.0",
|
|
15
|
+
"pyside6>=6.8.2.1",
|
|
16
|
+
"typing-extensions>=4.12.2",
|
|
17
|
+
]
|
|
18
|
+
authors = [{ name = "Gaël de Chalendar (aka Kleag)", email = "kleagg@gmail.com" }]
|
|
19
|
+
license = { text = "AGPL" }
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[tool.uv]
|
|
29
|
+
package = true
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
otripy = "otripy.main:main"
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
dev = ["pytest", "black", "ruff", "mypy"] # Development tools
|
|
36
|
+
build = ["bumpver"] # For packaging and uploading
|
|
37
|
+
deploy = ["uv"] # Add tools needed for deployment
|
|
38
|
+
|
|
39
|
+
[bumpver]
|
|
40
|
+
current_version = "1.0.0"
|
|
41
|
+
version_pattern = "MAJOR.MINOR.PATCH"
|
|
42
|
+
commit = true
|
|
43
|
+
tag = true
|
|
44
|
+
push = true # Set to true if you want to push automatically
|
|
45
|
+
|
|
46
|
+
[bumpver.file_patterns]
|
|
47
|
+
"pyproject.toml" = [
|
|
48
|
+
'version = "{version}"',
|
|
49
|
+
]
|
|
50
|
+
"src/otripy/__init__.py" = [
|
|
51
|
+
'__version__ = "{version}"',
|
|
52
|
+
]
|
|
53
|
+
|
otripy-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.0.0"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from PySide6.QtGui import QAction
|
|
2
|
+
from PySide6.QtWidgets import QApplication, QMainWindow, QDialog, QLabel, QLineEdit, QPushButton, QVBoxLayout, QMenuBar
|
|
3
|
+
from PySide6.QtCore import QSettings
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ConfigDialog(QDialog):
|
|
7
|
+
"""Dialog for configuring Nextcloud settings"""
|
|
8
|
+
def __init__(self, settings, parent=None):
|
|
9
|
+
super().__init__(parent)
|
|
10
|
+
self.settings = settings
|
|
11
|
+
self.setWindowTitle("Configure Otripy")
|
|
12
|
+
|
|
13
|
+
# Create widgets
|
|
14
|
+
self.url_label = QLabel("Nextcloud URL:")
|
|
15
|
+
self.url_input = QLineEdit()
|
|
16
|
+
|
|
17
|
+
self.username_label = QLabel("Nextcloud Username:")
|
|
18
|
+
self.username_input = QLineEdit()
|
|
19
|
+
|
|
20
|
+
self.password_label = QLabel("Nextcloud Password:")
|
|
21
|
+
self.password_input = QLineEdit()
|
|
22
|
+
self.password_input.setEchoMode(QLineEdit.Password) # Hide password
|
|
23
|
+
|
|
24
|
+
self.save_button = QPushButton("Save")
|
|
25
|
+
self.save_button.clicked.connect(self.save_settings)
|
|
26
|
+
|
|
27
|
+
# Layout
|
|
28
|
+
layout = QVBoxLayout()
|
|
29
|
+
layout.addWidget(self.url_label)
|
|
30
|
+
layout.addWidget(self.url_input)
|
|
31
|
+
layout.addWidget(self.username_label)
|
|
32
|
+
layout.addWidget(self.username_input)
|
|
33
|
+
layout.addWidget(self.password_label)
|
|
34
|
+
layout.addWidget(self.password_input)
|
|
35
|
+
layout.addWidget(self.save_button)
|
|
36
|
+
self.setLayout(layout)
|
|
37
|
+
|
|
38
|
+
# Load existing settings
|
|
39
|
+
self.load_settings()
|
|
40
|
+
|
|
41
|
+
def load_settings(self):
|
|
42
|
+
"""Load settings from QSettings"""
|
|
43
|
+
self.url_input.setText(self.settings.value("nextcloud/url", ""))
|
|
44
|
+
self.username_input.setText(self.settings.value("nextcloud/username", ""))
|
|
45
|
+
self.password_input.setText(self.settings.value("nextcloud/password", ""))
|
|
46
|
+
|
|
47
|
+
def save_settings(self):
|
|
48
|
+
"""Save settings to QSettings"""
|
|
49
|
+
self.settings.setValue("nextcloud/url", self.url_input.text())
|
|
50
|
+
self.settings.setValue("nextcloud/username", self.username_input.text())
|
|
51
|
+
self.settings.setValue("nextcloud/password", self.password_input.text())
|
|
52
|
+
self.accept() # Close the dialog
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class MainWindow(QMainWindow):
|
|
56
|
+
"""Main Application Window"""
|
|
57
|
+
def __init__(self):
|
|
58
|
+
super().__init__()
|
|
59
|
+
self.setWindowTitle("MyApp")
|
|
60
|
+
self.setGeometry(100, 100, 800, 600)
|
|
61
|
+
|
|
62
|
+
# QSettings initialization
|
|
63
|
+
self.settings = QSettings("Kleag", "Otripy")
|
|
64
|
+
|
|
65
|
+
# Menu bar
|
|
66
|
+
menubar = self.menuBar()
|
|
67
|
+
config_menu = menubar.addMenu("Configuration")
|
|
68
|
+
|
|
69
|
+
# Configuration action
|
|
70
|
+
config_action = QAction("Configure MyApp", self)
|
|
71
|
+
config_action.triggered.connect(self.open_config_dialog)
|
|
72
|
+
config_menu.addAction(config_action)
|
|
73
|
+
|
|
74
|
+
def open_config_dialog(self):
|
|
75
|
+
"""Open the configuration dialog"""
|
|
76
|
+
dialog = ConfigDialog(self.settings, self)
|
|
77
|
+
dialog.exec()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
app = QApplication([])
|
|
82
|
+
window = MainWindow()
|
|
83
|
+
window.show()
|
|
84
|
+
app.exec()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import List, Iterator
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from .location import Location
|
|
5
|
+
except ImportError:
|
|
6
|
+
from location import Location
|
|
7
|
+
|
|
8
|
+
class Journey:
|
|
9
|
+
def __init__(self, locations: List[Location] = None):
|
|
10
|
+
"""Initialize the journey with a list of Location objects."""
|
|
11
|
+
self._locations = locations if locations is not None else []
|
|
12
|
+
|
|
13
|
+
def __getitem__(self, index):
|
|
14
|
+
"""Enable indexing and slicing."""
|
|
15
|
+
return self._locations[index]
|
|
16
|
+
|
|
17
|
+
def __setitem__(self, index, value: Location):
|
|
18
|
+
"""Enable item assignment."""
|
|
19
|
+
if not isinstance(value, Location):
|
|
20
|
+
raise TypeError("Only Location instances can be added to the journey.")
|
|
21
|
+
self._locations[index] = value
|
|
22
|
+
|
|
23
|
+
def __delitem__(self, index):
|
|
24
|
+
"""Enable item deletion."""
|
|
25
|
+
del self._locations[index]
|
|
26
|
+
|
|
27
|
+
def __iter__(self) -> Iterator[Location]:
|
|
28
|
+
"""Enable iteration."""
|
|
29
|
+
return iter(self._locations)
|
|
30
|
+
|
|
31
|
+
def __len__(self) -> int:
|
|
32
|
+
"""Return the number of locations in the journey."""
|
|
33
|
+
return len(self._locations)
|
|
34
|
+
|
|
35
|
+
def append(self, location: Location):
|
|
36
|
+
"""Add a location to the journey."""
|
|
37
|
+
if not isinstance(location, Location):
|
|
38
|
+
raise TypeError("Only Location instances can be added to the journey.")
|
|
39
|
+
self._locations.append(location)
|
|
40
|
+
|
|
41
|
+
def insert(self, index: int, location: Location):
|
|
42
|
+
"""Insert a location at a specific index."""
|
|
43
|
+
if not isinstance(location, Location):
|
|
44
|
+
raise TypeError("Only Location instances can be inserted into the journey.")
|
|
45
|
+
self._locations.insert(index, location)
|
|
46
|
+
|
|
47
|
+
def remove(self, location: Location):
|
|
48
|
+
"""Remove a location from the journey."""
|
|
49
|
+
self._locations.remove(location)
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
return f"Journey({self._locations})"
|
|
53
|
+
|
|
54
|
+
def loc_by_id(self, id: str) -> Location:
|
|
55
|
+
for loc in self:
|
|
56
|
+
if loc.id == id:
|
|
57
|
+
return loc
|
|
58
|
+
return None
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
class Location:
|
|
9
|
+
def __init__(self,
|
|
10
|
+
lat: float = 0.0,
|
|
11
|
+
lon: float = 0.0,
|
|
12
|
+
note: Dict[str, str] = {"markdown": ""},
|
|
13
|
+
id: str = str(uuid.uuid4())):
|
|
14
|
+
logger.info(f"Location({lat}, {lon}, {note}, {id})")
|
|
15
|
+
self.id = id
|
|
16
|
+
self.lat = lat
|
|
17
|
+
self.lon = lon
|
|
18
|
+
self.note = note
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def from_data(cls, data: Dict[str, str | dict] = {}):
|
|
22
|
+
logger.info(f"Location.from_data({data})")
|
|
23
|
+
lat = float(data["lat"]) if "lat" in data else 0.0
|
|
24
|
+
lon = float(data["lon"]) if "lon" in data else 0.0
|
|
25
|
+
note = data["note"] if "note" in data else {"markdown": ""}
|
|
26
|
+
if type(note) is str:
|
|
27
|
+
note = {"markdown": note}
|
|
28
|
+
id = data["id"] if "id" in data else str(uuid.uuid4())
|
|
29
|
+
return cls(lat, lon, note, id)
|
|
30
|
+
|
|
31
|
+
def label(self):
|
|
32
|
+
return self.note["markdown"].split('\n')[0]
|
|
33
|
+
|
|
34
|
+
def to_html(self):
|
|
35
|
+
return self.note["markdown"].split('\n')[0].replace("\n", "<br>")
|
|
36
|
+
|
|
37
|
+
def location(self):
|
|
38
|
+
return [self.lat, self.lon]
|
|
39
|
+
|
|
40
|
+
def to_dict(self):
|
|
41
|
+
return {
|
|
42
|
+
"id": self.id,
|
|
43
|
+
"lat": self.lat,
|
|
44
|
+
"lon": self.lon,
|
|
45
|
+
"note": self.note
|
|
46
|
+
}
|