Skip to content

Commit

Permalink
Partial fixes for Android colors and fonts.
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Feb 25, 2023
1 parent 4a2944f commit fe92bb9
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 39 deletions.
3 changes: 3 additions & 0 deletions android/src/toga_android/libs/android/content/res.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from rubicon.java import JavaClass

ColorStateList = JavaClass("android/content/res/ColorStateList")
1 change: 0 additions & 1 deletion android/src/toga_android/libs/android/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@
Path = JavaClass("android/graphics/Path")
Path__Direction = JavaClass("android/graphics/Path$Direction")
Paint__Style = JavaClass("android/graphics/Paint$Style")
PorterDuff__Mode = JavaClass("android/graphics/PorterDuff$Mode")
Rect = JavaClass("android/graphics/Rect")
Typeface = JavaClass("android/graphics/Typeface")
7 changes: 4 additions & 3 deletions android/src/toga_android/widgets/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def set_child_bounds(self, widget, x, y, width, height):
self.native.updateViewLayout(widget.native, layout_params)

def set_background_color(self, value):
self.native.setBackgroundColor(
native_color(TRANSPARENT if (value is None) else value)
)
if value is None:
self.native.setBackgroundColor(native_color(TRANSPARENT))
else:
self.native.setBackgroundColor(native_color(value))
17 changes: 12 additions & 5 deletions android/src/toga_android/widgets/button.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from travertino.size import at_least

from toga.colors import TRANSPARENT
from toga_android.colors import native_color

from ..libs.android.graphics import PorterDuff__Mode
from ..libs.android.content.res import ColorStateList
from ..libs.android.util import TypedValue
from ..libs.android.view import OnClickListener, View__MeasureSpec
from ..libs.android.widget import Button as A_Button
Expand Down Expand Up @@ -42,14 +43,20 @@ def set_on_press(self, handler):
pass

def set_color(self, value):
if value:
if value is None:
pass
# TODO: set to system foreground
# self.native.setTextColor(native_color(value))
else:
self.native.setTextColor(native_color(value))

def set_background_color(self, value):
if value:
if value is None or value == TRANSPARENT:
self.native.setBackgroundTintList(None)
else:
# do not use self.native.setBackgroundColor - this messes with the button style!
self.native.getBackground().setColorFilter(
native_color(value), PorterDuff__Mode.MULTIPLY
self.native.setBackgroundTintList(
ColorStateList.valueOf(native_color(value))
)

def rehint(self):
Expand Down
18 changes: 14 additions & 4 deletions android/src/toga_android/widgets/label.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from travertino.size import at_least

from toga.colors import TRANSPARENT
from toga_android.colors import native_color

from ..libs.android.util import TypedValue
Expand All @@ -16,14 +17,23 @@ def set_text(self, value):
self.native.setText(value)

def set_font(self, font):
if font:
self.native.setTextSize(TypedValue.COMPLEX_UNIT_SP, font._impl.get_size())
self.native.setTypeface(font._impl.get_typeface(), font._impl.get_style())
self.native.setTextSize(TypedValue.COMPLEX_UNIT_SP, font._impl.get_size())
self.native.setTypeface(font._impl.get_typeface(), font._impl.get_style())

def set_color(self, color):
if color:
if color is None:
pass
# TODO: set to system foreground
# self.native.setTextColor(native_color(value))
else:
self.native.setTextColor(native_color(color))

def set_background_color(self, value):
if value is None:
self.native.setBackgroundColor(native_color(TRANSPARENT))
else:
self.native.setBackgroundColor(native_color(value))

def rehint(self):
# Refuse to rehint an Android TextView if it has no LayoutParams yet.
# Calling measure() on an Android TextView w/o LayoutParams raises NullPointerException.
Expand Down
6 changes: 6 additions & 0 deletions android/tests_backend/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ class SimpleProbe:
def __init__(self, widget):
self.widget = widget
self.native = widget._impl.native

# Store the device DPI, as it will be needed to scale some values
self.dpi = (
self.native.getContext().getResources().getDisplayMetrics().densityDpi
)

assert isinstance(self.native, self.native_class)

def assert_container(self, container):
Expand Down
11 changes: 11 additions & 0 deletions android/tests_backend/widgets/button.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
from java import jclass

from toga_android.libs.android import R__attr

from .label import LabelProbe
from .properties import toga_color


# On Android, a Button is just a TextView with a state-dependent background image.
class ButtonProbe(LabelProbe):
native_class = jclass("android.widget.Button")

@property
def background_color(self):
tint_list = self.native.getBackgroundTintList()
if tint_list:
return toga_color(tint_list.getColorForState([R__attr.state_enabled], 0))
else:
return None
8 changes: 6 additions & 2 deletions android/tests_backend/widgets/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from pytest import skip

from .base import SimpleProbe
from .properties import toga_color
from .properties import toga_color, toga_font


class LabelProbe(SimpleProbe):
Expand All @@ -12,13 +12,17 @@ class LabelProbe(SimpleProbe):
def color(self):
return toga_color(self.native.getCurrentTextColor())

@property
def background_color(self):
return toga_color(self.native.getBackgroundColor())

@property
def text(self):
return str(self.native.getText())

@property
def font(self):
skip("Font probe not implemented")
return toga_font(self.native.getTypeface(), self.native.getTextSize(), self.dpi)

@property
def alignment(self):
Expand Down
25 changes: 24 additions & 1 deletion android/tests_backend/widgets/properties.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from java import jint
from travertino.fonts import Font

from android.graphics import Color
from android.graphics import Color, Typeface
from toga.colors import rgba
from toga.fonts import BOLD, ITALIC, MONOSPACE, NORMAL, SANS_SERIF, SERIF, SYSTEM


def toga_color(color_int):
Expand All @@ -13,3 +15,24 @@ def toga_color(color_int):
Color.blue(color_int),
Color.alpha(color_int) / 255,
)


def toga_font(typeface, size, dpi):
# Android provides font details in pixels; that size needs to be converted
# using the ratio between the display DPI and the baseline DPI (160).
size_in_points = size / (dpi * 160)

return Font(
family={
Typeface.DEFAULT: SYSTEM,
Typeface.MONOSPACE: MONOSPACE,
Typeface.SANS_SERIF: SANS_SERIF,
Typeface.SERIF: SERIF,
# : CURSIVE ??
# : FANTASY ??
}.get(typeface, "Unknown"),
size=size_in_points,
style=ITALIC if typeface.isItalic() else NORMAL,
variant=NORMAL,
weight=BOLD if typeface.isBold() else NORMAL,
)
14 changes: 4 additions & 10 deletions iOS/tests_backend/widgets/properties.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from ctypes import byref
from dataclasses import dataclass

from rubicon.objc import CGFloat
from travertino.fonts import Font

from toga.colors import rgba
from toga.fonts import FANTASY, NORMAL, SYSTEM
Expand All @@ -28,22 +28,16 @@ def toga_color(color):
return None


@dataclass
class Font:
family: str
size: int
style: str = NORMAL
variant: str = NORMAL
weight: str = NORMAL


def toga_font(font):
return Font(
family={
".AppleSystemUIFont": SYSTEM,
"Papyrus": FANTASY,
}.get(str(font.familyName), str(font.familyName)),
size=font.pointSize,
style=NORMAL, # TODO: ITALIC if..., SMALL_CAPS if ...
variant=NORMAL,
weight=NORMAL, # TODO: BOLD if ...
)


Expand Down
4 changes: 2 additions & 2 deletions testbed/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ requires = [
"../core",
]
test_requires = [
"coverage==7.0.5",
"coverage==7.2.0",
"pytest==7.2.0",
"pytest-asyncio==0.20.3",
]
Expand Down Expand Up @@ -88,7 +88,7 @@ test_sources = [
"../android/tests_backend",
]
requires = [
"../android"
"../android",
]
# Coverage requires access to individual .py files.
build_gradle_extra_content = "android.defaultConfig.python.extractPackages 'toga_android'"
Expand Down
11 changes: 0 additions & 11 deletions testbed/tests/widgets/properties.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from pytest import mark

from toga.colors import RED, TRANSPARENT, color as named_color
from toga.fonts import FANTASY
from toga.platform import current_platform

from ..assertions import assert_color
from ..data import COLORS, TEXTS
Expand All @@ -18,10 +15,6 @@ async def test_text(widget, probe):
assert probe.text == text


@mark.skipif(
current_platform in {"android"},
reason="text width resizes don't work",
)
async def test_text_width_change(widget, probe):
"If the widget text is changed, the width of the widget changes"
orig_width = probe.width
Expand Down Expand Up @@ -76,10 +69,6 @@ async def test_color(widget, probe):
assert_color(probe.color, color)


@mark.skipif(
current_platform in {"android"},
reason="color resets don't work",
)
async def test_color_reset(widget, probe):
"The foreground color of a widget can be reset"
# Get the original color
Expand Down

0 comments on commit fe92bb9

Please sign in to comment.