-
-
Notifications
You must be signed in to change notification settings - Fork 685
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
Set default background color for widgets on iOS #3009
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's the start of some interesting cleanups here, but:
- This is all in the iOS backend, so we can lean into using iOS native colors. Trying to convert to Toga colors means we end up spending effort converting back and forth between the two formats for no real gain
- The changes to Button don't seem right. The existing implementation explicitly sets the background to None because that's the desired behavior. I will admit that I haven't run the testbed with these changes; but I spent a lot of time getting these settings right when they were originally implemented, so I'm starting from a point of scepticism that these changes are required for button.
- It's a little concerning that other than button, there's no changes to testbed tests. That means this change is either a no-op, or there are untested changes. If it's a no-op, we need to be clear why we're making this change.
iOS/src/toga_iOS/widgets/base.py
Outdated
|
||
# Set default background color | ||
try: | ||
# systemBackgroundColor() was introduced in iOS 13 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer need this branch; as a result of the PEP 730 changes, iOS 13 is the minimum supported iOS version. The iOS platform docs should also be updated to reflect this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I've removed that branch.
iOS/src/toga_iOS/widgets/base.py
Outdated
except AttributeError: # pragma: no cover | ||
self.native.backgroundColor = UIColor.whiteColor | ||
self.native.backgroundColor = ( | ||
native_color(self._default_background_color) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unnecessarily complex - doing a round trip from UIColor to toga.Color to UIColor just to get a (cached, and possibly stale) UIColor.systemBackgroundColor()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I've modified it to work with the native colors directly.
iOS/src/toga_iOS/widgets/canvas.py
Outdated
@@ -15,7 +15,7 @@ | |||
) | |||
from travertino.size import at_least | |||
|
|||
from toga.colors import BLACK, TRANSPARENT, color | |||
from toga.colors import BLACK, TRANSPARENT, color as named_color |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth noting that this is a little misleading - color
here isn't just named colors - it's a toga color that will accept any valid string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've renamed it to toga_color
iOS/src/toga_iOS/widgets/button.py
Outdated
self.native.backgroundColor = native_color(color) | ||
super().set_background_color( | ||
self._default_background_color if color in {None, TRANSPARENT} else color | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICT, this is a change in behavior. backgroundColor=None
is a required call in this instance, and this new implementation doesn't provide that as an option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've restored it. But it's worth noting that backgroundColor=None
produces the same result as backgroundColor=UIColor.clearColor
:
backgroundColor=None |
|
backgroundColor=UIColor.clearColor |
According to: https://developer.apple.com/documentation/uikit/uiview/1622591-backgroundcolor?language=objc:
Changes to this property can be animated. The default value is nil, which results in a transparent background color.
But according to: https://developer.apple.com/documentation/uikit/uibackgroundconfiguration/3600317-backgroundcolor
If the value is nil, the background color is the view’s tint color. Use clear for a transparent background with no color.
So, I have set the background color of widgets which should have transparent background by default to UIColor.clearColor
. But for button, I've set the default background color to None
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok - I think that interpretation of "None = Transparent" is what I was remembering. Based on the examples you've presented here, it looks like you've preserved the historical behavior.
Regarding enabling background color tests on all the widgets, I cannot enable background color tests on the testbed for all widgets, since there are problems associated with the widget background color on some platforms like on Android and Winforms. If I enable all 3 background color tests on every widget, then the testbed would pass on iOS, but would fail on other platforms. At the same time, I cannot correct their behavior to make them pass the tests as fixes for those platforms exist on separate PRs. I know you have told me that behavioral changes need tests that confirms their behavior. So, to prevent a deadlock situation that would prevent this PR from being merged, I want to propose that we create a new issue to keep track of the widgets on which background color tests are not enabled. Since, all 3 tests are enabled on most widgets so the list would be small. Afterwards, when all 3 dependent PRs are merged, we can enable all the 3 background color tests on all the widgets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're getting closer - and the sample project you've posted definitely suggests this PR is on the right track.
There's still some overly convoluted logic around the color reset (on button, in particular); I've flagged my concerns inline.
Regarding testbed testing - your explanation makes sense. From a process perspective, if this is something you've given thought to, it's helpful to include that context in the pull request description. You might think it's obvious given the history of the ticket - but a reviewer (read: me) is doing a lot of other things, and so the connection to "obvious" things might not always be so obvious.
iOS/src/toga_iOS/widgets/base.py
Outdated
def set_background_color_simple(self, value): | ||
if value: | ||
self.native.backgroundColor = native_color(value) | ||
def set_background_color(self, color, is_native_color=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a good idea. The API either takes a native color, or it doesn't. And given that the only usage that I can see of is_native_color=True
... uses native_color()
on the invocation, it seems to be completely unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set_background_color()
will receive a toga color from the core interface, but on the backend since we are working directly with the native UIColor
, so any invocation of set_background_color()
from the backend requires is_native_color=True
. This is why in the previous review, I was specifying _default_background_color
in the form of toga color instead of the native UIColor
.
But since now we are directly specfying the _default_background_color
in the form of native UIColor
, we need the additional indicator is_native_color=True
to prevent any incorrect interpretation while assigning the background color.
You were right.
iOS/src/toga_iOS/widgets/base.py
Outdated
default_background_color = getattr(self, "_default_background_color", None) | ||
if default_background_color is None: | ||
default_background_color = UIColor.systemBackgroundColor() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use _default_background_color
as the default in the call to getattr
?
Also - it feels like there's some ambiguity here about what "None" means in the context of default_background_color
- is it "transparent", or "system background"? Does it make a difference if the property is explicitly set to None, or the property is not defined at all? (it probably should - because it gives you a way to differentiate between two interpretations of "reset" behaviour - and that interpretation should be documented here).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have changed it to use UIColor.systemBackgroundColor()
as the default in the call to getattr
.
On the backends, there are 3 different possible values for set_background_color():
None | Default background color |
TRANSPARENT | Actual transparency |
Color | Actual color |
But for Button, the historical behavior is "None = TRANSPARENT", which I have preserved in this PR.
iOS/src/toga_iOS/widgets/button.py
Outdated
self.native.backgroundColor = native_color(color) | ||
super().set_background_color( | ||
self._default_background_color if color in {None, TRANSPARENT} else color | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok - I think that interpretation of "None = Transparent" is what I was remembering. Based on the examples you've presented here, it looks like you've preserved the historical behavior.
I agree, I should have added context for not enabling tests. I have edited the PR ticket to include the context and will keep in mind to add context on new PRs. I have created #3015 to keep track of the widgets on which background color tests are not enabled. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The structure of the PR is looking good now; the only question is about the actual colors used (and in particular the secondary background color change)
except AttributeError: # pragma: no cover | ||
self.native.backgroundColor = UIColor.whiteColor | ||
default_background_color = getattr( | ||
self, "_default_background_color", UIColor.secondarySystemBackgroundColor() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why secondarySystemBackgroundColor? This is a fairly big change - and looking at the most recent sample screenshot, it definitely doesn't look right for switch, and it's arguable whether it's correct for TextInput, MultilineTextInput et al
If we use systemBackgroundColor, the widgets are not distinguishable from the background:
I had used secondarySystemBackgroundColor since it made the widgets distinguisable and similar in appearance as the native settings app:
But looking closely, I now realize that the UISwitch widget itself has a background color of UIColor.clearColor and is inside a UIView which has a non-transparent background color.
|
Yes - but that's part of iOS's style guide. You can disagree with that style if you like (I know I definitely have my issues with the "minimalist" iOS style guide), but that doesn't give us liberty to "fix" it.
Yes - but the native settings app is specifically on a different background color. It's the "form" layout that is providing the background color, not the widget. The UISwitch is the widget that makes this distinction obvious.
By default, we shouldn't be making any change from the "default" value. Functionally, that may mean we need to encode (or capture at runtime) the default; but the background color of the widget should be the same as if we did nothing programatically. |
Fixes #767
This PR is broken out of #2484.
This PR sets default background color as TRANSPARENT for Box, Canvas, ImageView, Label, ProgressBar, ScrollContainer and Slider widgets on iOS.
Context for tests:
Currently all the 3 background color tests on the testbed cannot be enabled for all widgets, since there are problems associated with the widget background color on some platforms like on Android and Winforms. If we enable all 3 background color tests on every widget, then the testbed would pass on iOS, but would fail on other platforms. At the same time, we cannot correct their behavior to make them pass the tests as fixes for those platforms exist on separate PRs.
For example, If we enable all the 3 tests: test_background_color, test_background_color_reset, test_background_transparent on the Box widget then the tests would pass on iOS, but would fail on Winforms, since the fix for winforms exists on a separate PR.
Since behavioral changes need tests that confirms their behavior. So, to prevent a deadlock situation that would prevent this PR from being merged, I want to propose that we create a new issue to keep track of the widgets on which background color tests are not enabled. Since all 3 tests are enabled on most widgets so the list would be small. Afterwards, when all 3 dependent PRs are merged, we can enable all the 3 background color tests on all the widgets.
Issue for tracking background color tests on widgets: #3015
PR Checklist: