diff --git a/changes/2829.feature.rst b/changes/2829.feature.rst new file mode 100644 index 0000000000..c5517b973c --- /dev/null +++ b/changes/2829.feature.rst @@ -0,0 +1 @@ +The ActivityIndicator widget is now supported on iOS. diff --git a/docs/reference/api/widgets/activityindicator.rst b/docs/reference/api/widgets/activityindicator.rst index 0a19d4be23..04b0b1edb3 100644 --- a/docs/reference/api/widgets/activityindicator.rst +++ b/docs/reference/api/widgets/activityindicator.rst @@ -26,9 +26,11 @@ usually rendered as a "spinner" animation. Not supported - .. group-tab:: iOS |no| + .. group-tab:: iOS - Not supported + .. figure:: /reference/images/activityindicator-iOS.png + :align: center + :width: 100px .. group-tab:: Web |beta| diff --git a/docs/reference/data/widgets_by_platform.csv b/docs/reference/data/widgets_by_platform.csv index ccebcf7aff..f3108e1543 100644 --- a/docs/reference/data/widgets_by_platform.csv +++ b/docs/reference/data/widgets_by_platform.csv @@ -3,7 +3,7 @@ Application,Core Component,:class:`~toga.App`,The application itself,|y|,|y|,|y| Window,Core Component,:class:`~toga.Window`,An operating system-managed container of widgets.,|y|,|y|,|y|,|y|,|y|,|b|,|b| DocumentWindow,Core Component,:class:`~toga.DocumentWindow`,A window that can be used as the main interface to a document-based app.,|y|,|y|,|y|,,,, MainWindow,Core Component,:class:`~toga.MainWindow`,A window that can use the full set of window-level user interface elements.,|y|,|y|,|y|,|y|,|y|,|b|,|b| -ActivityIndicator,General Widget,:class:`~toga.ActivityIndicator`,A spinning activity animation,|y|,|y|,,,,|b|, +ActivityIndicator,General Widget,:class:`~toga.ActivityIndicator`,A spinning activity animation,|y|,|y|,,|y|,,|b|, Button,General Widget,:class:`~toga.Button`,Basic clickable Button,|y|,|y|,|y|,|y|,|y|,|b|,|b| Canvas,General Widget,:class:`~toga.Canvas`,A drawing area for 2D vector graphics.,|y|,|y|,|y|,|y|,|y|,, DateInput,General Widget,:class:`~toga.DateInput`,A widget to select a calendar date,,,|y|,,|y|,, diff --git a/docs/reference/images/activityindicator-iOS.png b/docs/reference/images/activityindicator-iOS.png new file mode 100644 index 0000000000..aec9f3c1a5 Binary files /dev/null and b/docs/reference/images/activityindicator-iOS.png differ diff --git a/gtk/pyproject.toml b/gtk/pyproject.toml index b4c5480add..13059a5e66 100644 --- a/gtk/pyproject.toml +++ b/gtk/pyproject.toml @@ -66,7 +66,10 @@ root = ".." dependencies = [ "gbulb >= 0.5.3", "pycairo >= 1.17.0", - "pygobject >= 3.46.0", + # New asyncio handling introduced in 3.50.0; that code is incompatible + # with gbulb, See #2550 for the code that replaces GBulb with the new + # asyncio code. + "pygobject < 3.50.0", "toga-core == {version}", ] diff --git a/iOS/src/toga_iOS/factory.py b/iOS/src/toga_iOS/factory.py index a8ac897ccb..0bf9c6f757 100644 --- a/iOS/src/toga_iOS/factory.py +++ b/iOS/src/toga_iOS/factory.py @@ -13,6 +13,7 @@ from .statusicons import MenuStatusIcon, SimpleStatusIcon, StatusIconSet # Widgets +from .widgets.activityindicator import ActivityIndicator from .widgets.box import Box from .widgets.button import Button from .widgets.canvas import Canvas @@ -47,6 +48,7 @@ def not_implemented(feature): __all__ = [ "not_implemented", + "ActivityIndicator", "App", "Command", # Resources diff --git a/iOS/src/toga_iOS/libs/uikit.py b/iOS/src/toga_iOS/libs/uikit.py index 8e1cd1ccc8..818900ce7c 100644 --- a/iOS/src/toga_iOS/libs/uikit.py +++ b/iOS/src/toga_iOS/libs/uikit.py @@ -117,6 +117,10 @@ def NSTextAlignment(alignment): UIKeyInput = ObjCProtocol("UIKeyInput") +###################################################################### +# UIActivityIndicatorView.h +UIActivityIndicatorView = ObjCClass("UIActivityIndicatorView") + ###################################################################### # UIAlertController.h UIAlertController = ObjCClass("UIAlertController") diff --git a/iOS/src/toga_iOS/widgets/activityindicator.py b/iOS/src/toga_iOS/widgets/activityindicator.py new file mode 100644 index 0000000000..4d17e4c8a0 --- /dev/null +++ b/iOS/src/toga_iOS/widgets/activityindicator.py @@ -0,0 +1,31 @@ +from rubicon.objc import CGSize + +from toga_iOS.libs import UIActivityIndicatorView +from toga_iOS.widgets.base import Widget + + +class ActivityIndicator(Widget): + def create(self): + self.native = UIActivityIndicatorView.new() + self.native.hidesWhenStopped = True + self.native.translatesAutoresizingMaskIntoConstraints = False + self.native.sizeToFit() + + self.add_constraints() + + def set_hidden(self, hidden): + self.native.setHidden((not self.is_running()) or hidden) + + def is_running(self): + return self.native.isAnimating() + + def start(self): + self.native.startAnimating() + + def stop(self): + self.native.stopAnimating() + + def rehint(self): + fitting_size = self.native.systemLayoutSizeFittingSize(CGSize(0, 0)) + self.interface.intrinsic.width = fitting_size.width + self.interface.intrinsic.height = fitting_size.height diff --git a/iOS/tests_backend/widgets/activityindicator.py b/iOS/tests_backend/widgets/activityindicator.py new file mode 100644 index 0000000000..bc20c88bab --- /dev/null +++ b/iOS/tests_backend/widgets/activityindicator.py @@ -0,0 +1,7 @@ +from toga_iOS.libs import UIActivityIndicatorView + +from .base import SimpleProbe + + +class ActivityIndicatorProbe(SimpleProbe): + native_class = UIActivityIndicatorView diff --git a/testbed/tests/widgets/test_activityindicator.py b/testbed/tests/widgets/test_activityindicator.py index a4b33308e0..15e97cc720 100644 --- a/testbed/tests/widgets/test_activityindicator.py +++ b/testbed/tests/widgets/test_activityindicator.py @@ -11,7 +11,7 @@ @pytest.fixture async def widget(): - skip_on_platforms("android", "iOS", "windows") + skip_on_platforms("android", "windows") return toga.ActivityIndicator()