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
64 changes: 23 additions & 41 deletions core/src/toga/widgets/detailedlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,21 @@ def __init__(
):
"""Create a new DetailedList widget.

Inherits from :class:`toga.Widget`.

:param id: The ID for the widget.
:param style: A style object. If no style is provided, a default style will be
applied to the widget.
:param data: The data to be displayed on the table. Can be a list of values or a
ListSource. See the definition of the :attr:`data` property for details on
how data can be specified and used.
:param accessors: The accessors to use to retrieve the data for each item. A tuple,
specifying the accessors for (title, subtitle, icon).
:param missing_value: The data to use subtitle to use when the data source doesn't provide a
title for a data item.
:param data: Initial :any:`data` to be displayed in the list.
:param accessors: The accessors to use to retrieve the data for each item, in
the form (title, subtitle, icon).
:param missing_value: The text that will be shown when a row doesn't provide a
value for its title or subtitle.
:param on_select: Initial :any:`on_select` handler.
:param primary_action: The name for the primary action.
:param on_primary_action: Initial :any:`on_primary_action` handler.
:param secondary_action: The name for the primary action.
:param secondary_action: The name for the secondary action.
:param on_secondary_action: Initial :any:`on_secondary_action` handler.
:param on_refresh: Initial :any:`on_refresh` handler.
:param on_delete: **DEPRECATED**; use :attr:`on_activate`.
:param on_delete: **DEPRECATED**; use ``on_primary_action``.
"""
super().__init__(id=id, style=style)

Expand Down Expand Up @@ -84,7 +80,7 @@ def __init__(
@property
def enabled(self) -> bool:
"""Is the widget currently enabled? i.e., can the user interact with the widget?
DetailList widgets cannot be disabled; this property will always return True; any
DetailedList widgets cannot be disabled; this property will always return True; any
attempt to modify it will be ignored.
"""
return True
Expand All @@ -99,29 +95,17 @@ def focus(self):

@property
def data(self) -> ListSource:
"""The data to display in the DetailedList, as a ListSource.
"""The data to display in the table.

When specifying data:
When setting this property:

* A ListSource will be used as-is
* A :any:`Source` will be used as-is. It must either be a :any:`ListSource`, or
a custom class that provides the same methods.

* A value of None is turned into an empty ListSource.

* A list or tuple of values will be converted into a ListSource. Each item in
the list will be converted into a Row object.

* If the item in the list is a dictionary, the keys of the dictionary will
become the attributes of the Row.

* All other values will be converted into a Row with attributes matching the
``accessors`` provided at time of construction (with the default accessors
of ``("title", "subtitle", "icon")``.

If the value is a string, or any other a non-iterable object, the Row will
have a single attribute matching the title's accessor.

If the value is a list, tuple, or any other iterable, values in the iterable
will be mapped in order to the accessors.
* Otherwise, the value must be an iterable, which is copied into a new
ListSource. Items are converted as shown :ref:`here <listsource-item>`.
"""
return self._data

Expand Down Expand Up @@ -159,13 +143,13 @@ def scroll_to_bottom(self):

@property
def accessors(self) -> list[str]:
"""The accessors used to populate the table"""
"""The accessors used to populate the list (read-only)"""
return self._accessors

@property
def missing_value(self) -> str:
"""The value that will be used when a data row doesn't provide an value for an
attribute.
"""The text that will be shown when a row doesn't provide a value for its
title or subtitle.
"""
return self._missing_value

Expand All @@ -185,9 +169,8 @@ def on_primary_action(self) -> callable:
"""The handler to invoke when the user performs the primary action on a row of
the DetailedList.

The primary action is "swipe left" on UIs that support swipe interactions;
platforms that don't use swipe interactions may manifest this action in other
ways (e.g, a context menu).
The primary action is "swipe left" on platforms that use swipe interactions;
other platforms may manifest this action in other ways (e.g, a context menu).

If no ``on_primary_action`` handler is provided, the primary action will be
disabled in the UI.
Expand All @@ -204,9 +187,8 @@ def on_secondary_action(self) -> callable:
"""The handler to invoke when the user performs the secondary action on a row of
the DetailedList.

The secondary action is "swipe right" on UIs that support swipe interactions;
platforms that don't use swipe interactions may manifest this action in other
ways (e.g, a context menu).
The secondary action is "swipe right" on platforms that use swipe interactions;
other platforms may manifest this action in other ways (e.g, a context menu).

If no ``on_secondary_action`` handler is provided, the secondary action will be
disabled in the UI.
Expand All @@ -221,7 +203,7 @@ def on_secondary_action(self, handler: callable):
@property
def on_refresh(self) -> callable:
"""The callback function to invoke when the user performs a refresh action
(usually "pull down to refresh") on the DetailedList.
(usually "pull down") on the DetailedList.

If no ``on_refresh`` handler is provided, the refresh UI action will be
disabled.
Expand Down Expand Up @@ -250,7 +232,7 @@ def on_select(self, handler: callable):

@property
def on_delete(self):
"""**DEPRECATED**: Use ``on_primary_action``"""
"""**DEPRECATED**; Use :any:`on_primary_action`"""
warnings.warn(
"DetailedList.on_delete has been renamed DetailedList.on_primary_action.",
DeprecationWarning,
Expand Down
37 changes: 15 additions & 22 deletions docs/reference/api/widgets/detailedlist.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
DetailedList
============

An ordered list of content where each item has an icon, a main heading, and a line of
supplementary text.
An ordered list where each item has an icon, a title, and a line of text. Scroll bars
will be provided if necessary.

.. figure:: /reference/images/DetailedList.png
:width: 300px
Expand All @@ -18,12 +18,7 @@ supplementary text.
Usage
-----

A DetailedList uses a :class:`~toga.sources.ListSource` to manage the data being
displayed. options. If ``data`` is not specified as a ListSource, it will be converted
into a ListSource at runtime. Each item in the data source is required to provide 3
values - an icon, a title, and a subtitle.

The simplest instantiation of a DetailedList is to use a list of dictionaries, with
The simplest way to create a DetailedList is to pass a list of dictionaries, with
each dictionary containing three keys: ``icon``, ``title``, and ``subtitle``:

.. code-block:: python
Expand All @@ -50,9 +45,9 @@ each dictionary containing three keys: ``icon``, ``title``, and ``subtitle``:
]
)

If you want to customize the data keys used to provide data, you can do this by
If you want to customize the keys used in the dictionary, you can do this by
providing an ``accessors`` argument to the DetailedList when it is constructed.
``accessors`` is a tuple, containing the attribute that will be used to provide the
``accessors`` is a tuple containing the attributes that will be used to provide the
icon, title, and subtitle, respectively:

.. code-block:: python
Expand Down Expand Up @@ -80,17 +75,17 @@ icon, title, and subtitle, respectively:
]
)

If the value provided by the accessor for title or subtitle is :any:`None`, or the
accessor isn't defined, the value of ``missing_value`` provided when constructing the
DetailedList will be used to populate the title and subtitle. Any other value will be
If the value provided by the accessor for ``title`` or ``subtitle`` is :any:`None`, or
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
the accessor isn't defined, the ``missing_value`` will be used. Any other value will be
converted into a string.

If the value provided by the accessor for icon is :any:`None`, or the accessor isn't
defined, a no icon will be displayed, but space for the icon will remain the the layout.
If the value provided by the accessor for ``icon`` is :any:`None`, or the accessor isn't
defined, then no icon will be displayed, but space for the icon will remain in the
layout.

Items in a DetailedList can respond to a primary and secondary action. On platforms that
support swipe interactions, the primary action will be associated with "swipe left"; the
secondary action will be associated with "swipe right". However, a platform may
use swipe interactions, the primary action will be associated with "swipe left", and the
secondary action will be associated with "swipe right". Other platforms may
implement the primary and secondary actions using a different UI interaction (e.g., a
right-click context menu). The primary and secondary actions will only be enabled in
the DetailedList UI if a handler has been provided.
Expand All @@ -103,11 +98,9 @@ deletion as part of the UI interaction. It is the responsibility of the applicat
implement any data deletion behavior as part of the ``on_primary_action`` handler.

The DetailedList as a whole can also respond to a refresh UI action. This is usually
implemented as a "pull down to refresh" action, such as you might see on a social media
timeline. If a DetailedList widget provides an ``on_refresh`` handler, the DetailedList
will respond to the refresh UI action, and the ``on_refresh`` handler will be invoked.
If no ``on_refresh`` handler is provided, the DetailedList will behave as a static list,
and will *not* respond to the refresh UI action.
implemented as a "pull down" action, such as you might see on a social media timeline.
This action will only be enabled in the UI if an ``on_refresh`` handler has been
provided.

Notes
-----
Expand Down
6 changes: 3 additions & 3 deletions testbed/tests/testbed.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ def get_terminal_size(*args, **kwargs):
except ValueError:
run_slow = False

# If `--coverage` is in the arguments, run the test suite in slow mode
# If `--coverage` is in the arguments, display a coverage report
try:
args.remove("--coverage")
report_coverage = True
except ValueError:
report_coverage = False

# If there are no other specified arguments, default to running the whole suite.
# Only enforce coverage if we're running the full suite.
# If there are no other specified arguments, default to running the whole suite,
# and reporting coverage.
if len(args) == 0:
args = ["tests"]
report_coverage = True
Expand Down
Loading