Hey everyone! 👋
In this blog I will showcase the latest updates of my project.
Some of this important changes include:

  • Improvement of the User Interface
  • Light/dark mode
  • Settings window
  • Added a toolbar to the main page
  • Colored feedback

Also, I've made public the repo of the project in case anyone wants to take a detailed look at it: https://github.com/nairec/FitVision 👀

Let's jump right onto it!


Changes in the User Interface 🖥️

Button display

The start and end detection buttons have been replaced by a toggle start/stop button and an end detection button.

class Home(QMainWindow):
    def __init__(self):
        ...
        self.pause_session_button.clicked.connect(self.update_pause_state)
        self.end_session_button.clicked.connect(self.end_detection)
        ...
class Home(QMainWindow):
    def initUI(self):
        self.paused = True
        self.detection_started = False
        ...
        self.end_session_button = QPushButton()
        self.end_session_button.setStyleSheet("width: 10px; height: 10px; margin-right: 200px")
        self.pause_session_button = QPushButton()
        self.pause_session_button.setStyleSheet("background: none; border: none; padding: 0px; margin-left: 200px")
        self.pause_session_button.setIcon(QIcon("icons/mediaplay.png"))
        self.pause_session_button.setIconSize(QSize(60, 60))
        ...

The display of the info labels has also been changed, but the code is a 5-lines-for-each-label type of code, so I decided not to include it here.

The class Inherited by Home() has been changed from QWidget() to QMainWindow() to enable the new toolbar.

Some methods of the Home() class have been updated to work with the change in the display of the main buttons, and two new methods have been created: update_pause_state() and update_pause_icon()

class Home(QMainWidget):
    ...
    def start_detection(self):
        self.paused = False
        self.update_pause_icon()
        self.app_signals.start_detection.emit()
    ...
class Home(QMainWidget):
    ...
    def end_detection(self):
        self.paused = True
        self.detection_started = False
        self.update_pause_icon()
        self.app_signals.end_detection.emit()
    ...
class Home(QMainWidget):
    ...
    def update_pause_state(self):
        if self.detection_started: # If detection has already started, pause
            self.paused = not self.paused
            self.update_pause_icon()
            self.app_signals.pause_detection.emit(self.paused)
        else: # If detection hasn't started, start it
            self.detection_started = True
            self.start_detection()
    ...
class Home(QMainWidget):
    ...
    def update_pause_icon(self):
        if self.paused:
            self.pause_session_button.setIcon(QIcon("icons/mediaplay.png"))
            self.pause_session_button.setIconSize(QSize(60, 60))
        else:
            self.pause_session_button.setIcon(QIcon("icons/mediapause.png"))
            self.pause_session_button.setIconSize(QSize(60, 60))
    ...

Colored feedback

Now, the user has the option to enable or disable (it is enabled by default) a coloration in the labels that show the information like rep count, timer, etc.
This coloration is based on the average values that would be considered low/medium/high or excessive/addequate.

class Home(QMainWindow):
    def __init__(self):
        ...
        self.feedback_on = True
        self.bad_feedback_color = "#94322E"
        self.medium_feedback_color = "#F0E68C"
        self.good_feedback_color = "#80FF80"
        ...

The logic behind the actual coloration of the labels is formed of some if statements that check the intervals of the values.

Color themes

Obviously, an application is not properly designed if it doesn't have an option to change between light and dark modes, so I added that posibility in the settings window.

The changes on the UI style based on the color theme selected are defined in a new method called toggle_theme().
I will skip the explanation of this method because it's mainly just boring CSS, and nobody likes CSS around here 🥱.

Settings window ⚙️

For communicating changes in the settings I created a new signal class

class SettingsSignals(QObject):
    toggle_feedback = pyqtSignal(bool)
    toggle_theme = pyqtSignal(str)

The first signal sends a bool value that represents wether the colored feedback is on or off, and the second one sends the selected color theme.

The class for the settings window is formed by inheriting the QWidget class and takes as parameters the SettingsSignals object and the current value of the color theme for defining the pre-selected theme on the combobox when opening the window.

class SettingsWindow(QWidget):
    def __init__(self, settings_signals:SettingsSignals, currentTheme:str):
    ...

I won't show fully the code of this class as it is not that interesting, but the two methods that control the change in feedback and theme options are the following:

class SettingsWindow(QWidget):
    ...
    def apply_toggle_feedback(self, state:bool):
        if state == Qt.Checked:
            self.settings_signals.toggle_feedback.emit(True)
        else:
            self.settings_signals.toggle_feedback.emit(False)

    def apply_toggle_theme(self, theme:str):
        self.settings_signals.toggle_theme.emit(theme)

The first one emits the value of the checkbox and the second one emits the label of the selected color theme.

Results! ✅

Light mode, colored feedback disabled:

Image visualization of the two windows on light mode, colored feedback disabled

Light mode, colored feedback enabled:

Image visualization of the two windows on light mode, colored feedback enabled

Dark mode, colored feedback disabled:

Image visualization of the two windows on darkmode, colored feedback disabled

Dark mode, colored feedback enabled:

Image visualization of the two windows on dark mode, colored feedback enabled

Next steps 📑

  • Saving session records
  • New color themes ?
  • Personalized color feedback

Thank you for reaching the end of the blog and see you in the next!