Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR3: Display changelog/announcement page in SLEAP GUI #1556

Open
wants to merge 45 commits into
base: shrivaths/changelog-announcement-2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b7f7748
Adding the bulletin dialog box class
shrivaths16 Oct 17, 2023
25eda37
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Oct 17, 2023
8706ccb
Add new variable to enable bulletin dialogue
shrivaths16 Oct 17, 2023
fdf5547
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Oct 19, 2023
d584de2
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Oct 30, 2023
f809bda
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Oct 30, 2023
cce7183
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Nov 2, 2023
2c68518
Add bulletin popup to application
shrivaths16 Nov 2, 2023
ca25347
Add Qthread to multiple windows
shrivaths16 Nov 14, 2023
27f0d28
Set dialog to top, maintain reference to thread, remove unused imports
Nov 14, 2023
168056e
bulletin pop up on top, change to pathlib
shrivaths16 Nov 28, 2023
5e2fb37
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Nov 30, 2023
944428f
merge with base branch shrivaths/changelog-announcent-2
shrivaths16 Dec 2, 2023
793faa6
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Dec 5, 2023
561a109
Fix bulletin dialog display conditions
shrivaths16 Dec 5, 2023
465eb3f
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Dec 5, 2023
f7c510d
small test modification
shrivaths16 Dec 6, 2023
d071ac8
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Dec 14, 2023
58ffca8
pyside6 >=6.0
shrivaths16 Dec 18, 2023
02aa249
setting environment variable QT_API to pyside2
shrivaths16 Dec 18, 2023
a724ec2
try with pyside6 and set environment variable
shrivaths16 Dec 19, 2023
9827510
pyside2 == 5.14.1
shrivaths16 Dec 19, 2023
cd98d7c
pyside6 ==6.2.2.1
shrivaths16 Dec 19, 2023
a9673d8
pyside6 ==6.2.2.1
shrivaths16 Dec 20, 2023
b7e475d
Resetting back to default
shrivaths16 Dec 20, 2023
2cc02d7
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Dec 20, 2023
709de70
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Dec 21, 2023
18974db
add pip install PySide2==5.14.1 in conda_mac build.sh
shrivaths16 Dec 21, 2023
cada26c
Add title to bulletin popup
shrivaths16 Dec 21, 2023
3c35dda
add navbar
shrivaths16 Jan 2, 2024
713c068
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Jan 3, 2024
86d1a44
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Jan 11, 2024
1737561
test skip method for macos
shrivaths16 Jan 11, 2024
7859b93
test with different os name
shrivaths16 Jan 11, 2024
ec2b2d7
correct pytest skip
shrivaths16 Jan 11, 2024
59f2438
test skip functionality
shrivaths16 Jan 11, 2024
bd8d004
test skipping entire module
shrivaths16 Jan 11, 2024
ea2111d
skip macos tests
shrivaths16 Jan 11, 2024
7ff49f0
misplaced skip
shrivaths16 Jan 11, 2024
5391131
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Jan 11, 2024
6ddb158
having online bulletin for macos
shrivaths16 Jan 12, 2024
895a074
Adjust test functions to include online bulletin
shrivaths16 Jan 12, 2024
af67d55
inlcude review changes
shrivaths16 Jan 17, 2024
b5d5139
Merge branch 'shrivaths/changelog-announcement-2' into shrivaths/chan…
shrivaths16 Jan 17, 2024
150453d
PR4: Add helpmenu option (#1628)
shrivaths16 Jan 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/bulletin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"title": "SLEAP v1.3.2",
"date": "10/30/2023",
"content": "\n\n\nSLEAP 1.3.2 adds some nice usability features thanks to both the community ideas and new contributors! See [1.3.0](https://github.com/talmolab/sleap/releases/tag/v1.3.0) and [1.3.1](https://github.com/talmolab/sleap/releases/tag/v1.3.1) for previous notable changes. As a reminder:\n\n> The 1.3.1 dependency update requires [Mamba](https://mamba.readthedocs.io/en/latest/index.html) for faster dependency resolution. If you already have anaconda installed, then you _can_ set the solver to libmamba in the base environment:\n>```\n>conda update -n base conda\n>conda install -n base conda-libmamba-solver\n>conda config --set solver libmamba\n>```\n>Any subsequent `mamba` commands in the docs will need to be replaced with `conda` if you choose to use your existing Anaconda installation. \n>\n>Otherwise, follow the [recommended installation instruction for Mamba](https://mamba.readthedocs.io/en/latest/installation.html).\n\n### Quick install\n**`mamba` (Windows/Linux/GPU)**:\n```\nmamba create -y -n sleap -c conda-forge -c nvidia -c sleap -c anaconda sleap=1.3.2\n```\n\n**`mamba` (Mac)**:\n```\nmamba create -y -n sleap -c conda-forge -c anaconda -c sleap sleap=1.3.2\n```\n\n**`pip` (any OS except Apple Silicon)**:\n```\npip install sleap[pypi]==1.3.2\n```\n\n### Highlights\n* Limit max tracks via track-local queues by @shrivaths16 and @talmo in https://github.com/talmolab/sleap/pull/1447\n* Add option to remove videos in batch by @gitttt-1234 in https://github.com/talmolab/sleap/pull/1382 and https://github.com/talmolab/sleap/pull/1406\n* Add shortcut to export analysis for current video by @KevinZ0217 in https://github.com/talmolab/sleap/pull/1414 and https://github.com/talmolab/sleap/pull/1444\n* Add video path and frame indices to metrics by @roomrys in https://github.com/talmolab/sleap/pull/1396\n* Add a button for copying model config to clipboard by @KevinZ0217 in https://github.com/talmolab/sleap/pull/1433\n* Add Option to Export CSV by @gitttt-1234 in https://github.com/talmolab/sleap/pull/1438\n\n### Full Changelog\n\n#### Enhancements\n* Add option to remove videos in batch by @gitttt-1234 in https://github.com/talmolab/sleap/pull/1382 and https://github.com/talmolab/sleap/pull/1406\n* Add `Track` when add `Instance` by @roomrys in https://github.com/talmolab/sleap/pull/1408\n* Add `Video` to cache when adding `Track` by @roomrys in https://github.com/talmolab/sleap/pull/1407\n* Add shortcut to export analysis for current video by @KevinZ0217 in https://github.com/talmolab/sleap/pull/1414 and https://github.com/talmolab/sleap/pull/1444\n* Add video path and frame indices to metrics by @roomrys in https://github.com/talmolab/sleap/pull/1396\n* Improve error message for detecting video backend by @roomrys in https://github.com/talmolab/sleap/pull/1441\n* Add a button for copying model config to clipboard by @KevinZ0217 in https://github.com/talmolab/sleap/pull/1433\n* Add Option to Export CSV by @gitttt-1234 in https://github.com/talmolab/sleap/pull/1438\n* Limit max tracks via track-local queues by @shrivaths16 and @talmo in https://github.com/talmolab/sleap/pull/1447\n\n#### Fixes\n* Minor fix in computation of OKS by @shrivaths16 in https://github.com/talmolab/sleap/pull/1383 and https://github.com/talmolab/sleap/pull/1399\n* Fix `Filedialog` to work across (mac)OS by @roomrys in https://github.com/talmolab/sleap/pull/1393\n* Fix panning bounding box by @gitttt-1234 in https://github.com/talmolab/sleap/pull/1398\n* Fix skeleton templates by @roomrys in https://github.com/talmolab/sleap/pull/1404\n* Fix labels export for json by @roomrys in https://github.com/talmolab/sleap/pull/1410\n* Correct GUI state emulation by @roomrys in https://github.com/talmolab/sleap/pull/1422\n* Update status message on status bar by @shrivaths16 in https://github.com/talmolab/sleap/pull/1411\n* Fix error thrown when last video is deleted by @shrivaths16 in https://github.com/talmolab/sleap/pull/1421\n* Add model folder to the unzip path by @roomrys in https://github.com/talmolab/sleap/pull/1445\n* Fix drag and drop by @talmo in https://github.com/talmolab/sleap/pull/1449\n\n#### Dependencies\n* Pin micromamba version by @roomrys in https://github.com/talmolab/sleap/pull/1376\n* Add pip extras by @roomrys in https://github.com/talmolab/sleap/pull/1481\n\n#### New Contributors\n* @shrivaths16 made their first contribution in https://github.com/talmolab/sleap/pull/1383\n* @gitttt-1234 made their first contribution in https://github.com/talmolab/sleap/pull/1382\n* @KevinZ0217 made their first contribution in https://github.com/talmolab/sleap/pull/1414\n\n**Full Changelog**: https://github.com/talmolab/sleap/compare/v1.3.1...v1.3.2\n"
}
]
56 changes: 53 additions & 3 deletions sleap/gui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,23 @@
from logging import getLogger
from pathlib import Path
from typing import Callable, List, Optional, Tuple
from datetime import date

from qtpy import QtCore, QtGui
from qtpy.QtCore import QEvent, Qt
from qtpy.QtCore import QEvent, Qt, QUrl
from qtpy.QtWidgets import QApplication, QMainWindow, QMessageBox

from qtpy.QtWebChannel import QWebChannel
from qtpy.QtWebEngineWidgets import QWebEngineView

import sleap
from sleap.gui.color import ColorManager
from sleap.gui.commands import CommandContext, UpdateTopic
from sleap.gui.dialogs.filedialog import FileDialog
from sleap.gui.dialogs.formbuilder import FormBuilderModalDialog
from sleap.gui.dialogs.metrics import MetricsTableDialog
from sleap.gui.dialogs.shortcuts import ShortcutDialog
from sleap.gui.dialogs.bulletin import BulletinDialog
from sleap.gui.overlays.instance import InstanceOverlay
from sleap.gui.overlays.tracks import TrackListOverlay, TrackTrailOverlay
from sleap.gui.shortcuts import Shortcuts
Expand Down Expand Up @@ -158,8 +163,21 @@ def __init__(
self.state["share usage data"] = prefs["share usage data"]
self.state["skeleton_preview_image"] = None
self.state["skeleton_description"] = "No skeleton loaded yet"
self.state["announcement last seen date"] = prefs["announcement last seen date"]
self.state["announcement"] = prefs["announcement"]

if prefs["announcement last seen date"]:
self.state["announcement last seen date"] = prefs[
"announcement last seen date"
]
else:
self.state["announcement last seen date"] = date.today().strftime(
"%m/%d/%Y"
)

if prefs["announcement"]:
self.state["announcement"] = prefs["announcement"]
else:
self.state["announcement"] = "No data to display"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value for announcement should be None or an empty string to clearly indicate the absence of an announcement.

-            self.state["announcement"] = "No data to display"
+            self.state["announcement"] = None

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
self.state["announcement"] = "No data to display"
self.state["announcement"] = None


if no_usage_data:
self.state["share usage data"] = False
self.state["clipboard_track"] = None
Expand All @@ -170,7 +188,9 @@ def __init__(
self.state.connect("show non-visible nodes", self.plotFrame)

self.release_checker = ReleaseChecker()

self.announcement_checker = AnnouncementChecker(state=self.state)
self.new_announcement_available = self.announcement_checker.new_announcement

if self.state["share usage data"]:
ping_analytics()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ping_analytics function should be wrapped in a conditional check to respect user preferences.

-            ping_analytics()
+            if self.state["share usage data"]:
+                ping_analytics()

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
ping_analytics()
if self.state["share usage data"]:
ping_analytics()

Expand All @@ -191,6 +211,36 @@ def __init__(
else:
self.state["project_loaded"] = False

# Display announcement bulletin popup
if self.new_announcement_available:
self.display_bulletin = BulletinDialog()
self.bulletin_dialog()

def bulletin_dialog(self):
"""Displays bulletin dialog is new announcement is available."""
announcement = self.announcement_checker.get_latest_announcement()

if announcement:
title, date, content = announcement
bulletin_markdown = "\n".join(content.split("\n"))

channel = QWebChannel()
channel.registerObject("content", self.display_bulletin)

self.display_bulletin.set_text(bulletin_markdown)

view = QWebEngineView()
view.page().setWebChannel(channel)
base_path = os.path.dirname(os.path.abspath(os.path.join(__file__)))
filepath = os.path.join(
base_path, "..", "gui", "dialogs", "bulletin", "markdown.html"
)
url = QUrl.fromLocalFile(filepath)
view.load(url)
view.resize(720, 540)
view.show()
QApplication.exec_()

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bulletin_dialog method is well implemented. It checks if there is a new announcement and if so, it displays the bulletin dialog. The use of QWebChannel and QWebEngineView allows for the dynamic updating of the announcement content in the GUI. However, the bulletin_dialog method could be refactored to improve readability and maintainability. Consider breaking it down into smaller methods, each with a single responsibility. For example, one method could handle the creation of the QWebChannel and QWebEngineView, another could handle the loading of the URL, and another could handle the display of the view.

def bulletin_dialog(self):
    """Displays bulletin dialog is new announcement is available."""
    announcement = self.announcement_checker.get_latest_announcement()

    if announcement:
        title, date, content = announcement
        bulletin_markdown = "\n".join(content.split("\n"))

        channel, view = self.create_web_channel_and_view(bulletin_markdown)
        self.load_url(view)
        self.display_view(view)

def create_web_channel_and_view(self, bulletin_markdown):
    channel = QWebChannel()
    channel.registerObject("content", self.display_bulletin)

    self.display_bulletin.set_text(bulletin_markdown)

    view = QWebEngineView()
    view.page().setWebChannel(channel)
    return channel, view

def load_url(self, view):
    base_path = os.path.dirname(os.path.abspath(os.path.join(__file__)))
    filepath = os.path.join(
        base_path, "..", "gui", "dialogs", "bulletin", "markdown.html"
    )
    url = QUrl.fromLocalFile(filepath)
    view.load(url)

def display_view(self, view):
    view.resize(720, 540)
    view.show()
    QApplication.exec_()

def setWindowTitle(self, value):
"""Sets window title (if value is not None)."""
if value is not None:
Expand Down
32 changes: 32 additions & 0 deletions sleap/gui/dialogs/bulletin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
GUI for displaying the new announcement.
"""

import os
import sleap
import sleap.gui.web
from qtpy.QtWidgets import QApplication
from qtpy.QtCore import Property, Signal, QObject, QUrl
from qtpy.QtWebChannel import QWebChannel
from qtpy.QtWebEngineWidgets import QWebEngineView
from sleap.gui.commands import CommandContext
from sleap.io.dataset import Labels


class BulletinDialog(QObject):
textChanged = Signal(str)

def __init__(self, parent=None):
super().__init__(parent)
self.m_text = ""
Comment on lines +59 to +61
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the previous review comment, consider adding an optional text parameter to the __init__ method of the Document class to allow setting the initial text upon instantiation.

-    def __init__(self, parent=None):
+    def __init__(self, parent=None, text=""):
         super().__init__(parent)
-        self.m_text = ""
+        self.m_text = text

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def __init__(self, parent=None):
super().__init__(parent)
self.m_text = ""
def __init__(self, parent=None, text=""):
super().__init__(parent)
self.m_text = text


Comment on lines +59 to +62
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The __init__ method initializes m_text as an empty string. If there's a possibility that text could be passed during initialization, consider adding it as an optional argument to __init__. This would allow for more flexible usage of the class.

-    def __init__(self, parent=None):
+    def __init__(self, parent=None, text=""):
         super().__init__(parent)
-        self.m_text = ""
+        self.m_text = text

Commitable suggestion (Beta)
Suggested change
def __init__(self, parent=None):
super().__init__(parent)
self.m_text = ""
def __init__(self, parent=None, text=""):
super().__init__(parent)
self.m_text = text

def get_text(self):
return self.m_text

def set_text(self, text):
if self.m_text == text:
return
self.m_text = text
self.textChanged.emit(self.m_text)

text = Property(str, fget=get_text, fset=set_text, notify=textChanged)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BulletinDialog class currently only has a text property. If there are more properties or methods that are expected to be added in the future, consider adding a docstring to the class and its methods to explain their purpose and usage. This will improve the maintainability of the code.

Loading
Loading