qcanvas 1.0.7__tar.gz → 1.0.9.dev0__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 (67) hide show
  1. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/PKG-INFO +3 -2
  2. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/pyproject.toml +6 -3
  3. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/file-download-failed.svg +5 -5
  4. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/file-downloaded.svg +5 -5
  5. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/file-not-downloaded.svg +5 -5
  6. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/file-unknown.svg +5 -5
  7. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/run.py +2 -2
  8. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/content_tree.py +10 -0
  9. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/course_tree.py +0 -4
  10. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py +0 -10
  11. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py +0 -8
  12. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/content_tab.py +12 -0
  13. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py +0 -9
  14. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py +0 -7
  15. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py +0 -10
  16. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py +0 -8
  17. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/status_bar_progress_display.py +5 -5
  18. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/setup/setup_dialog.py +21 -11
  19. qcanvas-1.0.9.dev0/qcanvas/util/url_checker.py +9 -0
  20. qcanvas-1.0.7/qcanvas/util/url_checker.py +0 -13
  21. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/README.md +0 -0
  22. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/__init__.py +0 -0
  23. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/app_start/__init__.py +0 -0
  24. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/backend_connectors/__init__.py +0 -0
  25. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/backend_connectors/frontend_resource_manager.py +0 -0
  26. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/backend_connectors/qcanvas_task_master.py +0 -0
  27. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/__init__.py +0 -0
  28. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/icons.qrc +0 -0
  29. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/main_icon.svg +0 -0
  30. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/rc_icons.py +0 -0
  31. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/icons/sync.svg +0 -0
  32. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/__init__.py +0 -0
  33. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/__init__.py +0 -0
  34. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/course_viewer.py +0 -0
  35. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/__init__.py +0 -0
  36. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/assignment_tab/__init__.py +0 -0
  37. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/mail_tab/__init__.py +0 -0
  38. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/page_tab/__init__.py +0 -0
  39. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/resource_rich_browser.py +0 -0
  40. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/course_viewer/tabs/util.py +0 -0
  41. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/__init__.py +0 -0
  42. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/course_viewer_container.py +0 -0
  43. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/options/__init__.py +0 -0
  44. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/options/quick_sync_option.py +0 -0
  45. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/options/sync_on_start_option.py +0 -0
  46. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/options/theme_selection_menu.py +0 -0
  47. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/main_ui/qcanvas_window.py +0 -0
  48. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/memory_tree/__init__.py +0 -0
  49. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/memory_tree/_tree_memory.py +0 -0
  50. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/memory_tree/memory_tree_widget.py +0 -0
  51. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/memory_tree/memory_tree_widget_item.py +0 -0
  52. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/setup/__init__.py +0 -0
  53. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/ui/setup/setup_checker.py +0 -0
  54. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/__init__.py +0 -0
  55. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/basic_fonts.py +0 -0
  56. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/fe_resource_manager.py +0 -0
  57. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/html_cleaner.py +0 -0
  58. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/layouts.py +0 -0
  59. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/logs.py +0 -0
  60. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/paths.py +0 -0
  61. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/qurl_util.py +0 -0
  62. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/settings/__init__.py +0 -0
  63. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/settings/_client_settings.py +0 -0
  64. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/settings/_mapped_setting.py +0 -0
  65. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/settings/_ui_settings.py +0 -0
  66. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/themes.py +0 -0
  67. {qcanvas-1.0.7 → qcanvas-1.0.9.dev0}/qcanvas/util/ui_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qcanvas
3
- Version: 1.0.7
3
+ Version: 1.0.9.dev0
4
4
  Summary: QCanvas is a desktop client for Canvas LMS.
5
5
  Author: QCanvas
6
6
  Author-email: QCanvas@noreply.codeberg.org
@@ -15,9 +15,10 @@ Requires-Dist: platformdirs (>=4.2.2,<5.0.0)
15
15
  Requires-Dist: pyqtdarktheme-fork (>=2.3.2,<3.0.0)
16
16
  Requires-Dist: qasync (>=0.27.1,<0.28.0)
17
17
  Requires-Dist: qcanvas-api-clients (>=0.2.2,<0.3.0)
18
- Requires-Dist: qcanvas-backend (==0.1.10a3)
18
+ Requires-Dist: qcanvas-backend (==0.1.10a5)
19
19
  Requires-Dist: qtpy (>=2.4.1,<3.0.0)
20
20
  Requires-Dist: sqlalchemy (>=2.0.31,<3.0.0)
21
+ Requires-Dist: validators (>=0.33.0,<0.34.0)
21
22
  Description-Content-Type: text/markdown
22
23
 
23
24
  # QCanvas
@@ -1,11 +1,13 @@
1
1
  [tool.poetry]
2
2
  name = "qcanvas"
3
- version = "1.0.7"
3
+ version = "1.0.9.dev0"
4
4
  description = "QCanvas is a desktop client for Canvas LMS."
5
5
  authors = ["QCanvas <QCanvas@noreply.codeberg.org>"]
6
6
  readme = "README.md"
7
7
  exclude = [
8
- "images"
8
+ "images",
9
+ "flatpak",
10
+ "appimage",
9
11
  ]
10
12
 
11
13
  [tool.poetry.scripts]
@@ -14,7 +16,7 @@ qcanvas = "qcanvas.run:main"
14
16
  [tool.poetry.dependencies]
15
17
  python = ">=3.11,<3.13"
16
18
  qcanvas-api-clients = "^0.2.2"
17
- qcanvas-backend = "0.1.10a3"
19
+ qcanvas-backend = "0.1.10a5"
18
20
  asynctaskpool = "^0.2.1"
19
21
  sqlalchemy = "^2.0.31"
20
22
  qtpy = "^2.4.1"
@@ -23,6 +25,7 @@ pyqtdarktheme-fork = "^2.3.2"
23
25
  qasync = "^0.27.1"
24
26
  lightdb = "^2.0"
25
27
  platformdirs = "^4.2.2"
28
+ validators = "^0.33.0"
26
29
 
27
30
  [tool.poetry.group.flatpak-exclude.dependencies]
28
31
  pyside6 = "^6.7.2"
@@ -1,6 +1,6 @@
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>
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
6
  </svg>
@@ -1,6 +1,6 @@
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>
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
6
  </svg>
@@ -1,6 +1,6 @@
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>
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
6
  </svg>
@@ -1,6 +1,6 @@
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>
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
6
  </svg>
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from logging import DEBUG, INFO, WARNING
2
+ from logging import INFO, WARNING
3
3
 
4
4
  import qcanvas.app_start
5
5
  from qcanvas.util import logs, paths
@@ -17,7 +17,7 @@ logs.set_levels(
17
17
  "qcanvas": INFO,
18
18
  "qcanvas.ui": WARNING,
19
19
  "qcanvas_backend": INFO,
20
- "qcanvas.ui.main_ui.status_bar_progress_display": DEBUG,
20
+ "qcanvas.ui.main_ui.status_bar_progress_display": INFO,
21
21
  }
22
22
  )
23
23
 
@@ -2,6 +2,7 @@ import logging
2
2
  from abc import abstractmethod
3
3
  from typing import *
4
4
 
5
+ import qcanvas_backend.database.types as db
5
6
  from qcanvas_backend.net.sync.sync_receipt import SyncReceipt
6
7
  from qtpy.QtCore import QItemSelection, Signal, Slot
7
8
  from qtpy.QtWidgets import *
@@ -12,11 +13,20 @@ from qcanvas.util.basic_fonts import bold_font, normal_font
12
13
  _logger = logging.getLogger(__name__)
13
14
 
14
15
  T = TypeVar("T")
16
+ U = TypeVar("U", bound=Type["ContentTree"])
15
17
 
16
18
 
17
19
  class ContentTree(MemoryTreeWidget, Generic[T]):
18
20
  item_selected = Signal(object)
19
21
 
22
+ @classmethod
23
+ def create_from_receipt(
24
+ cls: U, course: db.Course, *, sync_receipt: Optional[SyncReceipt]
25
+ ) -> Type[U]:
26
+ tree = cls(course.id)
27
+ tree.reload(course, sync_receipt=sync_receipt)
28
+ return tree
29
+
20
30
  def __init__(
21
31
  self,
22
32
  tree_name: str,
@@ -85,7 +85,3 @@ class CourseTree(ContentTree[Sequence[db.Term]]):
85
85
  term_widget.setFlags(Qt.ItemFlag.ItemIsEnabled)
86
86
 
87
87
  return term_widget
88
-
89
- # @Slot(db.Course, str)
90
- # def _on_course_renamed(self, course: db.Course, new_name: str) -> None:
91
- # self.course_renamed.emit(course, new_name)
@@ -16,16 +16,6 @@ _logger = logging.getLogger(__name__)
16
16
 
17
17
 
18
18
  class AssignmentTab(ContentTab):
19
- @staticmethod
20
- def create_from_receipt(
21
- *,
22
- course: db.Course,
23
- sync_receipt: Optional[SyncReceipt],
24
- downloader: ResourceManager,
25
- ) -> "AssignmentTab":
26
- return AssignmentTab(
27
- course=course, sync_receipt=sync_receipt, downloader=downloader
28
- )
29
19
 
30
20
  def __init__(
31
21
  self,
@@ -13,14 +13,6 @@ _logger = logging.getLogger(__name__)
13
13
 
14
14
 
15
15
  class AssignmentTree(ContentTree[db.Course]):
16
- @staticmethod
17
- def create_from_receipt(
18
- course: db.Course, *, sync_receipt: Optional[SyncReceipt]
19
- ) -> "AssignmentTree":
20
- tree = AssignmentTree(course.id)
21
- tree.reload(course, sync_receipt=sync_receipt)
22
- return tree
23
-
24
16
  def __init__(self, course_id: str):
25
17
  super().__init__(
26
18
  tree_name=f"course.{course_id}.assignment_groups",
@@ -14,8 +14,20 @@ from qcanvas.util.ui_tools import make_truncatable
14
14
 
15
15
  _logger = logging.getLogger(__name__)
16
16
 
17
+ T = TypeVar("T", bound=Type["ContentTab"])
18
+
17
19
 
18
20
  class ContentTab(QWidget):
21
+ @classmethod
22
+ def create_from_receipt(
23
+ cls: T,
24
+ *,
25
+ course: db.Course,
26
+ sync_receipt: Optional[SyncReceipt],
27
+ downloader: ResourceManager,
28
+ ) -> Type[T]:
29
+ return cls(course=course, sync_receipt=sync_receipt, downloader=downloader)
30
+
19
31
  def __init__(
20
32
  self,
21
33
  *,
@@ -17,15 +17,6 @@ _logger = logging.getLogger(__name__)
17
17
 
18
18
  # todo maybe update has_been_read? probably not the responsibility of this class though
19
19
  class MailTab(ContentTab):
20
- @staticmethod
21
- def create_from_receipt(
22
- *,
23
- course: db.Course,
24
- sync_receipt: Optional[SyncReceipt],
25
- downloader: ResourceManager,
26
- ) -> "MailTab":
27
- return MailTab(course=course, sync_receipt=sync_receipt, downloader=downloader)
28
-
29
20
  def __init__(
30
21
  self,
31
22
  *,
@@ -12,13 +12,6 @@ _logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
14
  class MailTree(ContentTree[db.Course]):
15
- @staticmethod
16
- def create_from_receipt(
17
- course: db.Course, *, sync_receipt: Optional[SyncReceipt]
18
- ) -> "MailTree":
19
- tree = MailTree(course.id)
20
- tree.reload(course, sync_receipt=sync_receipt)
21
- return tree
22
15
 
23
16
  def __init__(self, course_id: str):
24
17
  super().__init__(
@@ -12,16 +12,6 @@ _logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
14
  class PageTab(ContentTab):
15
-
16
- @staticmethod
17
- def create_from_receipt(
18
- *,
19
- course: db.Course,
20
- sync_receipt: Optional[SyncReceipt],
21
- downloader: ResourceManager,
22
- ) -> "PageTab":
23
- return PageTab(course=course, sync_receipt=sync_receipt, downloader=downloader)
24
-
25
15
  def __init__(
26
16
  self,
27
17
  *,
@@ -12,14 +12,6 @@ _logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
14
  class PageTree(ContentTree[db.Course]):
15
- @staticmethod
16
- def create_from_receipt(
17
- course: db.Course, *, sync_receipt: Optional[SyncReceipt]
18
- ) -> "PageTree":
19
- tree = PageTree(course.id)
20
- tree.reload(course, sync_receipt=sync_receipt)
21
- return tree
22
-
23
15
  def __init__(self, course_id: str):
24
16
  super().__init__(
25
17
  tree_name=f"course.{course_id}.modules",
@@ -62,7 +62,7 @@ class StatusBarProgressDisplay(QStatusBar):
62
62
 
63
63
  @asyncSlot(TaskID, object)
64
64
  async def _on_task_failed(self, task_id: TaskID, context: object) -> None:
65
- _logger.debug("%s failed", task_id)
65
+ _logger.info("%s failed", task_id)
66
66
 
67
67
  async with self._lock:
68
68
  self._remove_task(task_id)
@@ -83,8 +83,8 @@ class StatusBarProgressDisplay(QStatusBar):
83
83
  self._show_multiple_tasks_progress(list(self._tasks.values()))
84
84
 
85
85
  def _show_done(self) -> None:
86
- _logger.debug("Finished tasks. Tasks: %s", self._tasks)
87
- self.showMessage("All tasks finished", 5000)
86
+ _logger.info("Finished tasks. Tasks: %s", self._tasks)
87
+ self.showMessage("Done", 5000)
88
88
  self._progress_bar.hide()
89
89
 
90
90
  def _show_single_task_progress(self, task: Tuple[TaskID, _TaskProgress]) -> None:
@@ -132,12 +132,12 @@ class StatusBarProgressDisplay(QStatusBar):
132
132
 
133
133
  def _add_task(self, task: TaskID, current: int, total: int) -> None:
134
134
  self._tasks[task] = _TaskProgress(current, total)
135
- _logger.debug("Added task %s", task)
135
+ _logger.info("Added task %s", task)
136
136
  _logger.debug("Tasks: %s", self._tasks)
137
137
 
138
138
  def _remove_task(self, task: TaskID) -> None:
139
139
  self._tasks.pop(task, None)
140
- _logger.debug("Removed task %s", task)
140
+ _logger.info("Removed task %s", task)
141
141
  _logger.debug("Tasks: %s", self._tasks)
142
142
 
143
143
  @property
@@ -34,13 +34,16 @@ class SetupDialog(QDialog):
34
34
 
35
35
  self._semaphore = Semaphore()
36
36
  self._canvas_url_box = QLineEdit(settings.client.canvas_url)
37
+ self._canvas_url_box.setPlaceholderText("https://instance.canvas.com")
37
38
  self._canvas_api_key_box = QLineEdit(settings.client.canvas_api_key)
38
39
  self._canvas_api_key_box.setEchoMode(QLineEdit.EchoMode.Password)
39
40
  self._panopto_url_box = QLineEdit(settings.client.panopto_url)
41
+ self._panopto_url_box.setPlaceholderText("https://instance.panopto.com")
40
42
  self._button_box = self._setup_button_box()
41
43
  self._button_box.accepted.connect(self._accepted)
42
44
  self._button_box.helpRequested.connect(self._help_requested)
43
45
  self._waiting_indicator = self._setup_progress_bar()
46
+ self._status_bar = QStatusBar()
44
47
 
45
48
  self.setLayout(
46
49
  layout(
@@ -54,13 +57,14 @@ class SetupDialog(QDialog):
54
57
  ),
55
58
  self._waiting_indicator,
56
59
  self._button_box,
60
+ self._status_bar,
57
61
  )
58
62
  )
59
63
 
60
64
  def _setup_button_box(self) -> QDialogButtonBox:
61
65
  box = QDialogButtonBox()
62
66
  box.addButton(QDialogButtonBox.StandardButton.Ok)
63
- box.addButton("Get a canvas API key", QDialogButtonBox.ButtonRole.HelpRole)
67
+ box.addButton("Get a Canvas API key", QDialogButtonBox.ButtonRole.HelpRole)
64
68
  return box
65
69
 
66
70
  def _setup_progress_bar(self) -> QProgressBar:
@@ -81,10 +85,13 @@ class SetupDialog(QDialog):
81
85
  if self._semaphore.acquire(False):
82
86
  try:
83
87
  self._clear_errors()
84
- if self._check_inputs():
88
+
89
+ if not self._all_inputs_valid():
90
+ self._status_bar.showMessage("Invalid input!", 5000)
85
91
  return
86
92
 
87
93
  self._waiting_indicator.setVisible(True)
94
+ self._status_bar.showMessage("Checking configuration...")
88
95
 
89
96
  canvas_config = CanvasClientConfig(
90
97
  api_token=self._canvas_api_key_box.text().strip(),
@@ -97,7 +104,9 @@ class SetupDialog(QDialog):
97
104
  if not await self._check_panopto_config(canvas_config):
98
105
  self._show_panopto_help()
99
106
  return
100
-
107
+ except Exception as e:
108
+ self._status_bar.showMessage(f"An error occurred: {e}", 5000)
109
+ _logger.warning("Checking config failed", exc_info=e)
101
110
  finally:
102
111
  self._waiting_indicator.setVisible(False)
103
112
  self._semaphore.release()
@@ -113,23 +122,24 @@ class SetupDialog(QDialog):
113
122
  self._panopto_url_box,
114
123
  self._canvas_api_key_box,
115
124
  ]:
125
+ self._status_bar.clearMessage()
116
126
  line_edit.setStyleSheet(None)
117
127
  line_edit.setToolTip(None)
118
128
 
119
- def _check_inputs(self) -> bool:
120
- had_error = False
129
+ def _all_inputs_valid(self) -> bool:
130
+ all_valid = True
121
131
 
122
132
  if not is_url(self._get_url(self._canvas_url_box)):
123
- had_error = True
133
+ all_valid = False
124
134
  self._show_error(self._canvas_url_box, "Canvas URL is invalid")
125
135
  if len(self._canvas_api_key_box.text().strip()) == 0:
126
- had_error = True
136
+ all_valid = False
127
137
  self._show_error(self._canvas_api_key_box, "Canvas API key is empty")
128
138
  if not is_url(self._get_url(self._panopto_url_box)):
129
- had_error = True
139
+ all_valid = False
130
140
  self._show_error(self._panopto_url_box, "Panopto URL is invalid")
131
141
 
132
- return had_error
142
+ return all_valid
133
143
 
134
144
  def _get_url(self, line_edit: QLineEdit) -> str:
135
145
  url = line_edit.text().strip()
@@ -172,8 +182,8 @@ class SetupDialog(QDialog):
172
182
  msg = QMessageBox(
173
183
  QMessageBox.Icon.Information,
174
184
  "Panopto Authentication",
175
- "In order for QCanvas to use panopto, you need to link your panopto account to your canvas account. "
176
- "A page will open in your web browser to do this when you click OK. It may ask you to sign into canvas.\n\n"
185
+ "In order for QCanvas to use Panopto, you need to link your Panopto account to your Canvas account. "
186
+ "A page will open in your web browser to do this when you click OK. It may ask you to sign into Canvas.\n\n"
177
187
  'Please tick "Remember my authorisation for this service" or QCanvas may not function correctly.\n\n'
178
188
  "QCanvas can't access anything entered in your browser.",
179
189
  QMessageBox.StandardButton.Ok,
@@ -0,0 +1,9 @@
1
+ import logging
2
+
3
+ import validators
4
+
5
+ _logger = logging.getLogger(__name__)
6
+
7
+
8
+ def is_url(url: str) -> bool:
9
+ return validators.url(url) == True
@@ -1,13 +0,0 @@
1
- import logging
2
- from urllib.parse import urlparse
3
-
4
- _logger = logging.getLogger(__name__)
5
-
6
-
7
- def is_url(url: str) -> bool:
8
- # https://overflow.perennialte.ch/questions/7160737/how-to-validate-a-url-in-python-malformed-or-not#
9
- try:
10
- result = urlparse(url)
11
- return all([result.scheme, result.netloc])
12
- except ValueError:
13
- return False
File without changes