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

[widget Audit] toga.DetailedList #2025

Merged
merged 33 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8a3fbf1
Update docs and core API for DetailedList.
freakboy3742 Jul 4, 2023
796dbb2
Add changenotes.
freakboy3742 Jul 4, 2023
9a4e69f
Update docs index entry.
freakboy3742 Jul 4, 2023
e6e20c7
Update core tests for DetailedList.
freakboy3742 Jul 4, 2023
186aff3
Update examples to use new ListSource APIs.
freakboy3742 Jul 4, 2023
545a280
Deleting attributes is a notifiable change.
freakboy3742 Jul 4, 2023
1f260f5
Modify core API to use primary/secondary actions.
freakboy3742 Jul 5, 2023
6f49004
Cocoa DetailedList at 100%.
freakboy3742 Jul 6, 2023
6ec8eb8
iOS DetailedList to 100% coverage.
freakboy3742 Jul 6, 2023
ced26bb
Silence a test cleanup warning when running iOS tests non-slow.
freakboy3742 Jul 7, 2023
6484af2
More iOS test cleanups.
freakboy3742 Jul 7, 2023
b7fa33d
Clean up GTK DetailedList implementation
freakboy3742 Jul 7, 2023
dea9eaf
GTK DetailedList at 100% coverage.
freakboy3742 Jul 8, 2023
50b07dd
Add the ability to get a coverage report without running the full tes…
freakboy3742 Jul 8, 2023
6597a16
Ensure widgets have been made visible; Fixes #2026.
freakboy3742 Jul 8, 2023
cd02bfd
Merge branch 'audit-tree' into audit-detailedlist
freakboy3742 Jul 8, 2023
b3ac24a
Ensure GTK progressbar gets coverage.
freakboy3742 Jul 9, 2023
3dec76a
Use explicit calls to tableView methods to avoid ambiguous names, and…
freakboy3742 Jul 9, 2023
f92d9f8
Merge branch 'audit-tree' into audit-detailedlist
freakboy3742 Jul 17, 2023
230d3bb
Merge branch 'audit-tree' into audit-detailedlist
freakboy3742 Jul 26, 2023
0fe227b
Merge branch 'audit-tree' into audit-detailedlist
freakboy3742 Jul 26, 2023
12dc04e
Merge branch 'audit-tree' into audit-detailedlist
freakboy3742 Aug 4, 2023
812fe80
Merge branch 'main' into audit-detailedlist
freakboy3742 Aug 29, 2023
52be479
Documentation cleanups
mhsmith Aug 30, 2023
9d0a282
Winforms: support icons in Tables, but in first column only
mhsmith Sep 1, 2023
449a17a
WinForms DetailedList at 100%, but primary, secondary and refresh act…
mhsmith Sep 1, 2023
1dd7fea
In examples/table, make data structure clearer
mhsmith Sep 4, 2023
4d26f01
Remove workarounds for rubicon-java JNI reference issues
mhsmith Sep 6, 2023
b1b57d2
Android DetailedList at 100%
mhsmith Sep 7, 2023
ba31939
Make simulated Android swipes more realistic
mhsmith Sep 9, 2023
2b4ff7a
Rationalize usage of MainActivity.singletonThis
mhsmith Sep 9, 2023
09cb2a5
Move nested classes to module level
mhsmith Sep 9, 2023
4ff988c
Clarify DetailedList accessor docs
mhsmith Sep 9, 2023
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
50 changes: 30 additions & 20 deletions android/tests_backend/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,31 +182,41 @@ def find_dialog(self):
async def press(self):
self.native.performClick()

def motion_event(self, down_time, action, x, y):
event = MotionEvent.obtain(
down_time,
SystemClock.uptimeMillis(), # eventTime
action,
x,
y,
0, # metaState
)
def motion_event(self, down_time, event_time, action, x, y):
event = MotionEvent.obtain(down_time, event_time, action, x, y, 0)
self.native.dispatchTouchEvent(event)
event.recycle()

async def swipe(self, dx, dy):
async def swipe(self, start_x, start_y, end_x, end_y, *, duration=0.3, hold=0.2):
down_time = SystemClock.uptimeMillis()
start_x, start_y = (
self.native.getWidth() / 2,
self.native.getHeight() / 2,
)
end_x, end_y = (
start_x + (dx * self.scale_factor),
start_y + (dy * self.scale_factor),
self.motion_event(
down_time, down_time, MotionEvent.ACTION_DOWN, start_x, start_y
)
self.motion_event(down_time, MotionEvent.ACTION_DOWN, start_x, start_y)
self.motion_event(down_time, MotionEvent.ACTION_MOVE, end_x, end_y)
self.motion_event(down_time, MotionEvent.ACTION_UP, end_x, end_y)

# Convert to milliseconds
duration *= 1000
hold *= 1000
end_time = down_time + duration

dx, dy = end_x - start_x, end_y - start_y
while (time := SystemClock.uptimeMillis()) < end_time:
fraction = (time - down_time) / duration
self.motion_event(
down_time,
time,
MotionEvent.ACTION_MOVE,
start_x + (dx * fraction),
start_y + (dy * fraction),
)
await asyncio.sleep(0.02)

# Hold at the end of the swipe to prevent it becoming a "fling"
end_time += hold
while (time := SystemClock.uptimeMillis()) < end_time:
self.motion_event(down_time, time, MotionEvent.ACTION_MOVE, end_x, end_y)
await asyncio.sleep(0.02)

self.motion_event(down_time, time, MotionEvent.ACTION_UP, end_x, end_y)

@property
def is_hidden(self):
Expand Down
17 changes: 12 additions & 5 deletions android/tests_backend/widgets/detailedlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,18 @@ def refresh_available(self):
return self.scroll_position <= 0

async def non_refresh_action(self):
await self.swipe(0, 100)
await asyncio.sleep(0.5) # Handler isn't called until animation completes.
await self._swipe_down(80)

async def refresh_action(self, active=True):
await self.swipe(0, 300)
await self._swipe_down(180)

# The minimum distance to trigger a refresh is 128 dp.
async def _swipe_down(self, distance):
x = self.native.getWidth() * 0.5
start_y = self.native.getHeight() * 0.1
end_y = start_y + (distance * self.scale_factor)

await self.swipe(x, start_y, x, end_y)
await asyncio.sleep(0.5) # Handler isn't called until animation completes.

async def perform_primary_action(self, row, active=True):
Expand Down Expand Up @@ -127,8 +134,8 @@ async def _perform_action(self, row, action, active):
timestamp = SystemClock.uptimeMillis()
decor.dispatchKeyEvent(
KeyEvent(
timestamp,
timestamp,
timestamp, # downTime
timestamp, # eventTime
KeyEvent.ACTION_UP,
KeyEvent.KEYCODE_BACK,
0, # repeat
Expand Down
15 changes: 4 additions & 11 deletions android/tests_backend/widgets/scrollcontainer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import asyncio

from android.widget import HorizontalScrollView, RelativeLayout, ScrollView

from .base import SimpleProbe
Expand Down Expand Up @@ -33,14 +31,9 @@ def document_width(self):
return round(self.native_content.getWidth() / self.scale_factor)

async def scroll(self):
await self.swipe(0, -30) # Swipe up
x = self.native.getWidth() * 0.5
height = self.native.getHeight()
await self.swipe(x, height * 0.9, x, height * 0.1)

async def wait_for_scroll_completion(self):
position = self.widget.position
current = None
# Iterate until 2 successive reads of the scroll position,
# 0.05s apart, return the same value
while position != current:
position = current
await asyncio.sleep(0.05)
current = self.widget.position
pass
7 changes: 1 addition & 6 deletions testbed/tests/widgets/test_detailedlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,9 @@ async def test_refresh(widget, probe):
pytest.skip("This backend doesn't support the refresh action")

# Set a refresh handler that simulates a reload altering data.
async def add_row(event_widget, **kwargs):
def add_row(event_widget, **kwargs):
assert event_widget == widget
assert kwargs == {}

# Simulate a reload delay
await probe.redraw("Wait for simulated reload")
Copy link
Member

Choose a reason for hiding this comment

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

This made the test unreliable in --slow mode, because the handler and the test function are running in separate asyncio tasks and there's no guarantee of which one will finish awaiting first.


# Add new data as part of the reload.
widget.data.insert(0, {"a": "NEW A", "b": "NEW B"})

widget.on_refresh = add_row
Expand Down