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

Added a dark mode property on App. #2992

Merged
merged 4 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
8 changes: 8 additions & 0 deletions android/src/toga_android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,14 @@ def get_screens(self):
screen_list = display_manager.getDisplays()
return [ScreenImpl(self, screen) for screen in screen_list]

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
self.interface.factory.not_implemented("dark mode state")
return None

######################################################################
# App capabilities
######################################################################
Expand Down
1 change: 1 addition & 0 deletions changes/2841.feature.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Apps can now interrogate whether they are in dark mode on some platforms.
11 changes: 11 additions & 0 deletions cocoa/src/toga_cocoa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,17 @@ def set_main_window(self, window):
def get_screens(self):
return [ScreenImpl(native=screen) for screen in NSScreen.screens]

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
appearance = self.native.effectiveAppearance
# Standard theme names in MacOS
# https://developer.apple.com/documentation/appkit/nsappearance/name-swift.struct?language=objc
in_dark_mode = "Dark" in str(appearance.name)
return in_dark_mode

######################################################################
# App capabilities
######################################################################
Expand Down
9 changes: 9 additions & 0 deletions core/src/toga/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,15 @@ def home_page(self) -> str | None:
menu items."""
return self._home_page

@property
def dark_mode(self) -> bool | None:
"""Whether the user has dark mode enabled in their environment (read-only).

:returns: A Boolean describing if the app is in dark mode; ``None`` if Toga
cannot determine if the app is in dark mode.
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
"""
return self._impl.get_dark_mode_state()

@property
def icon(self) -> Icon:
"""The Icon for the app.
Expand Down
6 changes: 6 additions & 0 deletions core/tests/app/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,12 @@ async def on_running(self):
assert running["called"]


def test_dark_mode_state(app):
"""Dark mode settings can be read through the dark_mode property."""
# The dummy backend is currently set to always be True
assert app.dark_mode


def test_deprecated_id(event_loop):
"""The deprecated `id` constructor argument is ignored, and the property of the same
name is redirected to `app_id`"""
Expand Down
7 changes: 7 additions & 0 deletions dummy/src/toga_dummy/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ def get_screens(self):
def set_icon(self, icon):
self._action("set_icon", icon=icon)

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
return True

######################################################################
# App capabilities
######################################################################
Expand Down
8 changes: 8 additions & 0 deletions gtk/src/toga_gtk/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,14 @@ def get_screens(self):
]
return screen_list

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
self.interface.factory.not_implemented("dark mode state")
return None

######################################################################
# App capabilities
######################################################################
Expand Down
8 changes: 8 additions & 0 deletions iOS/src/toga_iOS/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ def set_main_window(self, window):
def get_screens(self):
return [ScreenImpl(UIScreen.mainScreen)]

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
self.interface.factory.not_implemented("dark mode state")
return None

######################################################################
# App capabilities
######################################################################
Expand Down
1 change: 1 addition & 0 deletions iOS/src/toga_iOS/screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Screen:
_instances = {}

def __new__(cls, native):
# native is an instance of UIScreen
if native in cls._instances:
return cls._instances[native]
else:
Expand Down
5 changes: 5 additions & 0 deletions testbed/tests/app/test_app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from types import NoneType
from unittest.mock import Mock

import toga
Expand Down Expand Up @@ -253,3 +254,7 @@ async def test_app_icon(app, app_probe):
app.icon = toga.Icon.APP_ICON
await app_probe.redraw("Revert app icon to default")
app_probe.assert_app_icon(None)


async def test_dark_mode_state_read(app):
assert isinstance(app.dark_mode, (NoneType, bool))
8 changes: 8 additions & 0 deletions textual/src/toga_textual/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ def set_main_window(self, window):
def get_screens(self):
return [ScreenImpl(window._impl.native) for window in self.interface.windows]

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
self.interface.factory.not_implemented("dark mode state")
return None
Copy link
Member

Choose a reason for hiding this comment

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

Textual has the ability to differentiate between light and dark themes, so this should probably be handled the same as other platforms.


######################################################################
# App capabilities
######################################################################
Expand Down
8 changes: 8 additions & 0 deletions web/src/toga_web/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ def set_main_window(self, window):
def get_screens(self):
return [ScreenImpl(js.document.documentElement)]

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
self.interface.factory.not_implemented("dark mode state")
return None

######################################################################
# App capabilities
######################################################################
Expand Down
8 changes: 8 additions & 0 deletions winforms/src/toga_winforms/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ def get_screens(self):
]
return screen_list

######################################################################
# App state
######################################################################

def get_dark_mode_state(self):
self.interface.factory.not_implemented("dark mode state")
return None

######################################################################
# App capabilities
######################################################################
Expand Down
Loading