qcanvas 1.0.12.dev3__tar.gz → 1.2.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.

Potentially problematic release.


This version of qcanvas might be problematic. Click here for more details.

Files changed (129) hide show
  1. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/PKG-INFO +16 -6
  2. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/README.md +12 -1
  3. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/pyproject.toml +12 -12
  4. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/app_start/__init__.py +6 -1
  5. qcanvas-1.2.0/qcanvas/icons/__init__.py +56 -0
  6. qcanvas-1.2.0/qcanvas/icons/_icon_type.py +42 -0
  7. qcanvas-1.2.0/qcanvas/icons/_update_icons.py +89 -0
  8. qcanvas-1.2.0/qcanvas/icons/dark/actions/exit.svg +3 -0
  9. qcanvas-1.2.0/qcanvas/icons/dark/actions/mark_all_read.svg +3 -0
  10. qcanvas-1.2.0/qcanvas/icons/dark/actions/open_downloads.svg +3 -0
  11. qcanvas-1.2.0/qcanvas/icons/dark/actions/quick_login.svg +3 -0
  12. qcanvas-1.2.0/qcanvas/icons/dark/actions/sync.svg +3 -0
  13. qcanvas-1.2.0/qcanvas/icons/dark/branding/logo_transparent.svg +303 -0
  14. qcanvas-1.2.0/qcanvas/icons/dark/options/auto_download.svg +3 -0
  15. qcanvas-1.2.0/qcanvas/icons/dark/options/theme.svg +3 -0
  16. qcanvas-1.2.0/qcanvas/icons/dark/tabs/assignments.svg +3 -0
  17. qcanvas-1.2.0/qcanvas/icons/dark/tabs/mail.svg +3 -0
  18. qcanvas-1.2.0/qcanvas/icons/dark/tabs/pages.svg +3 -0
  19. qcanvas-1.2.0/qcanvas/icons/dark/tree_items/assignment.svg +3 -0
  20. qcanvas-1.2.0/qcanvas/icons/dark/tree_items/mail.svg +3 -0
  21. qcanvas-1.2.0/qcanvas/icons/dark/tree_items/module.svg +3 -0
  22. qcanvas-1.2.0/qcanvas/icons/dark/tree_items/page.svg +3 -0
  23. qcanvas-1.2.0/qcanvas/icons/icons.qrc +46 -0
  24. qcanvas-1.2.0/qcanvas/icons/light/actions/exit.svg +3 -0
  25. qcanvas-1.2.0/qcanvas/icons/light/actions/mark_all_read.svg +3 -0
  26. qcanvas-1.2.0/qcanvas/icons/light/actions/open_downloads.svg +3 -0
  27. qcanvas-1.2.0/qcanvas/icons/light/actions/quick_login.svg +3 -0
  28. qcanvas-1.2.0/qcanvas/icons/light/actions/sync.svg +3 -0
  29. qcanvas-1.2.0/qcanvas/icons/light/branding/logo_transparent.svg +304 -0
  30. qcanvas-1.2.0/qcanvas/icons/light/options/auto_download.svg +3 -0
  31. qcanvas-1.2.0/qcanvas/icons/light/options/ignore_old.svg +3 -0
  32. qcanvas-1.2.0/qcanvas/icons/light/options/include_videos.svg +3 -0
  33. qcanvas-1.2.0/qcanvas/icons/light/options/theme.svg +3 -0
  34. qcanvas-1.2.0/qcanvas/icons/light/tabs/assignments.svg +3 -0
  35. qcanvas-1.2.0/qcanvas/icons/light/tabs/mail.svg +3 -0
  36. qcanvas-1.2.0/qcanvas/icons/light/tabs/pages.svg +3 -0
  37. qcanvas-1.2.0/qcanvas/icons/light/tree_items/assignment.svg +3 -0
  38. qcanvas-1.2.0/qcanvas/icons/light/tree_items/mail.svg +3 -0
  39. qcanvas-1.2.0/qcanvas/icons/light/tree_items/module.svg +3 -0
  40. qcanvas-1.2.0/qcanvas/icons/light/tree_items/page.svg +3 -0
  41. qcanvas-1.2.0/qcanvas/icons/rc_icons.py +2418 -0
  42. qcanvas-1.2.0/qcanvas/icons/universal/downloads/download_failed.svg +23 -0
  43. qcanvas-1.2.0/qcanvas/icons/universal/downloads/downloaded.svg +23 -0
  44. qcanvas-1.2.0/qcanvas/icons/universal/downloads/not_downloaded.svg +23 -0
  45. qcanvas-1.2.0/qcanvas/icons/universal/tabs/assignments_new_content.svg +3 -0
  46. qcanvas-1.2.0/qcanvas/icons/universal/tabs/mail_new_content.svg +3 -0
  47. qcanvas-1.2.0/qcanvas/icons/universal/tabs/pages_new_content.svg +3 -0
  48. qcanvas-1.2.0/qcanvas/icons/universal/tree_items/semester.svg +108 -0
  49. qcanvas-1.2.0/qcanvas/run.py +54 -0
  50. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/content_tree.py +28 -7
  51. qcanvas-1.2.0/qcanvas/ui/course_viewer/course_tree/__init__.py +1 -0
  52. qcanvas-1.2.0/qcanvas/ui/course_viewer/course_tree/_course_icon_generator.py +86 -0
  53. {qcanvas-1.0.12.dev3/qcanvas/ui/course_viewer → qcanvas-1.2.0/qcanvas/ui/course_viewer/course_tree}/course_tree.py +20 -6
  54. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/course_viewer.py +71 -24
  55. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py +15 -14
  56. qcanvas-1.2.0/qcanvas/ui/course_viewer/tabs/file_tab/__init__.py +1 -0
  57. qcanvas-1.2.0/qcanvas/ui/course_viewer/tabs/file_tab/file_tab.py +46 -0
  58. qcanvas-1.2.0/qcanvas/ui/course_viewer/tabs/file_tab/file_tree.py +99 -0
  59. qcanvas-1.2.0/qcanvas/ui/course_viewer/tabs/file_tab/pages_file_tree.py +56 -0
  60. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py +11 -11
  61. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py +13 -11
  62. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/resource_rich_browser.py +57 -56
  63. qcanvas-1.2.0/qcanvas/ui/course_viewer/tabs/util.py +11 -0
  64. qcanvas-1.2.0/qcanvas/ui/course_viewer/tree_widget_data_item.py +22 -0
  65. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/course_viewer_container.py +46 -3
  66. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/options/auto_download_resources_option.py +3 -1
  67. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/options/theme_selection_menu.py +2 -0
  68. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/qcanvas_window.py +18 -5
  69. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/status_bar_progress_display.py +17 -8
  70. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/memory_tree/_tree_memory.py +1 -0
  71. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/memory_tree/memory_tree_widget.py +2 -2
  72. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/setup/setup_checker.py +2 -2
  73. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/setup/setup_dialog.py +145 -66
  74. qcanvas-1.2.0/qcanvas/util/__init__.py +0 -0
  75. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/auto_downloader.py +1 -2
  76. qcanvas-1.2.0/qcanvas/util/file_icons.py +54 -0
  77. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/html_cleaner.py +2 -0
  78. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/layouts.py +5 -2
  79. qcanvas-1.2.0/qcanvas/util/paths.py +41 -0
  80. qcanvas-1.2.0/qcanvas/util/runtime.py +20 -0
  81. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/settings/_client_settings.py +11 -2
  82. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/settings/_mapped_setting.py +6 -1
  83. qcanvas-1.2.0/qcanvas/util/themes/__init__.py +2 -0
  84. qcanvas-1.2.0/qcanvas/util/themes/_colour_scheme_helper.py +38 -0
  85. qcanvas-1.2.0/qcanvas/util/themes/_selected_theme.py +10 -0
  86. qcanvas-1.2.0/qcanvas/util/themes/_theme_changed_event.py +17 -0
  87. qcanvas-1.2.0/qcanvas/util/themes/_theme_changer.py +86 -0
  88. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/ui_tools.py +5 -1
  89. qcanvas-1.0.12.dev3/qcanvas/icons/__init__.py +0 -7
  90. qcanvas-1.0.12.dev3/qcanvas/icons/file-download-failed.svg +0 -6
  91. qcanvas-1.0.12.dev3/qcanvas/icons/file-downloaded.svg +0 -6
  92. qcanvas-1.0.12.dev3/qcanvas/icons/file-not-downloaded.svg +0 -6
  93. qcanvas-1.0.12.dev3/qcanvas/icons/icons.qrc +0 -10
  94. qcanvas-1.0.12.dev3/qcanvas/icons/rc_icons.py +0 -608
  95. qcanvas-1.0.12.dev3/qcanvas/icons/sync.svg +0 -7
  96. qcanvas-1.0.12.dev3/qcanvas/run.py +0 -30
  97. qcanvas-1.0.12.dev3/qcanvas/ui/course_viewer/tabs/util.py +0 -1
  98. qcanvas-1.0.12.dev3/qcanvas/util/__init__.py +0 -2
  99. qcanvas-1.0.12.dev3/qcanvas/util/paths.py +0 -52
  100. qcanvas-1.0.12.dev3/qcanvas/util/themes.py +0 -24
  101. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/__init__.py +0 -0
  102. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/backend_connectors/__init__.py +0 -0
  103. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/backend_connectors/frontend_resource_manager.py +0 -0
  104. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/backend_connectors/qcanvas_task_master.py +0 -0
  105. {qcanvas-1.0.12.dev3/qcanvas/icons → qcanvas-1.2.0/qcanvas/icons/universal/branding}/main_icon.svg +0 -0
  106. /qcanvas-1.0.12.dev3/qcanvas/icons/file-unknown.svg → /qcanvas-1.2.0/qcanvas/icons/universal/downloads/unknown.svg +0 -0
  107. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/__init__.py +0 -0
  108. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/__init__.py +0 -0
  109. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/__init__.py +0 -0
  110. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/assignment_tab/__init__.py +0 -0
  111. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py +0 -0
  112. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/content_tab.py +0 -0
  113. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/mail_tab/__init__.py +0 -0
  114. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py +0 -0
  115. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/page_tab/__init__.py +0 -0
  116. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py +0 -0
  117. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/__init__.py +0 -0
  118. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/options/__init__.py +0 -0
  119. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/options/quick_sync_option.py +0 -0
  120. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/main_ui/options/sync_on_start_option.py +0 -0
  121. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/memory_tree/__init__.py +0 -0
  122. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/memory_tree/memory_tree_widget_item.py +0 -0
  123. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/ui/setup/__init__.py +0 -0
  124. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/basic_fonts.py +0 -0
  125. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/logs.py +0 -0
  126. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/qurl_util.py +0 -0
  127. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/settings/__init__.py +0 -0
  128. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/settings/_ui_settings.py +0 -0
  129. {qcanvas-1.0.12.dev3 → qcanvas-1.2.0}/qcanvas/util/url_checker.py +0 -0
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qcanvas
3
- Version: 1.0.12.dev3
3
+ Version: 1.2.0
4
4
  Summary: QCanvas is a desktop client for Canvas LMS.
5
5
  Author: QCanvas
6
6
  Author-email: QCanvas@noreply.codeberg.org
7
- Requires-Python: >=3.11,<3.13
7
+ Requires-Python: >3.11.0,<3.13
8
8
  Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.11
10
9
  Classifier: Programming Language :: Python :: 3.12
11
10
  Requires-Dist: aiosqlite (>=0.20.0,<0.21.0)
12
11
  Requires-Dist: asynctaskpool (>=0.2.1,<0.3.0)
@@ -14,8 +13,8 @@ Requires-Dist: lightdb (>=2.0,<3.0)
14
13
  Requires-Dist: platformdirs (>=4.2.2,<5.0.0)
15
14
  Requires-Dist: pyqtdarktheme-fork (>=2.3.2,<3.0.0)
16
15
  Requires-Dist: qasync (>=0.27.1,<0.28.0)
17
- Requires-Dist: qcanvas-api-clients (>=0.2.2,<0.3.0)
18
- Requires-Dist: qcanvas-backend (==0.1.10)
16
+ Requires-Dist: qcanvas-api-clients (>=0.3.0,<0.4.0)
17
+ Requires-Dist: qcanvas-backend (>=0.2.5,<0.3.0)
19
18
  Requires-Dist: qtpy (>=2.4.1,<3.0.0)
20
19
  Requires-Dist: sqlalchemy (>=2.0.31,<3.0.0)
21
20
  Requires-Dist: validators (>=0.33.0,<0.34.0)
@@ -25,9 +24,20 @@ Description-Content-Type: text/markdown
25
24
 
26
25
  QCanvas is an **unofficial** desktop client for Canvas LMS.
27
26
 
27
+ https://codeberg.org/QCanvas/QCanvas
28
+
29
+ https://github.com/QCanvas/QCanvasApp
30
+
28
31
  # Downloads
29
32
 
30
- Download it from [releases](https://github.com/QCanvas/QCanvasApp/releases)
33
+ <a href='https://flathub.org/apps/io.github.qcanvas.QCanvasApp'>
34
+ <img width='240' alt='Get it on Flathub' src='https://flathub.org/api/badge?svg&locale=en'/>
35
+ </a>
36
+
37
+ You can download a **windows** version from [releases](https://github.com/QCanvas/QCanvasApp/releases)
38
+
39
+ The appimage version is *not recommended* as it is not a proper portable appimage. It will only work on debian/ubuntu
40
+ based distros.
31
41
 
32
42
  # Development/Run from source
33
43
 
@@ -2,9 +2,20 @@
2
2
 
3
3
  QCanvas is an **unofficial** desktop client for Canvas LMS.
4
4
 
5
+ https://codeberg.org/QCanvas/QCanvas
6
+
7
+ https://github.com/QCanvas/QCanvasApp
8
+
5
9
  # Downloads
6
10
 
7
- Download it from [releases](https://github.com/QCanvas/QCanvasApp/releases)
11
+ <a href='https://flathub.org/apps/io.github.qcanvas.QCanvasApp'>
12
+ <img width='240' alt='Get it on Flathub' src='https://flathub.org/api/badge?svg&locale=en'/>
13
+ </a>
14
+
15
+ You can download a **windows** version from [releases](https://github.com/QCanvas/QCanvasApp/releases)
16
+
17
+ The appimage version is *not recommended* as it is not a proper portable appimage. It will only work on debian/ubuntu
18
+ based distros.
8
19
 
9
20
  # Development/Run from source
10
21
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "qcanvas"
3
- version = "1.0.12.dev3"
3
+ version = "1.2.0"
4
4
  description = "QCanvas is a desktop client for Canvas LMS."
5
5
  authors = ["QCanvas <QCanvas@noreply.codeberg.org>"]
6
6
  readme = "README.md"
@@ -15,9 +15,10 @@ exclude = [
15
15
  qcanvas = "qcanvas.run:main"
16
16
 
17
17
  [tool.poetry.dependencies]
18
- python = ">=3.11,<3.13"
19
- qcanvas-api-clients = "^0.2.2"
20
- qcanvas-backend = "0.1.10"
18
+ python = ">=3.11,<3.13,!=3.11.0"
19
+ qcanvas-api-clients = "^0.3.0"
20
+ qcanvas-backend = "^0.2.5"
21
+ #qcanvas-backend = { path = "../QCanvas-Backend/", develop = true }
21
22
  asynctaskpool = "^0.2.1"
22
23
  sqlalchemy = "^2.0.31"
23
24
  qtpy = "^2.4.1"
@@ -28,6 +29,7 @@ lightdb = "^2.0"
28
29
  platformdirs = "^4.2.2"
29
30
  validators = "^0.33.0"
30
31
 
32
+
31
33
  [tool.poetry.group.flatpak-exclude.dependencies]
32
34
  pyside6-essentials = "^6.7.2"
33
35
  #2024-07-18: Latest version causes error with pyinstaller
@@ -38,15 +40,13 @@ pyinstaller = "^6.9.0"
38
40
  optional = true
39
41
 
40
42
  [tool.poetry.group.dev-tools.dependencies]
41
- black = "^24.4.2"
42
- isort = "^5.13.2"
43
+ #nuitka = "^2.4.5"
44
+ rich = "^13.7.1"
45
+ pre-commit = "^3.8.0"
46
+ scalene = "^1.5.44.1"
47
+ xmltodict = "^0.13.0"
48
+ #block-timer = "^0.2.0"
43
49
 
44
- [tool.poetry.group.local-deps]
45
- optional = true
46
-
47
- [tool.poetry.group.local-deps.dependencies]
48
- #qcanvas-api-clients = { path = "../QCanvas-API-Clients/", develop = false }
49
- #qcanvas-backend = { path = "../QCanvas-Backend/", develop = true }
50
50
 
51
51
  [build-system]
52
52
  requires = ["poetry-core"]
@@ -4,12 +4,13 @@ import sys
4
4
 
5
5
  import qtpy
6
6
  from qasync import QEventLoop
7
+ from qtpy.QtGui import QGuiApplication
7
8
  from qtpy.QtWidgets import QApplication
8
9
 
9
10
  import qcanvas.backend_connectors.qcanvas_task_master as task_master
10
11
  from qcanvas.ui.main_ui.qcanvas_window import QCanvasWindow
11
12
  from qcanvas.ui.setup import SetupDialog, setup_checker
12
- from qcanvas.util import settings, themes
13
+ from qcanvas.util import runtime, settings, themes
13
14
 
14
15
  main_window = None
15
16
  setup_window = None
@@ -32,6 +33,10 @@ def launch():
32
33
  _show_qt_api_name()
33
34
 
34
35
  app = QApplication(sys.argv)
36
+
37
+ if runtime.is_running_as_flatpak:
38
+ QGuiApplication.setDesktopFileName("io.github.qcanvas.QCanvasApp")
39
+
35
40
  app.setApplicationName("QCanvas")
36
41
 
37
42
  task_master.register()
@@ -0,0 +1,56 @@
1
+ from qtpy.QtGui import QIcon
2
+
3
+ from ._icon_type import ThemeIcon, UniversalIcon
4
+ from .rc_icons import (
5
+ qt_resource_data as _, # Without this, icon data will not be loaded
6
+ )
7
+
8
+
9
+ # noinspection PyPep8Naming
10
+ class actions:
11
+ exit = QIcon.fromTheme("actions/exit")
12
+ mark_all_read = QIcon.fromTheme("actions/mark_all_read")
13
+ open_downloads = QIcon.fromTheme("actions/open_downloads")
14
+ quick_login = QIcon.fromTheme("actions/quick_login")
15
+ sync = QIcon.fromTheme("actions/sync")
16
+
17
+
18
+ # noinspection PyPep8Naming
19
+ class branding:
20
+ logo_transparent = QIcon.fromTheme("branding/logo_transparent")
21
+ main_icon = QIcon.fromTheme("branding/main_icon")
22
+
23
+
24
+ # noinspection PyPep8Naming
25
+ class options:
26
+ auto_download = QIcon.fromTheme("options/auto_download")
27
+ ignore_old = QIcon.fromTheme("options/ignore_old")
28
+ include_videos = QIcon.fromTheme("options/include_videos")
29
+ theme = QIcon.fromTheme("options/theme")
30
+
31
+
32
+ # noinspection PyPep8Naming
33
+ class tabs:
34
+ assignments = QIcon.fromTheme("tabs/assignments")
35
+ assignments_new_content = QIcon.fromTheme("tabs/assignments_new_content")
36
+ mail = QIcon.fromTheme("tabs/mail")
37
+ mail_new_content = QIcon.fromTheme("tabs/mail_new_content")
38
+ pages = QIcon.fromTheme("tabs/pages")
39
+ pages_new_content = QIcon.fromTheme("tabs/pages_new_content")
40
+
41
+
42
+ # noinspection PyPep8Naming
43
+ class tree_items:
44
+ assignment = QIcon.fromTheme("tree_items/assignment")
45
+ mail = QIcon.fromTheme("tree_items/mail")
46
+ module = QIcon.fromTheme("tree_items/module")
47
+ page = QIcon.fromTheme("tree_items/page")
48
+ semester = QIcon.fromTheme("tree_items/semester")
49
+
50
+
51
+ # noinspection PyPep8Naming
52
+ class downloads:
53
+ download_failed = QIcon.fromTheme("downloads/download_failed")
54
+ downloaded = QIcon.fromTheme("downloads/downloaded")
55
+ not_downloaded = QIcon.fromTheme("downloads/not_downloaded")
56
+ unknown = QIcon.fromTheme("downloads/unknown")
@@ -0,0 +1,42 @@
1
+ # Unused
2
+ import logging
3
+
4
+ from qtpy.QtGui import QIcon
5
+
6
+ _logger = logging.getLogger(__name__)
7
+
8
+
9
+ class ThemeIcon:
10
+ def __init__(self, theme_path: str):
11
+ self._theme_path = theme_path
12
+ self._icon = None
13
+
14
+ @property
15
+ def icon(self) -> QIcon:
16
+ if self._icon is None:
17
+ self._icon = QIcon.fromTheme(self._theme_path)
18
+
19
+ return self._icon
20
+
21
+ @property
22
+ def theme_path(self) -> str:
23
+ return self._theme_path
24
+
25
+ def __hash__(self) -> int:
26
+ return hash(self._theme_path)
27
+
28
+
29
+ class UniversalIcon(ThemeIcon):
30
+ def __init__(self, theme_path: str, full_path: str):
31
+ super().__init__(theme_path)
32
+ self._full_path = full_path
33
+
34
+ @property
35
+ def full_path(self) -> str:
36
+ return self._full_path
37
+
38
+ def __hash__(self) -> int:
39
+ return hash(self._theme_path) ^ hash(self.full_path)
40
+
41
+
42
+ AnyIcon = UniversalIcon | ThemeIcon
@@ -0,0 +1,89 @@
1
+ # This file regenerates icons.qrc, rc_icons.py and the icons definition file based on the icons in dark/, light/ and universal/
2
+
3
+ import glob
4
+ import logging
5
+ import os
6
+ import subprocess
7
+ from pathlib import Path
8
+
9
+ import xmltodict
10
+
11
+ _logger = logging.getLogger(__name__)
12
+
13
+
14
+ def remove_base_directory(path: str | Path) -> Path:
15
+ if isinstance(path, str):
16
+ path = Path(path)
17
+
18
+ return Path(*path.parts[1:])
19
+
20
+
21
+ def generate_xml(all_icons: list[Path]) -> str:
22
+ xml_dict = {
23
+ "RCC": {
24
+ "@version": "1.0",
25
+ "qresource": {"@prefix": "icons/", "file": all_icons},
26
+ }
27
+ }
28
+
29
+ return "<!DOCTYPE RCC>\n" + xmltodict.unparse(
30
+ xml_dict, pretty=True, full_document=False
31
+ )
32
+
33
+
34
+ def generate_icon_defs(icons: list[Path]) -> str:
35
+ icons_base_removed = [remove_base_directory(icon) for icon in icons]
36
+ groups = group_icons_by_category(icons_base_removed)
37
+ classes = [
38
+ generate_group_class(group_name, icons) for group_name, icons in groups.items()
39
+ ]
40
+
41
+ return f"""from .rc_icons import qt_resource_data as _ # Without this, icon data will not be loaded
42
+ from qtpy.QtGui import QIcon
43
+ from ._icon_type import UniversalIcon, ThemeIcon
44
+
45
+ """ + "\n\n".join(
46
+ classes
47
+ )
48
+
49
+
50
+ def group_icons_by_category(icons: list[Path]) -> dict[str, set[Path]]:
51
+ groups: dict[str, set[Path]] = {}
52
+
53
+ for icon in icons:
54
+ icon_category = icon.parts[0]
55
+ groups.setdefault(icon_category, set())
56
+ groups[icon_category].add(icon)
57
+
58
+ return groups
59
+
60
+
61
+ def generate_group_class(group_name: str, icons: set[Path]) -> str:
62
+ # pascal_case_class_name = "".join([part.title() for part in group_name.split("_")])
63
+ lines = ["# noinspection PyPep8Naming", f"class {group_name}:"]
64
+
65
+ for icon in sorted(icons):
66
+ path_no_ext = os.path.splitext(icon)[0]
67
+ lines.append(f' {icon.stem} = QIcon.fromTheme("{path_no_ext}")')
68
+
69
+ return "\n".join(lines)
70
+
71
+
72
+ def run_rcc() -> None:
73
+ subprocess.run(["pyside6-rcc", "icons.qrc", "-o", "rc_icons.py"])
74
+
75
+
76
+ def write(file_name: str, content: str) -> None:
77
+ with open(file_name, "w") as f:
78
+ f.write(content)
79
+
80
+
81
+ if __name__ == "__main__":
82
+ all_icons: list[Path] = [
83
+ Path(file) for file in glob.glob("**/*.svg", recursive=True)
84
+ ]
85
+ all_icons.sort()
86
+
87
+ write("icons.qrc", generate_xml(all_icons))
88
+ write("__init__.py", generate_icon_defs(all_icons))
89
+ run_rcc()
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
2
+ <path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
2
+ <path d="M120-280v-80h560v80H120Zm80-160v-80h560v80H200Zm80-160v-80h560v80H280Z"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
2
+ <path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640H447l-80-80H160v480l96-320h684L837-217q-8 26-29.5 41.5T760-160H160Zm84-80h516l72-240H316l-72 240Zm0 0 72-240-72 240Zm-84-400v-80 80Z"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
2
+ <path d="M480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-155.5t86-127Q252-817 325-848.5T480-880q83 0 155.5 31.5t127 86q54.5 54.5 86 127T880-480q0 82-31.5 155t-86 127.5q-54.5 54.5-127 86T480-80Zm0-82q26-36 45-75t31-83H404q12 44 31 83t45 75Zm-104-16q-18-33-31.5-68.5T322-320H204q29 50 72.5 87t99.5 55Zm208 0q56-18 99.5-55t72.5-87H638q-9 38-22.5 73.5T584-178ZM170-400h136q-3-20-4.5-39.5T300-480q0-21 1.5-40.5T306-560H170q-5 20-7.5 39.5T160-480q0 21 2.5 40.5T170-400Zm216 0h188q3-20 4.5-39.5T580-480q0-21-1.5-40.5T574-560H386q-3 20-4.5 39.5T380-480q0 21 1.5 40.5T386-400Zm268 0h136q5-20 7.5-39.5T800-480q0-21-2.5-40.5T790-560H654q3 20 4.5 39.5T660-480q0 21-1.5 40.5T654-400Zm-16-240h118q-29-50-72.5-87T584-782q18 33 31.5 68.5T638-640Zm-234 0h152q-12-44-31-83t-45-75q-26 36-45 75t-31 83Zm-200 0h118q9-38 22.5-73.5T376-782q-56 18-99.5 55T204-640Z"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
2
+ <path d="M160-160v-80h110l-16-14q-52-46-73-105t-21-119q0-111 66.5-197.5T400-790v84q-72 26-116 88.5T240-478q0 45 17 87.5t53 78.5l10 10v-98h80v240H160Zm400-10v-84q72-26 116-88.5T720-482q0-45-17-87.5T650-648l-10-10v98h-80v-240h240v80H690l16 14q49 49 71.5 106.5T800-482q0 111-66.5 197.5T560-170Z"/>
3
+ </svg>