qcanvas 1.0.11__py3-none-any.whl → 2026.1.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. qcanvas/__init__.py +60 -0
  2. qcanvas/app.py +72 -0
  3. qcanvas/backend_connectors/frontend_resource_manager.py +13 -5
  4. qcanvas/backend_connectors/qcanvas_task_master.py +2 -2
  5. qcanvas/icons/__init__.py +55 -6
  6. qcanvas/icons/_icon_type.py +42 -0
  7. qcanvas/icons/icons.qrc +48 -8
  8. qcanvas/icons/rc_icons.py +2477 -566
  9. qcanvas/settings/__init__.py +6 -0
  10. qcanvas/{util/settings → settings}/_client_settings.py +15 -6
  11. qcanvas/settings/_course_settings.py +54 -0
  12. qcanvas/{util/settings → settings}/_mapped_setting.py +8 -6
  13. qcanvas/{util/settings → settings}/_ui_settings.py +5 -5
  14. qcanvas/theme.py +101 -0
  15. qcanvas/ui/course_viewer/content_tree.py +37 -19
  16. qcanvas/ui/course_viewer/course_tree/__init__.py +1 -0
  17. qcanvas/ui/course_viewer/course_tree/_course_icon_generator.py +86 -0
  18. qcanvas/ui/course_viewer/{course_tree.py → course_tree/course_tree.py} +29 -14
  19. qcanvas/ui/course_viewer/course_viewer.py +79 -46
  20. qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py +107 -29
  21. qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py +19 -18
  22. qcanvas/ui/course_viewer/tabs/content_tab.py +33 -39
  23. qcanvas/ui/course_viewer/tabs/file_tab/__init__.py +1 -0
  24. qcanvas/ui/course_viewer/tabs/file_tab/file_tab.py +46 -0
  25. qcanvas/ui/course_viewer/tabs/file_tab/file_tree.py +96 -0
  26. qcanvas/ui/course_viewer/tabs/file_tab/pages_file_tree.py +55 -0
  27. qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py +50 -27
  28. qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py +18 -19
  29. qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py +3 -3
  30. qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py +18 -16
  31. qcanvas/ui/course_viewer/tabs/resource_rich_browser.py +61 -74
  32. qcanvas/ui/course_viewer/tree_widget_data_item.py +22 -0
  33. qcanvas/ui/memory_tree/_tree_memory.py +45 -41
  34. qcanvas/ui/memory_tree/memory_tree_widget.py +22 -18
  35. qcanvas/ui/memory_tree/memory_tree_widget_item.py +3 -3
  36. qcanvas/ui/qcanvas_window/__init__.py +1 -0
  37. qcanvas/ui/qcanvas_window/course_viewer_container.py +95 -0
  38. qcanvas/ui/{main_ui → qcanvas_window}/options/auto_download_resources_option.py +8 -6
  39. qcanvas/ui/{main_ui → qcanvas_window}/options/quick_sync_option.py +7 -6
  40. qcanvas/ui/{main_ui → qcanvas_window}/options/sync_on_start_option.py +7 -6
  41. qcanvas/ui/{main_ui → qcanvas_window}/options/theme_selection_menu.py +12 -10
  42. qcanvas/ui/{main_ui → qcanvas_window}/qcanvas_window.py +74 -45
  43. qcanvas/ui/{main_ui → qcanvas_window}/status_bar_progress_display.py +20 -12
  44. qcanvas/ui/qml_components/__init__.py +4 -0
  45. qcanvas/ui/qml_components/attachments_pane.py +70 -0
  46. qcanvas/ui/qml_components/comments_pane.py +83 -0
  47. qcanvas/ui/qml_components/qml/AttachmentsList.ui.qml +15 -0
  48. qcanvas/ui/qml_components/qml/AttachmentsListDelegate.qml +77 -0
  49. qcanvas/ui/qml_components/qml/AttachmentsListModel.qml +19 -0
  50. qcanvas/ui/qml_components/qml/AttachmentsPane.qml +11 -0
  51. qcanvas/ui/qml_components/qml/CommentsList.ui.qml +15 -0
  52. qcanvas/ui/qml_components/qml/CommentsListDelegate.ui.qml +118 -0
  53. qcanvas/ui/qml_components/qml/CommentsListModel.qml +56 -0
  54. qcanvas/ui/qml_components/qml/CommentsPane.qml +11 -0
  55. qcanvas/ui/qml_components/qml/DecoratedText.ui.qml +44 -0
  56. qcanvas/ui/qml_components/qml/Spacer.ui.qml +7 -0
  57. qcanvas/ui/qml_components/qml/ThemedRectangle.qml +53 -0
  58. qcanvas/ui/qml_components/qml/__init__.py +3 -0
  59. qcanvas/ui/qml_components/qml/rc_qml.py +709 -0
  60. qcanvas/ui/qml_components/qml/rc_qml.qrc +16 -0
  61. qcanvas/ui/qml_components/qml_bridge_types.py +95 -0
  62. qcanvas/ui/qml_components/qml_pane.py +21 -0
  63. qcanvas/ui/setup/setup_checker.py +3 -3
  64. qcanvas/ui/setup/setup_dialog.py +173 -80
  65. qcanvas/util/__init__.py +0 -2
  66. qcanvas/util/auto_downloader.py +9 -8
  67. qcanvas/util/basic_fonts.py +2 -2
  68. qcanvas/util/context_dict.py +12 -0
  69. qcanvas/util/file_icons.py +46 -0
  70. qcanvas/util/html_cleaner.py +2 -0
  71. qcanvas/util/layouts.py +9 -8
  72. qcanvas/util/paths.py +26 -22
  73. qcanvas/util/qurl_util.py +1 -1
  74. qcanvas/util/runtime.py +20 -0
  75. qcanvas/util/ui_tools.py +121 -7
  76. qcanvas/util/url_checker.py +1 -1
  77. qcanvas-2026.1.19.dist-info/METADATA +95 -0
  78. qcanvas-2026.1.19.dist-info/RECORD +92 -0
  79. {qcanvas-1.0.11.dist-info → qcanvas-2026.1.19.dist-info}/WHEEL +1 -1
  80. qcanvas-2026.1.19.dist-info/entry_points.txt +3 -0
  81. qcanvas/app_start/__init__.py +0 -54
  82. qcanvas/icons/file-download-failed.svg +0 -6
  83. qcanvas/icons/file-downloaded.svg +0 -6
  84. qcanvas/icons/file-not-downloaded.svg +0 -6
  85. qcanvas/icons/file-unknown.svg +0 -6
  86. qcanvas/icons/main_icon.svg +0 -325
  87. qcanvas/icons/sync.svg +0 -7
  88. qcanvas/run.py +0 -30
  89. qcanvas/ui/main_ui/__init__.py +0 -0
  90. qcanvas/ui/main_ui/course_viewer_container.py +0 -52
  91. qcanvas/util/settings/__init__.py +0 -9
  92. qcanvas/util/themes.py +0 -24
  93. qcanvas-1.0.11.dist-info/METADATA +0 -61
  94. qcanvas-1.0.11.dist-info/RECORD +0 -68
  95. qcanvas-1.0.11.dist-info/entry_points.txt +0 -3
  96. /qcanvas/ui/course_viewer/tabs/{util.py → constants.py} +0 -0
  97. /qcanvas/ui/{main_ui → qcanvas_window}/options/__init__.py +0 -0
qcanvas/util/paths.py CHANGED
@@ -1,27 +1,36 @@
1
1
  import logging
2
2
  import os
3
- import platform
4
- import sys
5
3
  from pathlib import Path
6
4
 
7
5
  import cachetools
8
6
  import platformdirs
9
- from qtpy.QtCore import QDir, QSettings
7
+ from PySide6.QtCore import QSettings
8
+
9
+ from qcanvas.util.runtime import (
10
+ is_running_as_compiled,
11
+ is_running_as_flatpak,
12
+ is_running_portable,
13
+ )
10
14
 
11
15
  _logger = logging.getLogger(__name__)
12
16
 
13
- _is_running_on_windows = platform.system() == "Windows"
14
- _is_running_on_linux = platform.system() == "Linux"
15
- _is_running_as_pyinstaller = getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS")
16
- _is_running_as_flatpak = os.environ.get("container", "") == "flatpak"
17
+
18
+ def data_storage() -> Path:
19
+ return root()
20
+
21
+
22
+ def config_storage() -> Path:
23
+ if is_running_portable:
24
+ return root()
25
+ else:
26
+ path = platformdirs.user_config_path("QCanvasTeam", "QCanvas")
27
+ path.mkdir(parents=True, exist_ok=True)
28
+ return path
17
29
 
18
30
 
19
31
  def client_settings() -> QSettings:
20
- if _is_running_as_pyinstaller and _is_running_on_windows:
21
- return QSettings(
22
- str(Path(QDir.homePath()) / ".config" / "QCanvasTeam" / "canvas.ini"),
23
- QSettings.Format.IniFormat,
24
- )
32
+ if is_running_portable:
33
+ return QSettings("QCanvas.ini", QSettings.Format.IniFormat)
25
34
  else:
26
35
  return QSettings("QCanvasTeam", "QCanvas")
27
36
 
@@ -30,19 +39,14 @@ def client_settings() -> QSettings:
30
39
  def root() -> Path:
31
40
  root_path = Path()
32
41
 
33
- if _is_running_as_flatpak:
42
+ if is_running_as_flatpak:
43
+ # Flatpak does not support portable mode
34
44
  root_path = Path(os.environ["XDG_DATA_HOME"])
35
- elif _is_running_as_pyinstaller:
45
+ elif not is_running_portable and is_running_as_compiled:
36
46
  root_path = platformdirs.user_data_path("QCanvasReborn", "QCanvasTeam")
47
+ elif not is_running_portable:
48
+ _logger.warning("Don't know how we're being run? Are you running from source?")
37
49
 
38
50
  print("Root path", root_path.absolute())
39
51
  _logger.debug("Root path %s", root_path.absolute())
40
52
  return root_path
41
-
42
-
43
- def ui_storage() -> Path:
44
- return root() / ".UI"
45
-
46
-
47
- def data_storage() -> Path:
48
- return root()
qcanvas/util/qurl_util.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from pathlib import Path
3
3
 
4
- from qtpy.QtCore import QUrl
4
+ from PySide6.QtCore import QUrl
5
5
 
6
6
  _logger = logging.getLogger(__name__)
7
7
 
@@ -0,0 +1,20 @@
1
+ import os
2
+ import platform
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ is_running_portable = Path(".portable").exists()
7
+ is_running_on_windows = platform.system() == "Windows"
8
+ is_running_on_linux = platform.system() == "Linux"
9
+ _is_nuitka = "__compiled__" in globals()
10
+ _is_pyinstaller = getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS")
11
+ is_running_as_compiled = _is_nuitka or _is_pyinstaller
12
+ is_running_as_flatpak = os.environ.get("container", "") == "flatpak"
13
+
14
+ __all__ = [
15
+ "is_running_portable",
16
+ "is_running_as_flatpak",
17
+ "is_running_on_linux",
18
+ "is_running_as_compiled",
19
+ "is_running_on_windows",
20
+ ]
qcanvas/util/ui_tools.py CHANGED
@@ -1,14 +1,124 @@
1
- import logging
2
- from typing import Any
1
+ from typing import Any, Sequence
3
2
 
4
- from qtpy.QtGui import QKeySequence
5
- from qtpy.QtWidgets import *
3
+ from PySide6.QtCore import QSize
4
+ from PySide6.QtGui import QAction, QIcon, QKeySequence, QPixmap, QFont
5
+ from PySide6.QtWidgets import (
6
+ QMenu,
7
+ QSizePolicy,
8
+ QLabel,
9
+ QWidget,
10
+ QFormLayout,
11
+ QDockWidget,
12
+ QLayout,
13
+ QHBoxLayout,
14
+ QVBoxLayout,
15
+ )
6
16
 
7
- _logger = logging.getLogger(__name__)
8
17
 
18
+ def font(*, point_size: float | int | None = None, bold: bool | None = None) -> QFont:
19
+ _font = QFont()
9
20
 
10
- def make_truncatable(widget: QWidget) -> None:
11
- widget.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Fixed)
21
+ if point_size is not None:
22
+ if isinstance(point_size, int):
23
+ _font.setPointSize(point_size)
24
+ elif isinstance(point_size, float):
25
+ _font.setPointSizeF(point_size)
26
+ else:
27
+ raise TypeError("point_size")
28
+
29
+ if bold is not None:
30
+ _font.setBold(bold)
31
+
32
+ return _font
33
+
34
+
35
+ _bold = font(bold=True)
36
+
37
+
38
+ def label(text: str, *, font: QFont = None, allow_truncation: bool = False) -> QLabel:
39
+ _label = QLabel(text)
40
+
41
+ if font is not None:
42
+ _label.setFont(font)
43
+
44
+ if allow_truncation:
45
+ _label.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Fixed)
46
+
47
+ return _label
48
+
49
+
50
+ def bold_label(text: str, *, allow_truncation: bool = False) -> QLabel:
51
+ return label(text, allow_truncation=allow_truncation, font=_bold)
52
+
53
+
54
+ def form_layout(
55
+ rows: dict[str, QWidget], label_font: QFont | None = _bold, label_suffix: str = ":"
56
+ ) -> QFormLayout:
57
+ layout = QFormLayout()
58
+
59
+ for name, widget in rows.items():
60
+ if label_font:
61
+ layout.addRow(label(name + label_suffix, font=label_font), widget)
62
+ else:
63
+ layout.addRow(name + label_suffix, widget)
64
+
65
+ return layout
66
+
67
+
68
+ def size(width: int, height: int):
69
+ return QSize(width, height)
70
+
71
+
72
+ def dock_widget(
73
+ *,
74
+ widget: QWidget,
75
+ title: str | None = None,
76
+ hide: bool = False,
77
+ name: str | None = None,
78
+ min_size: QSize | None = None,
79
+ features: QDockWidget.DockWidgetFeature | None = None,
80
+ parent: QWidget | None = None,
81
+ ) -> QDockWidget:
82
+ dock = QDockWidget(title, parent)
83
+ dock.setWidget(widget)
84
+
85
+ if name is not None:
86
+ dock.setObjectName(name)
87
+
88
+ if min_size is not None:
89
+ dock.setMinimumSize(min_size)
90
+
91
+ if features is not None:
92
+ dock.setFeatures(features)
93
+
94
+ if hide:
95
+ dock.hide()
96
+
97
+ return dock
98
+
99
+
100
+ def widget(layout: QLayout) -> QWidget:
101
+ widget = QWidget()
102
+ widget.setLayout(layout)
103
+ return widget
104
+
105
+
106
+ def hbox(*items: QWidget | QLayout) -> QHBoxLayout:
107
+ _add_layout_items(layout := QHBoxLayout(), items)
108
+ return layout
109
+
110
+
111
+ def vbox(*items: QWidget | QLayout) -> QVBoxLayout:
112
+ _add_layout_items(layout := QVBoxLayout(), items)
113
+ return layout
114
+
115
+
116
+ def _add_layout_items(layout: QLayout, items: Sequence[QWidget | QLayout]):
117
+ for item in items:
118
+ if isinstance(item, QLayout):
119
+ layout.addItem(item)
120
+ else:
121
+ layout.addWidget(item)
12
122
 
13
123
 
14
124
  def create_qaction(
@@ -19,6 +129,7 @@ def create_qaction(
19
129
  triggered: Any = None,
20
130
  checkable: bool | None = None,
21
131
  checked: bool | None = None,
132
+ icon: QIcon | QPixmap | None = None,
22
133
  ) -> QAction:
23
134
  action = QAction(name)
24
135
 
@@ -38,4 +149,7 @@ def create_qaction(
38
149
  if checked is not None:
39
150
  action.setChecked(checked)
40
151
 
152
+ if icon is not None:
153
+ action.setIcon(icon)
154
+
41
155
  return action
@@ -6,4 +6,4 @@ _logger = logging.getLogger(__name__)
6
6
 
7
7
 
8
8
  def is_url(url: str) -> bool:
9
- return validators.url(url) == True
9
+ return validators.url(url)
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: qcanvas
3
+ Version: 2026.1.19
4
+ Summary: View courses from Canvas LMS
5
+ Author: QCanvas
6
+ Author-email: QCanvas@noreply.codeberg.org
7
+ Requires-Python: >=3.12,<3.13
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Environment :: X11 Applications
10
+ Classifier: Environment :: X11 Applications :: Qt
11
+ Classifier: Framework :: Pydantic
12
+ Classifier: Framework :: Pydantic :: 2
13
+ Classifier: Intended Audience :: Education
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 10
19
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 11
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Operating System :: POSIX :: Linux
22
+ Classifier: Programming Language :: Python
23
+ Classifier: Programming Language :: Python :: 3
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3 :: Only
26
+ Classifier: Programming Language :: Python :: Implementation :: CPython
27
+ Classifier: Topic :: Database
28
+ Classifier: Topic :: Internet
29
+ Classifier: Topic :: Internet :: WWW/HTTP
30
+ Classifier: Topic :: Text Editors :: Text Processing
31
+ Classifier: Topic :: Text Processing :: Markup :: HTML
32
+ Classifier: Typing :: Typed
33
+ Requires-Dist: aiofile (>=3.9.0,<4.0.0)
34
+ Requires-Dist: aiosqlite (>=0.21.0,<0.22.0)
35
+ Requires-Dist: asynctaskpool (>=0.2.1,<0.3.0)
36
+ Requires-Dist: cachetools (>=6.2.4,<7.0.0)
37
+ Requires-Dist: libqcanvas (>=0.5.7,<0.6.0)
38
+ Requires-Dist: platformdirs (>=4.2.2,<5.0.0)
39
+ Requires-Dist: pyqtdarktheme-fork (>=2.3.2,<3.0.0)
40
+ Requires-Dist: qasync (>=0.28.0,<0.29.0)
41
+ Requires-Dist: sqlalchemy (>=2.0.45,<3.0.0)
42
+ Requires-Dist: validators (>=0.35.0,<0.36.0)
43
+ Description-Content-Type: text/markdown
44
+
45
+ # QCanvas
46
+
47
+ QCanvas is an **unofficial** desktop client for Canvas LMS.
48
+
49
+ https://codeberg.org/QCanvas/QCanvas
50
+
51
+ https://github.com/QCanvas/QCanvasApp
52
+
53
+ # Downloads
54
+
55
+ <a href='https://flathub.org/apps/io.github.qcanvas.QCanvasApp'>
56
+ <img width='240' alt='Get it on Flathub' src='https://flathub.org/api/badge?svg&locale=en'/>
57
+ </a>
58
+
59
+ You can download a **windows** version from [releases](https://github.com/QCanvas/QCanvasApp/releases)
60
+
61
+ An appimage version is also available from releases but is not recommended.
62
+
63
+ # Development/Run from source
64
+
65
+ ## Prerequisites
66
+
67
+ - Python 3.12
68
+ - Poetry
69
+
70
+ ## Get started
71
+
72
+ ```bash
73
+ git clone https://github.com/QCanvas/QCanvasApp.git
74
+ cd QCanvasApp
75
+
76
+ # Install packages and stuff
77
+ poetry install --with flatpak-exclude
78
+
79
+ # Run QCanvas (If you run `poetry shell`, you can drop the `poetry run` part)
80
+ poetry run qcanvas
81
+ # Alternative
82
+ poetry run python -m qcanvas
83
+ ```
84
+
85
+ ## Build custom AppImage
86
+
87
+ > [!WARNING]
88
+ > This is not recommended as the appimage produced by this process isn't a proper appimage. It's just a pyinstaller build bundled as an appimage.
89
+
90
+ > [!IMPORTANT]
91
+ > You will need [Appimagetool](https://github.com/AppImage/appimagetool)
92
+
93
+ ```bash
94
+ bash ./dev_scripts/build_appimage
95
+ ```
@@ -0,0 +1,92 @@
1
+ qcanvas/__init__.py,sha256=J4gpVRrBBlMqeqyXPZj0uLc6g-0UCYgoQc72f8LjDks,1946
2
+ qcanvas/app.py,sha256=lWIzD7Cimw2yzGiGXka09i-7XMnG6kA8Pmzuwa17CXo,2097
3
+ qcanvas/backend_connectors/__init__.py,sha256=Wj8cmxQng3SSlmlXJyzHaPmvxbkauwsxINckPb7WuHc,108
4
+ qcanvas/backend_connectors/frontend_resource_manager.py,sha256=uzi8z2bNBdQoVkvtwxWo4qX5r0s13qmH5QL2t0vD0d8,1613
5
+ qcanvas/backend_connectors/qcanvas_task_master.py,sha256=G46WgM4LA9VGWUDe3cBfRqHEYrOqcM70UJ5ipwc8hm0,740
6
+ qcanvas/icons/__init__.py,sha256=RHBT64IkUdQQtSRRxsMU1uiYRPvUoTHJV01x9WXHepA,1965
7
+ qcanvas/icons/_icon_type.py,sha256=_Xq0qwz_4OsAOhT6_4lEWTFMsPSqKVRkmQjfXbJAeAE,904
8
+ qcanvas/icons/icons.qrc,sha256=ec-_Hiy2GOA0NOQCeyRpIhexTZk0_SSDxZlWSvSUgno,2084
9
+ qcanvas/icons/rc_icons.py,sha256=SZBFaQaLym2jkJ90csM-2W8TKWgBLMyRxnZUO0yAw_0,74285
10
+ qcanvas/settings/__init__.py,sha256=GPOgh9fzK0zGiJhIy7fWfXJZVE86i6DE-ZjQSqFunco,176
11
+ qcanvas/settings/_client_settings.py,sha256=6Oy5eXlttlwC11YSqbqLcgyVa5Nk3jBdB4Ea-gFC-yw,1397
12
+ qcanvas/settings/_course_settings.py,sha256=mNNPNt88f5q1m_YtoqaHDUqoAiRnVZj4wUGd0xDlcjY,1547
13
+ qcanvas/settings/_mapped_setting.py,sha256=a9wq60chtn9X8RLpQrf6JR7XsDxJlJfWrq0hfHHJvyU,1928
14
+ qcanvas/settings/_ui_settings.py,sha256=gyC_ZwPdu4JzZgA4I6TelJmm6pXginBigp58u-fBd3w,753
15
+ qcanvas/theme.py,sha256=7GVSpc1VCHxQiM7eamPNQJJKikVE8rejAsUFYOvsuaQ,3077
16
+ qcanvas/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ qcanvas/ui/course_viewer/__init__.py,sha256=XkoFnh4ULw3_i-GDsOlueEWido0PkoDcN9_EX6-nkXY,76
18
+ qcanvas/ui/course_viewer/content_tree.py,sha256=ewgi4oNN3uCURjykpLLRb2efzBxfFws14UAQ3H6z-64,4602
19
+ qcanvas/ui/course_viewer/course_tree/__init__.py,sha256=N2XorJ4COFHzRYx53noANb4_qJYf6N8_YCjPdQuDCHs,36
20
+ qcanvas/ui/course_viewer/course_tree/_course_icon_generator.py,sha256=facgU1YPLpPy5C6EJG5KURuKTn7LOTu9ZmPEj-UQLFI,3080
21
+ qcanvas/ui/course_viewer/course_tree/course_tree.py,sha256=KaPVdvS2tPdMZFhggWCvg9DVSQugHS_EpGa12vgGNyw,3224
22
+ qcanvas/ui/course_viewer/course_viewer.py,sha256=AGZ6eQlRLb1i2ex-gbe2ygT3_sHYD7bvXy3tYQ2Jugc,4974
23
+ qcanvas/ui/course_viewer/tabs/__init__.py,sha256=SlfWUzk6_E5uM9GIV-y9BVeKMwqn3pRx_xWhMyb1dfI,54
24
+ qcanvas/ui/course_viewer/tabs/assignment_tab/__init__.py,sha256=w936dW7za10Fh6rN0zVA-7Kyiup3kd6C-mPAFHtxmy0,42
25
+ qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py,sha256=VJLs2BwgQSPM_3nB2iNAbHqRbkIxz04ejSzh3otmnqs,4849
26
+ qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py,sha256=Lwj3Sq_W_XFV240VpLK6W3kIUQ00NH9qB88mAKsYHNs,2908
27
+ qcanvas/ui/course_viewer/tabs/constants.py,sha256=rUVEGSREV9vTFs4o3AD2OjaSFA-GPsmelxYWz0J8OP4,48
28
+ qcanvas/ui/course_viewer/tabs/content_tab.py,sha256=l2h1Vl7t0GAFYXzEjihMzpBv596sOu8BJKiMz1lcFAE,3274
29
+ qcanvas/ui/course_viewer/tabs/file_tab/__init__.py,sha256=mMebnrNw_V-lQ-eBXS_kFinL-ZdUAXa459NmuyuCu6s,30
30
+ qcanvas/ui/course_viewer/tabs/file_tab/file_tab.py,sha256=SeKGKNRLmSmL5Ij96YSRx6Skl-1wC14uDfIPJy_xmzw,1398
31
+ qcanvas/ui/course_viewer/tabs/file_tab/file_tree.py,sha256=ely6qZTs6CFsKv9ZFDCAe_8unosJ6nt9AQFLkcuknvE,3357
32
+ qcanvas/ui/course_viewer/tabs/file_tab/pages_file_tree.py,sha256=C1QtoY9GA2Q_lbUearVrdZbHCAefV4ZpsIPHGBAUxPI,1875
33
+ qcanvas/ui/course_viewer/tabs/mail_tab/__init__.py,sha256=68iRUUWEP7mudbaxa4ZBKMra4rvs2oZKaZkBWwmUrsI,30
34
+ qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py,sha256=FGfRaEAcuLfcPo92_D7ZcyeIjePMbU_BSlpAtyT0qLo,2686
35
+ qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py,sha256=w4dkC4V_fKsMkVB68vbfvMRI1HBxbuKzxExclAn-AaQ,1762
36
+ qcanvas/ui/course_viewer/tabs/page_tab/__init__.py,sha256=lcafxlSEVZ0wqZySxT6hTrvExX-GU2AfcZQbp6W8haU,30
37
+ qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py,sha256=-u6RaH7kO1cCrvcXNF0hcLrEL6nomy6IUXfKEGhANgg,743
38
+ qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py,sha256=mxQzhjiiO7onQALhKbcyQQtsKEdBGAspQreXljRu9i4,2147
39
+ qcanvas/ui/course_viewer/tabs/resource_rich_browser.py,sha256=BlUHqoNKu5vzmLIYjUJZX6APxeNA2bia4xRZ3B0gaqc,6479
40
+ qcanvas/ui/course_viewer/tree_widget_data_item.py,sha256=z3CnXNFivtDtKemkH41E0a_Dc-l_tKJ6AEqNqM23eao,569
41
+ qcanvas/ui/memory_tree/__init__.py,sha256=-XLitM6teC0zmwPrGf-Q-A53-zgmIPASExdOtaLIvPU,107
42
+ qcanvas/ui/memory_tree/_tree_memory.py,sha256=kPsAw0sL5AFPIhWuhfKSS56043t9pQFi2YpBdYkbfm0,2231
43
+ qcanvas/ui/memory_tree/memory_tree_widget.py,sha256=NT8T9EMql7xxVRCQFkfb1p0h3gL7oQq9As2UGy_481k,4553
44
+ qcanvas/ui/memory_tree/memory_tree_widget_item.py,sha256=76a7IEZGXwYhqx7WMbq-tA_GvinvQW7hdueZNWAvFxg,435
45
+ qcanvas/ui/qcanvas_window/__init__.py,sha256=GeMsShFH9OGYLDDgB0KmKHlJr32NeewxurM-QzgabSQ,42
46
+ qcanvas/ui/qcanvas_window/course_viewer_container.py,sha256=oEPdqnGU752JTY0p4HfSlFyNDw-12AW4JzgxZ1A31J0,3502
47
+ qcanvas/ui/qcanvas_window/options/__init__.py,sha256=SlfWUzk6_E5uM9GIV-y9BVeKMwqn3pRx_xWhMyb1dfI,54
48
+ qcanvas/ui/qcanvas_window/options/auto_download_resources_option.py,sha256=oeVdUsFUSrCRKKjb6eyjsJecaMSMnEKR66L9FTlm_Eo,1379
49
+ qcanvas/ui/qcanvas_window/options/quick_sync_option.py,sha256=16zEFL__JRi-wE7Q99_Bqi-OHEBhRgf5QlnVUOUX3Eg,833
50
+ qcanvas/ui/qcanvas_window/options/sync_on_start_option.py,sha256=gL_FIulULN1uGBJJWgUszyjayQDw5WfppjoErbM3850,773
51
+ qcanvas/ui/qcanvas_window/options/theme_selection_menu.py,sha256=VMx79H45R7lcpMFpaN8eohbCxkQkq43MdH8W0nt2aTQ,1434
52
+ qcanvas/ui/qcanvas_window/qcanvas_window.py,sha256=qNRtV2jIuhLEw2MWgKUxBYHDa9IFg65nA5e6XFr1nIM,9302
53
+ qcanvas/ui/qcanvas_window/status_bar_progress_display.py,sha256=v8cL7EzhKIO6YDo-IJGC2TvjnaHvHb9F2VyJtW0W4U8,5047
54
+ qcanvas/ui/qml_components/__init__.py,sha256=_qCJGhqDvxx8k4dIDgLFpKU7z-R7AS6HWPlsrUlAj2Q,203
55
+ qcanvas/ui/qml_components/attachments_pane.py,sha256=tg8YuSNM0wEIJ0GPDghJhIc1UVp7TaH-A4NispXx2XM,2353
56
+ qcanvas/ui/qml_components/comments_pane.py,sha256=JCuPuhWCeV1avxjWEvawSRaX8I3yJgewXdfuyN5_5Og,2980
57
+ qcanvas/ui/qml_components/qml/AttachmentsList.ui.qml,sha256=kEgdn1s490hfvMtDtbba54_-_vF-3GUIEVpB8D12ET0,483
58
+ qcanvas/ui/qml_components/qml/AttachmentsListDelegate.qml,sha256=Frcd-vMd6lXBICF8SpPdpGJgxrk4vasvK29uTxXKAcs,2115
59
+ qcanvas/ui/qml_components/qml/AttachmentsListModel.qml,sha256=y4pQoJLVrSAEdl8BkeKZrMBln0pCCfjotCCxcCS9L6w,516
60
+ qcanvas/ui/qml_components/qml/AttachmentsPane.qml,sha256=xH3vSn4pW7KG93TlJdUKQbk8jHCY5-DgQ58A4zxmRKs,174
61
+ qcanvas/ui/qml_components/qml/CommentsList.ui.qml,sha256=l8uqDrqIGVeOIAHnn4rwQQGiedFXAdMFANzvcHflCJo,477
62
+ qcanvas/ui/qml_components/qml/CommentsListDelegate.ui.qml,sha256=iI-8Byw9dEOcbB18kQ6LGBH9IMCdmoK4Ak2WgSxkx78,3172
63
+ qcanvas/ui/qml_components/qml/CommentsListModel.qml,sha256=oEffdqXiavoO4zcyBu8aqIlR-0IYDQKli3aKlGUxltg,2230
64
+ qcanvas/ui/qml_components/qml/CommentsPane.qml,sha256=_ETxcUBOKMPJrkmGqFMDR6XGf49MBiBIPV6mQyJwGVU,163
65
+ qcanvas/ui/qml_components/qml/DecoratedText.ui.qml,sha256=U4p_P6gXRBj1GKDe0azJlp9-fT8yFw3XVjQH76L8MQ0,1003
66
+ qcanvas/ui/qml_components/qml/Spacer.ui.qml,sha256=RE86ASh90JUV82QLWV9FoD3pVzv9F_gHFNyDpk_Befo,78
67
+ qcanvas/ui/qml_components/qml/ThemedRectangle.qml,sha256=VBnt-orItX2vUXO-5Uv4bkg5mNUF8G2Hog-SfdY9t4E,1017
68
+ qcanvas/ui/qml_components/qml/__init__.py,sha256=SlfWUzk6_E5uM9GIV-y9BVeKMwqn3pRx_xWhMyb1dfI,54
69
+ qcanvas/ui/qml_components/qml/rc_qml.py,sha256=VlEdO8jkP59504nDUyI6Rcgd3FUQpCl4tlwiFdCwgJI,16534
70
+ qcanvas/ui/qml_components/qml/rc_qml.qrc,sha256=T4YFrztVZm-qmy3o0DcmFexa-gufzeKCCofp-peo7mY,486
71
+ qcanvas/ui/qml_components/qml_bridge_types.py,sha256=iHyG9ACG7bj8X_fty4Qpd5oSTmcW3zaFZdSi_KNXymE,2725
72
+ qcanvas/ui/qml_components/qml_pane.py,sha256=g4TDiWuZZ0eZ6rWagFJG4nE8aYXqS6cDl_UvjDBJi-Y,699
73
+ qcanvas/ui/setup/__init__.py,sha256=QWt2lEyLqWG5QC-BmCBlYyi0LZsBfsQYbP0XkvqA2f8,77
74
+ qcanvas/ui/setup/setup_checker.py,sha256=gU70geojUyOTW_fNgH-GzpTMrtYXsLHWf2wUnFaezmA,444
75
+ qcanvas/ui/setup/setup_dialog.py,sha256=RDZkxzUaTY3qfta6YmHDK9VHEa4_0sJSMHU1cRGJSso,10673
76
+ qcanvas/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
+ qcanvas/util/auto_downloader.py,sha256=DO2TCNQ2idUoITqlxxAp1tY8C5Zy52nghjCE4hv49aw,1905
78
+ qcanvas/util/basic_fonts.py,sha256=TqaY2UchDseHDZYB-Bh6r3xRoRuc5S9lf8j-fMGGCYQ,249
79
+ qcanvas/util/context_dict.py,sha256=05TlRto_fzmwdUBOVFEPVNCnch4gDYys1fpuMwLhpto,315
80
+ qcanvas/util/file_icons.py,sha256=TKHITkkd2HKAWR7mBJuXc034l76Ptp1YXM_eeLbEKW8,1509
81
+ qcanvas/util/html_cleaner.py,sha256=U-UbZVX9x85gatOvxLsQXe2hL6x4I86eUKwkm0p159E,710
82
+ qcanvas/util/layouts.py,sha256=in7V6mzJIlnVc1DbvhpxA5fIYBIUIQT-OPa9dHUYIrI,1498
83
+ qcanvas/util/logs.py,sha256=VZKFITiW2WR2POEFVv5GRpEXic23Pzjehry-vH3g3Gk,138
84
+ qcanvas/util/paths.py,sha256=lLqQqOmREefJB8D1xARH3gCNNXXlSELlIuDQaCHpDr4,1373
85
+ qcanvas/util/qurl_util.py,sha256=6nTk8VkQjT87wMOXyZucPBYdT6TTYzfCTElqsypLZPg,200
86
+ qcanvas/util/runtime.py,sha256=EO1HFCN7dZbQtKHQOILuvjZFXGT7SzhlmPvU8ma95Z8,617
87
+ qcanvas/util/ui_tools.py,sha256=cdwDrtljxIpzikvUt4CAMC06kogJ4WfhSTsC3lXAcz4,3575
88
+ qcanvas/util/url_checker.py,sha256=HkNFixp1ARwc_YjYkpHb-IMTyuaC7CylvYCgDyo3sh4,136
89
+ qcanvas-2026.1.19.dist-info/METADATA,sha256=U_dXL_gAq6-ZOEDngMWf1MVBGsXUDlkZYtgGxGKlB9U,3096
90
+ qcanvas-2026.1.19.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
91
+ qcanvas-2026.1.19.dist-info/entry_points.txt,sha256=hqG_g3MRYh_eLyQcDN4H3EXqmBia_fnJTJ-3nqZGzvY,40
92
+ qcanvas-2026.1.19.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.3.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ qcanvas=qcanvas:main
3
+
@@ -1,54 +0,0 @@
1
- import asyncio
2
- import logging
3
- import sys
4
-
5
- import qtpy
6
- from qasync import QEventLoop
7
- from qtpy.QtWidgets import QApplication
8
-
9
- import qcanvas.backend_connectors.qcanvas_task_master as task_master
10
- from qcanvas.ui.main_ui.qcanvas_window import QCanvasWindow
11
- from qcanvas.ui.setup import SetupDialog, setup_checker
12
- from qcanvas.util import settings, themes
13
-
14
- main_window = None
15
- setup_window = None
16
-
17
- _logger = logging.getLogger(__name__)
18
-
19
-
20
- def _show_main():
21
- global main_window
22
- main_window = QCanvasWindow()
23
- main_window.show()
24
-
25
-
26
- def _show_qt_api_name():
27
- print(f"Using Qt bindings from {qtpy.API_NAME}")
28
- _logger.info("Using Qt bindings from %s", qtpy.API_NAME)
29
-
30
-
31
- def launch():
32
- _show_qt_api_name()
33
-
34
- app = QApplication(sys.argv)
35
- app.setApplicationName("QCanvas")
36
-
37
- task_master.register()
38
- themes.apply(settings.ui.theme)
39
-
40
- event_loop = QEventLoop(app)
41
- asyncio.set_event_loop(event_loop)
42
-
43
- app_close_event = asyncio.Event()
44
- app.aboutToQuit.connect(app_close_event.set)
45
-
46
- if setup_checker.needs_setup():
47
- setup_window = SetupDialog()
48
- setup_window.show()
49
- setup_window.closed.connect(_show_main)
50
- else:
51
- _show_main()
52
-
53
- with event_loop:
54
- event_loop.run_until_complete(app_close_event.wait())
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
3
- <svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
4
- <title>file-times</title>
5
- <path d="M26.731 9.902c-0.005-0.035-0.011-0.066-0.019-0.095l0.001 0.005c-0.031-0.134-0.094-0.249-0.182-0.342l0 0-8-8c-0.092-0.087-0.207-0.15-0.335-0.181l-0.005-0.001c-0.027-0.008-0.059-0.014-0.092-0.019l-0.003-0c-0.026-0.007-0.059-0.014-0.092-0.019l-0.004-0h-12c-0.414 0-0.75 0.336-0.75 0.75v0 28c0 0.414 0.336 0.75 0.75 0.75h20c0.414-0 0.75-0.336 0.75-0.75v0-20c-0.005-0.038-0.012-0.071-0.020-0.103l0.001 0.005zM24.189 9.25h-5.439v-5.439zM6.75 29.25v-26.5h10.5v7.25c0 0.414 0.336 0.75 0.75 0.75h7.25v18.5zM20.066 15.935c-0.136-0.136-0.324-0.22-0.531-0.22s-0.395 0.084-0.531 0.22v0l-3.004 3.004-3.005-3.004c-0.136-0.141-0.327-0.228-0.538-0.228-0.414 0-0.75 0.336-0.75 0.75 0 0.211 0.087 0.402 0.228 0.538l3.004 3.005-3.004 3.004c-0.136 0.136-0.22 0.324-0.22 0.531 0 0.415 0.336 0.751 0.751 0.751 0.207 0 0.395-0.084 0.53-0.219v0l3.005-3.005 3.004 3.005c0.136 0.136 0.324 0.22 0.531 0.22 0.415 0 0.751-0.336 0.751-0.751 0-0.207-0.084-0.395-0.22-0.531l-3.005-3.004 3.005-3.005c0.135-0.136 0.218-0.323 0.218-0.53s-0.083-0.394-0.218-0.53l0 0z"></path>
6
- </svg>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
3
- <svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
4
- <title>file</title>
5
- <path d="M26.731 9.902c-0.005-0.035-0.011-0.066-0.019-0.095l0.001 0.005c-0.031-0.134-0.094-0.249-0.182-0.342l0 0-8-8c-0.092-0.087-0.207-0.15-0.335-0.181l-0.005-0.001c-0.027-0.008-0.059-0.014-0.092-0.019l-0.003-0c-0.026-0.007-0.059-0.014-0.092-0.019l-0.004-0h-12c-0.414 0-0.75 0.336-0.75 0.75v0 28c0 0.414 0.336 0.75 0.75 0.75h20c0.414-0 0.75-0.336 0.75-0.75v0-20c-0.005-0.038-0.012-0.071-0.020-0.103l0.001 0.005zM24.189 9.25h-5.439v-5.439zM6.75 29.25v-26.5h10.5v7.25c0 0.414 0.336 0.75 0.75 0.75h7.25v18.5z"></path>
6
- </svg>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
3
- <svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
4
- <title>file-arrow-down</title>
5
- <path d="M26.731 9.902c-0.005-0.035-0.011-0.066-0.019-0.095l0.001 0.005c-0.031-0.134-0.094-0.249-0.182-0.342l0 0-8-8c-0.092-0.087-0.207-0.15-0.335-0.181l-0.005-0.001c-0.027-0.008-0.059-0.014-0.092-0.019l-0.003-0c-0.026-0.007-0.059-0.014-0.092-0.019l-0.004-0h-12c-0.414 0-0.75 0.336-0.75 0.75v0 28c0 0.414 0.336 0.75 0.75 0.75h20c0.414-0 0.75-0.336 0.75-0.75v0-20c-0.005-0.038-0.012-0.071-0.020-0.103l0.001 0.005zM24.189 9.25h-5.439v-5.439zM6.75 29.25v-26.5h10.5v7.25c0 0.414 0.336 0.75 0.75 0.75h7.25v18.5zM20.469 20.91l-3.719 3.721v-10.676c0-0.414-0.336-0.75-0.75-0.75s-0.75 0.336-0.75 0.75v0 10.675l-3.72-3.72c-0.136-0.134-0.322-0.218-0.528-0.218-0.415 0-0.751 0.336-0.751 0.751 0 0.207 0.083 0.394 0.219 0.529l5 5c0.026 0.026 0.065 0.017 0.093 0.038 0.052 0.040 0.088 0.098 0.15 0.124 0.085 0.035 0.184 0.056 0.287 0.057h0c0 0 0 0 0 0 0.207 0 0.394-0.084 0.53-0.219l5.001-5c0.136-0.136 0.22-0.324 0.22-0.531 0-0.415-0.336-0.751-0.751-0.751-0.207 0-0.395 0.084-0.531 0.22v0z"></path>
6
- </svg>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
3
- <svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
4
- <title>question</title>
5
- <path d="M19.943 5.251c-1.145-0.635-2.511-1.008-3.964-1.008-1.461 0-2.834 0.378-4.026 1.040l0.042-0.022c-1.649 0.916-2.746 2.648-2.746 4.635 0 0.037 0 0.074 0.001 0.111l-0-0.006c0.001 0.413 0.336 0.747 0.75 0.747 0 0 0 0 0 0h-0c0.407-0.021 0.731-0.346 0.75-0.751l0-0.002c-0.001-0.026-0.001-0.058-0.001-0.089 0-1.441 0.8-2.694 1.98-3.341l0.020-0.010c0.934-0.511 2.047-0.812 3.23-0.812 1.178 0 2.287 0.298 3.255 0.824l-0.036-0.018c1.23 0.657 2.053 1.933 2.053 3.401 0 0.017-0 0.033-0 0.050l0-0.003c0.033 0.19 0.051 0.408 0.051 0.631 0 1.699-1.084 3.145-2.598 3.684l-0.027 0.008c-2.303 1.102-3.424 3.285-3.426 6.677 0 0 0 0 0 0.001 0 0.414 0.335 0.749 0.749 0.749h0.001c0.414-0 0.75-0.336 0.75-0.75v0c0.002-2.793 0.819-4.485 2.586-5.329 2.037-0.783 3.457-2.725 3.457-4.997 0-0.238-0.016-0.473-0.046-0.703l0.003 0.027c0-0.017 0-0.037 0-0.057 0-2.018-1.123-3.774-2.779-4.676l-0.028-0.014zM15.46 25.459c-0.123 0.145-0.198 0.334-0.2 0.541v0c-0.001 0.016-0.002 0.034-0.002 0.052 0 0.082 0.015 0.16 0.044 0.231l-0.002-0.004c0.039 0.094 0.093 0.173 0.16 0.24l0 0c0.071 0.076 0.158 0.137 0.255 0.178l0.005 0.002c0.084 0.026 0.18 0.041 0.28 0.041s0.196-0.015 0.287-0.043l-0.007 0.002c0.102-0.043 0.189-0.104 0.26-0.179l0-0c0.067-0.067 0.12-0.147 0.157-0.235l0.002-0.005c0.038-0.079 0.061-0.173 0.061-0.271 0-0.003-0-0.006-0-0.009v0c-0.010-0.209-0.092-0.397-0.221-0.542l0.001 0.001c-0.145-0.121-0.334-0.195-0.54-0.195s-0.395 0.074-0.541 0.196l0.001-0.001z"></path>
6
- </svg>