Compare commits
30 Commits
v4.0.0-RC2
...
v4.0.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d3cdb7abb | ||
|
|
5b8670814b | ||
|
|
19acf11b1a | ||
|
|
39056d1d91 | ||
|
|
436c54b733 | ||
|
|
b48a42dcc8 | ||
|
|
e00e21c46a | ||
|
|
2aa821ee65 | ||
|
|
5ab0c39aa9 | ||
|
|
f09bbd3311 | ||
|
|
91589018a3 | ||
|
|
d41c9e1ed6 | ||
|
|
0cbd9a7a0b | ||
|
|
7db68ab2ad | ||
|
|
c7c53b5a68 | ||
|
|
9d2443b0f0 | ||
|
|
2c3ffd5e66 | ||
|
|
485eccb373 | ||
|
|
faf9a5293a | ||
|
|
e58cf4d206 | ||
|
|
1b48405c14 | ||
|
|
c8fcb2c3e0 | ||
|
|
ab8403c16e | ||
|
|
7929c23ac5 | ||
|
|
707cc001cf | ||
|
|
4594237c09 | ||
|
|
10607c88ea | ||
|
|
f61527ed70 | ||
|
|
4e7ebcc2f5 | ||
|
|
16e2668fe9 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,3 +6,6 @@ data/
|
|||||||
*.qtds
|
*.qtds
|
||||||
artemis_rc.py
|
artemis_rc.py
|
||||||
site
|
site
|
||||||
|
Generated
|
||||||
|
app.build
|
||||||
|
app.dist
|
||||||
|
|||||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -3,7 +3,19 @@
|
|||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
> This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## [Unreleased] - 2024-05-28
|
## [Unreleased]
|
||||||
|
|
||||||
|
|
||||||
|
## [4.0.3] - 2024-06-10
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Optimized final package size (reduced by 30% to 50%) by explicitly including necessary plugins/DLLs and excluding unnecessary ones with Nuitka [#47](https://github.com/AresValley/Artemis/issues/47)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- When the links/urls in the description field of a signal are clicked, they open the default browser [#46](https://github.com/AresValley/Artemis/issues/46)
|
||||||
|
- Fixed an error occurig on Linux where configuration file path are not properly resolved during startup with the binary version of the program (they are if running from source) [#48](https://github.com/AresValley/Artemis/issues/48)
|
||||||
|
|
||||||
|
## [4.0.1] - 2024-06-9
|
||||||
### Added
|
### Added
|
||||||
- Database format has been changed from .csv to a proper relational DB (sqlite) which is much easier handled thanks to the native library shipped with python
|
- Database format has been changed from .csv to a proper relational DB (sqlite) which is much easier handled thanks to the native library shipped with python
|
||||||
- Possibility to create an arbitrary number of new databases for storing new custom signals
|
- Possibility to create an arbitrary number of new databases for storing new custom signals
|
||||||
@@ -12,13 +24,18 @@
|
|||||||
- Databases can be exported/imported for easy sharing
|
- Databases can be exported/imported for easy sharing
|
||||||
- Possibility to store and view all type of documents related to a signal entry
|
- Possibility to store and view all type of documents related to a signal entry
|
||||||
- Filtration process is now much more efficient due to usage of SQL queries
|
- Filtration process is now much more efficient due to usage of SQL queries
|
||||||
|
- D-Region Absorption Predictions (DRAP) and Aurora OVATION model are now present in the Space Weather window
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Updated GUI libray from PyQt5 to PySide6. Artemis 4 now relies on the QtQuick framework.
|
- Updated GUI libray from PyQt5 to PySide6. Artemis 4 now relies on the QtQuick framework.
|
||||||
- Undefined value for frequency and bandwidth is now deprecated.
|
- SigID standard database is now hosted on GitHub (the server is much faster) along with the website parser
|
||||||
|
- Undefined value for frequency and bandwidth is now deprecated
|
||||||
- Drastically reduced the number of third party libraries
|
- Drastically reduced the number of third party libraries
|
||||||
- The signals filtering page has been simplified to be more immediate and user friendly
|
- The signals filtering page has been simplified to be more immediate and user friendly
|
||||||
- Space weather page now relies on Poseidon daemon (hosted on aresvalley.com)
|
- Space weather page has been greatly improved and now relies on Poseidon daemon (hosted on aresvalley.com)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Artemis can be execunted inside standard pretected folder (such as Program Files) without using elevated privileges
|
||||||
|
|
||||||
## [3.2.4] - 2022-09-30
|
## [3.2.4] - 2022-09-30
|
||||||
### Fixed
|
### Fixed
|
||||||
@@ -84,7 +101,9 @@ First release.
|
|||||||
|
|
||||||
|
|
||||||
<!-- Links definitions -->
|
<!-- Links definitions -->
|
||||||
[Unreleased]: https://github.com/AresValley/Artemis/compare/v3.2.4...HEAD
|
[Unreleased]: https://github.com/AresValley/Artemis/compare/v4.0.3...HEAD
|
||||||
|
[4.0.1]: https://github.com/AresValley/Artemis/compare/v4.0.1...v4.0.3
|
||||||
|
[4.0.1]: https://github.com/AresValley/Artemis/compare/v3.2.4...v4.0.1
|
||||||
[3.2.4]: https://github.com/AresValley/Artemis/compare/v3.2.1...v3.2.4
|
[3.2.4]: https://github.com/AresValley/Artemis/compare/v3.2.1...v3.2.4
|
||||||
[3.2.3]: https://github.com/AresValley/Artemis/compare/v3.2.2...v3.2.3
|
[3.2.3]: https://github.com/AresValley/Artemis/compare/v3.2.2...v3.2.3
|
||||||
[3.2.2]: https://github.com/AresValley/Artemis/compare/v3.2.1...v3.2.2
|
[3.2.2]: https://github.com/AresValley/Artemis/compare/v3.2.1...v3.2.2
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
**Artemis** is a software designed to assist **radio frequency (RF) signal identification and storage**. It simplifies real-time spectrum analysis by leveraging one of the most extensive and community-driven databases, containing nearly **500 recognized signals**. This comprehensive software solution allows users to collect RF signals with specific parameters such as frequency, bandwidth, modulation, etc. Users can also store spectrum waterfalls, audio samples, and all types of documents for future reference. Artemis provides a robust platform to manage a wide range of RF data with precision and ease.
|
**Artemis** is a software designed to assist **radio frequency (RF) signal identification and storage**. It simplifies real-time spectrum analysis by leveraging one of the most extensive and community-driven databases, containing nearly **500 recognized signals**. This comprehensive software solution allows users to collect RF signals with specific parameters such as frequency, bandwidth, modulation, etc. Users can also store spectrum waterfalls, audio samples, and all types of documents for future reference. Artemis provides a robust platform to manage a wide range of RF data with precision and ease.
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="docs/assets/artemis_preview.png">
|
<img src="docs/assets/artemis_preview.webp">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<file>images/icons/player_play.svg</file>
|
<file>images/icons/player_play.svg</file>
|
||||||
<file>images/icons/player_stop.svg</file>
|
<file>images/icons/player_stop.svg</file>
|
||||||
<file>images/icons/player_loop.svg</file>
|
<file>images/icons/player_loop.svg</file>
|
||||||
|
<file>images/icons/player_mute.svg</file>
|
||||||
<file>images/icons/save.svg</file>
|
<file>images/icons/save.svg</file>
|
||||||
<file>images/icons/delete.svg</file>
|
<file>images/icons/delete.svg</file>
|
||||||
<file>images/icons/add.svg</file>
|
<file>images/icons/add.svg</file>
|
||||||
|
|||||||
2913
artemis/resources.py
2913
artemis/resources.py
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,13 @@ from PySide6.QtQml import QQmlApplicationEngine
|
|||||||
from PySide6.QtCore import QObject, Slot, Signal
|
from PySide6.QtCore import QObject, Slot, Signal
|
||||||
|
|
||||||
from artemis.utils.constants import Constants, Messages
|
from artemis.utils.constants import Constants, Messages
|
||||||
from artemis.utils.sys_utils import open_directory, pack_db, unpack_db
|
from artemis.utils.sys_utils import open_directory, make_tar, unpack_tar
|
||||||
from artemis.utils.sql_utils import ArtemisDatabase, ArtemisSignal
|
from artemis.utils.sql_utils import ArtemisDatabase, ArtemisSignal
|
||||||
from artemis.utils.path_utils import check_data_dir
|
from artemis.utils.path_utils import DATA_DIR
|
||||||
from artemis.utils.network_utils import NetworkManager
|
from artemis.utils.network_utils import NetworkManager
|
||||||
from artemis.utils.generic_utils import generate_filter_query
|
from artemis.utils.generic_utils import generate_filter_query
|
||||||
from artemis.utils.path_utils import normalize_dialog_path
|
from artemis.utils.path_utils import normalize_dialog_path
|
||||||
|
from artemis.utils.config_utils import CONFIGURE_QT
|
||||||
|
|
||||||
from artemis.ui.preferences import UIPreferences
|
from artemis.ui.preferences import UIPreferences
|
||||||
from artemis.ui.dbmanager import UIdbmanager
|
from artemis.ui.dbmanager import UIdbmanager
|
||||||
@@ -69,7 +70,7 @@ class UIArtemis(QObject):
|
|||||||
|
|
||||||
self.network_manager = NetworkManager(self)
|
self.network_manager = NetworkManager(self)
|
||||||
|
|
||||||
check_data_dir()
|
self.autoload_db()
|
||||||
|
|
||||||
|
|
||||||
def _connect(self):
|
def _connect(self):
|
||||||
@@ -277,7 +278,7 @@ class UIArtemis(QObject):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
dest_path = normalize_dialog_path(save_path)
|
dest_path = normalize_dialog_path(save_path)
|
||||||
pack_db(dest_path, self.loaded_db.db_dir)
|
make_tar(dest_path, self.loaded_db.db_dir)
|
||||||
self.dialog_popup(
|
self.dialog_popup(
|
||||||
Messages.DIALOG_TYPE_INFO,
|
Messages.DIALOG_TYPE_INFO,
|
||||||
Messages.GENERIC_SUCCESS,
|
Messages.GENERIC_SUCCESS,
|
||||||
@@ -300,7 +301,8 @@ class UIArtemis(QObject):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
origin_path = normalize_dialog_path(tar_path)
|
origin_path = normalize_dialog_path(tar_path)
|
||||||
unpack_db(origin_path, str(uuid.uuid4()))
|
save_path = DATA_DIR / str(uuid.uuid4())
|
||||||
|
unpack_tar(origin_path, save_path)
|
||||||
self.dialog_popup(
|
self.dialog_popup(
|
||||||
Messages.DIALOG_TYPE_INFO,
|
Messages.DIALOG_TYPE_INFO,
|
||||||
Messages.GENERIC_SUCCESS,
|
Messages.GENERIC_SUCCESS,
|
||||||
@@ -332,6 +334,13 @@ class UIArtemis(QObject):
|
|||||||
self.cateditor.load_cateditor_ui()
|
self.cateditor.load_cateditor_ui()
|
||||||
|
|
||||||
|
|
||||||
|
def autoload_db(self):
|
||||||
|
sig_id_path = DATA_DIR / 'SigID' / Constants.SQL_NAME
|
||||||
|
autoload = CONFIGURE_QT.value("Database", "autoload", 0)
|
||||||
|
if sig_id_path.exists() and int(autoload):
|
||||||
|
self.load_db('SigID')
|
||||||
|
|
||||||
|
|
||||||
def dialog_popup(self, message_type, title, message):
|
def dialog_popup(self, message_type, title, message):
|
||||||
""" Opens a general dialog popup
|
""" Opens a general dialog popup
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
from PySide6.QtQml import QQmlApplicationEngine
|
from PySide6.QtQml import QQmlApplicationEngine
|
||||||
from PySide6.QtCore import QObject, Signal, Slot
|
from PySide6.QtCore import QObject, Signal, Slot
|
||||||
|
|
||||||
from artemis.utils.path_utils import *
|
from artemis.utils.path_utils import DATA_DIR
|
||||||
from artemis.utils.generic_utils import *
|
from artemis.utils.generic_utils import *
|
||||||
from artemis.utils.sql_utils import ArtemisDatabase
|
from artemis.utils.sql_utils import ArtemisDatabase
|
||||||
from artemis.utils.constants import Constants
|
from artemis.utils.constants import Constants
|
||||||
|
from artemis.utils.sys_utils import delete_dir
|
||||||
|
|
||||||
|
|
||||||
class UIdbmanager(QObject):
|
class UIdbmanager(QObject):
|
||||||
@@ -67,7 +70,7 @@ class UIdbmanager(QObject):
|
|||||||
self._parent.lock_menu.emit(True)
|
self._parent.lock_menu.emit(True)
|
||||||
self._parent.clear_list.emit()
|
self._parent.clear_list.emit()
|
||||||
self._parent.clear_signal_page.emit()
|
self._parent.clear_signal_page.emit()
|
||||||
delete_db_dir(db_dir_name)
|
delete_dir(DATA_DIR / db_dir_name)
|
||||||
self.load_local_db_list()
|
self.load_local_db_list()
|
||||||
|
|
||||||
|
|
||||||
@@ -85,10 +88,10 @@ class UIdbmanager(QObject):
|
|||||||
return a dictionary containing only the valid ones with a summary
|
return a dictionary containing only the valid ones with a summary
|
||||||
"""
|
"""
|
||||||
valid_db_list = []
|
valid_db_list = []
|
||||||
db_dirs = next(os.walk(Constants.DB_DIR))[1]
|
db_dirs = next(os.walk(DATA_DIR))[1]
|
||||||
|
|
||||||
for db_dir_name in db_dirs:
|
for db_dir_name in db_dirs:
|
||||||
if valid_db(db_dir_name):
|
if self._valid_db(db_dir_name):
|
||||||
database = ArtemisDatabase(db_dir_name)
|
database = ArtemisDatabase(db_dir_name)
|
||||||
database.load()
|
database.load()
|
||||||
valid_db_list.append(
|
valid_db_list.append(
|
||||||
@@ -103,3 +106,22 @@ class UIdbmanager(QObject):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return valid_db_list
|
return valid_db_list
|
||||||
|
|
||||||
|
|
||||||
|
def _valid_db(self, db_dir_name):
|
||||||
|
""" Checks if db_dir_name is a valid db dir containing a `data.sqlite` file.
|
||||||
|
Db must be valid as well and should be properly initialized and loaded with
|
||||||
|
no errors.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db_dir_name (str): name of the db folder
|
||||||
|
"""
|
||||||
|
if os.path.exists(DATA_DIR / db_dir_name / Constants.SQL_NAME):
|
||||||
|
try:
|
||||||
|
database = ArtemisDatabase(db_dir_name)
|
||||||
|
database.load()
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False # Invalid or corrupted DB
|
||||||
|
else:
|
||||||
|
return False # The dir is not containing a data.sqlite file
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ from PySide6.QtCore import QObject, Slot, Signal, QUrl, QSaveFile, QDir, QIODevi
|
|||||||
from PySide6.QtNetwork import QNetworkReply, QNetworkRequest, QNetworkAccessManager
|
from PySide6.QtNetwork import QNetworkReply, QNetworkRequest, QNetworkAccessManager
|
||||||
|
|
||||||
from artemis.utils.config_utils import *
|
from artemis.utils.config_utils import *
|
||||||
from artemis.utils.sys_utils import delete_file, match_hash, unpack_db
|
from artemis.utils.sys_utils import delete_file, delete_dir, match_hash, unpack_tar
|
||||||
from artemis.utils.constants import Messages
|
from artemis.utils.constants import Messages
|
||||||
from artemis.utils.sys_utils import delete_db_dir
|
from artemis.utils.path_utils import DATA_DIR
|
||||||
|
|
||||||
|
|
||||||
class UIDownloader(QObject):
|
class UIDownloader(QObject):
|
||||||
# Python > QML Signals
|
# Python > QML Signals
|
||||||
show_ui = Signal()
|
show_ui = Signal()
|
||||||
close_ui = Signal()
|
close_ui = Signal()
|
||||||
|
update_progress_bar = Signal(int, int)
|
||||||
|
update_status = Signal(str)
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -21,8 +24,6 @@ class UIDownloader(QObject):
|
|||||||
self._engine = QQmlApplicationEngine()
|
self._engine = QQmlApplicationEngine()
|
||||||
self._engine.load('qrc:/ui/Downloader.qml')
|
self._engine.load('qrc:/ui/Downloader.qml')
|
||||||
self._window = self._engine.rootObjects()[0]
|
self._window = self._engine.rootObjects()[0]
|
||||||
self._progress_bar = self._window.findChild(QObject, "progressBar")
|
|
||||||
self._label_progress = self._window.findChild(QObject, "labelProgress")
|
|
||||||
|
|
||||||
self._connect()
|
self._connect()
|
||||||
|
|
||||||
@@ -34,6 +35,8 @@ class UIDownloader(QObject):
|
|||||||
# Python > QML connections
|
# Python > QML connections
|
||||||
self.show_ui.connect(self._window.show)
|
self.show_ui.connect(self._window.show)
|
||||||
self.close_ui.connect(self._window.close)
|
self.close_ui.connect(self._window.close)
|
||||||
|
self.update_progress_bar.connect(self._window.updateProgressBar)
|
||||||
|
self.update_status.connect(self._window.updateStatus)
|
||||||
|
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
@@ -42,7 +45,7 @@ class UIDownloader(QObject):
|
|||||||
the attributes of the UpdatesController class
|
the attributes of the UpdatesController class
|
||||||
"""
|
"""
|
||||||
url_file = QUrl(self._parent.network_manager.remote_db_url)
|
url_file = QUrl(self._parent.network_manager.remote_db_url)
|
||||||
dest_path = QDir(Constants.DB_DIR)
|
dest_path = QDir(DATA_DIR)
|
||||||
self.dest_file = dest_path.filePath(url_file.fileName())
|
self.dest_file = dest_path.filePath(url_file.fileName())
|
||||||
self.file = QSaveFile(self.dest_file)
|
self.file = QSaveFile(self.dest_file)
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ class UIDownloader(QObject):
|
|||||||
""" Stop the download when user press abort button """
|
""" Stop the download when user press abort button """
|
||||||
if self.reply:
|
if self.reply:
|
||||||
self.reply.abort()
|
self.reply.abort()
|
||||||
self._progress_bar.setProperty("value", 0)
|
self.update_progress_bar.emit(0, 0)
|
||||||
|
|
||||||
if self.file:
|
if self.file:
|
||||||
self.file.cancelWriting()
|
self.file.cancelWriting()
|
||||||
@@ -93,12 +96,12 @@ class UIDownloader(QObject):
|
|||||||
if self.file:
|
if self.file:
|
||||||
self.file.commit()
|
self.file.commit()
|
||||||
|
|
||||||
self._label_progress.setProperty("text", "Checking DB integrity (SHA-256)")
|
self.update_status.emit("Checking DB integrity (SHA-256)")
|
||||||
|
|
||||||
if match_hash(self.dest_file, self._parent.network_manager.remote_db_hash):
|
if match_hash(self.dest_file, self._parent.network_manager.remote_db_hash):
|
||||||
self._label_progress.setProperty("text", "Unpacking archive...")
|
self.update_status.emit("Unpacking archive...")
|
||||||
delete_db_dir('SigID')
|
delete_dir(DATA_DIR / 'SigID')
|
||||||
unpack_db(self.dest_file, 'SigID')
|
unpack_tar(self.dest_file, DATA_DIR / 'SigID')
|
||||||
delete_file(self.dest_file)
|
delete_file(self.dest_file)
|
||||||
self._parent.load_db('SigID')
|
self._parent.load_db('SigID')
|
||||||
self.close_ui.emit()
|
self.close_ui.emit()
|
||||||
@@ -109,9 +112,8 @@ class UIDownloader(QObject):
|
|||||||
""" Update progress bar and label
|
""" Update progress bar and label
|
||||||
"""
|
"""
|
||||||
total_bytes = self._parent.network_manager.remote_db_size
|
total_bytes = self._parent.network_manager.remote_db_size
|
||||||
self._label_progress.setProperty("text", "{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, total_bytes/10**6))
|
self.update_status.emit("{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, total_bytes/10**6))
|
||||||
self._progress_bar.setProperty("to", total_bytes)
|
self.update_progress_bar.emit(bytesReceived, total_bytes)
|
||||||
self._progress_bar.setProperty("value", bytesReceived)
|
|
||||||
|
|
||||||
|
|
||||||
@Slot(QNetworkReply.NetworkError)
|
@Slot(QNetworkReply.NetworkError)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class UIPreferences(QObject):
|
|||||||
show_ui = Signal()
|
show_ui = Signal()
|
||||||
load_material_accent = Signal(str)
|
load_material_accent = Signal(str)
|
||||||
load_material_theme = Signal(str)
|
load_material_theme = Signal(str)
|
||||||
|
load_autoload = Signal(int)
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
@@ -27,18 +28,21 @@ class UIPreferences(QObject):
|
|||||||
# QML > Python connections
|
# QML > Python connections
|
||||||
self._window.saveMaterialAccent.connect(self.save_material_accent)
|
self._window.saveMaterialAccent.connect(self.save_material_accent)
|
||||||
self._window.saveMaterialTheme.connect(self.save_material_theme)
|
self._window.saveMaterialTheme.connect(self.save_material_theme)
|
||||||
|
self._window.saveAutoload.connect(self.save_autoload)
|
||||||
|
|
||||||
# Python > QML connections
|
# Python > QML connections
|
||||||
self.show_ui.connect(self._window.show)
|
self.show_ui.connect(self._window.show)
|
||||||
self.load_material_accent.connect(self._window.loadMaterialAccent)
|
self.load_material_accent.connect(self._window.loadMaterialAccent)
|
||||||
self.load_material_theme.connect(self._window.loadMaterialTheme)
|
self.load_material_theme.connect(self._window.loadMaterialTheme)
|
||||||
|
self.load_autoload.connect(self._window.loadAutoload)
|
||||||
|
|
||||||
|
|
||||||
def load_preferences_ui(self):
|
def load_preferences_ui(self):
|
||||||
""" Loading all the initial preferences from the conf file to the UI
|
""" Loading all the initial preferences from the conf file to the UI
|
||||||
"""
|
"""
|
||||||
self.load_material_accent.emit(CONFIGURE_QT.get_or_default("Material", "Accent", "Green"))
|
self.load_material_accent.emit(CONFIGURE_QT.value("Material", "Accent", "Green"))
|
||||||
self.load_material_theme.emit(CONFIGURE_QT.get_or_default("Material", "Theme", "System"))
|
self.load_material_theme.emit(CONFIGURE_QT.value("Material", "Theme", "System"))
|
||||||
|
self.load_autoload.emit(int(CONFIGURE_QT.value("Database", "autoload", 0)))
|
||||||
self.show_ui.emit()
|
self.show_ui.emit()
|
||||||
|
|
||||||
|
|
||||||
@@ -54,3 +58,10 @@ class UIPreferences(QObject):
|
|||||||
""" Saving material theme setting
|
""" Saving material theme setting
|
||||||
"""
|
"""
|
||||||
CONFIGURE_QT.set("Material", "Theme", material_theme)
|
CONFIGURE_QT.set("Material", "Theme", material_theme)
|
||||||
|
|
||||||
|
|
||||||
|
@Slot(int)
|
||||||
|
def save_autoload(self, autoload):
|
||||||
|
""" Saving autoload setting
|
||||||
|
"""
|
||||||
|
CONFIGURE_QT.set("Database", "autoload", str(autoload))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from PySide6.QtCore import QObject, Signal, Slot
|
|||||||
from artemis.utils.path_utils import *
|
from artemis.utils.path_utils import *
|
||||||
from artemis.utils.generic_utils import *
|
from artemis.utils.generic_utils import *
|
||||||
from artemis.utils.sql_utils import ArtemisSignal
|
from artemis.utils.sql_utils import ArtemisSignal
|
||||||
|
from artemis.utils.sys_utils import delete_file
|
||||||
|
|
||||||
|
|
||||||
class UIsignaleditor(QObject):
|
class UIsignaleditor(QObject):
|
||||||
@@ -104,6 +105,7 @@ class UIsignaleditor(QObject):
|
|||||||
"""
|
"""
|
||||||
if param_type == 'Signal':
|
if param_type == 'Signal':
|
||||||
self._parent.loaded_sig.delete_signal()
|
self._parent.loaded_sig.delete_signal()
|
||||||
|
self._parent.lock_audio_player.emit()
|
||||||
for doc in self._parent.loaded_sig.documents:
|
for doc in self._parent.loaded_sig.documents:
|
||||||
doc_file_name = '{}.{}'.format(str(doc[0]), doc[1])
|
doc_file_name = '{}.{}'.format(str(doc[0]), doc[1])
|
||||||
doc_file_path = self._parent.loaded_db.media_dir / doc_file_name
|
doc_file_path = self._parent.loaded_db.media_dir / doc_file_name
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from artemis.utils.constants import Constants
|
|
||||||
|
from artemis.utils.path_utils import PREFERENCES_DIR, BASE_DIR
|
||||||
|
from artemis.utils.sys_utils import copy_file
|
||||||
|
|
||||||
|
|
||||||
class Config(ConfigParser):
|
class Config(ConfigParser):
|
||||||
""" Custom configuration class derived from ConfigParser.
|
""" Custom configuration class derived from ConfigParser.
|
||||||
Used to get, set, save and remove any configuration from the conf file
|
Used to get value, set, save and remove any configuration from the conf file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config_file_path, space_around_delimiters=False):
|
def __init__(self, config_file_path, space_around_delimiters=False):
|
||||||
@@ -13,11 +15,13 @@ class Config(ConfigParser):
|
|||||||
self.read(self._config_file_path)
|
self.read(self._config_file_path)
|
||||||
self._space_around_delimiters = space_around_delimiters
|
self._space_around_delimiters = space_around_delimiters
|
||||||
|
|
||||||
def get_or_default(self, section, option, default_value):
|
def value(self, section, option, default_value):
|
||||||
value = super().get(section, option)
|
value = super().get(section, option, fallback=default_value)
|
||||||
return value if value else default_value
|
return value
|
||||||
|
|
||||||
def set(self, section, option, value=None):
|
def set(self, section, option, value=None):
|
||||||
|
if not self.has_section(section):
|
||||||
|
self.add_section(section)
|
||||||
super().set(section, option, value)
|
super().set(section, option, value)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@@ -29,4 +33,43 @@ class Config(ConfigParser):
|
|||||||
with open(self._config_file_path, 'w') as f:
|
with open(self._config_file_path, 'w') as f:
|
||||||
self.write(f, space_around_delimiters=self._space_around_delimiters)
|
self.write(f, space_around_delimiters=self._space_around_delimiters)
|
||||||
|
|
||||||
CONFIGURE_QT = Config((Constants.PREFERENCES_DIR / 'qtquickcontrols2.conf').resolve().as_posix())
|
|
||||||
|
def merge_config_files(old_config_path, template_config_path):
|
||||||
|
""" Merge two configuration files: if the old one lacks some
|
||||||
|
sections or options from a comparison with a template,
|
||||||
|
this function will add what is missing to the old conf file
|
||||||
|
"""
|
||||||
|
old_config = ConfigParser()
|
||||||
|
old_config.read(old_config_path)
|
||||||
|
|
||||||
|
new_config = ConfigParser()
|
||||||
|
new_config.read(template_config_path)
|
||||||
|
|
||||||
|
for section in new_config.sections():
|
||||||
|
if not old_config.has_section(section):
|
||||||
|
old_config.add_section(section)
|
||||||
|
for option in new_config.options(section):
|
||||||
|
if not old_config.has_option(section, option):
|
||||||
|
old_config.set(section, option, new_config.get(section, option))
|
||||||
|
|
||||||
|
with open(old_config_path, 'w') as f:
|
||||||
|
old_config.write(f)
|
||||||
|
|
||||||
|
|
||||||
|
def check_conf_file():
|
||||||
|
""" Check the integrity of the used conf file.
|
||||||
|
If it is not present it will add a copy to the PREF_DIR
|
||||||
|
and if it is different in structure (different section/options)
|
||||||
|
it will merge the conf file with the new template one
|
||||||
|
"""
|
||||||
|
active_conf = (PREFERENCES_DIR / 'qtquickcontrols2.conf').resolve()
|
||||||
|
template_conf = (BASE_DIR / 'config' / 'qtquickcontrols2.conf').resolve()
|
||||||
|
|
||||||
|
if not active_conf.exists():
|
||||||
|
copy_file(template_conf, active_conf)
|
||||||
|
else:
|
||||||
|
merge_config_files(active_conf, template_conf)
|
||||||
|
|
||||||
|
|
||||||
|
check_conf_file()
|
||||||
|
CONFIGURE_QT = Config((PREFERENCES_DIR / 'qtquickcontrols2.conf').resolve().as_posix())
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import os
|
|
||||||
import locale
|
import locale
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PySide6.QtCore import qVersion
|
from PySide6.QtCore import qVersion
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
class Constants():
|
class Constants():
|
||||||
@@ -12,14 +10,7 @@ class Constants():
|
|||||||
APPLICATION_NAME = 'Artemis'
|
APPLICATION_NAME = 'Artemis'
|
||||||
ORGANIZATION_NAME = 'AresValley'
|
ORGANIZATION_NAME = 'AresValley'
|
||||||
ORGANIZATION_DOMAIN = 'aresvalley.com'
|
ORGANIZATION_DOMAIN = 'aresvalley.com'
|
||||||
APPLICATION_VERSION = '4.0.0'
|
APPLICATION_VERSION = '4.0.3'
|
||||||
|
|
||||||
BASE_DIR = Path(os.path.dirname(__file__)) / '../..'
|
|
||||||
PREFERENCES_DIR = BASE_DIR / 'config'
|
|
||||||
DB_DIR = BASE_DIR / 'data'
|
|
||||||
UI_DIR = BASE_DIR / 'ui'
|
|
||||||
IMAGES_DIR = BASE_DIR / 'images'
|
|
||||||
LOGS_DIR = BASE_DIR / 'logs'
|
|
||||||
|
|
||||||
SQL_NAME = 'data.sqlite'
|
SQL_NAME = 'data.sqlite'
|
||||||
|
|
||||||
@@ -68,13 +59,13 @@ class Query():
|
|||||||
|
|
||||||
############################## SELECT
|
############################## SELECT
|
||||||
|
|
||||||
SELECT_ALL_SIGNALS = "SELECT SIG_ID, NAME FROM signals ORDER BY NAME ASC"
|
SELECT_ALL_SIGNALS = "SELECT SIG_ID, NAME, DESCRIPTION FROM signals ORDER BY NAME ASC"
|
||||||
|
|
||||||
SELECT_ALL_MODULATION = "SELECT DISTINCT VALUE FROM modulation ORDER BY VALUE ASC"
|
SELECT_ALL_MODULATION = "SELECT DISTINCT VALUE FROM modulation ORDER BY VALUE ASC"
|
||||||
|
|
||||||
SELECT_ALL_LOCATION = "SELECT DISTINCT VALUE FROM location ORDER BY VALUE ASC"
|
SELECT_ALL_LOCATION = "SELECT DISTINCT VALUE FROM location ORDER BY VALUE ASC"
|
||||||
|
|
||||||
SELECT_SIG_ID = "SELECT SIG_ID, NAME FROM signals WHERE SIG_ID IN ({}) ORDER BY NAME ASC"
|
SELECT_SIG_ID = "SELECT SIG_ID, NAME, DESCRIPTION FROM signals WHERE SIG_ID IN ({}) ORDER BY NAME ASC"
|
||||||
|
|
||||||
SELECT_ALL_CAT_LABELS = "SELECT CLB_ID, VALUE FROM category_label ORDER BY VALUE ASC"
|
SELECT_ALL_CAT_LABELS = "SELECT CLB_ID, VALUE FROM category_label ORDER BY VALUE ASC"
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from packaging.version import Version
|
|||||||
from artemis.utils.constants import Constants, Messages
|
from artemis.utils.constants import Constants, Messages
|
||||||
from artemis.utils.sql_utils import ArtemisDatabase
|
from artemis.utils.sql_utils import ArtemisDatabase
|
||||||
from artemis.utils.sys_utils import is_windows, is_linux, is_macos
|
from artemis.utils.sys_utils import is_windows, is_linux, is_macos
|
||||||
|
from artemis.utils.path_utils import DATA_DIR
|
||||||
|
|
||||||
|
|
||||||
class NetworkManager:
|
class NetworkManager:
|
||||||
@@ -14,7 +15,7 @@ class NetworkManager:
|
|||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self.sigid_db_path = Constants.DB_DIR / 'sigID' / Constants.SQL_NAME
|
self.sigid_db_path = DATA_DIR / 'SigID' / Constants.SQL_NAME
|
||||||
|
|
||||||
self.show_popup = False
|
self.show_popup = False
|
||||||
self.db_update = None
|
self.db_update = None
|
||||||
@@ -92,7 +93,7 @@ class NetworkManager:
|
|||||||
""" Loads the local database if exists
|
""" Loads the local database if exists
|
||||||
"""
|
"""
|
||||||
if os.path.exists(self.sigid_db_path):
|
if os.path.exists(self.sigid_db_path):
|
||||||
local_db = ArtemisDatabase('sigID')
|
local_db = ArtemisDatabase('SigID')
|
||||||
local_db.load()
|
local_db.load()
|
||||||
return local_db
|
return local_db
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from artemis.utils.sql_utils import ArtemisDatabase
|
|
||||||
from artemis.utils.constants import Constants
|
from artemis.utils.constants import Constants
|
||||||
from artemis.utils.sys_utils import *
|
from artemis.utils.sys_utils import is_windows, is_linux, is_macos
|
||||||
|
|
||||||
|
|
||||||
def check_data_dir():
|
|
||||||
if not os.path.exists(Constants.DB_DIR):
|
|
||||||
os.makedirs(Constants.DB_DIR)
|
|
||||||
|
|
||||||
|
|
||||||
def normalize_dialog_path(path):
|
def normalize_dialog_path(path):
|
||||||
@@ -19,38 +13,37 @@ def normalize_dialog_path(path):
|
|||||||
return norm_path
|
return norm_path
|
||||||
|
|
||||||
|
|
||||||
def logs_dir():
|
def _app_dir():
|
||||||
if is_macos():
|
if is_macos():
|
||||||
logs_dir_path = Path.home() / 'Library/Logs/' / Constants.ORGANIZATION_NAME / Constants.APPLICATION_NAME
|
app_dir_path = Path.home() / 'Library' / 'Application Support' / Constants.ORGANIZATION_NAME / Constants.APPLICATION_NAME
|
||||||
elif is_windows():
|
elif is_windows():
|
||||||
logs_dir_path = Path.home() / 'AppData/Local/' / Constants.ORGANIZATION_NAME / Constants.APPLICATION_NAME / 'logs'
|
app_dir_path = Path.home() / 'AppData' / 'Local' / Constants.ORGANIZATION_NAME / Constants.APPLICATION_NAME
|
||||||
elif is_linux():
|
elif is_linux():
|
||||||
logs_dir_path = Path.home() / '/var/log/' / Constants.ORGANIZATION_NAME / Constants.APPLICATION_NAME
|
app_dir_path = Path.home() / '.local' / 'share' / Constants.ORGANIZATION_NAME / Constants.APPLICATION_NAME
|
||||||
else:
|
else:
|
||||||
logs_dir_path = Constants.LOGS_DIR
|
app_dir_path = BASE_DIR.resolve()
|
||||||
|
|
||||||
if not logs_dir_path.exists():
|
if not app_dir_path.exists():
|
||||||
logs_dir_path.mkdir(parents=True)
|
app_dir_path.mkdir(parents=True)
|
||||||
|
|
||||||
return logs_dir_path
|
return app_dir_path
|
||||||
|
|
||||||
|
|
||||||
def valid_db(db_dir_name):
|
def _data_dir():
|
||||||
""" Checks if db_dir_name is a valid db dir containing a `data.sqlite` file.
|
data_dir_path = APP_DIR / 'data'
|
||||||
Db must be valid as well and should be properly initialized and loaded with
|
if not data_dir_path.exists():
|
||||||
no errors.
|
data_dir_path.mkdir(parents=True)
|
||||||
|
return data_dir_path
|
||||||
|
|
||||||
Args:
|
|
||||||
db_dir_name (str): name of the db folder
|
def _preference_dir():
|
||||||
"""
|
preference_dir_path = APP_DIR / 'config'
|
||||||
if os.path.exists(Constants.DB_DIR / db_dir_name / Constants.SQL_NAME):
|
if not preference_dir_path.exists():
|
||||||
try:
|
preference_dir_path.mkdir(parents=True)
|
||||||
database = ArtemisDatabase(db_dir_name)
|
return preference_dir_path
|
||||||
database.load()
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
BASE_DIR = Path(os.path.dirname(__file__)) / '../..'
|
||||||
# Invalid or corrupted DB
|
APP_DIR = _app_dir()
|
||||||
return False
|
DATA_DIR = _data_dir()
|
||||||
else:
|
PREFERENCES_DIR = _preference_dir()
|
||||||
# The dir is not containing a data.sqlite file
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import sqlite3
|
|
||||||
import os
|
import os
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
from PySide6.QtCore import QUrl
|
from PySide6.QtCore import QUrl
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
from artemis.utils.constants import Query, Constants
|
from artemis.utils.constants import Query, Constants
|
||||||
from artemis.utils.generic_utils import *
|
from artemis.utils.path_utils import DATA_DIR
|
||||||
from contextlib import closing
|
from artemis.utils.generic_utils import format_frequency
|
||||||
|
|
||||||
|
|
||||||
class Database():
|
class Database():
|
||||||
@@ -51,7 +52,7 @@ class ArtemisDatabase(Database):
|
|||||||
|
|
||||||
def __init__(self, db_dir_name):
|
def __init__(self, db_dir_name):
|
||||||
self.db_dir_name = db_dir_name
|
self.db_dir_name = db_dir_name
|
||||||
self.db_dir = Constants.DB_DIR / db_dir_name
|
self.db_dir = DATA_DIR / db_dir_name
|
||||||
self.sql_path = self.db_dir / Constants.SQL_NAME
|
self.sql_path = self.db_dir / Constants.SQL_NAME
|
||||||
self.media_dir = self.db_dir / 'media'
|
self.media_dir = self.db_dir / 'media'
|
||||||
super().__init__(self.sql_path)
|
super().__init__(self.sql_path)
|
||||||
@@ -95,7 +96,7 @@ class ArtemisDatabase(Database):
|
|||||||
contains the SIG_ID and the NAME of the signal
|
contains the SIG_ID and the NAME of the signal
|
||||||
"""
|
"""
|
||||||
self.all_signals = self.execute(Query.SELECT_ALL_SIGNALS)
|
self.all_signals = self.execute(Query.SELECT_ALL_SIGNALS)
|
||||||
keys = ('SIG_ID', 'name')
|
keys = ('SIG_ID', 'name', 'description')
|
||||||
result = [dict(zip(keys, values)) for values in self.all_signals]
|
result = [dict(zip(keys, values)) for values in self.all_signals]
|
||||||
self.all_signals = result
|
self.all_signals = result
|
||||||
|
|
||||||
@@ -131,7 +132,7 @@ class ArtemisDatabase(Database):
|
|||||||
sig_ids = ",".join(str(num[0]) for num in matching_sig_ids)
|
sig_ids = ",".join(str(num[0]) for num in matching_sig_ids)
|
||||||
|
|
||||||
self.all_signals = self.execute(Query.SELECT_SIG_ID.format(sig_ids))
|
self.all_signals = self.execute(Query.SELECT_SIG_ID.format(sig_ids))
|
||||||
keys = ('SIG_ID', 'name')
|
keys = ('SIG_ID', 'name', 'description')
|
||||||
result = [dict(zip(keys, values)) for values in self.all_signals]
|
result = [dict(zip(keys, values)) for values in self.all_signals]
|
||||||
self.all_signals = result
|
self.all_signals = result
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import hashlib
|
|||||||
from shutil import rmtree, copyfile, make_archive, unpack_archive
|
from shutil import rmtree, copyfile, make_archive, unpack_archive
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from artemis.utils.constants import Constants, Messages
|
from artemis.utils.constants import Messages
|
||||||
|
|
||||||
|
|
||||||
def is_windows():
|
def is_windows():
|
||||||
@@ -46,29 +46,38 @@ def open_directory(directory, timeout=3):
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def delete_db_dir(db_dir_name):
|
|
||||||
"""Delete the db folder"""
|
|
||||||
db_dir = Constants.DB_DIR / db_dir_name
|
|
||||||
if os.path.exists(db_dir):
|
|
||||||
rmtree(db_dir)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_file(src_file_path, dst_file_path):
|
def copy_file(src_file_path, dst_file_path):
|
||||||
copyfile(src_file_path, dst_file_path)
|
copyfile(src_file_path, dst_file_path)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_dir(dir_path):
|
||||||
|
if os.path.exists(dir_path):
|
||||||
|
rmtree(dir_path)
|
||||||
|
|
||||||
|
|
||||||
def delete_file(file_path):
|
def delete_file(file_path):
|
||||||
if os.path.exists(file_path):
|
if os.path.exists(file_path):
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
|
|
||||||
|
|
||||||
def pack_db(save_path, db_dir):
|
def make_tar(save_path, origin_path):
|
||||||
make_archive(save_path, 'tar', db_dir.resolve().as_posix())
|
""" Create a tar archive from a folder
|
||||||
|
|
||||||
|
Args:
|
||||||
|
save_path: destination path where new tar is saved
|
||||||
|
origin_path: directory path of the folder to be archived
|
||||||
|
"""
|
||||||
|
make_archive(save_path, 'tar', origin_path.resolve().as_posix())
|
||||||
|
|
||||||
|
|
||||||
def unpack_db(tar_path, db_dir_name):
|
def unpack_tar(tar_path, destination_path):
|
||||||
db_dir = Constants.DB_DIR / db_dir_name
|
""" Unpack a tar archive in a folder
|
||||||
unpack_archive(tar_path, db_dir, 'tar')
|
|
||||||
|
Args:
|
||||||
|
tar_path: path of the tar to be unpacked
|
||||||
|
destination_path: path where the tar is extracted
|
||||||
|
"""
|
||||||
|
unpack_archive(tar_path, destination_path, 'tar')
|
||||||
|
|
||||||
|
|
||||||
def match_hash(data, reference_hash):
|
def match_hash(data, reference_hash):
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ from artemis.utils.config_utils import CONFIGURE_QT
|
|||||||
|
|
||||||
|
|
||||||
def set_ui():
|
def set_ui():
|
||||||
os.environ['QT_QUICK_CONTROLS_STYLE'] = CONFIGURE_QT.get_or_default('Controls', 'style', 'Material')
|
os.environ['QT_QUICK_CONTROLS_STYLE'] = CONFIGURE_QT.value('Controls', 'style', 'Material')
|
||||||
os.environ['QT_QUICK_CONTROLS_MATERIAL_VARIANT'] = CONFIGURE_QT.get_or_default('Material', 'variant', 'Dense')
|
os.environ['QT_QUICK_CONTROLS_MATERIAL_VARIANT'] = CONFIGURE_QT.value('Material', 'variant', 'Dense')
|
||||||
os.environ['QT_QUICK_CONTROLS_MATERIAL_THEME'] = CONFIGURE_QT.get_or_default('Material', 'theme', 'System')
|
os.environ['QT_QUICK_CONTROLS_MATERIAL_THEME'] = CONFIGURE_QT.value('Material', 'theme', 'System')
|
||||||
os.environ['QT_QUICK_CONTROLS_MATERIAL_ACCENT'] = CONFIGURE_QT.get_or_default('Material', 'accent', 'Green')
|
os.environ['QT_QUICK_CONTROLS_MATERIAL_ACCENT'] = CONFIGURE_QT.value('Material', 'accent', 'Green')
|
||||||
|
|
||||||
if is_windows():
|
if is_windows():
|
||||||
os.environ['QSG_RHI_BACKEND'] = 'opengl'
|
os.environ['QSG_RHI_BACKEND'] = 'opengl'
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ echo "Building Linux target ..."
|
|||||||
|
|
||||||
echo "Installing requirements ..."
|
echo "Installing requirements ..."
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install nuitka
|
pip install nuitka==2.3
|
||||||
|
|
||||||
echo "Building with Nuitka ..."
|
echo "Building with Nuitka ..."
|
||||||
python -m nuitka app.py \
|
python -m nuitka app.py \
|
||||||
@@ -12,13 +12,22 @@ python -m nuitka app.py \
|
|||||||
--follow-imports \
|
--follow-imports \
|
||||||
--show-modules \
|
--show-modules \
|
||||||
--assume-yes-for-downloads \
|
--assume-yes-for-downloads \
|
||||||
--disable-console \
|
|
||||||
--enable-plugin=pyside6 \
|
--enable-plugin=pyside6 \
|
||||||
--include-qt-plugins=sensible,styles,qml,multimedia \
|
--noinclude-dlls=libQt6Charts* \
|
||||||
|
--noinclude-dlls=libQt6Quick3D* \
|
||||||
|
--noinclude-dlls=libQt6Sensors* \
|
||||||
|
--noinclude-dlls=libQt6Test* \
|
||||||
|
--noinclude-dlls=libQt6WebEngine* \
|
||||||
|
--include-qt-plugins=sensible \
|
||||||
|
--include-qt-plugins=styles \
|
||||||
|
--include-qt-plugins=qml \
|
||||||
|
--include-qt-plugins=multimedia \
|
||||||
--include-data-files=./artemis/resources.py=./artemis/resources.py \
|
--include-data-files=./artemis/resources.py=./artemis/resources.py \
|
||||||
--include-data-files=./config/qtquickcontrols2.conf=./config/qtquickcontrols2.conf \
|
--include-data-files=./config/qtquickcontrols2.conf=./config/qtquickcontrols2.conf \
|
||||||
--include-data-files=./building/Linux/create_shortcut.sh=./create_shortcut.sh \
|
--include-data-files=./building/Linux/create_shortcut.sh=./create_shortcut.sh \
|
||||||
--include-data-files=./images/artemis_icon.svg=./images/artemis_icon.svg
|
--include-data-files=./images/artemis_icon.svg=./images/artemis_icon.svg \
|
||||||
|
--force-stderr-spec="{TEMP}/artemis.err.log" \
|
||||||
|
--force-stdout-spec="{TEMP}/artemis.out.log"
|
||||||
|
|
||||||
chmod 755 ./app.dist/app.bin
|
chmod 755 ./app.dist/app.bin
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Write-Output "Building Windows target"
|
|||||||
|
|
||||||
Write-Output "Installing requirements ..."
|
Write-Output "Installing requirements ..."
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install nuitka
|
pip install nuitka==2.3
|
||||||
|
|
||||||
Write-Output "Building with Nuitka ..."
|
Write-Output "Building with Nuitka ..."
|
||||||
python -m nuitka app.py `
|
python -m nuitka app.py `
|
||||||
@@ -10,15 +10,25 @@ python -m nuitka app.py `
|
|||||||
--follow-imports `
|
--follow-imports `
|
||||||
--show-modules `
|
--show-modules `
|
||||||
--assume-yes-for-downloads `
|
--assume-yes-for-downloads `
|
||||||
--disable-console `
|
--windows-console-mode=disable `
|
||||||
--enable-plugin=pyside6 `
|
--enable-plugin=pyside6 `
|
||||||
--include-qt-plugins=sensible,styles,qml,multimedia `
|
--noinclude-dlls="Qt6Charts*" `
|
||||||
|
--noinclude-dlls="Qt6Quick3D*" `
|
||||||
|
--noinclude-dlls="Qt6Sensors*" `
|
||||||
|
--noinclude-dlls="Qt6Test*" `
|
||||||
|
--noinclude-dlls="Qt6WebEngine*" `
|
||||||
|
--include-qt-plugins=sensible `
|
||||||
|
--include-qt-plugins=styles `
|
||||||
|
--include-qt-plugins=qml `
|
||||||
|
--include-qt-plugins=multimedia `
|
||||||
--include-data-files=.\artemis\resources.py=.\artemis\resources.py `
|
--include-data-files=.\artemis\resources.py=.\artemis\resources.py `
|
||||||
--include-data-files=.\config\qtquickcontrols2.conf=.\config\qtquickcontrols2.conf `
|
--include-data-files=.\config\qtquickcontrols2.conf=.\config\qtquickcontrols2.conf `
|
||||||
|
--force-stderr-spec="{TEMP}\artemis.err.log" `
|
||||||
|
--force-stdout-spec="{TEMP}\artemis.out.log" `
|
||||||
--windows-company-name=Aresvalley.com `
|
--windows-company-name=Aresvalley.com `
|
||||||
--windows-product-name=Artemis `
|
--windows-product-name=Artemis `
|
||||||
--windows-file-version=4.0.0 `
|
--windows-file-version=4.0.3 `
|
||||||
--windows-product-version=4.0.0 `
|
--windows-product-version=4.0.3 `
|
||||||
--windows-file-description=Artemis `
|
--windows-file-description=Artemis `
|
||||||
--windows-icon-from-ico=images\artemis_icon.ico
|
--windows-icon-from-ico=images\artemis_icon.ico
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#define MyAppName "Artemis"
|
#define MyAppName "Artemis"
|
||||||
#define MyAppVersion "4.0.0"
|
#define MyAppVersion "4.0.3"
|
||||||
#define MyAppPublisher "AresValley"
|
#define MyAppPublisher "AresValley"
|
||||||
#define MyAppURL "https://www.aresvalley.com/"
|
#define MyAppURL "https://www.aresvalley.com/"
|
||||||
#define MyAppExeName "artemis.exe"
|
#define MyAppExeName "artemis.exe"
|
||||||
@@ -18,7 +18,7 @@ LicenseFile=..\..\LICENSE
|
|||||||
PrivilegesRequiredOverridesAllowed=dialog
|
PrivilegesRequiredOverridesAllowed=dialog
|
||||||
OutputDir=..\
|
OutputDir=..\
|
||||||
OutputBaseFilename=Artemis
|
OutputBaseFilename=Artemis
|
||||||
SetupIconFile=..\..\images\artemis_icon.ico
|
SetupIconFile=..\..\images\installer_icon.ico
|
||||||
Compression=lzma2/ultra64
|
Compression=lzma2/ultra64
|
||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
VersionInfoVersion={#MyAppVersion}
|
VersionInfoVersion={#MyAppVersion}
|
||||||
@@ -42,3 +42,7 @@ Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: de
|
|||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||||
|
|
||||||
|
[UninstallDelete]
|
||||||
|
Type: filesandordirs; Name: "{localappdata}\{#MyAppPublisher}\{#MyAppName}\cache"
|
||||||
|
Type: filesandordirs; Name: "{localappdata}\{#MyAppPublisher}\{#MyAppName}\config"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ echo "Building maacOS target ..."
|
|||||||
|
|
||||||
echo "Installing requirements ..."
|
echo "Installing requirements ..."
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install nuitka imageio
|
pip install nuitka==2.3 imageio
|
||||||
|
|
||||||
echo "Building with Nuitka ..."
|
echo "Building with Nuitka ..."
|
||||||
python -m nuitka app.py \
|
python -m nuitka app.py \
|
||||||
@@ -12,7 +12,6 @@ python -m nuitka app.py \
|
|||||||
--follow-imports \
|
--follow-imports \
|
||||||
--show-modules \
|
--show-modules \
|
||||||
--assume-yes-for-downloads \
|
--assume-yes-for-downloads \
|
||||||
--disable-console \
|
|
||||||
--enable-plugin=pyside6 \
|
--enable-plugin=pyside6 \
|
||||||
--include-qt-plugins=sensible,styles,qml,multimedia \
|
--include-qt-plugins=sensible,styles,qml,multimedia \
|
||||||
--include-data-files=./artemis/resources.py=./artemis/resources.py \
|
--include-data-files=./artemis/resources.py=./artemis/resources.py \
|
||||||
@@ -24,6 +23,6 @@ python -m nuitka app.py \
|
|||||||
--macos-app-name=Artemis \
|
--macos-app-name=Artemis \
|
||||||
--macos-app-mode=gui \
|
--macos-app-mode=gui \
|
||||||
--macos-sign-identity=ad-hoc \
|
--macos-sign-identity=ad-hoc \
|
||||||
--macos-app-version=4.0.0
|
--macos-app-version=4.0.3
|
||||||
|
|
||||||
echo "Building Linux target finished."
|
echo "Building Linux target finished."
|
||||||
|
|||||||
@@ -5,3 +5,6 @@ style=Material
|
|||||||
variant=Dense
|
variant=Dense
|
||||||
theme=System
|
theme=System
|
||||||
accent=Green
|
accent=Green
|
||||||
|
|
||||||
|
[Database]
|
||||||
|
autoload=0
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"sigID_DB": {
|
"sigID_DB": {
|
||||||
"version": 60,
|
"version": 61,
|
||||||
"url": "https://github.com/AresValley/Artemis-DB/releases/download/v60/v60.tar",
|
"url": "https://github.com/AresValley/Artemis-DB/releases/download/v61/v61.tar",
|
||||||
"sha256_hash": "78a2c2e5fc00ef4e6c3c975436177eb726fe38ad05463e5cc84b16797225b803",
|
"sha256_hash": "c65d2ab65e9420cd7789190c100abef2f1575ea15489776c2d97b5b09cdc8410",
|
||||||
"total_bytes": 244070400
|
"total_bytes": 244449280
|
||||||
},
|
},
|
||||||
"windows": {
|
"windows": {
|
||||||
"version": "4.0.0"
|
"version": "4.0.1"
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
"version": "4.0.0"
|
"version": "4.0.1"
|
||||||
},
|
},
|
||||||
"mac": {
|
"mac": {
|
||||||
"version": "4.0.0"
|
"version": "4.0.0"
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 810 KiB |
BIN
docs/assets/artemis_preview.webp
Normal file
BIN
docs/assets/artemis_preview.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 209 KiB |
@@ -12,7 +12,7 @@
|
|||||||
* **Edit Tags:** Open the tags editor window. From here, you can add, rename, or delete tags. The tags can be added to a signal from the [tags menu](#4-tags)
|
* **Edit Tags:** Open the tags editor window. From here, you can add, rename, or delete tags. The tags can be added to a signal from the [tags menu](#4-tags)
|
||||||
* **Open Database Folder:** Shows the folder of the currently loaded database in the explorer.
|
* **Open Database Folder:** Shows the folder of the currently loaded database in the explorer.
|
||||||
* **Preferences:** Open the program settings window.
|
* **Preferences:** Open the program settings window.
|
||||||
* **Exit:** This will simply close the application.
|
* **Exit:** This will close the application.
|
||||||
|
|
||||||
### Signal
|
### Signal
|
||||||
* **New:** Add a new signal to the database.
|
* **New:** Add a new signal to the database.
|
||||||
@@ -22,7 +22,10 @@
|
|||||||
* **Check Report:** Open the main [Space Weather window](space_weather/current.md) and retrieve all the live data from Poseidon Crawler.
|
* **Check Report:** Open the main [Space Weather window](space_weather/current.md) and retrieve all the live data from Poseidon Crawler.
|
||||||
|
|
||||||
## 2. Signal List
|
## 2. Signal List
|
||||||
This is the signal list where all the database entries are shown. When a signal is selected, it will load on the right panel. On top of the list, there is a field for filtering signals by name: this filter has the highest priority among all the filters.
|
This is the signal list where all the database entries are shown. When a signal is selected, it will load on the right panel.
|
||||||
|
|
||||||
|
### Filter by Name/Description
|
||||||
|
On top of the list, there is a field for filtering signals by name or any keyword inside the description of the signal: this filter has the highest priority among all the filters.
|
||||||
|
|
||||||
## 3. Signal Menu
|
## 3. Signal Menu
|
||||||
Here you can swithc between the main **signal** window and the **filter** page.
|
Here you can swithc between the main **signal** window and the **filter** page.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Build Package
|
# Build Package
|
||||||
Building a distributable package with an executable for Artemis creates a practical solution for end-users, as they can run the application without needing to interact with the terminal and they can easily share the application as a stand-alone package.
|
Building a distributable package with an executable for Artemis creates a practical solution for end-users, as they can run the application without needing to interact with the terminal and they can easily share the application as a standalone package.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
* Python (3.11 or higher)
|
* Python (3.11 or higher)
|
||||||
@@ -8,7 +8,7 @@ Building a distributable package with an executable for Artemis creates a practi
|
|||||||
We assume that Python is already installed on the system and the Artemis source code has been downloaded and extracted. If these prerequisites are not met, please follow steps 1 to 3 in the [run from source section](run_from_source.md).
|
We assume that Python is already installed on the system and the Artemis source code has been downloaded and extracted. If these prerequisites are not met, please follow steps 1 to 3 in the [run from source section](run_from_source.md).
|
||||||
|
|
||||||
!!! warning "Cross-Compilation"
|
!!! warning "Cross-Compilation"
|
||||||
To generate standalone packages, an operating system that matches the target OS must be used, as Nuitka does not support cross-compilation. For example: you cannot build binaries on Windows that work on Linux or macOS.
|
An operating system that matches the target OS must be used to generate standalone packages, as Nuitka does not support cross-compilation. For example, you cannot build binaries on Windows that work on Linux or macOS.
|
||||||
|
|
||||||
## :simple-windows: Windows
|
## :simple-windows: Windows
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ Building a distributable package with an executable for Artemis creates a practi
|
|||||||
.\building\Windows\build_windows.ps1
|
.\building\Windows\build_windows.ps1
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Wait for the build process to complete. This may take a few minutes depending on your system's performance. Once the process finishes, check the `artemis.dist/` directory: it will contain the stand-alone software with the `artemis.exe` executable.
|
2. Wait for the build process to complete. This may take a few minutes depending on your system's performance. Once the process finishes, check the `artemis.dist/` directory: it will contain the standalone software with the `artemis.exe` executable.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Building a distributable package with an executable for Artemis creates a practi
|
|||||||
. ./building/Linux/build_linux.sh
|
. ./building/Linux/build_linux.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Wait for the build process to complete. This may take a few minutes depending on your system's performance. Once the process finishes, check the `artemis.dist/` directory: it will contain the stand-alone software with the `app.bin` executable.
|
2. Wait for the build process to complete. This may take a few minutes depending on your system's performance. Once the process finishes, check the `artemis.dist/` directory: it will contain the standalone software with the `app.bin` executable.
|
||||||
3. If you wish to create a shortcut, follows the procedure in the [installation section](installation.md/#create-a-shortcut)
|
3. If you wish to create a shortcut, follows the procedure in the [installation section](installation.md/#create-a-shortcut)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Contribute
|
# Contribute
|
||||||
Artemis is an open source project an every contribution, no matter how small, is valuable and greatly appreciated. Don't worry about getting everything perfect, we are happy to work with you on your contribution and help you along the way. This guide will help you get started by outlining various ways you can contribute.
|
Artemis is an open-source project, and every contribution, no matter how small, is valuable and greatly appreciated. Don't worry about getting everything perfect; we are happy to work with you on your contribution and help you along the way. This guide will help you get started by outlining various ways you can contribute.
|
||||||
|
|
||||||
<div class="grid cards" markdown>
|
<div class="grid cards" markdown>
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ Artemis is an open source project an every contribution, no matter how small, is
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Open an issue (or pull request) and let us know the problem you faced (or you're working on)
|
Please open an issue (or pull request) and let us know the problem you faced (or you're working on)
|
||||||
|
|
||||||
[:octicons-arrow-right-24: Open an Issue](https://github.com/AresValley/Artemis/issues)
|
[:octicons-arrow-right-24: Open an Issue](https://github.com/AresValley/Artemis/issues)
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ Artemis is an open source project an every contribution, no matter how small, is
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Create your own copy of the codebase that you can modify and submit pull requests from.
|
Create a copy of the codebase from which you can modify and submit pull requests.
|
||||||
|
|
||||||
|
|
||||||
[:octicons-arrow-right-24: Fork the repo](https://github.com/AresValley/Artemis)
|
[:octicons-arrow-right-24: Fork the repo](https://github.com/AresValley/Artemis)
|
||||||
@@ -24,7 +24,7 @@ Artemis is an open source project an every contribution, no matter how small, is
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Idea for a new feature? Open an issue on the project's GitHub repository to describe your proposal in detail.
|
Idea for a new feature? Open an issue on the project's GitHub repository to describe your proposal.
|
||||||
|
|
||||||
[:octicons-arrow-right-24: Open an Issue](https://github.com/AresValley/Artemis/issues)
|
[:octicons-arrow-right-24: Open an Issue](https://github.com/AresValley/Artemis/issues)
|
||||||
|
|
||||||
@@ -32,6 +32,6 @@ Artemis is an open source project an every contribution, no matter how small, is
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Do you like Artemis? Don't forgeto to share it with your network and your friends!
|
Do you like Artemis? Remember to share it with your network and your friends!
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,65 +12,3 @@ Artemis is maintained by Marco Dalla Tiezza and released under the [GPLv3](https
|
|||||||
* [**Eric Wiessner (KI7POL)**](https://github.com/WheezyE "GitHub profile") - *ARM port (Raspberry Pi3B+ and Pi4B)*
|
* [**Eric Wiessner (KI7POL)**](https://github.com/WheezyE "GitHub profile") - *ARM port (Raspberry Pi3B+ and Pi4B)*
|
||||||
* [**Pierpaolo Pravatto**](https://github.com/ppravatto "GitHub profile") - *Wiki page, β Tester*
|
* [**Pierpaolo Pravatto**](https://github.com/ppravatto "GitHub profile") - *Wiki page, β Tester*
|
||||||
* [**Francesco Capostagno**](https://github.com/fcapostagno "GitHub profile"), **Luca**, **Pietro** - *β Tester*
|
* [**Francesco Capostagno**](https://github.com/fcapostagno "GitHub profile"), **Luca**, **Pietro** - *β Tester*
|
||||||
|
|
||||||
## Donators
|
|
||||||
|
|
||||||
* Eric Hahn
|
|
||||||
* Alan Lawrence
|
|
||||||
* Diego Gil Fernandez
|
|
||||||
* Torsten Teichert
|
|
||||||
* Charles Preston
|
|
||||||
* Brad Hein
|
|
||||||
* Paolo Romani
|
|
||||||
* Michelle Corbani
|
|
||||||
* Martin van Duinen
|
|
||||||
* Valentino Zardi
|
|
||||||
* Emmanuel Fabre
|
|
||||||
* Oscar Nilsson
|
|
||||||
* Pierre Declercq
|
|
||||||
* Detlef Jahn
|
|
||||||
* Oliver Schellenberg
|
|
||||||
* Stephane Imbertone
|
|
||||||
* Roel Ketelaars
|
|
||||||
* Timothy Ehrhart
|
|
||||||
* George Mager
|
|
||||||
* Gerhard Amon
|
|
||||||
* Gerald Schmidt
|
|
||||||
* Carlos Rocha
|
|
||||||
* Joshua Frohberg
|
|
||||||
* Bill Riches
|
|
||||||
* Jeffrey Krehbiel
|
|
||||||
* Володимир Багмет
|
|
||||||
* Philip Hamlin
|
|
||||||
* David Davies
|
|
||||||
* Nigel P. Lawrence
|
|
||||||
* Marco Rissi (PP5ZX)
|
|
||||||
* Martin van Duinen
|
|
||||||
* Alex Diamantopulo
|
|
||||||
* Joseph Winter
|
|
||||||
* Mark Bender
|
|
||||||
* Rolf Gerhardt
|
|
||||||
* Denese Harris
|
|
||||||
* Benjamin Steele
|
|
||||||
* Alexander Irmscher
|
|
||||||
* Jonathan Chang
|
|
||||||
* Torsten Lipke
|
|
||||||
* Massimo Petrantoni
|
|
||||||
* William Arcand
|
|
||||||
* Jon Carp
|
|
||||||
* Robert Crone
|
|
||||||
* William Houston
|
|
||||||
* Richard Quasne
|
|
||||||
* Tom Krugliakov
|
|
||||||
* Francisco Neira Basso
|
|
||||||
* Alistair Macrae
|
|
||||||
* Kevin Arburn
|
|
||||||
* Marek Barłóg
|
|
||||||
* Gabriel Glösmann
|
|
||||||
* Corbin Williams
|
|
||||||
* Ton Machielsen
|
|
||||||
* Ivan Rancic
|
|
||||||
* Alipio Fernandez
|
|
||||||
* Matt Eisele
|
|
||||||
* Martin Dudel
|
|
||||||
* Harald Geier
|
|
||||||
|
|||||||
@@ -9,3 +9,7 @@ title: Documentation
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
**Artemis** is a software designed to assist **radio frequency (RF) signal identification and storage**. It simplifies real-time spectrum analysis by leveraging one of the most extensive and community-driven databases, containing nearly **500 recognized signals**. This comprehensive software solution allows users to collect RF signals with specific parameters such as frequency, bandwidth, modulation, etc. Users can also store spectrum waterfalls, audio samples, and all types of documents for future reference. Artemis provides a robust platform to manage a wide range of RF data with precision and ease.
|
**Artemis** is a software designed to assist **radio frequency (RF) signal identification and storage**. It simplifies real-time spectrum analysis by leveraging one of the most extensive and community-driven databases, containing nearly **500 recognized signals**. This comprehensive software solution allows users to collect RF signals with specific parameters such as frequency, bandwidth, modulation, etc. Users can also store spectrum waterfalls, audio samples, and all types of documents for future reference. Artemis provides a robust platform to manage a wide range of RF data with precision and ease.
|
||||||
|
|
||||||
|
<p align="center" markdown>
|
||||||
|
[Artemis Homepage](https://www.aresvalley.com){ .md-button }
|
||||||
|
</p>
|
||||||
|
|||||||
@@ -12,7 +12,12 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
## :simple-linux: Linux
|
## :simple-linux: Linux
|
||||||
1. Download `Artemis-Linux-x86_64-4.x.x.tar` in the Assets menu from the [:material-download: LATEST RELEASE](https://github.com/AresValley/Artemis/releases) and extract the tarball archive in a folder of your choice and run the executable `app.bin`.
|
1. Download `Artemis-Linux-x86_64-4.x.x.tar` in the Assets menu from the [:material-download: LATEST RELEASE](https://github.com/AresValley/Artemis/releases) and extract the tarball archive in a folder of your choice.
|
||||||
|
2. Before running `app.bin`, be sure to have the executable permissions to the binary file with:
|
||||||
|
|
||||||
|
```
|
||||||
|
chmod 700 app.bin
|
||||||
|
```
|
||||||
|
|
||||||
### Create a Shortcut
|
### Create a Shortcut
|
||||||
|
|
||||||
@@ -38,5 +43,5 @@ The support for the macOS compiled version of the program is temporarily limited
|
|||||||
|
|
||||||
* **Run the program directly from the source:** Follow the instructions provided in [this chapter](run_from_source.md) to launch the program from the source code.
|
* **Run the program directly from the source:** Follow the instructions provided in [this chapter](run_from_source.md) to launch the program from the source code.
|
||||||
* **Compile the Artemis 4 binaries on your machine:** In this case, you can contribute by reporting any issues you encounter by [opening an Issue](https://github.com/AresValley/Artemis/issues).
|
* **Compile the Artemis 4 binaries on your machine:** In this case, you can contribute by reporting any issues you encounter by [opening an Issue](https://github.com/AresValley/Artemis/issues).
|
||||||
* **Use the last available compiled version (3.2.1):** Although this version is no longer officially supported, it remains available for use: [:material-download: Artemis-3.2.1.dmg](https://aresvalley.com/download/11/).
|
* **Use the last available compiled version (3.2.1):** Although this version is no longer officially supported, it remains available for use: [:material-download: Artemis-3.2.1.dmg](https://www.aresvalley.com/?sdm_process_download=1&download_id=377).
|
||||||
|
|
||||||
|
|||||||
@@ -27,3 +27,18 @@ Running Artemis directly from the source code using the Python interpreter is co
|
|||||||
```
|
```
|
||||||
pyside6-rcc ./artemis.qrc -o artemis/resources.py
|
pyside6-rcc ./artemis.qrc -o artemis/resources.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Folders Structure
|
||||||
|
Artemis can be safely executed and/or installed in any folder (even protected ones, such as `Program Files (x86)` in Windows) because Artemis performs read-only operations in the `BASE_DIR` folder from where it runs. All the reading-writing operations (such as database ops, logging, etc.) are performed in standard folders as follow:
|
||||||
|
|
||||||
|
### :simple-windows: Windows
|
||||||
|
* Data, Cache, Configurations: `$USER\AppData\Local\AresValley\Artemis`
|
||||||
|
* Logs: `$USER\AppData\Local\Temp`
|
||||||
|
|
||||||
|
### :simple-linux: Linux
|
||||||
|
* Data, Cache, Configurations: `~/.local/share/AresValley/Artemis`
|
||||||
|
* Logs: `/tmp`
|
||||||
|
|
||||||
|
### :simple-apple: Mac OS
|
||||||
|
* Data, Cache, Configurations: `~/Library/Application Support/AresValley/Artemis`
|
||||||
|
* Logs: `/tmp`
|
||||||
|
|||||||
@@ -5,8 +5,21 @@
|
|||||||
## 1. Kp Index
|
## 1. Kp Index
|
||||||
The **K index** is a number (from 0 to 9) that shows how much Earth's magnetic field is disturbed. A K index of 1 means things are calm, while a K index of 5 or higher indicates a geomagnetic storm. These disturbances are measured with magnetometers that track changes in Earth's magnetic field every three hours. The K itself comes from a German word "Kennziffer" meaning "characteristic digit". To get a big picture of what's happening around the world, an official planetary **Kp index** is calculated. This is done by averaging the K indices from a special network of 13 geomagnetic observatories located around the globe at mid-latitudes.
|
The **K index** is a number (from 0 to 9) that shows how much Earth's magnetic field is disturbed. A K index of 1 means things are calm, while a K index of 5 or higher indicates a geomagnetic storm. These disturbances are measured with magnetometers that track changes in Earth's magnetic field every three hours. The K itself comes from a German word "Kennziffer" meaning "characteristic digit". To get a big picture of what's happening around the world, an official planetary **Kp index** is calculated. This is done by averaging the K indices from a special network of 13 geomagnetic observatories located around the globe at mid-latitudes.
|
||||||
|
|
||||||
## 2. A Index
|
|Index|Activity Level|High Latitudes|Low Latitudes|Possible Source|
|
||||||
The **A index** represents the three-hourly equivalent amplitude of geomagnetic activity at a specific magnetometer station, derived from the station-specific K index. Due to the quasi-logarithmic nature of the K-scale in relation to magnetometer fluctuations, directly averaging a set of K indices is not really meaningful. Instead each K is converted back into a linear scale. The **Ap index** is determined by averaging the eight daily A values, providing a measure of geomagnetic activity for a specific day. Days with higher levels of geomagnetic activity correspond to higher daily Ap values.
|
|-|-|-|-|-|
|
||||||
|
|**Kp 0**|Inactive|Weak & slow aurora possible|Aurora extremely unlikely|Small influx of particles due to some reconnections mostly at the magnetotail|
|
||||||
|
|**Kp 1**|Very Quiet|Weak & slow aurora likely|Aurora very unlikely|Vide supra|
|
||||||
|
|**Kp 2**|Quiet|Moderate auroral display|Aurora unlikely|Vide supra|
|
||||||
|
|**Kp 3**|Unsettled|Active auroral display, sporadic substorm possible|Weak aurora display possible|Coronal hole sending fast winds or remains after days of storming, enhanced solar wind|
|
||||||
|
|**Kp 4**|Active|Active auroral display, multiple sporadic substorms possible|Weak Aurora Display Possible|Vide supra|
|
||||||
|
|**Kp 5**|Minor Storm (G1)|Very active auroral display, multiple substorms likely|Aurora display likely|Coronal hole sending fast winds or coronal mass ejection (CME), enhanced solar wind|
|
||||||
|
|**Kp 6**|Moderate Storm (G2)|Strong auroral display, longer substorms|Active auroral display very likely|Vide supra|
|
||||||
|
|**Kp 7**|Strong Storm (G3)|Very strong auroral display|Strong auroral display extremely likely|Large CMEs caused by solar storms or flares, very enhanced solar wind with strong shock wave|
|
||||||
|
|**Kp 8**|Severe Storm (G4)|Extremely strong aurora, long periods of substorming|Strong auroral display extremely likely|Vide supra|
|
||||||
|
|**Kp 9**|Extreme Storm (G5)|Extremely strong aurora, long periods of substorming|Very strong auroral display, overhead aurora possible|Super CMEs, Carrington-class events, devastating solar wind with extreme shock waves|
|
||||||
|
|
||||||
|
## 2. Ap Index
|
||||||
|
The **A index** represents the three-hourly equivalent amplitude of geomagnetic activity at a specific magnetometer station, derived from the station-specific K index. Due to the quasi-logarithmic nature of the K-scale in relation to magnetometer fluctuations, directly averaging a set of K indices is not really meaningful. Instead each K is converted back into a linear scale. The **Ap index** is determined by averaging the eight daily Ap values (3-hour) and using the same stations grid explained for the Kp index in the previous section. This provides a measure of geomagnetic activity for a specific day. Days with higher levels of geomagnetic activity correspond to higher daily Ap values.
|
||||||
|
|
||||||
## 3. NOAA Space Weather Scale
|
## 3. NOAA Space Weather Scale
|
||||||
|
|
||||||
|
|||||||
1
images/icons/player_mute.svg
Normal file
1
images/icons/player_mute.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M671-177q-11 7-22 13t-23 11q-15 7-30.5 0T574-176q-6-15 1.5-29.5T598-227q7-3 13-6.5t12-7.5L480-368v111q0 27-24.5 37.5T412-228L280-360H160q-17 0-28.5-11.5T120-400v-160q0-17 11.5-28.5T160-600h88L84-764q-11-11-11-28t11-28q11-11 28-11t28 11l680 680q11 11 11 28t-11 28q-11 11-28 11t-28-11l-93-93Zm89-304q0-83-44-151.5T598-735q-15-7-22-21.5t-2-29.5q6-16 21.5-23t31.5 0q97 43 155 131t58 197q0 33-6 65.5T817-353q-8 22-24.5 27.5t-30.5.5q-14-5-22.5-18t-.5-30q11-26 16-52.5t5-55.5ZM591-623q33 21 51 63t18 80v10q0 5-1 10-2 13-14 17t-22-6l-51-51q-6-6-9-13.5t-3-15.5v-77q0-12 10.5-17.5t20.5.5Zm-201-59q-6-6-6-14t6-14l22-22q19-19 43.5-8.5T480-703v63q0 14-12 19t-22-5l-56-56Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 783 B |
BIN
images/installer_icon.ico
Normal file
BIN
images/installer_icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
@@ -55,8 +55,9 @@ Window {
|
|||||||
listModel.clear()
|
listModel.clear()
|
||||||
for (var i = 0; i < loadedList.length; i++) {
|
for (var i = 0; i < loadedList.length; i++) {
|
||||||
var name = loadedList[i].name.toLowerCase()
|
var name = loadedList[i].name.toLowerCase()
|
||||||
|
var description = loadedList[i].description.toLowerCase()
|
||||||
var search = textFieldSearch.text.toLowerCase()
|
var search = textFieldSearch.text.toLowerCase()
|
||||||
if (name.includes(search)) {
|
if (name.includes(search) || description.includes(search)) {
|
||||||
listModel.append(loadedList[i])
|
listModel.append(loadedList[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,9 +215,8 @@ Window {
|
|||||||
|
|
||||||
Page {
|
Page {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
leftPadding: 5
|
leftPadding: 10
|
||||||
rightPadding: 5
|
bottomPadding: 10
|
||||||
bottomPadding: 5
|
|
||||||
|
|
||||||
header: MenuBar {
|
header: MenuBar {
|
||||||
id: topBar
|
id: topBar
|
||||||
@@ -320,6 +320,11 @@ Window {
|
|||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Project Homepage"
|
||||||
|
onClicked: {Qt.openUrlExternally('https://aresvalley.com/')}
|
||||||
|
}
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Documentation"
|
text: "Documentation"
|
||||||
onClicked: {Qt.openUrlExternally('https://AresValley.github.io/Artemis')}
|
onClicked: {Qt.openUrlExternally('https://AresValley.github.io/Artemis')}
|
||||||
@@ -358,16 +363,18 @@ Window {
|
|||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 20
|
spacing: 10
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.maximumWidth: 250
|
Layout.maximumWidth: 250
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: textFieldSearch
|
id: textFieldSearch
|
||||||
|
Layout.preferredHeight: 39
|
||||||
|
Layout.topMargin: 5
|
||||||
enabled: false
|
enabled: false
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 10
|
|
||||||
placeholderText: qsTr("Search")
|
placeholderText: qsTr("Search")
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
refreshList()
|
refreshList()
|
||||||
@@ -416,16 +423,14 @@ Window {
|
|||||||
|
|
||||||
TabBar {
|
TabBar {
|
||||||
id: tabBar
|
id: tabBar
|
||||||
width: parent.width
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
TabButton {
|
TabButton {
|
||||||
text: qsTr("Signal")
|
text: qsTr("SIGNAL")
|
||||||
}
|
}
|
||||||
|
|
||||||
TabButton {
|
TabButton {
|
||||||
text: qsTr("Filter")
|
text: qsTr("FILTERS")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,18 +82,6 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function contentChanged() {
|
|
||||||
if (listView.currentIndex !== -1) {
|
|
||||||
myModel.set(
|
|
||||||
listView.currentIndex,
|
|
||||||
{
|
|
||||||
'name': nameField.text,
|
|
||||||
'description': descriptionField.text,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function lockMenu(toggle) {
|
function lockMenu(toggle) {
|
||||||
if (toggle) {
|
if (toggle) {
|
||||||
openButton.enabled = false
|
openButton.enabled = false
|
||||||
@@ -236,16 +224,18 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
Flickable {
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
ScrollBar.vertical.interactive: true
|
Layout.fillHeight: true
|
||||||
|
TextArea.flickable: TextArea {
|
||||||
TextArea {
|
|
||||||
id: newDescriptionField
|
id: newDescriptionField
|
||||||
placeholderText: qsTr("Description")
|
placeholderText: qsTr("Description")
|
||||||
|
font.pointSize: 10
|
||||||
wrapMode: TextEdit.WordWrap
|
wrapMode: TextEdit.WordWrap
|
||||||
}
|
}
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
width: 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,16 +283,18 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
Flickable {
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
ScrollBar.vertical.interactive: true
|
Layout.fillHeight: true
|
||||||
|
TextArea.flickable: TextArea {
|
||||||
TextArea {
|
|
||||||
id: editDescriptionField
|
id: editDescriptionField
|
||||||
placeholderText: qsTr("Description")
|
placeholderText: qsTr("Description")
|
||||||
|
font.pointSize: 10
|
||||||
wrapMode: TextEdit.WordWrap
|
wrapMode: TextEdit.WordWrap
|
||||||
}
|
}
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
width: 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,9 +438,7 @@ Window {
|
|||||||
id: nameField
|
id: nameField
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
placeholderText: qsTr("Name")
|
placeholderText: qsTr("Name")
|
||||||
onTextChanged: {
|
readOnly: true
|
||||||
contentChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
@@ -458,18 +448,18 @@ Window {
|
|||||||
readOnly: true
|
readOnly: true
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
Flickable {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
ScrollBar.vertical.interactive: true
|
TextArea.flickable: TextArea {
|
||||||
|
|
||||||
TextArea {
|
|
||||||
id: descriptionField
|
id: descriptionField
|
||||||
wrapMode: TextEdit.WordWrap
|
placeholderText: qsTr("Description")
|
||||||
|
readOnly: true
|
||||||
font.pointSize: 10
|
font.pointSize: 10
|
||||||
onTextChanged: {
|
wrapMode: TextEdit.WordWrap
|
||||||
contentChanged()
|
|
||||||
}
|
}
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
width: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Controls.Material
|
import QtQuick.Controls.Material
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
id: windowDownloader
|
id: windowDownloader
|
||||||
|
|
||||||
@@ -23,6 +24,15 @@ Window {
|
|||||||
|
|
||||||
signal onAbort()
|
signal onAbort()
|
||||||
|
|
||||||
|
function updateProgressBar(bytesReceived, bytesTotal) {
|
||||||
|
progressBar.value = bytesReceived
|
||||||
|
progressBar.to = bytesTotal
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStatus(arg) {
|
||||||
|
progressLabel.text = arg
|
||||||
|
}
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
id: page
|
id: page
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -37,17 +47,19 @@ Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProgressBar {
|
ProgressBar {
|
||||||
objectName: "progressBar"
|
id: progressBar
|
||||||
Layout.rightMargin: 20
|
Layout.rightMargin: 20
|
||||||
Layout.leftMargin: 20
|
Layout.leftMargin: 20
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
value: 0
|
value: 0
|
||||||
|
to: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
objectName: "labelProgress"
|
id: progressLabel
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: qsTr("Abort")
|
text: qsTr("Abort")
|
||||||
icon.source: "qrc:/images/icons/abort.svg"
|
icon.source: "qrc:/images/icons/abort.svg"
|
||||||
|
|||||||
@@ -213,6 +213,8 @@ Page {
|
|||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
anchors.topMargin: 10
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
rows: 2
|
rows: 2
|
||||||
|
|||||||
@@ -23,10 +23,12 @@ Window {
|
|||||||
|
|
||||||
signal saveMaterialAccent(string arg)
|
signal saveMaterialAccent(string arg)
|
||||||
signal saveMaterialTheme(string arg)
|
signal saveMaterialTheme(string arg)
|
||||||
|
signal saveAutoload(int arg)
|
||||||
|
|
||||||
function saveAll() {
|
function saveAll() {
|
||||||
saveMaterialAccent(comboBoxAccent.currentText)
|
saveMaterialAccent(comboBoxAccent.currentText)
|
||||||
saveMaterialTheme(comboBoxTheme.currentText)
|
saveMaterialTheme(comboBoxTheme.currentText)
|
||||||
|
saveAutoload(checkBoxAutoload.checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMaterialAccent(accent) {
|
function loadMaterialAccent(accent) {
|
||||||
@@ -47,6 +49,14 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadAutoload(toggle) {
|
||||||
|
if (toggle) {
|
||||||
|
checkBoxAutoload.checked = true
|
||||||
|
} else {
|
||||||
|
checkBoxAutoload.checked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DialogMessage {
|
DialogMessage {
|
||||||
id: dialogPreferencesSaved
|
id: dialogPreferencesSaved
|
||||||
modal: true
|
modal: true
|
||||||
@@ -67,10 +77,10 @@ Window {
|
|||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.rightMargin: 15
|
anchors.rightMargin: 10
|
||||||
anchors.leftMargin: 15
|
anchors.leftMargin: 10
|
||||||
anchors.bottomMargin: 15
|
anchors.bottomMargin: 10
|
||||||
anchors.topMargin: 15
|
anchors.topMargin: 10
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -132,6 +142,21 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Auto-load SigID Database on Startup"
|
||||||
|
font.pixelSize: 12
|
||||||
|
clip: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: checkBoxAutoload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,17 +154,18 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
Flickable {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 5
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
ScrollBar.vertical.interactive: true
|
Layout.topMargin: 5
|
||||||
|
TextArea.flickable: TextArea {
|
||||||
TextArea {
|
|
||||||
id: paramDescription
|
id: paramDescription
|
||||||
placeholderText: qsTr("Description")
|
placeholderText: qsTr("Description")
|
||||||
wrapMode: TextEdit.WordWrap
|
|
||||||
font.pointSize: 10
|
font.pointSize: 10
|
||||||
|
wrapMode: TextEdit.WordWrap
|
||||||
|
}
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
width: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ Page {
|
|||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
anchors.topMargin: 10
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: signalName
|
id: signalName
|
||||||
@@ -272,7 +274,6 @@ Page {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
width: 100
|
width: 100
|
||||||
height: 100
|
height: 100
|
||||||
@@ -571,18 +572,23 @@ Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
Flickable {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 5
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
ScrollBar.vertical.interactive: true
|
Layout.topMargin: 5
|
||||||
|
TextArea.flickable: TextArea {
|
||||||
TextArea {
|
|
||||||
id: descriptionTextArea
|
id: descriptionTextArea
|
||||||
|
placeholderText: qsTr("Description")
|
||||||
|
font.pointSize: 10
|
||||||
wrapMode: TextEdit.WordWrap
|
wrapMode: TextEdit.WordWrap
|
||||||
textFormat: Text.MarkdownText
|
textFormat: Text.MarkdownText
|
||||||
font.pointSize: 10
|
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
onLinkActivated: (link) => {
|
||||||
|
Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
width: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ Page {
|
|||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.rightMargin: 20
|
anchors.rightMargin: 10
|
||||||
anchors.leftMargin: 20
|
anchors.leftMargin: 10
|
||||||
anchors.bottomMargin: 20
|
anchors.bottomMargin: 10
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 10
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: imageBox
|
id: imageBox
|
||||||
|
|||||||
@@ -79,10 +79,10 @@ Page {
|
|||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.rightMargin: 20
|
anchors.rightMargin: 10
|
||||||
anchors.leftMargin: 20
|
anchors.leftMargin: 10
|
||||||
anchors.bottomMargin: 20
|
anchors.bottomMargin: 10
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 10
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ Page {
|
|||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.rightMargin: 20
|
anchors.rightMargin: 10
|
||||||
anchors.leftMargin: 20
|
anchors.leftMargin: 10
|
||||||
anchors.bottomMargin: 20
|
anchors.bottomMargin: 10
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 10
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: imageBox
|
id: imageBox
|
||||||
|
|||||||
@@ -120,10 +120,10 @@ Page {
|
|||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.rightMargin: 20
|
anchors.rightMargin: 10
|
||||||
anchors.leftMargin: 20
|
anchors.leftMargin: 10
|
||||||
anchors.bottomMargin: 20
|
anchors.bottomMargin: 10
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 10
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ Item {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
clip: true
|
clip: true
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("MAJOR STORM")
|
text: qsTr("STRONG STORM")
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -78,7 +78,7 @@ Item {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
clip: true
|
clip: true
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("MINOR STORM")
|
text: qsTr("MODERATE STORM")
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -94,7 +94,7 @@ Item {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
clip: true
|
clip: true
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("ACTIVE")
|
text: qsTr("ACTIVE-STORM")
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import QtMultimedia
|
|||||||
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: 200
|
width: 180
|
||||||
height: 80
|
height: 132
|
||||||
|
|
||||||
property bool loop: false
|
property bool loop: false
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ Item {
|
|||||||
buttonPause.enabled = true
|
buttonPause.enabled = true
|
||||||
buttonStop.enabled = true
|
buttonStop.enabled = true
|
||||||
buttonLoop.enabled = true
|
buttonLoop.enabled = true
|
||||||
playerPosition.enabled = player.seekable
|
positionSlider.enabled = player.seekable
|
||||||
player.play()
|
player.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,10 +65,12 @@ Item {
|
|||||||
buttonPause.enabled = false
|
buttonPause.enabled = false
|
||||||
buttonStop.enabled = false
|
buttonStop.enabled = false
|
||||||
buttonLoop.enabled = false
|
buttonLoop.enabled = false
|
||||||
playerPosition.enabled = false
|
positionSlider.enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: 0
|
spacing: 0
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
@@ -83,6 +85,10 @@ Item {
|
|||||||
onClicked: playSound()
|
onClicked: playSound()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
RoundButton {
|
RoundButton {
|
||||||
id: buttonPause
|
id: buttonPause
|
||||||
icon.color: Material.foreground
|
icon.color: Material.foreground
|
||||||
@@ -93,6 +99,10 @@ Item {
|
|||||||
onClicked: pauseSound()
|
onClicked: pauseSound()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
RoundButton {
|
RoundButton {
|
||||||
id: buttonStop
|
id: buttonStop
|
||||||
icon.color: Material.foreground
|
icon.color: Material.foreground
|
||||||
@@ -103,6 +113,10 @@ Item {
|
|||||||
onClicked: stopSound()
|
onClicked: stopSound()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
RoundButton {
|
RoundButton {
|
||||||
id: buttonLoop
|
id: buttonLoop
|
||||||
icon.color: Material.foreground
|
icon.color: Material.foreground
|
||||||
@@ -122,21 +136,43 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
Slider {
|
Slider {
|
||||||
id: playerPosition
|
id: positionSlider
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
Layout.preferredHeight: 20
|
Layout.preferredHeight: 20
|
||||||
enabled: player.seekable
|
enabled: player.seekable
|
||||||
value: player.duration > 0 ? player.position / player.duration : 0
|
value: player.duration > 0 ? player.position / player.duration : 0
|
||||||
|
Layout.fillWidth: true
|
||||||
onMoved: {
|
onMoved: {
|
||||||
player.position = player.duration * playerPosition.position
|
player.position = player.duration * positionSlider.position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Slider {
|
||||||
|
id: volumeSlider
|
||||||
|
Layout.preferredHeight: 20
|
||||||
|
value: 0.5
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
RoundButton {
|
||||||
|
id: buttonMute
|
||||||
|
icon.color: Material.foreground
|
||||||
|
icon.source: "qrc:/images/icons/player_mute.svg"
|
||||||
|
display: AbstractButton.IconOnly
|
||||||
|
enabled: true
|
||||||
|
flat: true
|
||||||
|
onClicked: {
|
||||||
|
volumeSlider.value = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaPlayer {
|
MediaPlayer {
|
||||||
id: player
|
id: player
|
||||||
audioOutput: audioOutput
|
audioOutput: audioOutput
|
||||||
|
|
||||||
onPlaybackStateChanged: {
|
onPlaybackStateChanged: {
|
||||||
if (player.playbackState === MediaPlayer.StoppedState) {
|
if (player.playbackState === MediaPlayer.StoppedState) {
|
||||||
if (loop) {
|
if (loop) {
|
||||||
@@ -150,7 +186,7 @@ Item {
|
|||||||
|
|
||||||
AudioOutput {
|
AudioOutput {
|
||||||
id: audioOutput
|
id: audioOutput
|
||||||
//volume: volumeSlider.value
|
volume: volumeSlider.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ Item {
|
|||||||
topLeftRadius: 10
|
topLeftRadius: 10
|
||||||
topRightRadius: 10
|
topRightRadius: 10
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("SUPER STORM")
|
text: qsTr("EXTREME STORM")
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -74,7 +74,7 @@ Item {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
clip: true
|
clip: true
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("EXTREME STORM")
|
text: qsTr("SEVERE STORM")
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -90,7 +90,7 @@ Item {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
clip: true
|
clip: true
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("SEVERE STORM")
|
text: qsTr("STRONG STORM")
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -106,7 +106,7 @@ Item {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
clip: true
|
clip: true
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("MAJOR STORM")
|
text: qsTr("MODERATE STORM")
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|||||||
Reference in New Issue
Block a user