working condition

This commit is contained in:
Yura 2024-09-15 20:57:02 +03:00
parent 417e54da96
commit 511e0b0379
517 changed files with 29187 additions and 32696 deletions

View File

@ -1,13 +1,13 @@
[app]
# (str) Title of your application
title = My Application
title = Uptime Check
# (str) Package name
package.name = myapp
package.name = uptimecheck
# (str) Package domain (needed for android/ios packaging)
package.domain = org.test
package.domain = local.meko
# (str) Source code where the main.py live
source.dir = .
@ -37,7 +37,7 @@ version = 0.1
# (list) Application requirements
# comma separated e.g. requirements = sqlite3,kivy
requirements = python3,kivy
requirements = python3,kivy,requests
# (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes

View File

@ -0,0 +1,7 @@
Copyright 2020 Nattōsai Mitō
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,57 @@
Metadata-Version: 2.1
Name: asyncgui
Version: 0.6.3
Summary: A thin layer that helps to wrap a callback-style API in an async/await-style API
Home-page: https://github.com/gottadiveintopython/asyncgui
License: MIT
Keywords: async
Author: Nattōsai Mitō
Author-email: flow4re2c@gmail.com
Requires-Python: >=3.8.1,<4.0.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: Software Development :: Libraries
Requires-Dist: exceptiongroup (>=1.0.4,<2.0.0) ; python_version < "3.11"
Project-URL: Repository, https://github.com/gottadiveintopython/asyncgui
Description-Content-Type: text/markdown
# AsyncGui
A thin layer that helps to wrap a callback-style API in an async/await-style API.
An async library that focuses on fast reaction.
[Documentation](https://asyncgui.github.io/asyncgui/)
## Installation
Pin the minor version.
```text
poetry add asyncgui@~0.6
pip install "asyncgui>=0.6,<0.7"
```
## Tested on
- CPython 3.8
- CPython 3.9
- CPython 3.10
- CPython 3.11
- CPython 3.12 (3.12.1 or later)
## Async libraries that rely on this
- [asynckivy](https://github.com/asyncgui/asynckivy)
- [asynctkinter](https://github.com/asyncgui/asynctkinter)
- [asyncpygame](https://github.com/asyncgui/asyncpygame)

View File

@ -0,0 +1,7 @@
__pycache__/asyncgui.cpython-311.pyc,,
asyncgui-0.6.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
asyncgui-0.6.3.dist-info/LICENSE,sha256=zdEfMrLu9-uJk1Y-D7fn_gqgODq71StrNs47LvNE5b0,1055
asyncgui-0.6.3.dist-info/METADATA,sha256=OTiDgXiKJm39p7OP5DZQ6ZtiY6UU2tawUD1QfFIvbFs,1729
asyncgui-0.6.3.dist-info/RECORD,,
asyncgui-0.6.3.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
asyncgui.py,sha256=89sbdDMVyRooyYsy7IqG7cLm8DJVY5U67K1kYQngBGE,27963

View File

@ -0,0 +1,4 @@
Wheel-Version: 1.0
Generator: poetry-core 1.6.1
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -0,0 +1,945 @@
__all__ = (
# core (exceptions)
'ExceptionGroup', 'BaseExceptionGroup', 'InvalidStateError', 'Cancelled',
# core
'Aw_or_Task', 'start', 'Task', 'TaskState', 'disable_cancellation', 'open_cancel_scope', 'CancelScope',
'dummy_task', 'current_task', '_current_task', 'sleep_forever', '_sleep_forever',
# structured concurrency
'wait_all', 'wait_any', 'and_', 'or_', 'wait_all_cm', 'wait_any_cm', 'move_on_when',
'run_as_main', 'run_as_daemon',
'open_nursery', 'Nursery',
# bridge between async-world and sync-world
'AsyncBox', 'AsyncEvent',
# deprecated
'Event', 'run_as_primary', 'run_as_secondary',
)
import types
import typing as T
from inspect import getcoroutinestate, CORO_CREATED, CORO_SUSPENDED, isawaitable
import sys
import itertools
from functools import cached_property, partial
import enum
from contextlib import asynccontextmanager
# -----------------------------------------------------------------------------
# Core
# -----------------------------------------------------------------------------
if sys.version_info < (3, 11):
from exceptiongroup import BaseExceptionGroup, ExceptionGroup
else:
BaseExceptionGroup = BaseExceptionGroup #: :meta private:
ExceptionGroup = ExceptionGroup #: :meta private:
potential_bug_msg = \
r"This may be a bug of this library. Please make a minimal code that reproduces the bug, and open an issue at " \
r"the GitHub repository, then post the code there. (https://github.com/asyncgui/asyncgui)."
class InvalidStateError(Exception):
"""The operation is not allowed in the current state."""
class _Cancelled(BaseException):
@cached_property
def level(self) -> int:
return self.args[0]
Cancelled = (_Cancelled, GeneratorExit, )
'''
Exception class that represents cancellation.
See :ref:`dealing-with-cancellation`.
.. warning::
Actually, this is not an exception class but a tuple of exception classes for now.
But that's an implementation detail, and it might become an actual class in the future;
therefore, your code must be compatible in both cases.
:meta hide-value:
'''
class TaskState(enum.Enum):
'''
Enum class that represents the Task state.
'''
CREATED = enum.auto()
'''
Waiting to start execution.
:meta hide-value:
'''
STARTED = enum.auto()
'''
Currently running or suspended.
:meta hide-value:
'''
CANCELLED = enum.auto()
'''
The execution has been cancelled.
The cause of cancellation can be either :meth:`Task.cancel` or an unhandled exception.
:meta hide-value:
'''
FINISHED = enum.auto()
'''
The execution has been completed.
:meta hide-value:
'''
_next_Task_uid = itertools.count().__next__
class Task:
__slots__ = (
'_uid', '_root_coro', '_state', '_result', '_on_end',
'_exc_caught', '_suppresses_exc',
'_cancel_disabled', '_cancel_depth', '_cancel_level',
)
def __init__(self, aw: T.Awaitable, /):
if not isawaitable(aw):
raise ValueError(str(aw) + " is not awaitable.")
self._uid = _next_Task_uid()
self._cancel_disabled = 0
self._root_coro = self._wrapper(aw)
self._state = TaskState.CREATED
self._on_end = None
self._cancel_depth = 0
self._cancel_level = None
self._exc_caught = None
self._suppresses_exc = False
def __str__(self):
return f'Task(state={self._state.name}, uid={self._uid})'
@property
def uid(self) -> int:
'''
An unique integer assigned to the task.
This exists solely for inspection purposes.
'''
return self._uid
@property
def root_coro(self) -> T.Coroutine:
'''
The starting point of the coroutine chain for the task.
This exists solely for inspection purposes.
'''
return self._root_coro
@property
def state(self) -> TaskState:
'''
The current state of the task.
This exists solely for inspection purposes.
'''
return self._state
@property
def finished(self) -> bool:
'''Whether the task has been completed.'''
return self._state is TaskState.FINISHED
@property
def cancelled(self) -> bool:
'''Whether the task has been cancelled.'''
return self._state is TaskState.CANCELLED
@property
def result(self) -> T.Any:
'''Result of the task. If the task is not finished, :exc:`InvalidStateError` will be raised. '''
state = self._state
if state is TaskState.FINISHED:
return self._result
elif state is TaskState.CANCELLED:
raise InvalidStateError(f"{self} was cancelled")
else:
raise InvalidStateError(f"Result of {self} is not ready")
async def _wrapper(self, aw, /):
try:
self._state = TaskState.STARTED
self._result = await aw
except _Cancelled as e:
self._state = TaskState.CANCELLED
assert e.level == 0, potential_bug_msg
assert self._cancel_level == 0, potential_bug_msg
except Exception as e:
self._state = TaskState.CANCELLED
self._exc_caught = e
if not self._suppresses_exc:
raise
except: # noqa: E722
self._state = TaskState.CANCELLED
raise
else:
self._state = TaskState.FINISHED
finally:
assert self._cancel_depth == 0, potential_bug_msg
if (on_end := self._on_end) is not None:
on_end(self)
def cancel(self, _level=0, /):
'''Cancel the task as soon as possible.'''
if self._cancel_level is None:
self._cancel_level = _level
state = getcoroutinestate(self._root_coro)
if state is CORO_SUSPENDED:
if not self._cancel_disabled:
self._actual_cancel()
elif state is CORO_CREATED:
self._root_coro.close()
self._state = TaskState.CANCELLED
else:
self._cancel_level = min(self._cancel_level, _level)
def _actual_cancel(self):
try:
self._root_coro.throw(_Cancelled(self._cancel_level))(self)
except StopIteration:
pass
else:
self._cancel_if_needed()
close = cancel
'''An alias for :meth:`cancel`.'''
@property
def _cancel_requested(self) -> bool:
return self._cancel_level is not None
@property
def _is_cancellable(self) -> bool:
'''Whether the task can be cancelled immediately.'''
return (not self._cancel_disabled) and getcoroutinestate(self._root_coro) is CORO_SUSPENDED
def _cancel_if_needed(self, getcoroutinestate=getcoroutinestate, CORO_SUSPENDED=CORO_SUSPENDED):
if (self._cancel_level is None) or self._cancel_disabled or \
(getcoroutinestate(self._root_coro) is not CORO_SUSPENDED):
pass
else:
self._actual_cancel()
def _step(self, *args, **kwargs):
coro = self._root_coro
if getcoroutinestate(coro) is not CORO_SUSPENDED:
return
try:
coro.send((args, kwargs, ))(self)
except StopIteration:
pass
else:
self._cancel_if_needed()
def _throw_exc(self, exc):
'''停止中のTaskへ例外を投げる。Taskが停止中ではない場合は :exc:`InvalidStateError` が起こる。'''
coro = self._root_coro
if getcoroutinestate(coro) is not CORO_SUSPENDED:
raise InvalidStateError("Throwing an exception to an unstarted/running/closed task is not allowed.")
try:
coro.throw(exc)(self)
except StopIteration:
pass
else:
self._cancel_if_needed()
Aw_or_Task = T.Union[T.Awaitable, Task]
def start(aw: Aw_or_Task, /) -> Task:
'''*Immediately* start a Task/Awaitable.
If the argument is a :class:`Task`, itself will be returned. If it's an :class:`typing.Awaitable`,
it will be wrapped in a Task, and that Task will be returned.
.. code-block::
async def async_func():
...
task = start(async_func())
'''
if isawaitable(aw):
task = Task(aw)
elif isinstance(aw, Task):
task = aw
if task._state is not TaskState.CREATED:
raise ValueError(f"{task} has already started")
else:
raise ValueError("Argument must be either a Task or an awaitable.")
try:
task._root_coro.send(None)(task)
except StopIteration:
pass
else:
task._cancel_if_needed()
return task
class CancelScope:
'''
An equivalence of :class:`trio.CancelScope`.
You should not directly instantiate this, use :func:`open_cancel_scope`.
'''
__slots__ = ('_task', '_level', 'cancelled_caught', 'cancel_called', )
def __init__(self, task: Task, /):
self._task = task
self.cancelled_caught = False #: Whether the scope caught a corresponding :class:`Cancelled` instance.
self.cancel_called = False #: Whether the :meth:`cancel` has been called.
def __enter__(self) -> 'CancelScope':
t = self._task
t._cancel_depth = self._level = t._cancel_depth + 1
return self
def __exit__(self, exc_type, exc, __):
# LOAD_FAST
task = self._task
level = task._cancel_level
scope_level = self._level
self._task = None
task._cancel_depth -= 1
if level is not None:
if level == scope_level:
task._cancel_level = None
else:
assert level < scope_level, potential_bug_msg
if exc_type is not _Cancelled:
return
level = exc.level
if level == scope_level:
self.cancelled_caught = True
return True
else:
assert level < scope_level, potential_bug_msg
@property
def closed(self) -> bool:
'''
Whether this scope has been closed.
The cause of the closure of the scope can be either an exception occurred or the scope exited gracefully,
'''
return self._task is None
def cancel(self):
'''Cancel the execution inside this scope as soon as possible. '''
if self.cancel_called:
return
self.cancel_called = True
if not self.closed:
self._task.cancel(self._level)
class open_cancel_scope:
'''
Same as :class:`trio.CancelScope` except this one returns an async context manager.
.. code-block::
async with open_cancel_scope() as scope:
...
'''
__slots__ = ('_scope', )
async def __aenter__(self) -> T.Awaitable[CancelScope]:
self._scope = CancelScope(await current_task())
return self._scope.__enter__()
async def __aexit__(self, *args):
return self._scope.__exit__(*args)
def _current_task(task):
return task._step(task)
@types.coroutine
def current_task(_f=_current_task) -> T.Awaitable[Task]:
'''Returns the Task instance corresponding to the caller.
.. code-block::
task = await current_task()
'''
return (yield _f)[0][0]
class disable_cancellation:
'''
Return an async context manager that protects its code-block from cancellation.
.. code-block::
async with disable_cancellation():
await something # <- never gets cancelled
'''
__slots__ = ('_task', )
async def __aenter__(self):
self._task = task = await current_task()
task._cancel_disabled += 1
async def __aexit__(self, *__):
self._task._cancel_disabled -= 1
def _sleep_forever(task):
pass
@types.coroutine
def sleep_forever(_f=_sleep_forever) -> T.Awaitable:
'''
.. code-block::
await sleep_forever()
'''
yield _f
dummy_task = Task(sleep_forever())
'''
An already closed task.
This can be utilized to prevent the need for the common null validation mentioned below.
*Before:*
.. code-block::
:emphasize-lines: 3, 6,7
class MyClass:
def __init__(self):
self._task = None
def restart(self):
if self._task is not None:
self._task.cancel()
self._task = asyncgui.start(self.main())
async def main(self):
...
*After:*
.. code-block::
:emphasize-lines: 3, 6
class MyClass:
def __init__(self):
self._task = asyncgui.dummy_task
def restart(self):
self._task.cancel()
self._task = asyncgui.start(self.main())
async def main(self):
...
'''
dummy_task.cancel()
# -----------------------------------------------------------------------------
# Bridge between async-world and sync-world
# -----------------------------------------------------------------------------
class AsyncEvent:
'''
.. code-block::
async def async_fn(e):
args, kwargs = await e.wait()
assert args == (2, )
assert kwargs == {'crow': 'raven', }
args, kwargs = await e.wait()
assert args == (3, )
assert kwargs == {'toad': 'frog', }
e = AsyncEvent()
e.fire(1, crocodile='alligator')
start(async_fn(e))
e.fire(2, crow='raven')
e.fire(3, toad='frog')
.. warning::
This class is not designed for inter-task synchronization, unlike :class:`asyncio.Event`.
When multiple tasks simultaneously try to wait for the same event to fire, it will raise an exception.
'''
__slots__ = ('_callback', )
def __init__(self):
self._callback = None
def fire(self, *args, **kwargs):
if (f := self._callback) is not None:
f(*args, **kwargs)
@types.coroutine
def wait(self):
if self._callback is not None:
raise InvalidStateError("There's already a task waiting for the event to fire.")
try:
return (yield self._attach_task)
finally:
self._callback = None
def _attach_task(self, task):
self._callback = task._step
class AsyncBox:
'''
.. code-block::
async def async_fn(b1, b2):
args, kwargs = await b1.get()
assert args == (1, )
assert kwargs == {'crow': 'raven', }
args, kwargs = await b2.get()
assert args == (2, )
assert kwargs == {'frog': 'toad', }
args, kwargs = await b1.get()
assert args == (1, )
assert kwargs == {'crow': 'raven', }
b1 = AsyncBox()
b2 = AsyncBox()
b1.put(1, crow='raven')
start(async_fn(b1, b2))
b2.put(2, frog='toad')
.. warning::
This class is not designed for inter-task synchronization, unlike :class:`asyncio.Event`.
When multiple tasks simultaneously try to get an item from the same box, it will raise an exception.
'''
__slots__ = ('_item', '_callback', )
def __init__(self):
self._item = None
self._callback = None
@property
def is_empty(self) -> bool:
'''Whether the box is empty.'''
return self._item is None
def put(self, *args, **kwargs):
'''Put an item into the box if it's empty.'''
if self._item is None:
self.put_or_update(*args, **kwargs)
def update(self, *args, **kwargs):
'''Replace the item in the box if there is one already.'''
if self._item is not None:
self.put_or_update(*args, **kwargs)
def put_or_update(self, *args, **kwargs):
self._item = (args, kwargs, )
if (callback := self._callback) is not None:
callback(*args, **kwargs)
@types.coroutine
def get(self):
'''Get the item from the box if there is one. Otherwise, wait until it's put.'''
if self._callback is not None:
raise InvalidStateError("There's already a task waiting for an item to be put in the box.")
if self._item is None:
try:
return (yield self._attach_task)
finally:
self._callback = None
else:
return self._item
def clear(self):
'''Remove the item from the box if there is one.'''
self._item = None
_attach_task = AsyncEvent._attach_task
class Event:
'''
Similar to :class:`asyncio.Event`.
The differences are:
* :meth:`set` accepts any number of arguments but doesn't use them at all so it can be used as a callback function
in any library.
* :attr:`is_set` is a property not a function.
.. code-block::
e = Event()
any_library.register_callback(e.set)
.. deprecated:: 0.6.2
This class is deprecated, and will be removed before 1.0.0.
Use :class:`asyncgui_ext.synctools.event.Event` instead.
'''
__slots__ = ('_flag', '_waiting_tasks', )
def __init__(self):
self._flag = False
self._waiting_tasks = []
@property
def is_set(self) -> bool:
return self._flag
def set(self, *args, **kwargs):
'''
Set the event.
Unlike asyncio's, all tasks waiting for this event to be set will be resumed *immediately*.
'''
if self._flag:
return
self._flag = True
tasks = self._waiting_tasks
self._waiting_tasks = []
for t in tasks:
if t is not None:
t._step()
def clear(self):
'''Unset the event.'''
self._flag = False
@types.coroutine
def wait(self) -> T.Awaitable:
'''
Wait for the event to be set.
Return *immediately* if it's already set.
'''
if self._flag:
return
try:
tasks = self._waiting_tasks
idx = len(tasks)
yield tasks.append
finally:
tasks[idx] = None
# -----------------------------------------------------------------------------
# Structured concurrency
# -----------------------------------------------------------------------------
class TaskCounter:
'''
(internal)
数値が零になった事を通知する仕組みを持つカウンター
親taskが自分の子task達の終了を待つのに用いる
'''
__slots__ = ('_box', '_n_tasks', )
def __init__(self, initial=0, /):
self._n_tasks = initial
self._box = AsyncBox()
def increase(self):
self._n_tasks += 1
def decrease(self):
n = self._n_tasks - 1
assert n >= 0, potential_bug_msg
self._n_tasks = n
if not n:
self._box.put()
async def to_be_zero(self) -> T.Awaitable:
if self._n_tasks:
box = self._box
box._item = None
await box.get()
def __bool__(self):
return not not self._n_tasks # 'not not' is not a typo
async def _wait_xxx(debug_msg, on_child_end, *aws: T.Iterable[Aw_or_Task]) -> T.Awaitable[T.Sequence[Task]]:
children = tuple(v if isinstance(v, Task) else Task(v) for v in aws)
if not children:
return children
counter = TaskCounter(len(children))
parent = await current_task()
try:
with CancelScope(parent) as scope:
on_child_end = partial(on_child_end, scope, counter)
for c in children:
c._suppresses_exc = True
c._on_end = on_child_end
start(c)
await counter.to_be_zero()
finally:
if counter:
for c in children:
c.cancel()
if counter:
try:
parent._cancel_disabled += 1
await counter.to_be_zero()
finally:
parent._cancel_disabled -= 1
exceptions = tuple(e for c in children if (e := c._exc_caught) is not None)
if exceptions:
raise ExceptionGroup(debug_msg, exceptions)
if (parent._cancel_level is not None) and (not parent._cancel_disabled):
await sleep_forever()
assert False, potential_bug_msg
return children
def _on_child_end__ver_all(scope, counter, child):
counter.decrease()
if child._exc_caught is not None:
scope.cancel()
def _on_child_end__ver_any(scope, counter, child):
counter.decrease()
if child._exc_caught is not None or child.finished:
scope.cancel()
_wait_xxx_type = T.Callable[..., T.Awaitable[T.Sequence[Task]]]
wait_all: _wait_xxx_type = partial(_wait_xxx, "wait_all()", _on_child_end__ver_all)
'''
Run multiple tasks concurrently, and wait for **all** of them to **end**. When any of them raises an exception, the
others will be cancelled, and the exception will be propagated to the caller, like :class:`trio.Nursery`.
.. code-block::
tasks = await wait_all(async_fn1(), async_fn2(), async_fn3())
if tasks[0].finished:
print("The return value of async_fn1() :", tasks[0].result)
'''
wait_any: _wait_xxx_type = partial(_wait_xxx, "wait_any()", _on_child_end__ver_any)
'''
Run multiple tasks concurrently, and wait for **any** of them to **finish**. As soon as that happens, the others will be
cancelled. When any of them raises an exception, the others will be cancelled, and the exception will be propagated to
the caller, like :class:`trio.Nursery`.
.. code-block::
tasks = await wait_any(async_fn1(), async_fn2(), async_fn3())
if tasks[0].finished:
print("The return value of async_fn1() :", tasks[0].result)
'''
@asynccontextmanager
async def _wait_xxx_cm(debug_msg, on_child_end, wait_bg, aw: Aw_or_Task):
counter = TaskCounter(1)
fg_task = await current_task()
bg_task = aw if isinstance(aw, Task) else Task(aw)
exc = None
try:
with CancelScope(fg_task) as scope:
bg_task._on_end = partial(on_child_end, scope, counter)
bg_task._suppresses_exc = True
yield start(bg_task)
if wait_bg:
await counter.to_be_zero()
except Exception as e:
exc = e
finally:
bg_task.cancel()
if counter:
try:
fg_task._cancel_disabled += 1
await counter.to_be_zero()
finally:
fg_task._cancel_disabled -= 1
excs = tuple(
e for e in (exc, bg_task._exc_caught, )
if e is not None
)
if excs:
raise ExceptionGroup(debug_msg, excs)
if (fg_task._cancel_level is not None) and (not fg_task._cancel_disabled):
await sleep_forever()
assert False, potential_bug_msg
_wait_xxx_cm_type = T.Callable[[Aw_or_Task], T.AsyncContextManager[Task]]
wait_all_cm: _wait_xxx_cm_type = partial(_wait_xxx_cm, "wait_all_cm()", _on_child_end__ver_all, True)
'''
The context manager form of :func:`wait_all`.
.. code-block::
async with wait_all_cm(async_fn()) as bg_task:
...
'''
wait_any_cm: _wait_xxx_cm_type = partial(_wait_xxx_cm, "wait_any_cm()", _on_child_end__ver_any, False)
'''
The context manager form of :func:`wait_any`, an equivalence of :func:`trio_util.move_on_when`.
.. code-block::
async with wait_any_cm(async_fn()) as bg_task:
...
'''
run_as_main: _wait_xxx_cm_type = partial(_wait_xxx_cm, "run_as_main()", _on_child_end__ver_any, True)
'''
.. code-block::
async with run_as_main(async_fn()) as task:
...
.. note::
You need to use its older name, ``run_as_primary``, if you are using ``asyncgui`` 0.6.2 or older.
'''
run_as_daemon: _wait_xxx_cm_type = partial(_wait_xxx_cm, "run_as_daemon()", _on_child_end__ver_all, False)
'''
.. code-block::
async with run_as_daemon(async_fn()) as bg_task:
...
'''
class Nursery:
'''
Similar to :class:`trio.Nursery`.
You should not directly instantiate this, use :func:`open_nursery`.
'''
__slots__ = ('_closed', '_children', '_scope', '_counters', '_callbacks', '_gc_in_every', '_n_until_gc', )
def __init__(self, scope, counter, daemon_counter, gc_in_every):
self._gc_in_every = self._n_until_gc = gc_in_every
self._closed = False
self._children = []
self._scope = scope
self._counters = (daemon_counter, counter, )
self._callbacks = (
partial(_on_child_end__ver_all, scope, daemon_counter),
partial(_on_child_end__ver_all, scope, counter),
)
def start(self, aw: Aw_or_Task, /, *, daemon=False) -> Task:
'''
*Immediately* start a Task/Awaitable under the supervision of the nursery.
If the argument is a :class:`Task`, itself will be returned. If it's an :class:`typing.Awaitable`,
it will be wrapped in a Task, and that Task will be returned.
The ``daemon`` parameter acts like the one in the :mod:`threading` module.
When only daemon tasks are left, they get cancelled, and the nursery closes.
'''
if self._closed:
raise InvalidStateError("Nursery has been already closed")
if not self._n_until_gc:
self._collect_garbage()
self._n_until_gc = self._gc_in_every
self._n_until_gc -= 1
child = aw if isinstance(aw, Task) else Task(aw)
child._suppresses_exc = True
child._on_end = self._callbacks[not daemon]
self._counters[not daemon].increase()
self._children.append(child)
return start(child)
def _collect_garbage(self, STARTED=TaskState.STARTED):
self._children = [
c for c in self._children
if c.state is STARTED or c._exc_caught is not None
]
def close(self):
'''Cancel all the child tasks in the nursery as soon as possible. '''
self._closed = True
self._scope.cancel()
@property
def closed(self) -> bool:
return self._closed
@asynccontextmanager
async def open_nursery(*, _gc_in_every=1000) -> T.AsyncIterator[Nursery]:
'''
Similar to :func:`trio.open_nursery`.
.. code-block::
async with open_nursery() as nursery:
nursery.start(async_fn1())
nursery.start(async_fn2(), daemon=True)
'''
exc = None
parent = await current_task()
counter = TaskCounter()
daemon_counter = TaskCounter()
try:
with CancelScope(parent) as scope:
nursery = Nursery(scope, counter, daemon_counter, _gc_in_every)
yield nursery
await counter.to_be_zero()
except Exception as e:
exc = e
finally:
nursery._closed = True
children = nursery._children
for c in children:
c.cancel()
try:
parent._cancel_disabled += 1
await daemon_counter.to_be_zero()
await counter.to_be_zero()
finally:
parent._cancel_disabled -= 1
excs = tuple(
e for e in itertools.chain((exc, ), (c._exc_caught for c in children))
if e is not None
)
if excs:
raise ExceptionGroup("Nursery", excs)
if (parent._cancel_level is not None) and (not parent._cancel_disabled):
await sleep_forever()
assert False, potential_bug_msg
# -----------------------------------------------------------------------------
# Aliases
# -----------------------------------------------------------------------------
run_as_primary = run_as_main
run_as_secondary = run_as_daemon
and_ = wait_all #: An alias for :func:`wait_all`.
or_ = wait_any #: An alias for :func:`wait_any`.
move_on_when = wait_any_cm #: An alias for :func:`wait_any_cm`.

View File

@ -0,0 +1,7 @@
Copyright 2019 gottadiveintopython
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,177 @@
Metadata-Version: 2.1
Name: asynckivy
Version: 0.6.4
Summary: Async library for Kivy
Home-page: https://github.com/asyncgui/asynckivy
License: MIT
Keywords: async,kivy
Author: Nattōsai Mitō
Author-email: flow4re2c@gmail.com
Requires-Python: >=3.9,<4.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Requires-Dist: asyncgui (>=0.6,<0.7)
Project-URL: Repository, https://github.com/asyncgui/asynckivy
Description-Content-Type: text/markdown
# AsyncKivy
[Youtube](https://www.youtube.com/playlist?list=PLNdhqAjzeEGjTpmvNck4Uykps8s9LmRTJ)
[日本語doc](README_jp.md)
`asynckivy` is an async library that saves you from ugly callback-style code,
like most of async libraries do.
Let's say you want to do:
1. `print('A')`
1. wait for 1sec
1. `print('B')`
1. wait for a button to be pressed
1. `print('C')`
in that order.
Your code would look like this:
```python
from kivy.clock import Clock
def what_you_want_to_do(button):
print('A')
def one_sec_later(__):
print('B')
button.bind(on_press=on_button_press)
Clock.schedule_once(one_sec_later, 1)
def on_button_press(button):
button.unbind(on_press=on_button_press)
print('C')
what_you_want_to_do(...)
```
It's not easy to understand.
If you use `asynckivy`, the code above will become:
```python
import asynckivy as ak
async def what_you_want_to_do(button):
print('A')
await ak.sleep(1)
print('B')
await ak.event(button, 'on_press')
print('C')
ak.start(what_you_want_to_do(...))
```
## Installation
Pin the minor version.
```text
poetry add asynckivy@~0.6
pip install "asynckivy>=0.6,<0.7"
```
## Usage
```python
import asynckivy as ak
async def some_task(button):
# waits for 2 seconds to elapse
dt = await ak.sleep(2)
print(f'{dt} seconds have elapsed')
# waits for a button to be pressed
await ak.event(button, 'on_press')
# waits for the value of 'button.x' to change
__, x = await ak.event(button, 'x')
print(f'button.x is now {x}')
# waits for the value of 'button.x' to become greater than 100
if button.x <= 100:
__, x = await ak.event(button, 'x', filter=lambda __, x: x>100)
print(f'button.x is now {x}')
# waits for either 5 seconds to elapse or a button to be pressed.
# i.e. waits at most 5 seconds for a button to be pressed
tasks = await ak.wait_any(
ak.sleep(5),
ak.event(button, 'on_press'),
)
print("Timeout" if tasks[0].finished else "The button was pressed")
# same as the above
async with ak.move_on_after(5) as bg_task:
await ak.event(button, 'on_press')
print("Timeout" if bg_task.finished else "The button was pressed")
# waits for both 5 seconds to elapse and a button to be pressed.
tasks = await ak.wait_all(
ak.sleep(5),
ak.event(button, 'on_press'),
)
# nest as you want.
# waits for a button to be pressed, and either 5 seconds to elapse or 'other_async_func' to complete.
tasks = await ak.wait_all(
ak.event(button, 'on_press'),
ak.wait_any(
ak.sleep(5),
other_async_func(),
),
)
child_tasks = tasks[1].result
print("5 seconds elapsed" if child_tasks[0].finished else "other_async_func has completed")
ak.start(some_task(some_button))
```
For more details, read the [documentation](https://asyncgui.github.io/asynckivy/).
## Tested on
- CPython 3.8 + Kivy 2.3.0
- CPython 3.9 + Kivy 2.3.0
- CPython 3.10 + Kivy 2.3.0
- CPython 3.11 + Kivy 2.3.0
- CPython 3.12 + Kivy 2.3.0 (3.12.0 is not supported due to [this issue](https://github.com/python/cpython/issues/111058))
## Why this even exists
Kivy supports two legitimate async libraries, [asyncio][asyncio] and [Trio][trio], starting from version 2.0.0, so developing another one seems like [reinventing the wheel][reinventing].
Actually, I started this one just to learn how the async/await syntax works, so it initially was "reinventing the wheel".
But after playing with Trio and Kivy for a while, I noticed that Trio is not suitable for the situation where fast reactions are required e.g. touch events.
The same is true of asyncio.
You can confirm that by running `investigation/why_xxx_is_not_suitable_for_handling_touch_events.py`, and mashing a mouse button as quickly as possible.
You'll see sometimes `up` is not paired with `down`.
You'll see the coordinates aren't relative to the `RelativeLayout` even though the `target` belongs to it.
The cause of those problems is that `trio.Event.set()` and `asyncio.Event.set()` don't *immediately* resume the tasks waiting for the `Event` to be set.
They just schedule the tasks to resume.
Same thing can be said to `nursery.start_soon()` and `asyncio.create_task()`.
Trio and asyncio are async **I/O** libraries after all.
They probably don't have to immediately resumes/starts tasks, which I think necessary for touch handling in Kivy.
(If you fail to handle touches promptly, their state might undergo changes, leaving no time to wait for tasks to resume/start).
Their core design might not be suitable for GUI in the first place.
That's why I'm still developing this `asynckivy` library to this day.
[asyncio]:https://docs.python.org/3/library/asyncio.html
[trio]:https://trio.readthedocs.io/en/stable/
[reinventing]:https://en.wikipedia.org/wiki/Reinventing_the_wheel

View File

@ -0,0 +1,31 @@
asynckivy-0.6.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
asynckivy-0.6.4.dist-info/LICENSE,sha256=2jxtLdIltPBFl7vb9bLmquYKRJiyidCvO_DhOgFWIe8,1059
asynckivy-0.6.4.dist-info/METADATA,sha256=P3n9htW_NrrBuy5BHojYoUgkePfNn2y4h__APrwdK5w,5876
asynckivy-0.6.4.dist-info/RECORD,,
asynckivy-0.6.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
asynckivy/__init__.py,sha256=Ttzd2FLPuQEAPrNINViuIK8Yj4i5swu2wKKkl0vCMoA,1285
asynckivy/__pycache__/__init__.cpython-311.pyc,,
asynckivy/__pycache__/_anim_attrs.cpython-311.pyc,,
asynckivy/__pycache__/_anim_with_xxx.cpython-311.pyc,,
asynckivy/__pycache__/_animation.cpython-311.pyc,,
asynckivy/__pycache__/_event.cpython-311.pyc,,
asynckivy/__pycache__/_exceptions.cpython-311.pyc,,
asynckivy/__pycache__/_interpolate.cpython-311.pyc,,
asynckivy/__pycache__/_n_frames.cpython-311.pyc,,
asynckivy/__pycache__/_sleep.cpython-311.pyc,,
asynckivy/__pycache__/_threading.cpython-311.pyc,,
asynckivy/__pycache__/_touch.cpython-311.pyc,,
asynckivy/__pycache__/_utils.cpython-311.pyc,,
asynckivy/__pycache__/vanim.cpython-311.pyc,,
asynckivy/_anim_attrs.py,sha256=VCWAPMFtwZU4HOdfhcFDR1JIvjMDW-nuaSvn2MAnu3Q,3838
asynckivy/_anim_with_xxx.py,sha256=IzJ-NYCJI9mFgOH1oRtZ0VLcsIY7TNjf88VuaoU9Lo4,3516
asynckivy/_animation.py,sha256=6J2vwvXXJJegLk48nx4KrHYrZM5uZiulE6pTH4n9A4U,3589
asynckivy/_event.py,sha256=_1O6bKZXZKkV5a-i4Qo3pmZHU1jCobf6bwIS9TUJG-U,1711
asynckivy/_exceptions.py,sha256=Pg2qkGaVbF2OgVrfcxqOPobEgvavAPYr4RZRDtvyV-o,764
asynckivy/_interpolate.py,sha256=ojjQhiND4-rkTol5q79R2eblXL-2XhQPQMzWovSkDoU,2252
asynckivy/_n_frames.py,sha256=Rwtc-9nVBGT-IT5dRwQBowAS0ENBEnrzQKxVhPp4qoE,868
asynckivy/_sleep.py,sha256=qiNN_4PUJiz8pxnLqUykHSLcZhSLuLnHnfekTTEKDWQ,3354
asynckivy/_threading.py,sha256=onV5x3H0qfDYzHs3PRIprxlJR3dpSbdZWjjChRXI35E,1621
asynckivy/_touch.py,sha256=C_Z3qoYNVPE-KWYrc56Q4Uj79sLK2V0L_6Pj6ZTdPYU,7669
asynckivy/_utils.py,sha256=qr4__ywCImXrfNdxnxAfn7PLux1KGAwWud_Pzb9ixVo,7705
asynckivy/vanim.py,sha256=-9kRfu3yJsKX8Z4xp8Wm6cOfUxzg54oeohUDV1FKktA,608

View File

@ -0,0 +1,4 @@
Wheel-Version: 1.0
Generator: poetry-core 1.9.0
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -0,0 +1,42 @@
__all__ = (
'MotionEventAlreadyEndedError',
'anim_attrs',
'anim_attrs_abbr',
'anim_with_dt',
'anim_with_dt_et',
'anim_with_dt_et_ratio',
'anim_with_et',
'anim_with_ratio',
'animate',
'create_texture_from_text',
'event',
'fade_transition',
'interpolate',
'move_on_after',
'n_frames',
'repeat_sleeping',
'rest_of_touch_events',
'run_in_executor',
'run_in_thread',
'sleep',
'sleep_free',
'suppress_event',
'sync_attr',
'sync_attrs',
'touch_up_event',
'transform',
'watch_touch',
)
from asyncgui import *
from ._exceptions import MotionEventAlreadyEndedError
from ._sleep import sleep, sleep_free, repeat_sleeping, move_on_after
from ._event import event
from ._anim_with_xxx import anim_with_dt, anim_with_et, anim_with_ratio, anim_with_dt_et, anim_with_dt_et_ratio
from ._animation import animate
from ._anim_attrs import anim_attrs, anim_attrs_abbr
from ._interpolate import interpolate, fade_transition
from ._touch import watch_touch, rest_of_touch_events, rest_of_touch_moves, touch_up_event
from ._threading import run_in_executor, run_in_thread
from ._n_frames import n_frames
from ._utils import transform, suppress_event, create_texture_from_text, sync_attr, sync_attrs

View File

@ -0,0 +1,114 @@
__all__ = ('anim_attrs', 'anim_attrs_abbr', )
import typing as T
import types
from functools import partial
import kivy.clock
from kivy.animation import AnimationTransition
import asyncgui
def _update(setattr, zip, min, obj, duration, transition, output_seq_type, anim_params, task, p_time, dt):
time = p_time[0] + dt
p_time[0] = time
# calculate progression
progress = min(1., time / duration)
t = transition(progress)
# apply progression on obj
for attr_name, org_value, slope, is_seq in anim_params:
if is_seq:
new_value = output_seq_type(
slope_elem * t + org_elem
for org_elem, slope_elem in zip(org_value, slope)
)
setattr(obj, attr_name, new_value)
else:
setattr(obj, attr_name, slope * t + org_value)
# time to stop ?
if progress >= 1.:
task._step()
return False
_update = partial(_update, setattr, zip, min)
@types.coroutine
def _anim_attrs(
obj, duration, step, transition, output_seq_type, animated_properties,
getattr=getattr, isinstance=isinstance, tuple=tuple, str=str, partial=partial, native_seq_types=(tuple, list),
zip=zip, Clock=kivy.clock.Clock, AnimationTransition=AnimationTransition,
_update=_update, _current_task=asyncgui._current_task, _sleep_forever=asyncgui._sleep_forever, /):
if isinstance(transition, str):
transition = getattr(AnimationTransition, transition)
# get current values & calculate slopes
anim_params = tuple(
(
org_value := getattr(obj, attr_name),
is_seq := isinstance(org_value, native_seq_types),
(
org_value := tuple(org_value),
slope := tuple(goal_elem - org_elem for goal_elem, org_elem in zip(goal_value, org_value)),
) if is_seq else (slope := goal_value - org_value),
) and (attr_name, org_value, slope, is_seq, )
for attr_name, goal_value in animated_properties.items()
)
try:
clock_event = Clock.schedule_interval(
partial(_update, obj, duration, transition, output_seq_type, anim_params, (yield _current_task)[0][0],
[0., ]),
step,
)
yield _sleep_forever
finally:
clock_event.cancel()
def anim_attrs(obj, *, duration=1.0, step=0, transition=AnimationTransition.linear, output_seq_type=tuple,
**animated_properties) -> T.Awaitable:
'''
Animates attibutes of any object.
.. code-block::
import types
obj = types.SimpleNamespace(x=0, size=(200, 300))
await anim_attrs(obj, x=100, size=(400, 400))
The ``output_seq_type`` parameter:
.. code-block::
obj = types.SimpleNamespace(size=(200, 300))
await anim_attrs(obj, size=(400, 400), output_seq_type=list)
assert type(obj.size) is list
.. warning::
Unlike :class:`kivy.animation.Animation`, this one does not support dictionary-type and nested-sequence.
.. code-block::
await anim_attrs(obj, pos_hint={'x': 1.}) # not supported
await anim_attrs(obj, nested_sequence=[[10, 20, ]]) # not supported
await anim_attrs(obj, color=(1, 0, 0, 1), pos=(100, 200)) # OK
.. versionadded:: 0.6.1
'''
return _anim_attrs(obj, duration, step, transition, output_seq_type, animated_properties)
def anim_attrs_abbr(obj, *, d=1.0, s=0, t=AnimationTransition.linear, output_seq_type=tuple,
**animated_properties) -> T.Awaitable:
'''
:func:`anim_attrs` cannot animate attributes named ``step``, ``duration`` and ``transition`` but this one can.
.. versionadded:: 0.6.1
'''
return _anim_attrs(obj, d, s, t, output_seq_type, animated_properties)

View File

@ -0,0 +1,146 @@
__all__ = (
'anim_with_dt', 'anim_with_et', 'anim_with_ratio', 'anim_with_dt_et', 'anim_with_dt_et_ratio',
)
from ._sleep import repeat_sleeping
async def anim_with_dt(*, step=0):
'''
An async form of :meth:`kivy.clock.Clock.schedule_interval`. The following callback-style code:
.. code-block::
def callback(dt):
print(dt)
if some_condition:
return False
Clock.schedule_interval(callback, 0.1)
is equivalent to the following async-style code:
.. code-block::
async for dt in anim_with_dt(step=0.1):
print(dt)
if some_condition:
break
.. versionadded:: 0.6.1
'''
async with repeat_sleeping(step=step) as sleep:
while True:
yield await sleep()
async def anim_with_et(*, step=0):
'''
Same as :func:`anim_with_dt` except this one generates the total elapsed time of the loop instead of the elapsed
time between frames.
.. code-block::
timeout = 3.0
async for et in anim_with_et(...):
...
if et > timeout:
break
You can calculate ``et`` by yourself if you want to:
.. code-block::
et = 0.
timeout = 3.0
async for dt in anim_with_dt(...):
et += dt
...
if et > timeout:
break
which should be as performant as the former.
.. versionadded:: 0.6.1
'''
et = 0.
async with repeat_sleeping(step=step) as sleep:
while True:
et += await sleep()
yield et
async def anim_with_dt_et(*, step=0):
'''
:func:`anim_with_dt` and :func:`anim_with_et` combined.
.. code-block::
async for dt, et in anim_with_dt_et(...):
...
.. versionadded:: 0.6.1
'''
et = 0.
async with repeat_sleeping(step=step) as sleep:
while True:
dt = await sleep()
et += dt
yield dt, et
async def anim_with_ratio(*, duration=1., step=0):
'''
Same as :func:`anim_with_et` except this one generates the total progression ratio of the loop.
.. code-block::
async for p in anim_with_ratio(duration=3.0):
print(p * 100, "%")
If you want to progress at a non-consistant rate, :class:`kivy.animation.AnimationTransition` may be helpful.
.. code-block::
from kivy.animation import AnimationTransition
in_cubic = AnimationTransition.in_cubic
async for p in anim_with_ratio(duration=3.0):
p = in_cubic(p)
print(p * 100, "%")
.. versionadded:: 0.6.1
'''
async with repeat_sleeping(step=step) as sleep:
if not duration:
await sleep()
yield 1.0
return
et = 0.
while et < duration:
et += await sleep()
yield et / duration
async def anim_with_dt_et_ratio(*, duration=1., step=0):
'''
:func:`anim_with_dt`, :func:`anim_with_et` and :func:`anim_with_ratio` combined.
.. code-block::
async for dt, et, p in anim_with_dt_et_ratio(...):
...
.. versionadded:: 0.6.1
'''
async with repeat_sleeping(step=step) as sleep:
if not duration:
dt = await sleep()
yield dt, dt, 1.0
return
et = 0.
while et < duration:
dt = await sleep()
et += dt
yield dt, et, et / duration

View File

@ -0,0 +1,115 @@
__all__ = ('animate', )
import typing as T
import types
from functools import partial
from kivy.clock import Clock
from kivy.animation import AnimationTransition
from asyncgui import _sleep_forever, _current_task
@types.coroutine
def animate(obj, *, duration=1.0, step=0, transition=AnimationTransition.linear, **animated_properties) -> T.Awaitable:
'''
Animates attibutes of any object. This is basically an async form of :class:`kivy.animation.Animation`.
.. code-block::
import types
obj = types.SimpleNamespace(x=0, size=(200, 300, ))
await animate(obj, x=100, size=(400, 400))
Kivy has two compound animations, :class:`kivy.animation.Sequence` and :class:`kivy.animation.Parallel`.
You can achieve the same functionality as them in asynckivy as follows:
.. code-block::
import asynckivy as ak
async def sequential_animation(widget):
await ak.animate(widget, x=100)
await ak.animate(widget, x=0)
async def parallel_animation(widget):
await ak.wait_all(
ak.animate(widget, x=100),
ak.animate(widget, y=100, duration=2),
)
.. deprecated:: 0.6.1
This will be removed before version 1.0.0.
Use :func:`asynckivy.anim_attrs` or :func:`asynckivy.anim_attrs_abbr` instead.
'''
if not duration:
for key, value in animated_properties.items():
setattr(obj, key, value)
return
if isinstance(transition, str):
transition = getattr(AnimationTransition, transition)
# get current values
properties = {}
for key, value in animated_properties.items():
original_value = getattr(obj, key)
if isinstance(original_value, (tuple, list)):
original_value = original_value[:]
elif isinstance(original_value, dict):
original_value = original_value.copy()
properties[key] = (original_value, value)
try:
clock_event = Clock.schedule_interval(
partial(_update, obj, duration, transition, properties, (yield _current_task)[0][0], [0., ]),
step,
)
yield _sleep_forever
finally:
clock_event.cancel()
def _calculate(isinstance, list, tuple, dict, range, len, a, b, t):
'''The logic of this function is identical to 'kivy.animation.Animation._calculate()'
'''
if isinstance(a, list) or isinstance(a, tuple):
if isinstance(a, list):
tp = list
else:
tp = tuple
return tp([_calculate(a[x], b[x], t) for x in range(len(a))])
elif isinstance(a, dict):
d = {}
for x in a:
if x not in b:
# User requested to animate only part of the dict.
# Copy the rest
d[x] = a[x]
else:
d[x] = _calculate(a[x], b[x], t)
return d
else:
return (a * (1. - t)) + (b * t)
def _update(setattr, _calculate, obj, duration, transition, properties, task, p_time, dt):
time = p_time[0] + dt
p_time[0] = time
# calculate progression
progress = min(1., time / duration)
t = transition(progress)
# apply progression on obj
for key, values in properties.items():
a, b = values
value = _calculate(a, b, t)
setattr(obj, key, value)
# time to stop ?
if progress >= 1.:
task._step()
return False
_calculate = partial(_calculate, isinstance, list, tuple, dict, range, len)
_update = partial(_update, setattr, _calculate)

View File

@ -0,0 +1,57 @@
__all__ = ('event', )
import typing as T
import types
from functools import partial
from asyncgui import _current_task, _sleep_forever
@types.coroutine
def event(event_dispatcher, event_name, *, filter=None, stop_dispatching=False) -> T.Awaitable[tuple]:
'''
Returns an awaitable that can be used to wait for:
* a Kivy event to occur.
* a Kivy property's value to change.
.. code-block::
# Wait for a button to be pressed.
await event(button, 'on_press')
# Wait for an 'on_touch_down' event to occur.
__, touch = await event(widget, 'on_touch_down')
# Wait for 'widget.x' to change.
__, x = await ak.event(widget, 'x')
The ``filter`` parameter:
.. code-block::
# Wait for an 'on_touch_down' event to occur inside a widget.
__, touch = await event(widget, 'on_touch_down', filter=lambda w, t: w.collide_point(*t.opos))
# Wait for 'widget.x' to become greater than 100.
if widget.x <= 100:
await event(widget, 'x', filter=lambda __, x: x > 100)
The ``stop_dispatching`` parameter:
It only works for events not for properties.
See :ref:`kivys-event-system` for details.
'''
task = (yield _current_task)[0][0]
bind_id = event_dispatcher.fbind(event_name, partial(_callback, filter, task, stop_dispatching))
assert bind_id # check if binding succeeded
try:
return (yield _sleep_forever)[0]
finally:
event_dispatcher.unbind_uid(event_name, bind_id)
def _callback(filter, task, stop_dispatching, *args, **kwargs):
if (filter is None) or filter(*args, **kwargs):
task._step(*args)
return stop_dispatching

View File

@ -0,0 +1,27 @@
__all__ = (
'MotionEventAlreadyEndedError',
)
class MotionEventAlreadyEndedError(Exception):
'''
This error occurs when an already-ended touch is passed to an asynckivy API that expects an ongoing touch.
For instance:
.. code-block::
:emphasize-lines: 4
import asynckivy as ak
class MyWidget(Widget):
def on_touch_up(self, touch): # not 'on_touch_down', oops!
ak.start(self.handle_touch(touch))
return True
async def handle_touch(self, touch):
try:
async for __ in ak.rest_of_touch_events(widget, touch):
...
except ak.MotionEventAlreadyEndedError:
...
'''

View File

@ -0,0 +1,75 @@
__all__ = ('interpolate', 'fade_transition', )
import typing as T
from contextlib import asynccontextmanager
from kivy.animation import AnimationTransition
from ._anim_with_xxx import anim_with_ratio
linear = AnimationTransition.linear
async def interpolate(start, end, *, duration=1.0, step=0, transition=linear) -> T.AsyncIterator:
'''
Interpolates between the values ``start`` and ``end`` in an async-manner.
Inspired by wasabi2d's interpolate_.
.. code-block::
async for v in interpolate(0, 100, duration=1.0, step=.3):
print(int(v))
============ ======
elapsed time output
============ ======
0 sec 0
0.3 sec 30
0.6 sec 60
0.9 sec 90
**1.2 sec** 100
============ ======
.. _interpolate: https://wasabi2d.readthedocs.io/en/stable/coros.html#clock.coro.interpolate
'''
if isinstance(transition, str):
transition = getattr(AnimationTransition, transition)
slope = end - start
yield transition(0.) * slope + start
async for p in anim_with_ratio(step=step, duration=duration):
if p >= 1.0:
break
yield transition(p) * slope + start
yield transition(1.) * slope + start
@asynccontextmanager
async def fade_transition(*widgets, duration=1.0, step=0) -> T.AsyncContextManager:
'''
Returns an async context manager that:
* fades-out the given widgets on ``__aenter__``.
* fades-in the given widgets on ``__aexit__``.
.. code-block::
async with fade_transition(widget1, widget2):
...
The ``widgets`` don't have to be actual Kivy widgets.
Anything that has an attribute named ``opacity`` would work.
'''
half_duration = duration / 2.
org_opas = tuple(w.opacity for w in widgets)
try:
async for p in anim_with_ratio(duration=half_duration, step=step):
p = 1.0 - p
for w, o in zip(widgets, org_opas):
w.opacity = p * o
yield
async for p in anim_with_ratio(duration=half_duration, step=step):
for w, o in zip(widgets, org_opas):
w.opacity = p * o
finally:
for w, o in zip(widgets, org_opas):
w.opacity = o

View File

@ -0,0 +1,43 @@
__all__ = ('n_frames', )
import typing as T
import types
from kivy.clock import Clock
from asyncgui import _current_task, _sleep_forever
@types.coroutine
def n_frames(n: int) -> T.Awaitable:
'''
Waits for a specified number of frames.
.. code-block::
await n_frames(2)
If you want to wait for one frame, :func:`asynckivy.sleep` is preferable for a performance reason.
.. code-block::
await sleep(0)
'''
if n < 0:
raise ValueError(f"Waiting for {n} frames doesn't make sense.")
if not n:
return
task = (yield _current_task)[0][0]
def callback(dt):
nonlocal n
n -= 1
if not n:
task._step()
return False
clock_event = Clock.schedule_interval(callback, 0)
try:
yield _sleep_forever
finally:
clock_event.cancel()

View File

@ -0,0 +1,125 @@
__all__ = ('sleep', 'sleep_free', 'repeat_sleeping', 'move_on_after', )
import typing as T
import types
from kivy.clock import Clock
from asyncgui import _current_task, _sleep_forever, move_on_when, Task, Cancelled
@types.coroutine
def sleep(duration) -> T.Awaitable[float]:
'''
An async form of :meth:`kivy.clock.Clock.schedule_once`.
.. code-block::
dt = await sleep(5) # wait for 5 seconds
'''
task = (yield _current_task)[0][0]
clock_event = Clock.create_trigger(task._step, duration, False, False)
clock_event()
try:
return (yield _sleep_forever)[0][0]
except Cancelled:
clock_event.cancel()
raise
@types.coroutine
def sleep_free(duration) -> T.Awaitable[float]:
'''
An async form of :meth:`kivy.clock.Clock.schedule_once_free`.
.. code-block::
dt = await sleep_free(5) # wait for 5 seconds
'''
task = (yield _current_task)[0][0]
clock_event = Clock.create_trigger_free(task._step, duration, False, False)
clock_event()
try:
return (yield _sleep_forever)[0][0]
except Cancelled:
clock_event.cancel()
raise
class repeat_sleeping:
'''
Returns an async context manager that provides an efficient way to repeat sleeping.
When there is a piece of code like this:
.. code-block::
while True:
await sleep(0)
...
it can be translated to:
.. code-block::
async with repeat_sleeping(step=0) as sleep:
while True:
await sleep()
...
The latter is more suitable for situations requiring frequent sleeps, such as moving an object in every frame.
**Restriction**
You are not allowed to perform any kind of async operations inside the with-block except you can
``await`` the return value of the function that is bound to the identifier of the as-clause.
.. code-block::
async with repeat_sleeping(step=0) as sleep:
await sleep() # OK
await something_else # NOT ALLOWED
async with async_context_manager: # NOT ALLOWED
...
async for __ in async_iterator: # NOT ALLOWED
...
'''
__slots__ = ('_step', '_trigger', )
@types.coroutine
def _sleep(_f=_sleep_forever):
return (yield _f)[0][0]
def __init__(self, *, step=0):
self._step = step
@types.coroutine
def __aenter__(self, _sleep=_sleep) -> T.Awaitable[T.Callable[[], T.Awaitable[float]]]:
task = (yield _current_task)[0][0]
self._trigger = Clock.create_trigger(task._step, self._step, True, False)
self._trigger()
return _sleep
async def __aexit__(self, exc_type, exc_val, exc_tb):
self._trigger.cancel()
def move_on_after(seconds: float) -> T.AsyncContextManager[Task]:
'''
Returns an async context manager that applies a time limit to its code block,
like :func:`trio.move_on_after` does.
.. code-block::
async with move_on_after(seconds) as bg_task:
...
if bg_task.finished:
print("The code block was interrupted due to a timeout")
else:
print("The code block exited gracefully.")
.. versionadded:: 0.6.1
'''
return move_on_when(sleep(seconds))

View File

@ -0,0 +1,64 @@
__all__ = ('run_in_thread', 'run_in_executor', )
import typing as T
from threading import Thread
from concurrent.futures import ThreadPoolExecutor
from kivy.clock import Clock
import asyncgui
def _wrapper(func, ev):
ret = None
exc = None
try:
ret = func()
except Exception as e:
exc = e
finally:
Clock.schedule_once(lambda __: ev.fire(ret, exc))
async def run_in_thread(func, *, daemon=None) -> T.Awaitable:
'''
Creates a new thread, runs a function within it, then waits for the completion of that function.
.. code-block::
return_value = await run_in_thread(func)
See :ref:`io-in-asynckivy` for details.
'''
ev = asyncgui.AsyncEvent()
Thread(
name='asynckivy.run_in_thread',
target=_wrapper, daemon=daemon, args=(func, ev, ),
).start()
ret, exc = (await ev.wait())[0]
if exc is not None:
raise exc
return ret
async def run_in_executor(executor: ThreadPoolExecutor, func) -> T.Awaitable:
'''
Runs a function within a :class:`concurrent.futures.ThreadPoolExecutor`, and waits for the completion of the
function.
.. code-block::
executor = ThreadPoolExecutor()
...
return_value = await run_in_executor(executor, func)
See :ref:`io-in-asynckivy` for details.
'''
ev = asyncgui.AsyncEvent()
future = executor.submit(_wrapper, func, ev)
try:
ret, exc = (await ev.wait())[0]
except asyncgui.Cancelled:
future.cancel()
raise
assert future.done()
if exc is not None:
raise exc
return ret

View File

@ -0,0 +1,196 @@
__all__ = ('watch_touch', 'rest_of_touch_moves', 'rest_of_touch_events', 'touch_up_event', )
import typing as T
import types
from functools import partial
from asyncgui import wait_any, current_task
from ._exceptions import MotionEventAlreadyEndedError
from ._sleep import sleep
from ._event import event
class watch_touch:
'''
Returns an async context manager that provides an easy way to handle touch events.
.. code-block::
async with watch_touch(widget, touch) as in_progress:
while await in_progress():
print('on_touch_move')
print('on_touch_up')
The ``await in_progress()`` waits for either an ``on_touch_move`` event or an ``on_touch_up`` event to occur, and
returns True or False respectively when they occurred.
**Caution**
* You are not allowed to perform any kind of async operations inside the with-block except ``await in_progress()``.
.. code-block::
async with watch_touch(widget, touch) as in_progress:
await in_progress() # OK
await something_else # NOT ALLOWED
async with async_context_manager: # NOT ALLOWED
...
async for __ in async_iterator: # NOT ALLOWED
...
* If the ``widget`` is the type of widget that grabs touches by itself, such as :class:`kivy.uix.button.Button`,
you probably want to set the ``stop_dispatching`` parameter to True in most cases.
* There are widgets/behaviors that can simulate a touch (e.g. :class:`kivy.uix.scrollview.ScrollView`,
:class:`kivy.uix.behaviors.DragBehavior` and ``kivy_garden.draggable.KXDraggableBehavior``).
If many such widgets are in the parent stack of the ``widget``, this API might mistakenly raise a
:exc:`asynckivy.MotionEventAlreadyEndedError`. If that happens, increase the ``timeout`` parameter.
'''
__slots__ = ('_widget', '_touch', '_stop_dispatching', '_timeout', '_uid_up', '_uid_move', '_no_cleanup', )
def __init__(self, widget, touch, *, stop_dispatching=False, timeout=1.):
self._widget = widget
self._touch = touch
self._stop_dispatching = stop_dispatching
self._timeout = timeout
self._no_cleanup = False
def _on_touch_up_sd(step, touch, w, t):
if t is touch:
if t.grab_current is w:
t.ungrab(w)
step(False)
return True
def _on_touch_move_sd(step, touch, w, t):
if t is touch:
if t.grab_current is w:
step(True)
return True
def _on_touch_up(step, touch, w, t):
if t.grab_current is w and t is touch:
t.ungrab(w)
step(False)
return True
def _on_touch_move(step, touch, w, t):
if t.grab_current is w and t is touch:
step(True)
return True
_callbacks = ((_on_touch_up_sd, _on_touch_move_sd, ), (_on_touch_up, _on_touch_move, ), )
del _on_touch_up, _on_touch_move, _on_touch_up_sd, _on_touch_move_sd
@staticmethod
@types.coroutine
def _true_if_touch_move_false_if_touch_up() -> bool:
return (yield lambda step_coro: None)[0][0]
@staticmethod
@types.coroutine
def _always_false() -> bool:
return False
yield # just to make this function a generator function
async def __aenter__(self) -> T.Awaitable[T.Callable[[], T.Awaitable[bool]]]:
touch = self._touch
widget = self._widget
if touch.time_end != -1:
# `on_touch_up` might have been already fired so we need to find out it actually was or not.
tasks = await wait_any(
sleep(self._timeout),
event(widget, 'on_touch_up', filter=lambda w, t: t is touch),
)
if tasks[0].finished:
raise MotionEventAlreadyEndedError(f"MotionEvent(uid={touch.uid}) has already ended")
self._no_cleanup = True
return self._always_false
step = (await current_task())._step
on_touch_up, on_touch_move = self._callbacks[not self._stop_dispatching]
touch.grab(widget)
self._uid_up = widget.fbind('on_touch_up', partial(on_touch_up, step, touch))
self._uid_move = widget.fbind('on_touch_move', partial(on_touch_move, step, touch))
assert self._uid_up
assert self._uid_move
return self._true_if_touch_move_false_if_touch_up
async def __aexit__(self, *args):
if self._no_cleanup:
return
w = self._widget
self._touch.ungrab(w)
w.unbind_uid('on_touch_up', self._uid_up)
w.unbind_uid('on_touch_move', self._uid_move)
async def touch_up_event(widget, touch, *, stop_dispatching=False, timeout=1.) -> T.Awaitable:
'''
*(experimental state)*
Returns an awaitable that can be used to wait for the ``on_touch_up`` event of the given ``touch`` to occur.
.. code-block::
__, touch = await event(widget, 'on_touch_down')
...
await touch_up_event(widget, touch)
You might wonder what the differences are compared to the code below.
.. code-block::
:emphasize-lines: 3
__, touch = await event(widget, 'on_touch_down')
...
await event(widget, 'on_touch_up', filter=lambda w, t: t is touch)
The latter has two problems:
If the ``on_touch_up`` event of the ``touch`` occurred before the highlighted line,
the execution will halt indefinitely at that point.
Even if the event didn't occur before that line, the execution still might halt because
`Kivy does not guarantee`_ that all touch events are delivered to all widgets.
This API takes care of both problems in the same way as :func:`watch_touch`.
If the ``on_touch_up`` event has already occurred, it raises a :exc:`MotionEventAlreadyEndedError` exception.
And it grabs/ungrabs the ``touch`` so that it won't miss any touch events.
Needless to say, if you want to wait for both ``on_touch_move`` and ``on_touch_up`` events at the same time,
use :func:`watch_touch` or :func:`rest_of_touch_events` instead.
.. _Kivy does not guarantee: https://kivy.org/doc/stable/guide/inputs.html#grabbing-touch-events
'''
touch.grab(widget)
try:
awaitable = event(
widget, 'on_touch_up', stop_dispatching=stop_dispatching,
filter=lambda w, t: t.grab_current is w and t is touch,
)
if touch.time_end == -1:
await awaitable
else:
tasks = await wait_any(sleep(timeout), awaitable)
if tasks[0].finished:
raise MotionEventAlreadyEndedError(f"MotionEvent(uid={touch.uid}) has already ended")
finally:
touch.ungrab(widget)
async def rest_of_touch_events(widget, touch, *, stop_dispatching=False, timeout=1.) -> T.AsyncIterator[None]:
'''
Returns an async iterator that iterates the number of times ``on_touch_move`` occurs,
and ends the iteration when ``on_touch_up`` occurs.
.. code-block::
async for __ in rest_of_touch_events(widget, touch):
print('on_touch_move')
print('on_touch_up')
This is a wrapper for :class:`watch_touch`. Although this one, I believe, is more intuitive than
:class:`watch_touch`, it has a couple of disadvantages - see :ref:`the-problem-with-async-generators`.
'''
async with watch_touch(widget, touch, stop_dispatching=stop_dispatching, timeout=timeout) as in_progress:
while await in_progress():
yield
rest_of_touch_moves = rest_of_touch_events

View File

@ -0,0 +1,256 @@
__all__ = ('transform', 'suppress_event', 'create_texture_from_text', 'sync_attr', 'sync_attrs', )
import typing as T
from contextlib import contextmanager
from functools import partial
from kivy.event import EventDispatcher
from kivy.graphics import PushMatrix, PopMatrix, InstructionGroup
from kivy.graphics.texture import Texture
from kivy.core.text import Label as CoreLabel
from kivy.core.text.markup import MarkupLabel as CoreMarkupLabel
@contextmanager
def transform(widget, *, use_outer_canvas=False) -> T.ContextManager[InstructionGroup]:
'''
Returns a context manager that sandwiches the ``widget``'s existing canvas instructions between
a :class:`kivy.graphics.PushMatrix` and a :class:`kivy.graphics.PopMatrix`, and inserts an
:class:`kivy.graphics.InstructionGroup` right next to the ``PushMatrix``. Those three instructions will be removed
when the context manager exits.
This may be useful when you want to animate a widget.
**Usage**
.. code-block::
from kivy.graphics import Rotate
async def rotate_widget(widget, *, angle=360.):
with transform(widget) as ig: # <- InstructionGroup
ig.add(rotate := Rotate(origin=widget.center))
await anim_attrs(rotate, angle=angle)
If the position or size of the ``widget`` changes during the animation, you might need :class:`sync_attr`.
**The use_outer_canvas parameter**
While the context manager is active, the content of the widget's canvas would be:
.. code-block:: yaml
# ... represents existing instructions
Widget:
canvas.before:
...
canvas:
PushMatrix
InstructionGroup
...
PopMatrix
canvas.after:
...
but if ``use_outer_canvas`` is True, it would be:
.. code-block:: yaml
Widget:
canvas.before:
PushMatrix
InstructionGroup
...
canvas:
...
canvas.after:
...
PopMatrix
'''
c = widget.canvas
if use_outer_canvas:
before = c.before
after = c.after
push_mat_idx = 0
ig_idx = 1
else:
c.before # ensure 'canvas.before' exists
# Index starts from 1 because 'canvas.before' is sitting at index 0 and we usually want it to remain first.
# See https://github.com/kivy/kivy/issues/7945 for details.
push_mat_idx = 1
ig_idx = 2
before = after = c
push_mat = PushMatrix()
ig = InstructionGroup()
pop_mat = PopMatrix()
before.insert(push_mat_idx, push_mat)
before.insert(ig_idx, ig)
after.add(pop_mat)
try:
yield ig
finally:
after.remove(pop_mat)
before.remove(ig)
before.remove(push_mat)
class suppress_event:
'''
Returns a context manager that prevents the callback functions (including the default handler) bound to an event
from being called.
.. code-block::
:emphasize-lines: 4
from kivy.uix.button import Button
btn = Button()
btn.bind(on_press=lambda __: print("pressed"))
with suppress_event(btn, 'on_press'):
btn.dispatch('on_press')
The above code prints nothing because the callback function won't be called.
Strictly speaking, this context manager doesn't prevent all callback functions from being called.
It only prevents the callback functions that were bound to an event before the context manager enters.
Thus, the following code prints ``pressed``.
.. code-block::
:emphasize-lines: 5
from kivy.uix.button import Button
btn = Button()
with suppress_event(btn, 'on_press'):
btn.bind(on_press=lambda __: print("pressed"))
btn.dispatch('on_press')
.. warning::
You need to be careful when you suppress an ``on_touch_xxx`` event.
See :ref:`kivys-event-system` for details.
'''
__slots__ = ('_dispatcher', '_name', '_bind_uid', '_filter', )
def __init__(self, event_dispatcher, event_name, *, filter=lambda *args, **kwargs: True):
self._dispatcher = event_dispatcher
self._name = event_name
self._filter = filter
def __enter__(self):
self._bind_uid = self._dispatcher.fbind(self._name, self._filter)
def __exit__(self, *args):
self._dispatcher.unbind_uid(self._name, self._bind_uid)
def create_texture_from_text(*, markup=False, **label_kwargs) -> Texture:
'''
.. code-block::
from kivy.metrics import sp
texture = create_texture_from_text(
text='Hello',
font_size=sp(50),
font_name='Roboto',
color=(1, 0, 0, 1),
)
The keyword arguments are similar to :external:kivy:doc:`api-kivy.uix.label` 's.
'''
core_cls = CoreMarkupLabel if markup else CoreLabel
core = core_cls(**label_kwargs)
core.refresh()
return core.texture
class sync_attr:
'''
Returns a context manager that creates one-directional binding between attributes.
.. code-block::
import types
widget = Widget()
obj = types.SimpleNamespace()
with sync_attr(from_=(widget, 'x'), to_=(obj, 'xx')):
widget.x = 10
assert obj.xx == 10 # synchronized
obj.xx = 20
assert widget.x == 10 # but not the other way around
This can be particularly useful when combined with :func:`transform`.
.. code-block::
from kivy.graphics import Rotate
async def rotate_widget(widget, *, angle=360.):
with transform(widget) as ig:
ig.add(rotate := Rotate(origin=widget.center))
with sync_attr(from_=(widget, 'center'), to_=(rotate, 'origin')):
await anim_attrs(rotate, angle=angle)
.. versionadded:: 0.6.1
'''
__slots__ = ('_from', '_to', '_bind_uid', )
def __init__(self, from_: T.Tuple[EventDispatcher, str], to_: T.Tuple[T.Any, str]):
self._from = from_
self._to = to_
def _sync(setattr, obj, attr_name, event_dispatcher, new_value):
setattr(obj, attr_name, new_value)
def __enter__(self, partial=partial, sync=partial(_sync, setattr)):
self._bind_uid = self._from[0].fbind(self._from[1], partial(sync, *self._to))
def __exit__(self, *args):
self._from[0].unbind_uid(self._from[1], self._bind_uid)
del _sync
class sync_attrs:
'''
When multiple :class:`sync_attr` calls take the same ``from_`` argument, they can be merged into a single
:class:`sync_attrs` call. For instance, the following code:
.. code-block::
with sync_attr((widget, 'x'), (obj1, 'x')), sync_attr((widget, 'x'), (obj2, 'xx')):
...
can be replaced with the following one:
.. code-block::
with sync_attrs((widget, 'x'), (obj1, 'x'), (obj2, 'xx')):
...
.. versionadded:: 0.6.1
'''
__slots__ = ('_from', '_to', '_bind_uid', )
def __init__(self, from_: T.Tuple[EventDispatcher, str], *to_):
self._from = from_
self._to = to_
def _sync(setattr, to_, event_dispatcher, new_value):
for obj, attr_name in to_:
setattr(obj, attr_name, new_value)
def __enter__(self, partial=partial, sync=partial(_sync, setattr)):
self._bind_uid = self._from[0].fbind(self._from[1], partial(sync, self._to))
def __exit__(self, *args):
self._from[0].unbind_uid(self._from[1], self._bind_uid)
del _sync

View File

@ -0,0 +1,20 @@
__all__ = (
'dt', 'delta_time',
'et', 'elapsed_time',
'dt_et', 'delta_time_elapsed_time',
'progress',
'dt_et_progress', 'delta_time_elapsed_time_progress',
)
import warnings
from . import _anim_with_xxx
warnings.warn("The 'vanim' module is deprecated. Use 'asynckivy.anim_with_xxx' instead.")
delta_time = dt = _anim_with_xxx.anim_with_dt
elapsed_time = et = _anim_with_xxx.anim_with_et
progress = _anim_with_xxx.anim_with_ratio
delta_time_elapsed_time = dt_et = _anim_with_xxx.anim_with_dt_et
delta_time_elapsed_time_progress = dt_et_progress = _anim_with_xxx.anim_with_dt_et_ratio

View File

@ -1,394 +0,0 @@
../../../bin/kivymd.add_view,sha256=u2N52U9NKr85se5a66gdG5Old498YxKwDezJ-cwIZAY,266
../../../bin/kivymd.create_project,sha256=6LnjVohJ7V3MZYfVCtWqtyHHaku6Io-y0pN1BFPmDAM,272
../../../bin/kivymd.make_release,sha256=hKmHIsjNRMSeSS3A2PNqeer_kEliqi6NhzI9bmLc0Zo,269
kivymd-1.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
kivymd-1.2.0.dist-info/LICENSE,sha256=bWmhpIowwWDSSAQwBDm2S0_cUBhZc2yzQ0DwcT9-TrY,1691
kivymd-1.2.0.dist-info/METADATA,sha256=GNIP7_ZragUNLOP6JBXj04nv3clgw33m1MlflQ8a9g4,15020
kivymd-1.2.0.dist-info/RECORD,,
kivymd-1.2.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd-1.2.0.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
kivymd-1.2.0.dist-info/entry_points.txt,sha256=1-yhsSzIhBNRiKNTmevRDT02q8qzg3upZcWAyrr880w,342
kivymd-1.2.0.dist-info/top_level.txt,sha256=ABq82F4nFM8sy3xAhxiO5XXT_lAen0YqiDD29qRiPhc,7
kivymd/__init__.py,sha256=Lk1_FB7hhUcfOVc2hAVZdmpJa9RStEhpKf3Gx-Nm1C8,2158
kivymd/__pycache__/__init__.cpython-311.pyc,,
kivymd/__pycache__/_version.cpython-311.pyc,,
kivymd/__pycache__/app.cpython-311.pyc,,
kivymd/__pycache__/color_definitions.cpython-311.pyc,,
kivymd/__pycache__/factory_registers.cpython-311.pyc,,
kivymd/__pycache__/font_definitions.cpython-311.pyc,,
kivymd/__pycache__/icon_definitions.cpython-311.pyc,,
kivymd/__pycache__/material_resources.cpython-311.pyc,,
kivymd/__pycache__/theming.cpython-311.pyc,,
kivymd/__pycache__/theming_dynamic_text.cpython-311.pyc,,
kivymd/_version.py,sha256=KnOtqZaS5l4zlFEKhhqjLzpQaqc4Kmdc5stnQiKUDYs,140
kivymd/app.py,sha256=M1rwjNfNURnCdhVB_Rk7Hz5cljpwJxN8T6UhKkR4qaI,4222
kivymd/color_definitions.py,sha256=vkOEWwRem3-Vh4dOIyJdSPrg88kyLaD6QZtpx7ecuV0,21550
kivymd/effects/__init__.py,sha256=ySU96kLlmPF4QB-hDa0WM_Y0Odq1MPSR568yI_hiaqI,24
kivymd/effects/__pycache__/__init__.cpython-311.pyc,,
kivymd/effects/fadingedge/__init__.py,sha256=ED7rP0TF96RxwjtLhj3KdAfqo7-YQuA4B10jnWuuMEg,41
kivymd/effects/fadingedge/__pycache__/__init__.cpython-311.pyc,,
kivymd/effects/fadingedge/__pycache__/fadingedge.cpython-311.pyc,,
kivymd/effects/fadingedge/fadingedge.py,sha256=ZM3JRhQ7kvNuj8Z52VUq6MLF2sh7BEoa4_5oc7-mvcg,6054
kivymd/effects/roulettescroll/__init__.py,sha256=Ep2YTxf03Y_A2GbosQIsm8AFsuOeE-w5VPL_NxckTbY,49
kivymd/effects/roulettescroll/__pycache__/__init__.cpython-311.pyc,,
kivymd/effects/roulettescroll/__pycache__/roulettescroll.cpython-311.pyc,,
kivymd/effects/roulettescroll/roulettescroll.py,sha256=b4pJtyKDUqRzSGW4iIZpgUWV91QlRxgUXaPreBUVVEI,8092
kivymd/effects/stiffscroll/__init__.py,sha256=tkGDtFz6s7W3iFtHRDo6NYWadL85cn7GXKAQQfpiJRk,43
kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc,,
kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc,,
kivymd/effects/stiffscroll/stiffscroll.py,sha256=3bSj43xOzhBcBSn58iLUiaNWevlHuO8seklAyfvZsJE,7117
kivymd/factory_registers.py,sha256=0wC2kYMlYCNdShEzETUWEyLsESwwDgnGrgsvVL3t7-M,6431
kivymd/font_definitions.py,sha256=2-4eWkHy4GUT_HhIr5GSEK7CUd71th6Mvi3QAPibkTA,1628
kivymd/fonts/Roboto-Black.ttf,sha256=OHLps5dgobWaweGSYz27O1jllbTUI5MKx97VJemuJeA,171480
kivymd/fonts/Roboto-BlackItalic.ttf,sha256=AT0ipPsmOK26KFVe4ZNm9FhfbcUzt8My9JMaIxSXyyI,177552
kivymd/fonts/Roboto-Bold.ttf,sha256=fQuZHuPgvnrwGtfqjNK-6mwAol5nmgImtnN_B5qv_4Y,170760
kivymd/fonts/Roboto-BoldItalic.ttf,sha256=pLysFPQZqX3gkXGYpLxRw-1PxKPbn2ilEC8jZk7gE1Q,174952
kivymd/fonts/Roboto-Italic.ttf,sha256=X86Lb4up9NGfDVNeJB1WorjnK7B-ffcR2WjQku9_n8o,173932
kivymd/fonts/Roboto-Light.ttf,sha256=ptND1CW8ONuQFS-gYFixxzkeypJk8zTvZcHOF1CFxvY,170420
kivymd/fonts/Roboto-LightItalic.ttf,sha256=Nkoj4Txkk3w_zqPbd4YouJN5yJOEm7reblv4PF9gXGo,176616
kivymd/fonts/Roboto-Medium.ttf,sha256=8gXMURgh6lYHihBVV_zqYlMSlATUEcmX4YZvvQBqu2g,172064
kivymd/fonts/Roboto-MediumItalic.ttf,sha256=8Xfu0Q0kcNE-xo0EkHpYKCnQ7oKB-KAqkG9pVMeBblg,176864
kivymd/fonts/Roboto-Regular.ttf,sha256=eehRQEZX2sIQaz0irSVtR4JKmldlRY7bcskQKkWBbZU,171676
kivymd/fonts/Roboto-Thin.ttf,sha256=PZH3qmnLf3BkA1iVxWasXLmyCEWC01Gvcme7Tg-6YPU,171904
kivymd/fonts/Roboto-ThinItalic.ttf,sha256=9eiaNEiUpg8PmPHAGCulH1BG4p3eMRiCDTkCVEWuqug,176300
kivymd/fonts/materialdesignicons-webfont.ttf,sha256=pY7LVPRe7Br628ITFNHwkyzwCeXLx_MiXX5KThtx72s,1279992
kivymd/icon_definitions.py,sha256=NPLejj2aOoR3N97zW8H8K2Sw7ECqYXQ_xLALkD0Yo-c,276638
kivymd/images/alpha_layer.png,sha256=FRlE7o8oQebgftB_P9I-o-a6mslCr7aIrY3Zo6QGuAs,553
kivymd/images/black.png,sha256=2oJF5FzBeTXDdA7lE2kQ_ftDv8TRtCOiTQtfvCf_qlM,147
kivymd/images/blue.png,sha256=vOIOgEL_pAc4anbPSOhe6dxcEYi58dh3jlprNc36ASQ,147
kivymd/images/folder.png,sha256=xY9uUYegh7hDzFI4iPEA-zyFBzq9IE007zaJGGY5JY0,2311
kivymd/images/green.png,sha256=GK69rWfb7kTIlxD8nPjSq1X6k06SO1AxstcJLskJtp4,147
kivymd/images/logo/kivymd-icon-128.png,sha256=VjWHaIJ-MSyP7ZnM25xgBfp_wG4vbQhr8B8QOTcXeaM,19826
kivymd/images/logo/kivymd-icon-256.png,sha256=5iJVryvz0D-IvqLGTsaeJlYhZYk2R7OxskKiNgw25Ks,31943
kivymd/images/logo/kivymd-icon-512.png,sha256=JAtfTEA7AWBPcMhFGqlwSQmQSq-lWAEJ8Y98qmDe0I0,54349
kivymd/images/red.png,sha256=_4J3FtVS8IKWHCmr2e9GOy2cOGKmwV_0lzAbQf1IKLM,147
kivymd/images/transparent.png,sha256=yM2bydAM4U0tnbs4zAuK2GnCC6I6NgAIfpw7rQhG1BQ,156
kivymd/images/yellow.png,sha256=TH_ecR8dfP9R-8zYD4Ez24qZjaEbDTgJ0RcIcbHBIeE,147
kivymd/material_resources.py,sha256=Ph4x6f5Lp7XOI4jqIkOBo_tZ_yMUPZDToO34A7akOlo,1763
kivymd/theming.py,sha256=hQ5RfjoQlE8hWQKdQ2ZVOF_83ok-o8o0BzR-Kv5XDmA,58553
kivymd/theming_dynamic_text.py,sha256=5TaO0Tc98EqK4-qTDMUO4FQHIU_wVxk6Y2GHhD6UcRk,2920
kivymd/toast/__init__.py,sha256=1gkx40QSHU_0YprtsIJfog8Nnj6t_ZuXMLGhI7QZ0ww,238
kivymd/toast/__pycache__/__init__.cpython-311.pyc,,
kivymd/toast/androidtoast/__init__.py,sha256=CCs95Gih3ri4OcO1J-xPFVmhGKPdY9idW3-V0mIjQ_s,226
kivymd/toast/androidtoast/__pycache__/__init__.cpython-311.pyc,,
kivymd/toast/androidtoast/__pycache__/androidtoast.cpython-311.pyc,,
kivymd/toast/androidtoast/androidtoast.py,sha256=cpbgUhZUjOU1go4Sn-qOo9h61Qhk4EAx1SFI9b4tC8o,2363
kivymd/toast/kivytoast/__init__.py,sha256=mFY2Qi4xK_ttQxx7DnEg7XZxX68he0Hr09rZ60Pm95A,51
kivymd/toast/kivytoast/__pycache__/__init__.cpython-311.pyc,,
kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-311.pyc,,
kivymd/toast/kivytoast/kivytoast.py,sha256=jRLOmiUV2Hf_09tTxnEfJUM5lEBZWfo_wEmgC9zLq5M,4135
kivymd/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/__pycache__/argument_parser.cpython-311.pyc,,
kivymd/tools/argument_parser.py,sha256=oxgJoS5WZH_ATDlaEU0HDtm7ve4DOJ23CnOILIBygy8,3193
kivymd/tools/hotreload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc,,
kivymd/tools/hotreload/app.py,sha256=cJxyUxz1GbQ58pgPY3GZNSl-CoawoPUPoCUF3lECltI,16803
kivymd/tools/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/packaging/pyinstaller/__init__.py,sha256=ibpoURJJkyGuSgWhz8t-RuLnCmQf15TiFNr-HKTCPHA,1480
kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc,,
kivymd/tools/packaging/pyinstaller/hook-kivymd.py,sha256=cN0arGlcA_vLA8FTaAdzKgn7s2YQRCclv7G0e4c4o-Y,1053
kivymd/tools/patterns/MVC/Model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc,,
kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc,,
kivymd/tools/patterns/MVC/Model/database_firebase.py,sha256=5SlPAn-ROkh_ytnv2nteaVRAMC0MUSDM9u115Crfh-o,1376
kivymd/tools/patterns/MVC/Model/database_restdb.py,sha256=Wc-zPffP-Wriyn-JGKCQrw3SGZMiAk-8LrVjParRtGM,3866
kivymd/tools/patterns/MVC/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/MVC/data/locales/po/en.po,sha256=1b2jIsEnyQi_T_gnpe5QeO90IdaQLwWClk5pn46ZjME,425
kivymd/tools/patterns/MVC/data/locales/po/ru.po,sha256=mQd6ol2abec-PUJsrnRWNoah0din3IAg_F4gPf5VBVw,425
kivymd/tools/patterns/MVC/libs/__init__.py,sha256=B6Kln9GZ6UrMOxr4lOnpTxGBMaoKlcar5wpyTGyUlIk,54
kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc,,
kivymd/tools/patterns/MVC/libs/translation.py,sha256=LiiMZUxVbAmUy71mVA-PyEkxwYrCAOcjeiDnlbCSPvQ,1411
kivymd/tools/patterns/MVC/messages.pot,sha256=2cutqkylhtiY07tkXzE8yNqpux9eeoW3tdeoEbXdB1Y,582
kivymd/tools/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc,,
kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc,,
kivymd/tools/patterns/add_view.py,sha256=4J41yOosi9KkNrMBI6h6yJ_0LoncdJzmJDy-iShaArk,6576
kivymd/tools/patterns/create_project.py,sha256=x3g37U3Dbk-ivUJ_aGgwvjpwBkyM4zIcPF3Bcyw1ASQ,39373
kivymd/uix/__init__.py,sha256=iYE45157qMg3owm8X0BMVuStS8kU6bFyWr04VTjIPcw,2892
kivymd/uix/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/boxlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/carousel.cpython-311.pyc,,
kivymd/uix/__pycache__/circularlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/floatlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/gridlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/hero.cpython-311.pyc,,
kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/recycleview.cpython-311.pyc,,
kivymd/uix/__pycache__/relativelayout.cpython-311.pyc,,
kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc,,
kivymd/uix/__pycache__/screen.cpython-311.pyc,,
kivymd/uix/__pycache__/screenmanager.cpython-311.pyc,,
kivymd/uix/__pycache__/scrollview.cpython-311.pyc,,
kivymd/uix/__pycache__/stacklayout.cpython-311.pyc,,
kivymd/uix/__pycache__/taptargetview.cpython-311.pyc,,
kivymd/uix/__pycache__/widget.cpython-311.pyc,,
kivymd/uix/anchorlayout.py,sha256=lrw9QiThjutmOTQix71atzJKP_cauoGUykiLdLfW99Q,1025
kivymd/uix/backdrop/__init__.py,sha256=_9OLuWRMGEDqI1-ix6u0VJbuOpHJ6FLnJuODPYw2Eko,46
kivymd/uix/backdrop/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/backdrop/__pycache__/backdrop.cpython-311.pyc,,
kivymd/uix/backdrop/backdrop.kv,sha256=L0w8al59AMQlkUrqjJsX1o7pMC9S70zt5KwulOON18g,1407
kivymd/uix/backdrop/backdrop.py,sha256=eiJyqjY3hT-CFUVUX97f-2-npPxsr4TfsECjTGIrhTE,16311
kivymd/uix/banner/__init__.py,sha256=JimxFPqzTx8l1pwI4rknb8r3QiDhLcI9xb4pIfpselo,42
kivymd/uix/banner/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/banner/__pycache__/banner.cpython-311.pyc,,
kivymd/uix/banner/banner.kv,sha256=Mb5jq9VSLr0A4DqvTpSF9tKKh-JvpiN3oM9jKh8V5vs,1679
kivymd/uix/banner/banner.py,sha256=E99gUMVE51jKNpTG3gyQKVAiaxQ4yeIznLzcGeOO4-A,12053
kivymd/uix/behaviors/__init__.py,sha256=htl-U1oP2Tkmgul6gvkWV54LOzrTKe_jhwpT7dd372M,979
kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/backgroundcolor_behavior.py,sha256=a8Oa41plDW4G4tiIL-QNLc963VsW-5u7BuwvCTFfl3s,8962
kivymd/uix/behaviors/declarative_behavior.py,sha256=MI2KelKtrkhXMIXoqu53ivHf_Zn7CQNQUtRHiwHpe9A,10236
kivymd/uix/behaviors/elevation.py,sha256=cdQgXKUxM1-2YS1H3IM2yssc5FUQOJtptccMn7xQZvo,22211
kivymd/uix/behaviors/focus_behavior.py,sha256=fhqtqiTMEopNMP7-_xWTVTtwiuKS9pkjnIIirjm3PcA,4240
kivymd/uix/behaviors/hover_behavior.py,sha256=mhogwYWLTxJzqrO_Yk38v5BhYY7rFhVZ1xQfcEeXGq8,7616
kivymd/uix/behaviors/magic_behavior.py,sha256=wwN40b_0NTG3Dopdhqt89PXYqY5mXSM4lY2xuIk1v9Q,4570
kivymd/uix/behaviors/motion_behavior.py,sha256=15cwgX1UWlS2TJVBVOCia5FhYEOyr6PG9OPJRn_6aqU,7342
kivymd/uix/behaviors/ripple_behavior.py,sha256=LoS_lIpYlzIGQWAX1FNh_56EmZ5NE_FsxNdQWaVvYZg,16658
kivymd/uix/behaviors/rotate_behavior.py,sha256=Z8Ux_UwKZHoeu-cCl8hNc2EDVgC_hWni-ld8BpbL1uE,3268
kivymd/uix/behaviors/scale_behavior.py,sha256=2ONpA7LKW5UhNI-ibBLlyQtOP_xyHDkasNxmqLO-z_c,4062
kivymd/uix/behaviors/stencil_behavior.py,sha256=k6S2fwKMrxsFQKgI36q5-zCaQZ6LMFmv97jDPXD8e2Y,3017
kivymd/uix/behaviors/toggle_behavior.py,sha256=wGi3INtIa_6chPcJMekye5jTaGkLMbwPtmW0aFdL_fE,8451
kivymd/uix/behaviors/touch_behavior.py,sha256=uSP_AE8QuU_t_Q_Q-lUxuxh_Ms8TOZCewxUvSDsj04U,2475
kivymd/uix/bottomnavigation/__init__.py,sha256=oAt66rNw5qp5ueAqLxfXs2iPpp68IWp5jVEnY3xMkwQ,85
kivymd/uix/bottomnavigation/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/bottomnavigation/__pycache__/bottomnavigation.cpython-311.pyc,,
kivymd/uix/bottomnavigation/bottomnavigation.kv,sha256=7swDhIg8quCg7Vtm01jy1BnEtMx9qvMueFT88QBnkvU,4082
kivymd/uix/bottomnavigation/bottomnavigation.py,sha256=BpVHD3XKnkZe2tLvNDn6Z23Kuq7l0lneY3TrRMK1pec,27138
kivymd/uix/bottomsheet/__init__.py,sha256=VhYEno0toWnl6OmaxgYT7as1MIXYXLxhZHnTTrZ4TAY,255
kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc,,
kivymd/uix/bottomsheet/bottomsheet.kv,sha256=83LTxxGThfDnPN1ATAw4zU0_LB-jmERiFQyC8b3iedA,1047
kivymd/uix/bottomsheet/bottomsheet.py,sha256=zv5Y3x7e3YdqnL_RJgMunpRrSd5BP4Oro7iO-QDLC7w,36674
kivymd/uix/boxlayout.py,sha256=cWQuo2HJNnCoeY-HwXxsxZrv0YXR-IE4GGf8ymPVswI,1694
kivymd/uix/button/__init__.py,sha256=hflz-R7RufS_l2SBqnwYtmAV5WAnsnmD2jwr3OQeusc,385
kivymd/uix/button/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/button/__pycache__/button.cpython-311.pyc,,
kivymd/uix/button/button.kv,sha256=Z4AKWPAoRfPUflwHeUH81NpXSGZKrsiuSbAuy5GDTTA,6614
kivymd/uix/button/button.py,sha256=O4u_5Ph7bVeicDk_fxc1HTiCzIZUr8rTGoyTIiPDnMU,75206
kivymd/uix/card/__init__.py,sha256=DRguLhBrd_iil2DlVN7R8Euq711j6M81Hbkyfv9f4fs,130
kivymd/uix/card/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/card/__pycache__/card.cpython-311.pyc,,
kivymd/uix/card/card.kv,sha256=dMijf_VPWw1Vc6cM7LdCf3KCFEcHtC9QnAU2icmAeXk,192
kivymd/uix/card/card.py,sha256=cVm6dSVT6bUsWjyh2MbXUTPbCbgpGR7ekLWQb2afIJc,33665
kivymd/uix/carousel.py,sha256=371UKLVsrndHekRbtAgnEtUU_ZQVDdzgXFJfhpJIr1c,7044
kivymd/uix/chip/__init__.py,sha256=gpNRYAODC-ip0mjg36rcw8SMTQh_-223GPQsPPY65OE,50
kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/chip/__pycache__/chip.cpython-311.pyc,,
kivymd/uix/chip/chip.kv,sha256=2ZUAugzJb3yw-Mf0rw7yKA07foheqB1gS9LhK0WQrZ4,1035
kivymd/uix/chip/chip.py,sha256=a7xTg3jyQFhsJrmjBI2eVqBwhIJSY2UdjAufll0A75U,34934
kivymd/uix/circularlayout.py,sha256=rG9QqC_1PoEqNhHCS8OK4oLcSvqBC2RSRZh9BHc8I0w,5506
kivymd/uix/controllers/__init__.py,sha256=WNbi76mp899CTLeSZUnVJ0b5gSeUMJ9ganvmhEcNR40,231
kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc,,
kivymd/uix/controllers/windowcontroller.py,sha256=msVZQJwaekkIw4XUECXWAMOAsXw5NkFe38xIel1wG84,2335
kivymd/uix/datatables/__init__.py,sha256=UQ_0tOrl5F-VSHQUpByyFw5LQzKTFAnWBNrUAnmPN2k,49
kivymd/uix/datatables/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/datatables/__pycache__/datatables.cpython-311.pyc,,
kivymd/uix/datatables/datatables.kv,sha256=4u8JMT66faxazxGdVDAbHF3aT_ioNQRN04O_asr5Si0,6558
kivymd/uix/datatables/datatables.py,sha256=OfoHMXPE1LYaNF03th3M8dMp_ZcgNV4wuQF0FTL5yc0,71271
kivymd/uix/dialog/__init__.py,sha256=GcaS3dDIcvTSuJ9hYwNAsSKe89OKj1F7DEyu2j2HxCw,54
kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc,,
kivymd/uix/dialog/dialog.kv,sha256=0afWO3x6OXEsOUHUSdxO7q3m6mOU7HlizEal4FCBCYQ,2155
kivymd/uix/dialog/dialog.py,sha256=YjK1ozUeZ1HQpzSQvZQav0D3SWfavFJwB6g6vZlAaTs,21874
kivymd/uix/dropdownitem/__init__.py,sha256=KyXd1v0gdOilE48z8Sp-Pqig_KJOdl0fyzWY8gPjA0U,54
kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc,,
kivymd/uix/dropdownitem/dropdownitem.kv,sha256=w46i9i807rDqqk1iZyBTqf2wzrt4jtRv2TKxyZaWxGI,906
kivymd/uix/dropdownitem/dropdownitem.py,sha256=uVveaPSF27cjPCe8WiVp1zjfIIqU36e79NIUPhn193U,2633
kivymd/uix/expansionpanel/__init__.py,sha256=fOxf-XTewfdiUEsKs4O8-ZFCLxG_zC12oWWIIGtO1Xc,182
kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc,,
kivymd/uix/expansionpanel/expansionpanel.kv,sha256=ImVy4Axm1-EqLYn52AR5gE6ypSE_jiDjQLz-FnrNZQM,355
kivymd/uix/expansionpanel/expansionpanel.py,sha256=wPMCjQaN8HE1KwUd7-t97gI-xu-SxwZQAwrh4cRC55M,14229
kivymd/uix/filemanager/__init__.py,sha256=TR0eAXbR-lzZUQLiVcGcVp5D1myeiLoXGpSWZitrWKI,52
kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc,,
kivymd/uix/filemanager/filemanager.kv,sha256=PCTjXk8I4yeZSwio4YwyXf2DkXDT0Uz92d0Bk16zKq8,2863
kivymd/uix/filemanager/filemanager.py,sha256=k_NztZeWL75BPtCCf2e-cNuKgjiRlp6FRjWg9Z6ekKc,25313
kivymd/uix/fitimage/__init__.py,sha256=BVf16byn839UfzikgsfJj_s5xH0PjGgU9gUuetb1dsU,44
kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc,,
kivymd/uix/fitimage/fitimage.py,sha256=o2RLSBlr9ahCeZZkmp1zyuhzPN24NKkSknWajBN1dhg,6516
kivymd/uix/floatlayout.py,sha256=CUeL6e-k20Jg2zqWBL9sMvGzWgO7nNAsTd5So0UMgd4,1202
kivymd/uix/gridlayout.py,sha256=HULtL-Zg0V_qN_7PZxe9Rr7jEuvGrnRA398tVZQSPkc,1671
kivymd/uix/hero.py,sha256=P-rsRLF7OL5zHWpw6dgMRsWWWboXghyhFUw9GWpVu-I,17379
kivymd/uix/imagelist/__init__.py,sha256=O4MQYEuq07GdwTytyXcE48Frp5Cy86zd8sqaYTPMFnk,47
kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc,,
kivymd/uix/imagelist/imagelist.kv,sha256=lRzJikpng24-TNQl2olHbgg4CUUKnwu8XEhaOY2ts1M,921
kivymd/uix/imagelist/imagelist.py,sha256=DkSpHgpVgN1hHlFYQddWW-BxcxcuXCg90KEq0C-q3mU,8000
kivymd/uix/label/__init__.py,sha256=DHLIPzLH5Uq0ChimIQIUVHQ42iAilC-F2xYzWqeqiXY,48
kivymd/uix/label/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/label/__pycache__/label.cpython-311.pyc,,
kivymd/uix/label/label.kv,sha256=pQa0LHD7haztYEiOKnKLYiK4NbbKe_gwUQWrbPPDKb0,2055
kivymd/uix/label/label.py,sha256=h_kFBoEXrzPlf9poja-lyLOTJVcgIq9kyPGnKu3lPXI,27892
kivymd/uix/list/__init__.py,sha256=vaqucd89ij0ssXVPdvdl9bmsiXWbsUX7uZi-qT6QzIc,788
kivymd/uix/list/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/list/__pycache__/list.cpython-311.pyc,,
kivymd/uix/list/list.kv,sha256=7tm7YcnXRURc_CHXRTYSw9zNObeviasG7arladTBZ5U,4715
kivymd/uix/list/list.py,sha256=ymc8r18Eex4lNKAyp1UjbyWBFFKw-yaBe9WBy3dQDcs,45486
kivymd/uix/menu/__init__.py,sha256=2a7cHJKvQmKiqu4_YWWQMF96owFFkRiMnEPX2R_kMbA,46
kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/menu/__pycache__/menu.cpython-311.pyc,,
kivymd/uix/menu/menu.kv,sha256=ZJ3j-XggUkcEOsEdYRlMnsGit9jZQ1VvKICBgovy2DA,14002
kivymd/uix/menu/menu.py,sha256=7dnA5hi2CXLWhlrRsBKj59J1FWthaBs2JneIdDzioTw,40950
kivymd/uix/navigationdrawer/__init__.py,sha256=YFHzu07n8mPUmONaMYhwkx5OzK-J5mrzi109Mfj8S8o,240
kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc,,
kivymd/uix/navigationdrawer/navigationdrawer.kv,sha256=Sh9d6kvvLONwvFSGJyXFGJ_hzsMhBekMNVnc4Kv5J9U,3586
kivymd/uix/navigationdrawer/navigationdrawer.py,sha256=zg1m9K_Y2oYRgd5b2lvHAq5QxG5qc2Mzqpco0jTOcJA,46331
kivymd/uix/navigationrail/__init__.py,sha256=4chGrBkw62foF0LYSBv7fkL9E5MvwUExi7-VG_cSbtM,155
kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc,,
kivymd/uix/navigationrail/navigationrail.kv,sha256=xDomPL_lSc_ssaPUQsOfQizMZc5Gc3ZBFbAQO2dyN0o,5588
kivymd/uix/navigationrail/navigationrail.py,sha256=Vr8PjkkbPkCjuvYAW_3Wd-Az9IxwOUWPSOACsQ3dz5k,42888
kivymd/uix/pickers/__init__.py,sha256=7FvCnbWhjGmwOTqCMFrzTyPOa77Yytkrger5Vz7nOqI,152
kivymd/uix/pickers/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/pickers/colorpicker/__init__.py,sha256=7HqXXTyARgnSu9I26V08PEj53OZw34MrOGmymOFOPJs,52
kivymd/uix/pickers/colorpicker/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/pickers/colorpicker/__pycache__/colorpicker.cpython-311.pyc,,
kivymd/uix/pickers/colorpicker/colorpicker.kv,sha256=mbHuEnvYGd97CUJLfrnjZ0qCuJZ8SR14sj9ztUOI-yQ,8272
kivymd/uix/pickers/colorpicker/colorpicker.py,sha256=ucG1wqZWrG2WBTcUp3kE3uzfVKNMGEMCI4BqOgvEg38,22794
kivymd/uix/pickers/datepicker/__init__.py,sha256=-_u_4EUwtwFtCh5E58y7aMi4XCK4CJi0R5cZmDptDaE,107
kivymd/uix/pickers/datepicker/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/pickers/datepicker/__pycache__/datepicker.cpython-311.pyc,,
kivymd/uix/pickers/datepicker/datepicker.kv,sha256=yk5zBwAZZJ_LOADiGBNLVNnx73Y-D58NoqCqooP0vss,14321
kivymd/uix/pickers/datepicker/datepicker.py,sha256=MBsMiUwYOIumJnI_Dtmhu3UOESv1CjMDWhI84w0SCvw,50563
kivymd/uix/pickers/timepicker/__init__.py,sha256=ZWB8oTmsgA1Uy5zv2I5QmwZ2N3spznS0anLvK-aytVQ,50
kivymd/uix/pickers/timepicker/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/pickers/timepicker/__pycache__/timepicker.cpython-311.pyc,,
kivymd/uix/pickers/timepicker/timepicker.kv,sha256=1REiI_DBcT9868oWTAK1BmPhFn0LltmR9Lwq0EHVs-g,10618
kivymd/uix/pickers/timepicker/timepicker.py,sha256=H3qUswLdaBQ63zbF19bt0y-WiHmCGUBNQt2Qh-_sUlY,25249
kivymd/uix/progressbar/__init__.py,sha256=YLT-xcOX3Z_O8py_ENTH9wFIletQiMJ5vUVK6nr3Qco,52
kivymd/uix/progressbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/progressbar/__pycache__/progressbar.cpython-311.pyc,,
kivymd/uix/progressbar/progressbar.kv,sha256=p0LzgpX6k_hd-r_CUTbQA2K2yO7M7SIyW8nx-0B8r4Q,1423
kivymd/uix/progressbar/progressbar.py,sha256=5EYTXRxrV3JkCSidbmXRXt9FNt9tBF3gTTvGzOvh7cI,8523
kivymd/uix/recyclegridlayout.py,sha256=gvtUVMG04EjsCw2wOPBWgGwu_anZS7buKjFAnZqVhyQ,1804
kivymd/uix/recycleview.py,sha256=uBxnIU6FgjS44cE6K-Wqp4xel4tuV726_Vaa6W5f5tw,1008
kivymd/uix/refreshlayout/__init__.py,sha256=r6yH7AYvn831mRtdu6KN_p4L42JBJh2qKpNIuHyckao,66
kivymd/uix/refreshlayout/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/refreshlayout/__pycache__/refreshlayout.cpython-311.pyc,,
kivymd/uix/refreshlayout/refreshlayout.kv,sha256=5jMCt1kBIA91ll4rWNYZ33fheUvMxph3uUBAj0BhdH0,602
kivymd/uix/refreshlayout/refreshlayout.py,sha256=lHL1nGOpHWiPqjD7r0dkSabhR6d_Qzis7xtuhpr8RjA,9638
kivymd/uix/relativelayout.py,sha256=hYfETginxPuQvYU37w22E184wZD_A-eTfRgFw5SqwAE,1062
kivymd/uix/responsivelayout.py,sha256=N1GMNejHlNssk8ZpC9kMuZELuWywUs9Dms_AzHcpU1Q,5409
kivymd/uix/screen.py,sha256=WhRKHyC8o7t8c_lgBfX4_hpIz7L2kArKYSAVM7MA0cI,2280
kivymd/uix/screenmanager.py,sha256=YD3pJ79LdINVEH2QS1zC-FpPQcg3m4mSZakYKh3a9Wc,5091
kivymd/uix/scrollview.py,sha256=fKCNMqezyYpNlNrYXSueRQ7ISy1Qd6PD74INrPURvdE,948
kivymd/uix/segmentedbutton/__init__.py,sha256=WpaigD2XLpcvKEEAqWoJTZiZRy3S4J47_KU36FhNPNc,96
kivymd/uix/segmentedbutton/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/segmentedbutton/__pycache__/segmentedbutton.cpython-311.pyc,,
kivymd/uix/segmentedbutton/segmentedbutton.kv,sha256=1cE5UXZOI46aItAYYpM0cJdgWgPXc6dcqKMFG_0ZD2Y,840
kivymd/uix/segmentedbutton/segmentedbutton.py,sha256=JjKLG0GO2AVyk-EJQwD8EBeKaaV3Rrk0tr_pkJRRs7Q,19122
kivymd/uix/segmentedcontrol/__init__.py,sha256=z8ZZj8D5wDxyr__hqHZjscxexIw8CRDkYX6Dl9tZxxs,99
kivymd/uix/segmentedcontrol/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/segmentedcontrol/__pycache__/segmentedcontrol.cpython-311.pyc,,
kivymd/uix/segmentedcontrol/segmentedcontrol.kv,sha256=jhZiaohChE-DqhZC-hA3_HHxJqQ08eEGmGSF7euyA4A,959
kivymd/uix/segmentedcontrol/segmentedcontrol.py,sha256=AJQyaQN0et40snqGp9A1ag8HWRMEJqj5PeZ5hrit_sA,11084
kivymd/uix/selection/__init__.py,sha256=12J_d15BRpSKymQbsMwSZ51Bo_5FauKwaY-d0z_2uAk,52
kivymd/uix/selection/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/selection/__pycache__/selection.cpython-311.pyc,,
kivymd/uix/selection/selection.kv,sha256=lpA5YyksPcf2tJmmE754eOGsTRkNhLa0IGHAjmlXD70,379
kivymd/uix/selection/selection.py,sha256=0j-12oo2dVzs-KZDJqHTLIIHDbLcQNerZzds-NFgq8Y,21378
kivymd/uix/selectioncontrol/__init__.py,sha256=n1yw1X7ccriTWj1GPN-V9LvFXgxuFNfEy6uRHPyhQGA,71
kivymd/uix/selectioncontrol/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/selectioncontrol/__pycache__/selectioncontrol.cpython-311.pyc,,
kivymd/uix/selectioncontrol/selectioncontrol.kv,sha256=4_Xlvgjpfi_3OmC2BPE7eZ_P4XRRGJw5AcmlXWsf1C0,4873
kivymd/uix/selectioncontrol/selectioncontrol.py,sha256=Nu-eGtbmgjcaI8A4Ke7nleFOXqPnWuB4q0GTe7aZ4Yc,27724
kivymd/uix/slider/__init__.py,sha256=TQwpwsmQElirZufuKGck-QZuYLe1V1Vd2HVUwSnPx8k,42
kivymd/uix/slider/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/slider/__pycache__/slider.cpython-311.pyc,,
kivymd/uix/slider/slider.kv,sha256=ddb5p6jonpz3R9Lqg4tfKqKVTTy2s0_pkURnwUovmtA,6144
kivymd/uix/slider/slider.py,sha256=nmYRtmX0OOnokQFr-xbWgomK6DnkoBjQXSfe6SjNcaU,8502
kivymd/uix/sliverappbar/__init__.py,sha256=axuqy95RR0oDLXpBtH3EauoTZN56p6EAp3JFBC-MoYI,103
kivymd/uix/sliverappbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/sliverappbar/__pycache__/sliverappbar.cpython-311.pyc,,
kivymd/uix/sliverappbar/sliverappbar.kv,sha256=_Ck4u11h0HJUQa4gNwEkCBR28xHspd6KNhZ-1oHPzac,1208
kivymd/uix/sliverappbar/sliverappbar.py,sha256=ABfFDECbD9dbefONxHxKd6qFDhS-WNGOtlZE81r5VPs,14833
kivymd/uix/snackbar/__init__.py,sha256=wG6Czix7Tb-3f69MAZqdxy2oY_-lQF8mYHQ_rueZ2lI,124
kivymd/uix/snackbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/snackbar/__pycache__/snackbar.cpython-311.pyc,,
kivymd/uix/snackbar/snackbar.kv,sha256=M0HYjCKUR6-aSrleQaqVjXzrO2tbhCTgyuYTgn0s3S8,761
kivymd/uix/snackbar/snackbar.py,sha256=9alYRqr9yxqFlMPHbuUrXCCcron2VOZiZSA_7hZz9gA,14432
kivymd/uix/spinner/__init__.py,sha256=QI6bPGhsNGXXrXR-fPvEkbEfTUF3V3tY1wHTx_zZAJI,44
kivymd/uix/spinner/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/spinner/__pycache__/spinner.cpython-311.pyc,,
kivymd/uix/spinner/spinner.kv,sha256=UerB-S-STJiBnjZw6HsRqAGCNxLw0bvfu5EegQQpzDQ,521
kivymd/uix/spinner/spinner.py,sha256=PCRVUq07-ZP0ADAWSz5vATEZE9Blx62onzKc_AdOoNs,9121
kivymd/uix/stacklayout.py,sha256=VE-OemocOjID3yVA6cwOt1KUn64NwdVCgVA1ssD1nAM,1724
kivymd/uix/swiper/__init__.py,sha256=yjVyswA0HfoLRx9UW7k_GR497shvH5EthBbQk8CoU_4,43
kivymd/uix/swiper/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/swiper/__pycache__/swiper.cpython-311.pyc,,
kivymd/uix/swiper/swiper.kv,sha256=iTaioAm-1WWmrGV4mqTizz3f4Qobv8WJZT-cwhEqyD0,291
kivymd/uix/swiper/swiper.py,sha256=4Wwnj_jFvNhRlyPFvyXyPt01ZHeJt_25KcyjeZAB-II,14656
kivymd/uix/tab/__init__.py,sha256=ui2pD_Y163wYI19O3JdSlVHhXUs83FHQUrZFi9FcGHs,62
kivymd/uix/tab/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/tab/__pycache__/tab.cpython-311.pyc,,
kivymd/uix/tab/tab.kv,sha256=UuHLg4fS1CwROB4wwjWLxOmFk7xU5W78qWLZxSMMvSM,3809
kivymd/uix/tab/tab.py,sha256=WnsmGmgjPWTYbtuNkOLRZSFRciGZwHOaaAWS_zHJaNM,67730
kivymd/uix/taptargetview.py,sha256=8oIPH-HC-kxSOsKua0NJqeacb1oxjNIExPDFz46p3-k,26995
kivymd/uix/templates/__init__.py,sha256=N58Ktx4cjBdiBsabyRkeJKOczHNQCGhWpQV_bGEy6CY,216
kivymd/uix/templates/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/templates/rotatewidget/__init__.py,sha256=44Zf8a5sc5FSSfYX2RTWLAikbOzgi9g3Sm_LhroTsv4,39
kivymd/uix/templates/rotatewidget/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/templates/rotatewidget/__pycache__/rotatewidget.cpython-311.pyc,,
kivymd/uix/templates/rotatewidget/rotatewidget.py,sha256=Ea9ImstSgTxTeNKikN7GQlu_tWcgjaAkE-iMJpuYAr4,764
kivymd/uix/templates/scalewidget/__init__.py,sha256=QeR6z6AC4N1ylUnh0aI2cBAVDuOhsqUNF0Ux9Dza2zQ,37
kivymd/uix/templates/scalewidget/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/templates/scalewidget/__pycache__/scalewidget.cpython-311.pyc,,
kivymd/uix/templates/scalewidget/scalewidget.py,sha256=xnV2r-bw3gwvhyiwWtueNkCODC7uTg2sSJCNwlTSWuA,804
kivymd/uix/templates/stencilwidget/__init__.py,sha256=1hoHSMc_CudX4ixsz4dlvAPQi_ppki1ht1zi7oSza_g,41
kivymd/uix/templates/stencilwidget/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/templates/stencilwidget/__pycache__/stencilwidget.cpython-311.pyc,,
kivymd/uix/templates/stencilwidget/stencilwidget.py,sha256=VbMTYBRJXH1BGh-1jxFIXLZVGOfVj47K-1DHCzCQG4U,843
kivymd/uix/textfield/__init__.py,sha256=TsquVODAqOW9KRaVdZEwDSuj84xNu3btukztMO1u-R8,64
kivymd/uix/textfield/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/textfield/__pycache__/textfield.cpython-311.pyc,,
kivymd/uix/textfield/textfield.kv,sha256=1YRvhffqhGvrTT6ak7-9Q8igtweGh3heUkudK5vAsog,11995
kivymd/uix/textfield/textfield.py,sha256=ZgKSMcO0rPjbgbhZ9sKDtCEZ4UsQS9AlUhaJkwgS9fc,66314
kivymd/uix/toolbar/__init__.py,sha256=ERxUgGcxjesHxwJoadRRiboL22K2gdMaIu1h57GJCcM,163
kivymd/uix/toolbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/toolbar/__pycache__/toolbar.cpython-311.pyc,,
kivymd/uix/toolbar/toolbar.kv,sha256=XTLAQDaSN1lMW350XzY1Wy9gpIm-GVWQzuBhngsr2-g,3569
kivymd/uix/toolbar/toolbar.py,sha256=qOySilG3qNjHwyFEKfcqWEzbTjeLLIEc0h1JwM9QwIU,67947
kivymd/uix/tooltip/__init__.py,sha256=TrHnzd6U1iKu-TzPaBG4jPRL7Cdaa91FqQQiS37ce9o,64
kivymd/uix/tooltip/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/tooltip/__pycache__/tooltip.cpython-311.pyc,,
kivymd/uix/tooltip/tooltip.kv,sha256=eiA1FwuWCUm8BTdTilYPS01V2lDoVh0mW-BkeEldGPY,1171
kivymd/uix/tooltip/tooltip.py,sha256=_-crrT-DxKx12VGfCBqe3sV_nIPTmdklEDRGhngAl4k,10861
kivymd/uix/transition/__init__.py,sha256=QA3XDj483c_iPrbiVHdkvVZhCKPu495dr5_6hBZRLgw,113
kivymd/uix/transition/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/transition/__pycache__/transition.cpython-311.pyc,,
kivymd/uix/transition/transition.py,sha256=xwN5NcfogHwl4xeuzA1R49Vu88LBpuwmmv2N394UWV0,11349
kivymd/uix/widget.py,sha256=6oQLzQuKgp4Rnulq63Zlw4fPjJ0RmkttrFx7NJbCMug,1074
kivymd/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/utils/__pycache__/__init__.cpython-311.pyc,,
kivymd/utils/__pycache__/asynckivy.cpython-311.pyc,,
kivymd/utils/__pycache__/fpsmonitor.cpython-311.pyc,,
kivymd/utils/__pycache__/set_bars_colors.cpython-311.pyc,,
kivymd/utils/asynckivy.py,sha256=veVrps6-mxT5JFgRpwzZ18_HFzx9CeG4IZomp8cTtyQ,1544
kivymd/utils/fpsmonitor.py,sha256=QzWJs1lr9SIk2NDVeDUC2HRSyMXNXTWB39HvLDtL0vI,1024
kivymd/utils/set_bars_colors.py,sha256=uhCQdrRhRW-P--5D5MJR6rcauOA8wmiFoapJJczkf14,4050

View File

@ -1,18 +1,7 @@
MIT License
Copyright (c) 2022 Andrés Rodríguez and other contributors - KivyMD library up to version 0.1.2
Copyright (c) 2022 KivyMD Team and other contributors - KivyMD library version 0.1.3 and higher
Other libraries used in the project:
Copyright (c) 2010-2022 Kivy Team and other contributors
Copyright (c) 2022 Brian Knapp - Androidoast library
Copyright (c) 2022 LogicalDash - stiffscroll library
Copyright (c) 2022 Kivy Garden - tabs module
Copyright (c) 2022 Nattōsai Mitō - asynckivy module
Copyright (c) 2022 tshirtman - magic_behavior module
Copyright (c) 2022 shashi278 - taptargetview module
Copyright (c) 2022 Benedikt Zwölfer - fitimage module
Copyright (c) 2024 Andrés Rodríguez and other contributors - KivyMD library up to version 0.1.2
Copyright (c) 2024 KivyMD Team and other contributors - KivyMD library version 0.1.3 and higher
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: kivymd
Version: 1.2.0
Version: 2.0.1.dev0
Summary: Set of widgets for Kivy inspired by Google's Material Design
Home-page: https://github.com/kivymd/KivyMD
Author: Andres Rodriguez, fork author - Ivanov Yuri
@ -40,8 +40,10 @@ Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.7
Description-Content-Type: text/markdown; charset=UTF-8
License-File: LICENSE
Requires-Dist: kivy>=2.2.0
Requires-Dist: kivy>=2.3.0
Requires-Dist: pillow
Requires-Dist: materialyoucolor>=2.0.7
Requires-Dist: asynckivy<0.7,>=0.6
Provides-Extra: dev
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: black; extra == "dev"
@ -54,14 +56,14 @@ Requires-Dist: pytest-timeout; extra == "dev"
Requires-Dist: coveralls; extra == "dev"
Requires-Dist: pyinstaller[hook_testing]; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx; extra == "docs"
Requires-Dist: sphinx-autoapi==1.4.0; extra == "docs"
Requires-Dist: furo; extra == "docs"
Requires-Dist: sphinx==7.3.7; extra == "docs"
Requires-Dist: sphinx-autoapi==3.0.0; extra == "docs"
Requires-Dist: sphinx-book-theme; extra == "docs"
Requires-Dist: sphinx-notfound-page; extra == "docs"
Requires-Dist: sphinx-copybutton; extra == "docs"
Requires-Dist: sphinx-tabs; extra == "docs"
# KivyMD [1.2.0](https://kivymd.readthedocs.io/en/latest/changelog/index.html)
# KivyMD [2.0.0](https://kivymd.readthedocs.io/en/latest/changelog/index.html)
<img align="right" height="256" src="https://github.com/kivymd/internal/raw/main/logo/kivymd_logo_blue.png"/>
@ -106,15 +108,16 @@ may be offered to you without asking too.
## Installation
```bash
pip install kivymd==1.2.0
pip install kivymd==2.0.0
```
### Dependencies:
- [Kivy](https://github.com/kivy/kivy) >= 2.2.0 ([Installation](https://kivy.org/doc/stable/gettingstarted/installation.html))
- [Kivy](https://github.com/kivy/kivy) >= 2.3.0 ([Installation](https://kivy.org/doc/stable/gettingstarted/installation.html))
- [Python 3.7+](https://www.python.org/)
- [Pillow](https://github.com/python-pillow/Pillow/)
- [MaterialColor](https://github.com/T-Dynamos/materialyoucolor-pyhton)
- [MaterialColor](https://github.com/T-Dynamos/materialyoucolor-python)
- [asynckivy](https://github.com/asyncgui/asynckivy)
### How to install
@ -144,25 +147,16 @@ pip install .
use a shallow clone (`git clone https://github.com/kivymd/KivyMD.git --depth 1`)
to save time. If you need full commit history, then remove `--depth 1`.
### How to fix a shader bug on an android device
Use `Kivy` from master branch or `Kivy` >= `2.2.0` and `KivyMD` (from master branch):
```bash
pip install https://github.com/kivy/kivy/archive/master.zip
pip install https://github.com/kivymd/KivyMD/archive/master.zip
```
And use with `Buildozer`:
```ini
requirements = kivy==master, https://github.com/kivymd/KivyMD/archive/master.zip
```
### How to use with [Buildozer](https://github.com/kivy/buildozer)
```ini
requirements = kivy==2.2.0, kivymd==1.2.0
requirements = python3,
kivy,
https://github.com/kivymd/KivyMD/archive/master.zip,
materialyoucolor,
exceptiongroup,
asyncgui,
asynckivy
```
This will download latest release version of KivyMD from [PyPI](https://pypi.org/project/kivymd).
@ -171,7 +165,7 @@ If you want to use development version from [master](https://github.com/kivymd/K
branch, you should specify link to zip archive:
```ini
requirements = kivy==2.1.0, https://github.com/kivymd/KivyMD/archive/master.zip
requirements = kivy, https://github.com/kivymd/KivyMD/archive/master.zip
```
Do not forget to run `buildozer android clean` or remove `.buildozer` directory
@ -356,6 +350,13 @@ and get your logo on our Readme with a link to your website.
<a href="https://opencollective.com/peter-surda?requireActive=false" target="_blank"><img src="https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/gold-sponsor-1.png?requireActive=false"></a>
<a href="https://route4me.com" target="_blank" style="display: inline-block; text-align: center;">
<div style="text-align: center;">
<img width="280" src="https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/route4me.png" alt="Best Route Planner"><br>
Best Route Planner - Route Optimization Software
</div>
</a>
#### Backers
[Become a Backer](https://opencollective.com/kivymd/contribute/backer-16159) if you want to help develop this project.

View File

@ -0,0 +1,332 @@
../../../bin/kivymd.add_view,sha256=u2N52U9NKr85se5a66gdG5Old498YxKwDezJ-cwIZAY,266
../../../bin/kivymd.create_project,sha256=6LnjVohJ7V3MZYfVCtWqtyHHaku6Io-y0pN1BFPmDAM,272
../../../bin/kivymd.make_release,sha256=hKmHIsjNRMSeSS3A2PNqeer_kEliqi6NhzI9bmLc0Zo,269
kivymd-2.0.1.dev0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
kivymd-2.0.1.dev0.dist-info/LICENSE,sha256=mAllwI3MAD8PljsyLcDu8ByZZYChrptzwCCA7pXK-70,1230
kivymd-2.0.1.dev0.dist-info/METADATA,sha256=gFwEntEUBVZqXg9ZkEARN2wJJ3LRdRr49tfGGCKZt3c,15236
kivymd-2.0.1.dev0.dist-info/RECORD,,
kivymd-2.0.1.dev0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd-2.0.1.dev0.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91
kivymd-2.0.1.dev0.dist-info/direct_url.json,sha256=4K7_rCzsQAA6VPgFZkDLzO5m3GluAszqZihOmO2M4Lo,82
kivymd-2.0.1.dev0.dist-info/entry_points.txt,sha256=1-yhsSzIhBNRiKNTmevRDT02q8qzg3upZcWAyrr880w,342
kivymd-2.0.1.dev0.dist-info/top_level.txt,sha256=ABq82F4nFM8sy3xAhxiO5XXT_lAen0YqiDD29qRiPhc,7
kivymd/__init__.py,sha256=d_a46HKOE97-WwIhBsv9yjAciPPx7yOLTeVzDynBVMI,1957
kivymd/__pycache__/__init__.cpython-311.pyc,,
kivymd/__pycache__/_version.cpython-311.pyc,,
kivymd/__pycache__/animation.cpython-311.pyc,,
kivymd/__pycache__/app.cpython-311.pyc,,
kivymd/__pycache__/dynamic_color.cpython-311.pyc,,
kivymd/__pycache__/factory_registers.cpython-311.pyc,,
kivymd/__pycache__/font_definitions.cpython-311.pyc,,
kivymd/__pycache__/icon_definitions.cpython-311.pyc,,
kivymd/__pycache__/material_resources.cpython-311.pyc,,
kivymd/__pycache__/theming.cpython-311.pyc,,
kivymd/_version.py,sha256=6I20Wxx3c8MaIw5uF7UNh0yNERX7X5SkzUyMzzVsxno,115
kivymd/animation.py,sha256=UMkBmLxjTlgz_tPVYrAGYxPIgVWAshAZivwlX_t983Q,6361
kivymd/app.py,sha256=7As7g0jn_HnzRNDwPvulXGQtLd208x4Bm8dIeaRtEpE,4921
kivymd/dynamic_color.py,sha256=jjlCogPmF5nmNHZzg9eG2YKZkoGtPUgaMb67RD5KGNo,16408
kivymd/effects/__init__.py,sha256=ySU96kLlmPF4QB-hDa0WM_Y0Odq1MPSR568yI_hiaqI,24
kivymd/effects/__pycache__/__init__.cpython-311.pyc,,
kivymd/effects/stiffscroll/__init__.py,sha256=tkGDtFz6s7W3iFtHRDo6NYWadL85cn7GXKAQQfpiJRk,43
kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc,,
kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc,,
kivymd/effects/stiffscroll/stiffscroll.py,sha256=3bSj43xOzhBcBSn58iLUiaNWevlHuO8seklAyfvZsJE,7117
kivymd/factory_registers.py,sha256=MEdyWS0DPv8XnVbLEbygs_8pB0DHoNLPxLO56Qn9GX0,7775
kivymd/font_definitions.py,sha256=4WLZWIPY_hdCbY3a-8mPhL-0pmxMmWvBbzN9MDqRo4E,3774
kivymd/fonts/Roboto-Black.ttf,sha256=Ws4NCDOrg_8Y6pTkp3RfkZxFiuTqvCmCGCJt9CdczU0,168060
kivymd/fonts/Roboto-BlackItalic.ttf,sha256=iy-H-wj_S11i51PHUP4ykYE1hlAfoU3SWLGtC_ulM64,174108
kivymd/fonts/Roboto-Bold.ttf,sha256=7GhaRhBSlv5GyHRNpKEc-BGLpsEScZQXZvelRt9qp8c,167336
kivymd/fonts/Roboto-BoldItalic.ttf,sha256=Yd9Zf3PJHyOMvoj-PFNnAtEg0Ei3myX6D094GP0SOm8,171508
kivymd/fonts/Roboto-Italic.ttf,sha256=meSoUGETbpngUpKe0NheNjhPulw0t3MTmo9kM5xgmUM,170504
kivymd/fonts/Roboto-Light.ttf,sha256=xXbFBkInG82__-0E-S3I1qmB2vMAkU0KIMilpaVwFcc,167000
kivymd/fonts/Roboto-LightItalic.ttf,sha256=pIQGImhU00_plkKlJKQ7L9Jqfb7KgC1RAKipjSDhtz0,173172
kivymd/fonts/Roboto-Medium.ttf,sha256=nQ1VowO_0Tt5qHch9lGF6T8jXi13_jmLLcpnrFGZFfU,168644
kivymd/fonts/Roboto-MediumItalic.ttf,sha256=0_MXyX9AA4ksuWm8_OjePcnWf7-W_a-miy41lTF7DZQ,173416
kivymd/fonts/Roboto-Regular.ttf,sha256=ThR6tkuf322J0B9rjDygs83cWdYIqOIhj5olBLXJjhQ,168260
kivymd/fonts/Roboto-Thin.ttf,sha256=ZySPfoxu2zzn73Ow8ApTSn9CwRFs72POIbIDW16XmgY,168488
kivymd/fonts/Roboto-ThinItalic.ttf,sha256=KM4lGpnNV9AKmCJaj8tmtgtp2vELCUfH7E7VA8Iq_-8,172860
kivymd/fonts/materialdesignicons-webfont.ttf,sha256=YeirpaTpgf4iz3yOi82-oAR251xiw38Bv37jM2HWhCg,1307660
kivymd/icon_definitions.py,sha256=DAc0bD1hlaFBeIiHo5p2_HFzZHr7IUhBXC3t3SBRffQ,282946
kivymd/images/folder.png,sha256=xY9uUYegh7hDzFI4iPEA-zyFBzq9IE007zaJGGY5JY0,2311
kivymd/images/logo/kivymd-icon-128.png,sha256=VjWHaIJ-MSyP7ZnM25xgBfp_wG4vbQhr8B8QOTcXeaM,19826
kivymd/images/logo/kivymd-icon-256.png,sha256=5iJVryvz0D-IvqLGTsaeJlYhZYk2R7OxskKiNgw25Ks,31943
kivymd/images/logo/kivymd-icon-512.png,sha256=JAtfTEA7AWBPcMhFGqlwSQmQSq-lWAEJ8Y98qmDe0I0,54349
kivymd/images/transparent.png,sha256=yM2bydAM4U0tnbs4zAuK2GnCC6I6NgAIfpw7rQhG1BQ,156
kivymd/material_resources.py,sha256=XnkSLVe-kTAEmEl9QzJRV-qs5sgmXjKT-V5GY30KXjY,576
kivymd/theming.py,sha256=4dUslqibyGwEd9noplpmhGbH9daoGfdaqr-XlP55a-E,33018
kivymd/toast/__init__.py,sha256=AWk597R4COWhbrfiUSjceBpmeaVer3-f3-L4dHOCQEY,54
kivymd/toast/__pycache__/__init__.cpython-311.pyc,,
kivymd/toast/__pycache__/androidtoast.cpython-311.pyc,,
kivymd/toast/androidtoast.py,sha256=nPo0oay5MbILuwE36H4B_WtbMtAMSNtH89bCbZF0ULU,2361
kivymd/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/__pycache__/argument_parser.cpython-311.pyc,,
kivymd/tools/argument_parser.py,sha256=oxgJoS5WZH_ATDlaEU0HDtm7ve4DOJ23CnOILIBygy8,3193
kivymd/tools/hotreload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc,,
kivymd/tools/hotreload/app.py,sha256=cJxyUxz1GbQ58pgPY3GZNSl-CoawoPUPoCUF3lECltI,16803
kivymd/tools/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/packaging/pyinstaller/__init__.py,sha256=ibpoURJJkyGuSgWhz8t-RuLnCmQf15TiFNr-HKTCPHA,1480
kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc,,
kivymd/tools/packaging/pyinstaller/hook-kivymd.py,sha256=cN0arGlcA_vLA8FTaAdzKgn7s2YQRCclv7G0e4c4o-Y,1053
kivymd/tools/patterns/MVC/Model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc,,
kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc,,
kivymd/tools/patterns/MVC/Model/database_firebase.py,sha256=5SlPAn-ROkh_ytnv2nteaVRAMC0MUSDM9u115Crfh-o,1376
kivymd/tools/patterns/MVC/Model/database_restdb.py,sha256=Wc-zPffP-Wriyn-JGKCQrw3SGZMiAk-8LrVjParRtGM,3866
kivymd/tools/patterns/MVC/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/MVC/data/locales/po/en.po,sha256=1b2jIsEnyQi_T_gnpe5QeO90IdaQLwWClk5pn46ZjME,425
kivymd/tools/patterns/MVC/data/locales/po/ru.po,sha256=mQd6ol2abec-PUJsrnRWNoah0din3IAg_F4gPf5VBVw,425
kivymd/tools/patterns/MVC/libs/__init__.py,sha256=B6Kln9GZ6UrMOxr4lOnpTxGBMaoKlcar5wpyTGyUlIk,54
kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc,,
kivymd/tools/patterns/MVC/libs/translation.py,sha256=LiiMZUxVbAmUy71mVA-PyEkxwYrCAOcjeiDnlbCSPvQ,1411
kivymd/tools/patterns/MVC/messages.pot,sha256=2cutqkylhtiY07tkXzE8yNqpux9eeoW3tdeoEbXdB1Y,582
kivymd/tools/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc,,
kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc,,
kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc,,
kivymd/tools/patterns/add_view.py,sha256=4J41yOosi9KkNrMBI6h6yJ_0LoncdJzmJDy-iShaArk,6576
kivymd/tools/patterns/create_project.py,sha256=x3g37U3Dbk-ivUJ_aGgwvjpwBkyM4zIcPF3Bcyw1ASQ,39373
kivymd/uix/__init__.py,sha256=OP4CD9D1ezU3v3LGF0Yo91GIMIIJAUPMFSZNSLWdLOo,2793
kivymd/uix/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/boxlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/circularlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/floatlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/gridlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/hero.cpython-311.pyc,,
kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc,,
kivymd/uix/__pycache__/recycleview.cpython-311.pyc,,
kivymd/uix/__pycache__/relativelayout.cpython-311.pyc,,
kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc,,
kivymd/uix/__pycache__/screen.cpython-311.pyc,,
kivymd/uix/__pycache__/screenmanager.cpython-311.pyc,,
kivymd/uix/__pycache__/scrollview.cpython-311.pyc,,
kivymd/uix/__pycache__/stacklayout.cpython-311.pyc,,
kivymd/uix/__pycache__/widget.cpython-311.pyc,,
kivymd/uix/anchorlayout.py,sha256=K40IAwhpYiCemdh9jvOtTYF4IHnF3wdce3CjD6gXQy4,1365
kivymd/uix/appbar/__init__.py,sha256=rL3GwJPgu7s0GcKDYri7sDtIznAYaniO2B_UxVEWU7A,264
kivymd/uix/appbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/appbar/__pycache__/appbar.cpython-311.pyc,,
kivymd/uix/appbar/appbar.kv,sha256=EsSrZb-6aoYWc_kCZODw0EH6kzrTsbBESmRGv5ADzvU,2565
kivymd/uix/appbar/appbar.py,sha256=6dquqLBAOLaBkxiwG7RQKAFF7t1OjHkBm8U83EGnSqg,38722
kivymd/uix/badge/__init__.py,sha256=7CIBe8jXrxme7ankbSEmiPjT0EbJhPqawZHEcUa17mk,40
kivymd/uix/badge/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/badge/__pycache__/badge.cpython-311.pyc,,
kivymd/uix/badge/badge.kv,sha256=LW70SjdLKfULFydUYceLZCLE3ulJdjUI9DLOe5zo-Ck,545
kivymd/uix/badge/badge.py,sha256=3coq8IQq9St8t2lQOVA4gzu9ZEk3owPBCh4VdI-lnMk,1429
kivymd/uix/behaviors/__init__.py,sha256=VWDGd99o9hPc4Ej4nuQmuVk8P3jRU4D2iQGj9h3zUyo,745
kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/state_layer_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc,,
kivymd/uix/behaviors/backgroundcolor_behavior.py,sha256=wtIo7A8wBr562wc9MliDk3vLkQGl8MzOEnWT6E-Jiqg,5275
kivymd/uix/behaviors/declarative_behavior.py,sha256=E6vfUjq5QoVhm7pO5BKbWZrZjiLLq0wJ-lpKDi6mwgY,9776
kivymd/uix/behaviors/elevation.py,sha256=ybmb_IQnpLv2gZZWrEhvp5hwNxDkapdZ9IfQFD7ciFI,20274
kivymd/uix/behaviors/focus_behavior.py,sha256=lE84JzIeMGQyoRLYPt2z2OyaoNaJ6irKMUBhjzxKwa8,2865
kivymd/uix/behaviors/hover_behavior.py,sha256=4Dslyh8758uViHlpbJOWzOqF0I-XEdrfO-NbWbFxZ-k,7745
kivymd/uix/behaviors/magic_behavior.py,sha256=wwN40b_0NTG3Dopdhqt89PXYqY5mXSM4lY2xuIk1v9Q,4570
kivymd/uix/behaviors/motion_behavior.py,sha256=Jl7v9KM19gRjXQ5K-stwtj89udxn20pKRSbYjnFd1ek,13820
kivymd/uix/behaviors/ripple_behavior.py,sha256=o2Nl94jjd7HhH0b5kwEQcby1IAZT-gcjVaYTX6Vs4yg,16973
kivymd/uix/behaviors/rotate_behavior.py,sha256=Z8Ux_UwKZHoeu-cCl8hNc2EDVgC_hWni-ld8BpbL1uE,3268
kivymd/uix/behaviors/scale_behavior.py,sha256=2ONpA7LKW5UhNI-ibBLlyQtOP_xyHDkasNxmqLO-z_c,4062
kivymd/uix/behaviors/state_layer_behavior.py,sha256=vr_ZNA8ggVcqDIjNDHgsa66HqlzoO4BgNOQeF4CCrLI,22138
kivymd/uix/behaviors/stencil_behavior.py,sha256=yJtQY5Te-sa635lhz0pRwGGfyJeG5NtuzKpw3x1i8tw,3015
kivymd/uix/behaviors/toggle_behavior.py,sha256=9dcZhoFTDMYNEMY8vNn0_Ei9VMLzy1aHyu26RcAOxEs,8644
kivymd/uix/behaviors/touch_behavior.py,sha256=tOxMS2XyX-8o9romBRSqJJ-G0_Kp1P7mDXyylOC1t1U,2776
kivymd/uix/bottomsheet/__init__.py,sha256=_pvnNLykM_K6xdruglPD6BbAmq7jo2uXfLarsoehxeo,158
kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc,,
kivymd/uix/bottomsheet/bottomsheet.kv,sha256=bemuxX5ABIiWP1v_dddvTEGaVwCJO6tOB6xSlgSj_jU,1163
kivymd/uix/bottomsheet/bottomsheet.py,sha256=NBm4KJe4zPbdYHZ78jgxUj2YCjrJExd0Mdmq9sYys2E,12793
kivymd/uix/boxlayout.py,sha256=KKONYwmEON79f2c6TLCxN4KNDj7E9yvuXs2oT5vEiMc,2031
kivymd/uix/button/__init__.py,sha256=YhX34jdEnmi9kDofnQXg5v3H1NJWC_uX10f5fOmMFuo,239
kivymd/uix/button/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/button/__pycache__/button.cpython-311.pyc,,
kivymd/uix/button/button.kv,sha256=0dJtZ_6IzOXbmHsBCDG64-OawofWV1okG1-eWP5nwQk,13278
kivymd/uix/button/button.py,sha256=D7Rg3a4nT6zEJIZ6QONTigHfukAyQX8Ly1CuZ6tVINU,32731
kivymd/uix/card/__init__.py,sha256=hjAO06DlaWnFP_wYQC5ZFMR4lobKDY0aztACZCvWgd8,113
kivymd/uix/card/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/card/__pycache__/card.cpython-311.pyc,,
kivymd/uix/card/card.kv,sha256=DZMWfl8xWTrWaZ35miD23vBNtl5g_86QY3tv3mMyGdo,2926
kivymd/uix/card/card.py,sha256=vdewoU57GGQDC5JjPsd3Z8Xy5aCKRtX_sEpYbpU7kig,27567
kivymd/uix/chip/__init__.py,sha256=1uvEh6w800aZE4KV-LA6xch01o8Netw-h8N3Wy4Jb6E,135
kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/chip/__pycache__/chip.cpython-311.pyc,,
kivymd/uix/chip/chip.kv,sha256=WUigEnF_XgGmwpv-5OUxaMY8LRZeXWxD4Ew36tk0JHI,3445
kivymd/uix/chip/chip.py,sha256=n5-qQWzqXr6-eTGavpU7apsgX7WdsSnAP2MhKQ_6DyA,35420
kivymd/uix/circularlayout.py,sha256=S5Z4R2Z7ENwSoDB-UqWjOl0lCoemTessK_C4KT3jru8,5407
kivymd/uix/controllers/__init__.py,sha256=WNbi76mp899CTLeSZUnVJ0b5gSeUMJ9ganvmhEcNR40,231
kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc,,
kivymd/uix/controllers/windowcontroller.py,sha256=msVZQJwaekkIw4XUECXWAMOAsXw5NkFe38xIel1wG84,2335
kivymd/uix/dialog/__init__.py,sha256=6dLZqaNu832pAEUyZBrEU6BdQ46SSOx9LI8jOMsnHD4,182
kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc,,
kivymd/uix/dialog/dialog.kv,sha256=cLK7ZK50QwBmT73D3WgjnGbGGQ0BLrkQ8VHYmwFLFVA,2958
kivymd/uix/dialog/dialog.py,sha256=iAr3ur0C0afToFtVXYSVpJrswIn6LX5_0IHZXaiobQI,18598
kivymd/uix/divider/__init__.py,sha256=p52N9PonSJQ90tycWEJRDRpk8-D5R-ClBX0NN3xycl0,44
kivymd/uix/divider/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/divider/__pycache__/divider.cpython-311.pyc,,
kivymd/uix/divider/divider.kv,sha256=hn-zA8BMGFadxbyojHmC07pvge-TLSxF0VCv2sMPizE,250
kivymd/uix/divider/divider.py,sha256=GRPGVGjSQEaIefqehWO5untZom69GD-OgIAaGd7srhY,3702
kivymd/uix/dropdownitem/__init__.py,sha256=e4eaF7uU5hU119DKcnTkj2hC-DtQoJ5gpx4n-EilUvI,74
kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc,,
kivymd/uix/dropdownitem/dropdownitem.kv,sha256=7ZljjTLoW__Fixl4jPTJG96upstMIfRxijwFLmbsWvc,1180
kivymd/uix/dropdownitem/dropdownitem.py,sha256=6uneYSSjErpJSYaFnjGMNsOodt8c0VIs8OlZyKzRZkg,4773
kivymd/uix/expansionpanel/__init__.py,sha256=OFJC5zK9iAI9doEVtptYDVPRuCQ2WTqd8LjScXQetEA,123
kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc,,
kivymd/uix/expansionpanel/expansionpanel.kv,sha256=vK3HR_n4ihGzD-lRSV5Y_RKRdk5a151YjUr7QlClK78,279
kivymd/uix/expansionpanel/expansionpanel.py,sha256=9KwYGUFkpZGdLrnHZ2YsVovDzDE9vwqRlHnffRT8dzo,14722
kivymd/uix/filemanager/__init__.py,sha256=TR0eAXbR-lzZUQLiVcGcVp5D1myeiLoXGpSWZitrWKI,52
kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc,,
kivymd/uix/filemanager/filemanager.kv,sha256=chfHadHr34MRk_UAuqPv9MOWLFhV_Ne84XfqL-NQF0I,2550
kivymd/uix/filemanager/filemanager.py,sha256=Bsd_iFa2Yk_1JsW6rgobOOV2jOZDORrV5d5Y8IO9FWY,25902
kivymd/uix/fitimage/__init__.py,sha256=BVf16byn839UfzikgsfJj_s5xH0PjGgU9gUuetb1dsU,44
kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc,,
kivymd/uix/fitimage/fitimage.py,sha256=r364DXB21psGT2Mw8MIDZtXYgTbujb0ya6b5t5PD1jA,3250
kivymd/uix/floatlayout.py,sha256=QfF_RcIiG7ITlKfxvsmcW0gy97fXdk5BmVVyvAqibpg,1541
kivymd/uix/gridlayout.py,sha256=HJCj1dEvIXwJj0tOK9lWNgovFYMMUAmtf5-SZO9__f8,2013
kivymd/uix/hero.py,sha256=Pkdo1qCbwQnErS8zExJBOO23pM2TM56UaKgaftGwCq8,18420
kivymd/uix/imagelist/__init__.py,sha256=VgCXsVvUFA9yfBpB3cEwLWqQR0_s6um2SMohe0wTcv4,111
kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc,,
kivymd/uix/imagelist/imagelist.kv,sha256=ukH2JEHvszq165W2Joylu7HoVl3pKYqMd7xhk_YWR54,1052
kivymd/uix/imagelist/imagelist.py,sha256=hfJphayTAaVMQ-2BQsq5I3u8Tvyzm4ka_yNfNmAlRBg,7010
kivymd/uix/label/__init__.py,sha256=DHLIPzLH5Uq0ChimIQIUVHQ42iAilC-F2xYzWqeqiXY,48
kivymd/uix/label/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/label/__pycache__/label.cpython-311.pyc,,
kivymd/uix/label/label.kv,sha256=wCK0divTBiNdEqsDlxLAWStH69MYIDiLqiVZw9wg9fA,1323
kivymd/uix/label/label.py,sha256=cQVTn_ArbRQsoPXMq-tgDP99ebU05oF4fILP-TQZPoc,26088
kivymd/uix/list/__init__.py,sha256=JQbupFYB2E24FxZaz4y94ImASKQfS1eGrZPdfEpJ4-E,364
kivymd/uix/list/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/list/__pycache__/list.cpython-311.pyc,,
kivymd/uix/list/list.kv,sha256=T7A3DeE6Vcsba2UacXMPPck2OBo2Kxzp7OOWPt1GjoI,4563
kivymd/uix/list/list.py,sha256=koECDdLVSW1gluCNYT-VEST8N3fV6Y-jkAenKQ8fWXs,16560
kivymd/uix/menu/__init__.py,sha256=2a7cHJKvQmKiqu4_YWWQMF96owFFkRiMnEPX2R_kMbA,46
kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/menu/__pycache__/menu.cpython-311.pyc,,
kivymd/uix/menu/menu.kv,sha256=f35OBRCv2GiFoIoQsmJiD5OO6HJBMtWvtGFG8l7Njks,13637
kivymd/uix/menu/menu.py,sha256=s5ykbqIKmZokiYRCbNsPImOrPxulVxuQnmOxEjl-sr8,40145
kivymd/uix/navigationbar/__init__.py,sha256=a30ldn9-lWqS5o8UjCD2T2bUF95jRiC-yKF_r3KqXOs,139
kivymd/uix/navigationbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/navigationbar/__pycache__/navigationbar.cpython-311.pyc,,
kivymd/uix/navigationbar/navigationbar.kv,sha256=-yaGGm2VOpgyAhvTtRNQD5rVKRuga9ZaADtbPgj-9SA,4035
kivymd/uix/navigationbar/navigationbar.py,sha256=NCULciX76Vbe6DkQnWXhcDmRb8zvoaMGpdt9h07CgSQ,17122
kivymd/uix/navigationdrawer/__init__.py,sha256=JNRnAbxuu0x2Xb8oO7lwBjKwKnYn2grJo_RZBcvBEIA,351
kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc,,
kivymd/uix/navigationdrawer/navigationdrawer.kv,sha256=R6xE6aRpthfbeEfUm62pvnWRBA7uE-Za_mNa--H9JpA,2031
kivymd/uix/navigationdrawer/navigationdrawer.py,sha256=gxkX3v9U5LCQXZLRPjcXJLoz_bUd-fTbP-M2H2qQCGM,38521
kivymd/uix/navigationrail/__init__.py,sha256=1fQMqMVg-A3g6ZOFOrX-adJd8k9R7Xe5kijzq_U3Ksw,216
kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc,,
kivymd/uix/navigationrail/navigationrail.kv,sha256=fMPYmHmNdS3WnSl2zpaxSuQMbLwg01YRU_3MbTh5eMs,2935
kivymd/uix/navigationrail/navigationrail.py,sha256=MDMM8pdO5oGvH1gVGG4T2sLsz9lIWnrfR1C4qQe6Zsw,22302
kivymd/uix/pickers/__init__.py,sha256=mhnmC4YAXu71eD90YcUe_l9kuMXUjHKALTFG6GdvtZM,242
kivymd/uix/pickers/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/pickers/datepicker/__init__.py,sha256=gXQyrdPWJP9UxOwZ8VWuXZn8FB6S2AYnhl0FmAhI8Pc,116
kivymd/uix/pickers/datepicker/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/pickers/datepicker/__pycache__/datepicker.cpython-311.pyc,,
kivymd/uix/pickers/datepicker/datepicker.kv,sha256=ZyWURj3ZzJ1Vb0-Fr4nI33sJQSLS2gAsjanoVHYBD5I,11736
kivymd/uix/pickers/datepicker/datepicker.py,sha256=bYMdgC533VJdkR9vFVHM8mkyUyOrnUwbi7YvywR4hIs,60382
kivymd/uix/pickers/timepicker/__init__.py,sha256=SBtSeGRb0VrrQgzFUGZxl0tQRwmUjKw5jpLhg371tNc,126
kivymd/uix/pickers/timepicker/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/pickers/timepicker/__pycache__/timepicker.cpython-311.pyc,,
kivymd/uix/pickers/timepicker/timepicker.kv,sha256=xXlxSukPBj9L05B2hP-IdxEAvI3_O0hmuMQttlyCWGc,11334
kivymd/uix/pickers/timepicker/timepicker.py,sha256=k6kbkVFug5fY_IN98j9YGWtewSsztqIVYa8zbQo51wY,38753
kivymd/uix/progressindicator/__init__.py,sha256=dA8bwUMDtdx1CglUx3R73Xz6j9uUiiZT6qVphrx9me8,112
kivymd/uix/progressindicator/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/progressindicator/__pycache__/progressindicator.cpython-311.pyc,,
kivymd/uix/progressindicator/progressindicator.kv,sha256=3XXvaGnEXAYpAFgQGE8gR3VGnYNYHapx827RBFtViDE,2221
kivymd/uix/progressindicator/progressindicator.py,sha256=nuzNdqp1yGaQ6R80OQlYgXiYl42IPIRC2lRT9s1bwjw,18195
kivymd/uix/recyclegridlayout.py,sha256=I399c4gsmyHAedTU1Biwd7QRYG60QJ-gx33WVct7CCc,2140
kivymd/uix/recycleview.py,sha256=FVhr4SI0wjbQy08q68nDjh-Mqsdg6nfjwONZfHTBctY,1348
kivymd/uix/refreshlayout/__init__.py,sha256=r6yH7AYvn831mRtdu6KN_p4L42JBJh2qKpNIuHyckao,66
kivymd/uix/refreshlayout/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/refreshlayout/__pycache__/refreshlayout.cpython-311.pyc,,
kivymd/uix/refreshlayout/refreshlayout.kv,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/uix/refreshlayout/refreshlayout.py,sha256=lHL1nGOpHWiPqjD7r0dkSabhR6d_Qzis7xtuhpr8RjA,9638
kivymd/uix/relativelayout.py,sha256=9ewM64QYa1PI_-yBWo5d6mY5PfWudJ5gYu94q9OYEm8,1434
kivymd/uix/responsivelayout.py,sha256=N1GMNejHlNssk8ZpC9kMuZELuWywUs9Dms_AzHcpU1Q,5409
kivymd/uix/screen.py,sha256=MgpjK_06QR66Zr4qdxfyiW3ACcaRHclBu-vGsep9Xuo,2625
kivymd/uix/screenmanager.py,sha256=gSccPZXnmadWd6ueyl9jXXZK4vpUNgEaw0iHVBd262s,5549
kivymd/uix/scrollview.py,sha256=jeE7XEi8AIigV_BAL-uUOzACu1hEwrTg0FrpabexNok,10744
kivymd/uix/segmentedbutton/__init__.py,sha256=4xtmjrtfPcihaUtek7R5GXm6ltBYdyY6vz7UokAM1hY,147
kivymd/uix/segmentedbutton/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/segmentedbutton/__pycache__/segmentedbutton.cpython-311.pyc,,
kivymd/uix/segmentedbutton/segmentedbutton.kv,sha256=JjfYB1naUJjHn8_quYhjnA8rgHH552eeoCLJb6JegRs,3468
kivymd/uix/segmentedbutton/segmentedbutton.py,sha256=WaZ5DBY-7bmKdoclIl6W7q_ZN7ZgmKnPcJ75TbKiwng,22680
kivymd/uix/selectioncontrol/__init__.py,sha256=n1yw1X7ccriTWj1GPN-V9LvFXgxuFNfEy6uRHPyhQGA,71
kivymd/uix/selectioncontrol/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/selectioncontrol/__pycache__/selectioncontrol.cpython-311.pyc,,
kivymd/uix/selectioncontrol/selectioncontrol.kv,sha256=RylxUp5CUsYur5Md_kzX76tcy93rwbfcrOr_eMy9HuQ,5311
kivymd/uix/selectioncontrol/selectioncontrol.py,sha256=mIgPK-LLcm4We5LfJ8vv2Ue6uuLQ-biiy0EkN5ZXJQQ,24706
kivymd/uix/slider/__init__.py,sha256=f2N0xMmmO7e9aNdxn0vDqKRgpMIV8EScrsRl71OG1yU,78
kivymd/uix/slider/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/slider/__pycache__/slider.cpython-311.pyc,,
kivymd/uix/slider/slider.kv,sha256=ydvIp5T2Htrh7Q2YMb2joStz8FVKENTnREmh6FcdVuk,7066
kivymd/uix/slider/slider.py,sha256=DuuUi_jEpU8c5cyNmjZ5ZeKV4wU-sqNuyicWDOW8f28,17486
kivymd/uix/sliverappbar/__init__.py,sha256=axuqy95RR0oDLXpBtH3EauoTZN56p6EAp3JFBC-MoYI,103
kivymd/uix/sliverappbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/sliverappbar/__pycache__/sliverappbar.cpython-311.pyc,,
kivymd/uix/sliverappbar/sliverappbar.kv,sha256=jcGxg6SQqadnGHJVJ6S1U6MmwDwALuJ1dGV6Ra651YU,1370
kivymd/uix/sliverappbar/sliverappbar.py,sha256=Usg3jZdwnaUwO-f2YycHVl9qJIkB29QLtURi0W2_OuA,11439
kivymd/uix/snackbar/__init__.py,sha256=wP0ppgJbwiGlR3HEMdTo5Umbkq5xeCMkmmJI8ohv8lU,223
kivymd/uix/snackbar/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/snackbar/__pycache__/snackbar.cpython-311.pyc,,
kivymd/uix/snackbar/snackbar.kv,sha256=JSszxvKOLOGvX3KR5DRekgPVRx8yqEq9BXwgRhbeqno,1836
kivymd/uix/snackbar/snackbar.py,sha256=Li_UxO9IkrAf29Rkq1vFyoIr9CzVRm-HsFb46Z1ciTg,11746
kivymd/uix/stacklayout.py,sha256=UDmj4W66Js16Y_RaHRA3WzXz1lBVwvhhtZkIIhQYfco,2067
kivymd/uix/swiper/__init__.py,sha256=yjVyswA0HfoLRx9UW7k_GR497shvH5EthBbQk8CoU_4,43
kivymd/uix/swiper/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/swiper/__pycache__/swiper.cpython-311.pyc,,
kivymd/uix/swiper/swiper.kv,sha256=iTaioAm-1WWmrGV4mqTizz3f4Qobv8WJZT-cwhEqyD0,291
kivymd/uix/swiper/swiper.py,sha256=lG0_lK1TIfIIz5jkrSnQS67ecA9_Ty6DbwcTXN9olck,12618
kivymd/uix/tab/__init__.py,sha256=Cr-a9CGP8XGLa7QkvU08OpIS1mXu2-o_8V2CONFH1fE,192
kivymd/uix/tab/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/tab/__pycache__/tab.cpython-311.pyc,,
kivymd/uix/tab/tab.kv,sha256=ZBRG7PYPNPuI8pwfw7RNHI5wYgDP_oNPnZLzR4B_pMc,2255
kivymd/uix/tab/tab.py,sha256=GTbl_ONS94t4-Lyb3tg5UXG6plx_t3QjDDZCxZtYyRQ,41727
kivymd/uix/textfield/__init__.py,sha256=q0cpSrgMsws4Csqjz1xv-OCiiFkSstO9P1Vxi6H3sTo,195
kivymd/uix/textfield/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/textfield/__pycache__/textfield.cpython-311.pyc,,
kivymd/uix/textfield/textfield.kv,sha256=Yu3KxUoBhim0ZI-7if-dY4HI0ZqhPA7mUHyLW7M4obo,13507
kivymd/uix/textfield/textfield.py,sha256=G0freQCtBynqyvvfYrkqFg3tqfFyAOHla119eFworC0,60112
kivymd/uix/tooltip/__init__.py,sha256=QPH-5XUDaiDQm6TO5gKyE7lUveO7F4Y4ZiWOfZkxD08,182
kivymd/uix/tooltip/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/tooltip/__pycache__/tooltip.cpython-311.pyc,,
kivymd/uix/tooltip/tooltip.kv,sha256=gdM-7qQFuTcS-OXzsd6MgFZEalzgx_4wq5azAy1MxoM,2012
kivymd/uix/tooltip/tooltip.py,sha256=I7UbwBjgaXQQJAsbYsSRZA3kskhZaOilUxav4akYfAM,14636
kivymd/uix/transition/__init__.py,sha256=Akw-XkRM_JWV17J_SkneutkxlsKZZKqAEkCA4Rd8XYQ,141
kivymd/uix/transition/__pycache__/__init__.cpython-311.pyc,,
kivymd/uix/transition/__pycache__/transition.cpython-311.pyc,,
kivymd/uix/transition/transition.py,sha256=6uWH24w6ZUK4abdQrc1ZuQqbOem9j_coS0zH16KvR-Q,17974
kivymd/uix/widget.py,sha256=tR6SyGcoofexLHh_P9YUI7qcYrbHEzOkPwWQhpMoRJ4,1457
kivymd/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
kivymd/utils/__pycache__/__init__.cpython-311.pyc,,
kivymd/utils/__pycache__/fpsmonitor.cpython-311.pyc,,
kivymd/utils/__pycache__/set_bars_colors.cpython-311.pyc,,
kivymd/utils/fpsmonitor.py,sha256=F1g2HqSr1QH2_SIoQReesMSMmyRj5YJxolBGlK1Tgs8,1514
kivymd/utils/set_bars_colors.py,sha256=uhCQdrRhRW-P--5D5MJR6rcauOA8wmiFoapJJczkf14,4050

View File

@ -1,5 +1,5 @@
Wheel-Version: 1.0
Generator: setuptools (74.1.2)
Generator: setuptools (74.1.3)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -0,0 +1 @@
{"archive_info": {}, "url": "https://github.com/kivymd/KivyMD/archive/master.zip"}

View File

@ -26,12 +26,10 @@ import os
import kivy
from kivy.logger import Logger
__version__ = "1.2.0"
"""KivyMD version."""
from kivymd._version import __version__, release
release = False
if "READTHEDOCS" not in os.environ:
kivy.require("2.2.0")
kivy.require("2.3.0")
try:
from kivymd._version import __date__, __hash__, __short_hash__
@ -59,13 +57,8 @@ _log_message = (
+ f' (installed at "{__file__}")'
)
Logger.info(_log_message)
Logger.warning(
"KivyMD: "
"Version 1.2.0 is deprecated and is no longer supported. "
"Use KivyMD version 2.0.0 from the master branch "
"(pip install https://github.com/kivymd/KivyMD/archive/master.zip)"
)
import kivymd.factory_registers # NOQA
import kivymd.font_definitions # NOQA
import kivymd.animation # NOQA
from kivymd.tools.packaging.pyinstaller import hooks_path # NOQA

View File

@ -1,5 +1,5 @@
# THIS FILE IS GENERATED FROM KIVYMD SETUP.PY
__version__ = '1.2.0'
__hash__ = 'Unknown'
__short_hash__ = 'Unknown'
__date__ = '2024-09-15'
release = False
__version__ = "2.0.1.dev0"
__hash__ = "Unknown"
__short_hash__ = "Unknown"
__date__ = "2024-09-15"

View File

@ -0,0 +1,224 @@
"""
Animation
=========
.. versionadded:: 2.0.0
Adds new transitions to the :class:`~kivy.animation.AnimationTransition` class:
- "easing_standard"
- "easing_decelerated"
- "easing_accelerated"
- "easing_linear"
.. code-block:: python
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.metrics import dp
from kivy.properties import ListProperty
from kivymd.app import MDApp
class AnimBox(BoxLayout):
obj_pos = ListProperty([0, 0])
UI = '''
<AnimBox>:
transition:"in_out_bounce"
size_hint_y:None
height:dp(100)
obj_pos:[dp(40), self.pos[-1] + dp(40)]
canvas:
Color:
rgba:app.theme_cls.primaryContainerColor
Rectangle:
size:[self.size[0], dp(5)]
pos:self.pos[0], self.pos[-1] + dp(50)
Color:
rgba:app.theme_cls.primaryColor
Rectangle:
size:[dp(30)] * 2
pos:root.obj_pos
MDLabel:
adaptive_height:True
text:root.transition
padding:[dp(10), 0]
halign:"center"
MDGridLayout:
orientation:"lr-tb"
cols:1
md_bg_color:app.theme_cls.backgroundColor
spacing:dp(10)
'''
class MotionApp(MDApp):
def build(self):
return Builder.load_string(UI)
def on_start(self):
for transition in [
"easing_linear",
"easing_accelerated",
"easing_decelerated",
"easing_standard",
"in_out_cubic"
]: # Add more here for comparison
print(transition)
widget = AnimBox()
widget.transition = transition
self.root.add_widget(widget)
Clock.schedule_once(self.run_animation, 1)
_inverse = True
def run_animation(self, dt):
x = (self.root.children[0].width - dp(30)) if self._inverse else 0
for widget in self.root.children:
Animation(
obj_pos=[x, widget.obj_pos[-1]], t=widget.transition, d=3
).start(widget)
self._inverse = not self._inverse
Clock.schedule_once(self.run_animation, 3.1)
MotionApp().run()
.. image:: https://github.com/kivymd/KivyMD/assets/68729523/21c847b0-284a-4796-b704-e4a2531fbb1b
:align: center
"""
import math
import sys
import kivy.animation
float_epsilon = 8.3446500e-7
if sys.version_info < (3, 11):
cbrt = lambda number: (abs(number) ** (1/3)) * (-1 if number < 0 else 1)
else:
cbrt = math.cbrt
class CubicBezier:
"""Ported from Android source code"""
p0 = 0
p1 = 0
p2 = 0
p3 = 0
def __init__(self, *args):
self.p0, self.p1, self.p2, self.p3 = args
def evaluate_cubic(self, p1, p2, t):
a = 1.0 / 3.0 + (p1 - p2)
b = p2 - 2.0 * p1
c = p1
return 3.0 * ((a * t + b) * t + c) * t
def clamp_range(self, r):
if r < 0.0:
if -float_epsilon <= r < 0.0:
return 0.0
else:
return math.nan
elif r > 1.0:
if 1.0 <= r <= 1.0 + float_epsilon:
return 1.0
else:
return math.nan
else:
return r
def close_to(self, x, y):
return abs(x - y) < float_epsilon
def find_first_cubic_root(self, p0, p1, p2, p3):
a = 3.0 * (p0 - 2.0 * p1 + p2)
b = 3.0 * (p1 - p0)
c = p0
d = -p0 + 3.0 * (p1 - p2) + p3
if self.close_to(d, 0.0):
if self.close_to(a, 0.0):
if self.close_to(b, 0.0):
return math.nan
return self.clamp_range(-c / b)
else:
q = math.sqrt(b * b - 4.0 * a * c)
a2 = 2.0 * a
root = self.clamp_range((q - b) / a2)
if not math.isnan(root):
return root
return self.clamp_range((-b - q) / a2)
a /= d
b /= d
c /= d
o3 = (3.0 * b - a * a) / 9.0
q2 = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0
discriminant = q2 * q2 + o3 * o3 * o3
a3 = a / 3.0
if discriminant < 0.0:
mp33 = -(o3 * o3 * o3)
r = math.sqrt(mp33)
t = -q2 / r
cos_phi = max(-1.0, min(t, 1.0))
phi = math.acos(cos_phi)
t1 = 2.0 * cbrt(r)
root = self.clamp_range(t1 * math.cos(phi / 3.0) - a3)
if not math.isnan(root):
return root
root = self.clamp_range(
t1 * math.cos((phi + 2.0 * math.pi) / 3.0) - a3
)
if not math.isnan(root):
return root
return self.clamp_range(
t1 * math.cos((phi + 4.0 * math.pi) / 3.0) - a3
)
elif self.close_to(discriminant, 0.0):
u1 = -cbrt(q2)
root = self.clamp_range(2.0 * u1 - a3)
if not math.isnan(root):
return root
return self.clamp_range(-u1 - a3)
sd = math.sqrt(discriminant)
u1 = cbrt(-q2 + sd)
v1 = cbrt(q2 + sd)
return self.clamp_range(u1 - v1 - a3)
def t(self, value: float):
return self.evaluate_cubic(
self.p1,
self.p3,
self.find_first_cubic_root(
-value,
self.p0 - value,
self.p2 - value,
1.0 - value,
),
)
class MDAnimationTransition(kivy.animation.AnimationTransition):
"""KivyMD's equivalent of kivy's `AnimationTransition`"""
easing_standard = CubicBezier(0.4, 0.0, 0.2, 1.0).t
easing_decelerated = CubicBezier(0.0, 0.0, 0.2, 1.0).t
easing_accelerated = CubicBezier(0.4, 0.0, 1.0, 1.0).t
easing_linear = CubicBezier(0.0, 0.0, 1.0, 1.0).t
# TODO: add `easing_emphasized` here
# it's defination is
# path(M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1)
# Monkey patch kivy's animation module
kivy.animation.AnimationTransition = MDAnimationTransition

View File

@ -3,14 +3,15 @@ Themes/Material App
===================
This module contains :class:`MDApp` class that is inherited from
:class:`~kivy.app.App`. :class:`MDApp` has some properties needed for ``KivyMD``
library (like :attr:`~MDApp.theme_cls`). You can turn on the monitor displaying
the current ``FPS`` value in your application:
:class:`~kivy.app.App`. :class:`MDApp` has some properties needed for `KivyMD`
library (like :attr:`~MDApp.theme_cls`). You can turn on the monitor
displaying the current `FP` value in your application:
.. code-block:: python
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
MDLabel:
text: "Hello, World!"
@ -32,10 +33,23 @@ the current ``FPS`` value in your application:
MainApp().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fps-monitor.png
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fps-monitor-dark.png
:width: 350 px
:align: center
.. note::
Note that if you override the built-in on_start method, you will
definitely need to call the super method:
.. code-block:: python
class MainApp(MDApp):
def build(self):
[...]
def on_start(self):
[...]
"""
__all__ = ("MDApp",)
@ -55,7 +69,12 @@ class FpsMonitoring:
"""Implements a monitor to display the current FPS in the toolbar."""
def fps_monitor_start(self, anchor: str = "top") -> None:
"""Adds a monitor to the main application window."""
"""
Adds a monitor to the main application window.
:type anchor: str;
:param anchor: anchor FPS panel ('top' or 'bottom');
"""
def add_monitor(*args):
from kivy.core.window import Window
@ -114,6 +133,14 @@ class MDApp(App, FpsMonitoring):
super().__init__(**kwargs)
self.theme_cls = ThemeManager()
def _run_prepare(self):
self.theme_cls.bind(
theme_style=self.theme_cls.update_theme_colors,
primary_palette=self.theme_cls.set_colors
)
self.theme_cls.set_colors()
super()._run_prepare()
def load_all_kv_files(self, path_to_directory: str) -> None:
"""
Recursively loads KV files from the selected directory.
@ -128,8 +155,8 @@ class MDApp(App, FpsMonitoring):
if "kivymd" in path_to_directory:
Logger.critical(
"KivyMD: "
"Do not use the word 'kivymd' in the name of the directory "
"from where you download KV files"
"Do not use the word 'kivymd' in the name of the "
"directory from where you download KV files"
)
if (
"venv" in path_to_dir

View File

@ -1,954 +0,0 @@
"""
Themes/Color Definitions
========================
.. seealso::
`Material Design spec, The color system <https://material.io/design/color/the-color-system.html>`_
`Material Design spec, The color tool <https://material.io/resources/color/#!/?view.left=0&view.right=0>`_
Material colors palette to use in :class:`kivymd.theming.ThemeManager`.
:data:`~colors` is a dict-in-dict where the first key is a value from
:data:`~palette` and the second key is a value from :data:`~hue`. Color is a hex
value, a string of 6 characters (0-9, A-F) written in uppercase.
For example, ``colors["Red"]["900"]`` is ``"B71C1C"``.
"""
colors = {
"Red": {
"50": "FFEBEE",
"100": "FFCDD2",
"200": "EF9A9A",
"300": "E57373",
"400": "EF5350",
"500": "F44336",
"600": "E53935",
"700": "D32F2F",
"800": "C62828",
"900": "B71C1C",
"A100": "FF8A80",
"A200": "FF5252",
"A400": "FF1744",
"A700": "D50000",
},
"Pink": {
"50": "FCE4EC",
"100": "F8BBD0",
"200": "F48FB1",
"300": "F06292",
"400": "EC407A",
"500": "E91E63",
"600": "D81B60",
"700": "C2185B",
"800": "AD1457",
"900": "880E4F",
"A100": "FF80AB",
"A200": "FF4081",
"A400": "F50057",
"A700": "C51162",
},
"Purple": {
"50": "F3E5F5",
"100": "E1BEE7",
"200": "CE93D8",
"300": "BA68C8",
"400": "AB47BC",
"500": "9C27B0",
"600": "8E24AA",
"700": "7B1FA2",
"800": "6A1B9A",
"900": "4A148C",
"A100": "EA80FC",
"A200": "E040FB",
"A400": "D500F9",
"A700": "AA00FF",
},
"DeepPurple": {
"50": "EDE7F6",
"100": "D1C4E9",
"200": "B39DDB",
"300": "9575CD",
"400": "7E57C2",
"500": "673AB7",
"600": "5E35B1",
"700": "512DA8",
"800": "4527A0",
"900": "311B92",
"A100": "B388FF",
"A200": "7C4DFF",
"A400": "651FFF",
"A700": "6200EA",
},
"Indigo": {
"50": "E8EAF6",
"100": "C5CAE9",
"200": "9FA8DA",
"300": "7986CB",
"400": "5C6BC0",
"500": "3F51B5",
"600": "3949AB",
"700": "303F9F",
"800": "283593",
"900": "1A237E",
"A100": "8C9EFF",
"A200": "536DFE",
"A400": "3D5AFE",
"A700": "304FFE",
},
"Blue": {
"50": "E3F2FD",
"100": "BBDEFB",
"200": "90CAF9",
"300": "64B5F6",
"400": "42A5F5",
"500": "2196F3",
"600": "1E88E5",
"700": "1976D2",
"800": "1565C0",
"900": "0D47A1",
"A100": "82B1FF",
"A200": "448AFF",
"A400": "2979FF",
"A700": "2962FF",
},
"LightBlue": {
"50": "E1F5FE",
"100": "B3E5FC",
"200": "81D4FA",
"300": "4FC3F7",
"400": "29B6F6",
"500": "03A9F4",
"600": "039BE5",
"700": "0288D1",
"800": "0277BD",
"900": "01579B",
"A100": "80D8FF",
"A200": "40C4FF",
"A400": "00B0FF",
"A700": "0091EA",
},
"Cyan": {
"50": "E0F7FA",
"100": "B2EBF2",
"200": "80DEEA",
"300": "4DD0E1",
"400": "26C6DA",
"500": "00BCD4",
"600": "00ACC1",
"700": "0097A7",
"800": "00838F",
"900": "006064",
"A100": "84FFFF",
"A200": "18FFFF",
"A400": "00E5FF",
"A700": "00B8D4",
},
"Teal": {
"50": "E0F2F1",
"100": "B2DFDB",
"200": "80CBC4",
"300": "4DB6AC",
"400": "26A69A",
"500": "009688",
"600": "00897B",
"700": "00796B",
"800": "00695C",
"900": "004D40",
"A100": "A7FFEB",
"A200": "64FFDA",
"A400": "1DE9B6",
"A700": "00BFA5",
},
"Green": {
"50": "E8F5E9",
"100": "C8E6C9",
"200": "A5D6A7",
"300": "81C784",
"400": "66BB6A",
"500": "4CAF50",
"600": "43A047",
"700": "388E3C",
"800": "2E7D32",
"900": "1B5E20",
"A100": "B9F6CA",
"A200": "69F0AE",
"A400": "00E676",
"A700": "00C853",
},
"LightGreen": {
"50": "F1F8E9",
"100": "DCEDC8",
"200": "C5E1A5",
"300": "AED581",
"400": "9CCC65",
"500": "8BC34A",
"600": "7CB342",
"700": "689F38",
"800": "558B2F",
"900": "33691E",
"A100": "CCFF90",
"A200": "B2FF59",
"A400": "76FF03",
"A700": "64DD17",
},
"Lime": {
"50": "F9FBE7",
"100": "F0F4C3",
"200": "E6EE9C",
"300": "DCE775",
"400": "D4E157",
"500": "CDDC39",
"600": "C0CA33",
"700": "AFB42B",
"800": "9E9D24",
"900": "827717",
"A100": "F4FF81",
"A200": "EEFF41",
"A400": "C6FF00",
"A700": "AEEA00",
},
"Yellow": {
"50": "FFFDE7",
"100": "FFF9C4",
"200": "FFF59D",
"300": "FFF176",
"400": "FFEE58",
"500": "FFEB3B",
"600": "FDD835",
"700": "FBC02D",
"800": "F9A825",
"900": "F57F17",
"A100": "FFFF8D",
"A200": "FFFF00",
"A400": "FFEA00",
"A700": "FFD600",
},
"Amber": {
"50": "FFF8E1",
"100": "FFECB3",
"200": "FFE082",
"300": "FFD54F",
"400": "FFCA28",
"500": "FFC107",
"600": "FFB300",
"700": "FFA000",
"800": "FF8F00",
"900": "FF6F00",
"A100": "FFE57F",
"A200": "FFD740",
"A400": "FFC400",
"A700": "FFAB00",
},
"Orange": {
"50": "FFF3E0",
"100": "FFE0B2",
"200": "FFCC80",
"300": "FFB74D",
"400": "FFA726",
"500": "FF9800",
"600": "FB8C00",
"700": "F57C00",
"800": "EF6C00",
"900": "E65100",
"A100": "FFD180",
"A200": "FFAB40",
"A400": "FF9100",
"A700": "FF6D00",
},
"DeepOrange": {
"50": "FBE9E7",
"100": "FFCCBC",
"200": "FFAB91",
"300": "FF8A65",
"400": "FF7043",
"500": "FF5722",
"600": "F4511E",
"700": "E64A19",
"800": "D84315",
"900": "BF360C",
"A100": "FF9E80",
"A200": "FF6E40",
"A400": "FF3D00",
"A700": "DD2C00",
},
"Brown": {
"50": "EFEBE9",
"100": "D7CCC8",
"200": "BCAAA4",
"300": "A1887F",
"400": "8D6E63",
"500": "795548",
"600": "6D4C41",
"700": "5D4037",
"800": "4E342E",
"900": "3E2723",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Gray": {
"50": "FAFAFA",
"100": "F5F5F5",
"200": "EEEEEE",
"300": "E0E0E0",
"400": "BDBDBD",
"500": "9E9E9E",
"600": "757575",
"700": "616161",
"800": "424242",
"900": "212121",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"BlueGray": {
"50": "ECEFF1",
"100": "CFD8DC",
"200": "B0BEC5",
"300": "90A4AE",
"400": "78909C",
"500": "607D8B",
"600": "546E7A",
"700": "455A64",
"800": "37474F",
"900": "263238",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Light": {
"StatusBar": "E0E0E0",
"AppBar": "F5F5F5",
"Background": "FAFAFA",
"CardsDialogs": "FFFFFF",
"FlatButtonDown": "cccccc",
},
"Dark": {
"StatusBar": "000000",
"AppBar": "1f1f1f",
"Background": "121212",
"CardsDialogs": "212121",
"FlatButtonDown": "999999",
},
}
"""
Color palette. Taken from `2014 Material Design color palettes
<https://material.io/design/color/the-color-system.html>`_.
To demonstrate the shades of the palette, you can run the following code:
.. code-block:: python
from kivy.lang import Builder
from kivy.properties import ListProperty, StringProperty
from kivymd.color_definitions import colors
from kivymd.uix.tab import MDTabsBase
from kivymd.uix.boxlayout import MDBoxLayout
demo = '''
<Root@MDBoxLayout>
orientation: 'vertical'
MDTopAppBar:
title: app.title
MDTabs:
id: android_tabs
on_tab_switch: app.on_tab_switch(*args)
size_hint_y: None
height: "48dp"
tab_indicator_anim: False
RecycleView:
id: rv
key_viewclass: "viewclass"
key_size: "height"
RecycleBoxLayout:
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<ItemColor>
size_hint_y: None
height: "42dp"
MDLabel:
text: root.text
halign: "center"
<Tab>
'''
from kivy.factory import Factory
from kivymd.app import MDApp
class Tab(MDBoxLayout, MDTabsBase):
pass
class ItemColor(MDBoxLayout):
text = StringProperty()
color = ListProperty()
class Palette(MDApp):
title = "Colors definitions"
def build(self):
Builder.load_string(demo)
self.screen = Factory.Root()
for name_tab in colors.keys():
tab = Tab(title=name_tab)
self.screen.ids.android_tabs.add_widget(tab)
return self.screen
def on_tab_switch(
self, instance_tabs, instance_tab, instance_tabs_label, tab_text
):
self.screen.ids.rv.data = []
if not tab_text:
tab_text = 'Red'
for value_color in colors[tab_text]:
self.screen.ids.rv.data.append(
{
"viewclass": "ItemColor",
"md_bg_color": colors[tab_text][value_color],
"title": value_color,
}
)
def on_start(self):
self.on_tab_switch(
None,
None,
None,
self.screen.ids.android_tabs.ids.layout.children[-1].text,
)
Palette().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/palette.gif
:align: center
"""
palette = [
"Red",
"Pink",
"Purple",
"DeepPurple",
"Indigo",
"Blue",
"LightBlue",
"Cyan",
"Teal",
"Green",
"LightGreen",
"Lime",
"Yellow",
"Amber",
"Orange",
"DeepOrange",
"Brown",
"Gray",
"BlueGray",
]
"""Valid values for color palette selecting."""
hue = [
"50",
"100",
"200",
"300",
"400",
"500",
"600",
"700",
"800",
"900",
"A100",
"A200",
"A400",
"A700",
]
"""Valid values for color hue selecting."""
light_colors = {
"Red": ["50", "100", "200", "300", "A100"],
"Pink": ["50", "100", "200", "A100"],
"Purple": ["50", "100", "200", "A100"],
"DeepPurple": ["50", "100", "200", "A100"],
"Indigo": ["50", "100", "200", "A100"],
"Blue": ["50", "100", "200", "300", "400", "A100"],
"LightBlue": [
"50",
"100",
"200",
"300",
"400",
"500",
"A100",
"A200",
"A400",
],
"Cyan": [
"50",
"100",
"200",
"300",
"400",
"500",
"600",
"A100",
"A200",
"A400",
"A700",
],
"Teal": ["50", "100", "200", "300", "400", "A100", "A200", "A400", "A700"],
"Green": [
"50",
"100",
"200",
"300",
"400",
"500",
"A100",
"A200",
"A400",
"A700",
],
"LightGreen": [
"50",
"100",
"200",
"300",
"400",
"500",
"600",
"A100",
"A200",
"A400",
"A700",
],
"Lime": [
"50",
"100",
"200",
"300",
"400",
"500",
"600",
"700",
"800",
"A100",
"A200",
"A400",
"A700",
],
"Yellow": [
"50",
"100",
"200",
"300",
"400",
"500",
"600",
"700",
"800",
"900",
"A100",
"A200",
"A400",
"A700",
],
"Amber": [
"50",
"100",
"200",
"300",
"400",
"500",
"600",
"700",
"800",
"900",
"A100",
"A200",
"A400",
"A700",
],
"Orange": [
"50",
"100",
"200",
"300",
"400",
"500",
"600",
"700",
"A100",
"A200",
"A400",
"A700",
],
"DeepOrange": ["50", "100", "200", "300", "400", "A100", "A200"],
"Brown": ["50", "100", "200"],
"Gray": ["50", "100", "200", "300", "400", "500"],
"BlueGray": ["50", "100", "200", "300"],
"Dark": [],
"Light": ["White", "MainBackground", "DialogBackground"],
}
"""Which colors are light. Other are dark."""
text_colors = {
"Red": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "FFFFFF",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"Pink": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "FFFFFF",
"400": "FFFFFF",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"Purple": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "FFFFFF",
"400": "FFFFFF",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"DeepPurple": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "FFFFFF",
"400": "FFFFFF",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"Indigo": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "FFFFFF",
"400": "FFFFFF",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"Blue": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"LightBlue": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "FFFFFF",
},
"Cyan": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "000000",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Teal": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Green": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"LightGreen": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "000000",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Lime": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "000000",
"700": "000000",
"800": "000000",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Yellow": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "000000",
"700": "000000",
"800": "000000",
"900": "000000",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Amber": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "000000",
"700": "000000",
"800": "000000",
"900": "000000",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"Orange": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "000000",
"700": "000000",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "000000",
"A700": "000000",
},
"DeepOrange": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "000000",
"A200": "000000",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"Brown": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "FFFFFF",
"400": "FFFFFF",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "FFFFFF",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"Gray": {
"50": "FFFFFF",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "000000",
"500": "000000",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "FFFFFF",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
"BlueGray": {
"50": "000000",
"100": "000000",
"200": "000000",
"300": "000000",
"400": "FFFFFF",
"500": "FFFFFF",
"600": "FFFFFF",
"700": "FFFFFF",
"800": "FFFFFF",
"900": "FFFFFF",
"A100": "FFFFFF",
"A200": "FFFFFF",
"A400": "FFFFFF",
"A700": "FFFFFF",
},
}
"""
Text colors generated from :data:`~light_colors`. "000000" for light and
"FFFFFF" for dark.
How to generate text_colors dict
.. code-block:: python
text_colors = {}
for p in palette:
text_colors[p] = {}
for h in hue:
if h in light_colors[p]:
text_colors[p][h] = "000000"
else:
text_colors[p][h] = "FFFFFF"
"""
theme_colors = [
"Primary",
"Secondary",
"Background",
"Surface",
"Error",
"On_Primary",
"On_Secondary",
"On_Background",
"On_Surface",
"On_Error",
]
"""Valid theme colors."""

View File

@ -0,0 +1,632 @@
"""
Components/Dynamic color
========================
.. seealso::
`Material Design spec, Dynamic color
<https://m3.material.io/styles/color/dynamic-color/overview>`_
.. rubric:: Dynamic color can create accessible UI color schemes based on
content or user settings
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color.png
:align: center
Dynamic color experiences are built with M3 color schemes. Beginning with
Android 12, users can generate individualized schemes through wallpaper
selection and other customization settings. With M3 as a foundation,
user-generated colors can coexist with app colors, putting a range of
customizable visual experiences in the hands of users.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color-preview.png
:align: center
1. Baseline scheme
2. Colors extracted from a wallpaper
3. Colors extracted from content
Example of dynamic color from the list of standard color schemes
----------------------------------------------------------------
.. code-block:: python
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty, ColorProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.utils import hex_colormap
from kivymd.uix.menu import MDDropdownMenu
from kivymd.app import MDApp
KV = '''
<ColorCard>
orientation: "vertical"
MDLabel:
text: root.text
color: "grey"
adaptive_height: True
MDCard:
theme_bg_color: "Custom"
md_bg_color: root.bg_color
MDScreen:
md_bg_color: app.theme_cls.backgroundColor
MDIconButton:
on_release: app.open_menu(self)
pos_hint: {"top": .98}
x: "12dp"
icon: "menu"
MDRecycleView:
id: card_list
viewclass: "ColorCard"
bar_width: 0
size_hint_y: None
height: root.height - dp(68)
RecycleGridLayout:
cols: 3
spacing: "16dp"
padding: "16dp"
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
'''
class ColorCard(BoxLayout):
text = StringProperty()
bg_color = ColorProperty()
class Example(MDApp):
menu: MDDropdownMenu = None
def build(self):
self.theme_cls.dynamic_color = True
return Builder.load_string(KV)
def get_instance_from_menu(self, name_item):
index = 0
rv = self.menu.ids.md_menu
opts = rv.layout_manager.view_opts
datas = rv.data[0]
for data in rv.data:
if data["text"] == name_item:
index = rv.data.index(data)
break
instance = rv.view_adapter.get_view(
index, datas, opts[index]["viewclass"]
)
return instance
def open_menu(self, menu_button):
menu_items = []
for item, method in {
"Set palette": lambda: self.set_palette(),
"Switch theme style": lambda: self.theme_switch(),
}.items():
menu_items.append({"text": item, "on_release": method})
self.menu = MDDropdownMenu(
caller=menu_button,
items=menu_items,
)
self.menu.open()
def set_palette(self):
instance_from_menu = self.get_instance_from_menu("Set palette")
available_palettes = [
name_color.capitalize() for name_color in hex_colormap.keys()
]
menu_items = []
for name_palette in available_palettes:
menu_items.append(
{
"text": name_palette,
"on_release": lambda x=name_palette: self.switch_palette(x),
}
)
MDDropdownMenu(
caller=instance_from_menu,
items=menu_items,
).open()
def switch_palette(self, selected_palette):
self.theme_cls.primary_palette = selected_palette
Clock.schedule_once(self.generate_cards, 0.5)
def theme_switch(self) -> None:
self.theme_cls.switch_theme()
Clock.schedule_once(self.generate_cards, 0.5)
def generate_cards(self, *args):
self.root.ids.card_list.data = []
for color in self.theme_cls.schemes_name_colors:
value = f"{color}Color"
self.root.ids.card_list.data.append(
{
"bg_color": getattr(self.theme_cls, value),
"text": value,
}
)
def on_start(self):
Clock.schedule_once(self.generate_cards)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color.gif
:align: center
Example of a dynamic color from an image
----------------------------------------
.. seealso::
:attr:`kivymd.theming.ThemeManager.path_to_wallpaper`
.. code-block:: python
import os
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.core.window.window_sdl2 import WindowSDL
from kivy.lang import Builder
from kivy.properties import StringProperty, ColorProperty
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.app import MDApp
KV = '''
<ColorCard>
orientation: "vertical"
MDLabel:
text: root.text
color: "grey"
adaptive_height: True
MDCard:
theme_bg_color: "Custom"
md_bg_color: root.bg_color
MDScreen:
md_bg_color: app.theme_cls.backgroundColor
MDRecycleView:
id: card_list
viewclass: "ColorCard"
bar_width: 0
RecycleGridLayout:
cols: 3
spacing: "16dp"
padding: "16dp"
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
'''
class ColorCard(MDBoxLayout):
text = StringProperty()
bg_color = ColorProperty()
class Example(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Window.bind(on_dropfile=self.on_drop_file)
def on_drop_file(self, sdl: WindowSDL, path_to_file: str) -> None:
ext = os.path.splitext(path_to_file)[1]
if isinstance(path_to_file, bytes):
path_to_file = path_to_file.decode()
if isinstance(ext, bytes):
ext = ext.decode()
if ext in [".png", ".jpg"]:
self.theme_cls.path_to_wallpaper = path_to_file
Clock.schedule_once(self.generate_cards, 0.5)
def build(self):
self.theme_cls.dynamic_color = True
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
def theme_switch(self) -> None:
self.theme_cls.switch_theme()
Clock.schedule_once(self.generate_cards, 0.5)
def generate_cards(self, *args):
self.root.ids.card_list.data = []
for color in self.theme_cls.schemes_name_colors:
value = f"{color}Color"
self.root.ids.card_list.data.append(
{
"bg_color": getattr(self.theme_cls, value),
"text": value,
}
)
def on_start(self):
Clock.schedule_once(self.generate_cards)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color-path-to_wallpapper.gif
:align: center
"""
from kivy.properties import ColorProperty
class DynamicColor:
"""
Dynamic color class.
.. versionadded:: 2.0.0
"""
# Primary.
primaryColor = ColorProperty()
"""
Primary color.
:attr:`primaryColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
primaryContainerColor = ColorProperty()
"""
Primary container color.
:attr:`primaryContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# On Primary.
onPrimaryColor = ColorProperty()
"""
On primary color.
:attr:`onPrimaryColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
onPrimaryContainerColor = ColorProperty()
"""
On primary container color.
:attr:`onPrimaryContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Secondary.
secondaryColor = ColorProperty()
"""
Secondary color.
:attr:`secondaryColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
secondaryContainerColor = ColorProperty()
"""
Secondary container color.
:attr:`secondaryContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# On Secondary.
onSecondaryColor = ColorProperty()
"""
On secondary color.
:attr:`onSecondaryColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
onSecondaryContainerColor = ColorProperty()
"""
On secondary container color.
:attr:`onSecondaryContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Tertiary.
tertiaryColor = ColorProperty()
"""
Tertiary color.
:attr:`tertiaryColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
tertiaryContainerColor = ColorProperty()
"""
Tertiary container color.
:attr:`tertiaryContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# On Tertiary.
onTertiaryColor = ColorProperty()
"""
On tertiary color.
:attr:`onTertiaryColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
onTertiaryContainerColor = ColorProperty()
"""
On tertiary container color.
:attr:`onTertiaryContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Surface.
surfaceColor = ColorProperty()
"""
Surface color.
:attr:`surfaceColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceDimColor = ColorProperty()
"""
Surface dim color.
:attr:`surfaceDimColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceBrightColor = ColorProperty()
"""
Surface bright color.
:attr:`surfaceBrightColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceContainerLowestColor = ColorProperty()
"""
Surface container lowest color.
:attr:`surfaceContainerLowestColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceContainerLowColor = ColorProperty()
"""
Surface container low color.
:attr:`surfaceContainerLowColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceContainerColor = ColorProperty()
"""
Surface container color.
:attr:`surfaceContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceContainerHighColor = ColorProperty()
"""
Surface container high color.
:attr:`surfaceContainerHighColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceContainerHighestColor = ColorProperty()
"""
Surface container highest color.
:attr:`surfaceContainerHighestColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceVariantColor = ColorProperty()
"""
Surface variant color.
:attr:`surfaceVariantColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
surfaceTintColor = ColorProperty()
"""
Surface tint color.
:attr:`surfaceTintColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# On Surface.
onSurfaceColor = ColorProperty()
"""
On surface color.
:attr:`onSurfaceColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
onSurfaceLightColor = ColorProperty()
"""
On surface light color.
:attr:`onSurfaceLightColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
onSurfaceVariantColor = ColorProperty()
"""
On surface variant color.
:attr:`onSurfaceVariantColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Inverse.
inverseSurfaceColor = ColorProperty()
"""
Inverse surface color.
:attr:`inverseSurfaceColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
inverseOnSurfaceColor = ColorProperty()
"""
Inverse on surface color.
:attr:`inverseOnSurfaceColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
inversePrimaryColor = ColorProperty()
"""
Inverse primary color.
:attr:`inversePrimaryColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Background.
backgroundColor = ColorProperty()
"""
Background color.
:attr:`backgroundColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# On Background.
onBackgroundColor = ColorProperty()
"""
On background color.
:attr:`onBackgroundColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Error.
errorColor = ColorProperty()
"""
Error color.
:attr:`errorColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
errorContainerColor = ColorProperty()
"""
Error container color.
:attr:`errorContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# On Error.
onErrorColor = ColorProperty()
"""
On error color.
:attr:`onErrorColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
onErrorContainerColor = ColorProperty()
"""
On error container color.
:attr:`onErrorContainerColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Outline.
outlineColor = ColorProperty()
"""
Outline color.
:attr:`outlineColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
outlineVariantColor = ColorProperty()
"""
Outline variant color.
:attr:`outlineVariantColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Shadow/scrim.
shadowColor = ColorProperty()
"""
Shadow color.
:attr:`shadowColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
scrimColor = ColorProperty()
"""
Scrim color.
:attr:`scrimColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Disabled.
disabledTextColor = ColorProperty()
"""
Disabled text color.
:attr:`disabledTextColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
# Transparent.
transparentColor = ColorProperty([0, 0, 0, 0])
"""
Transparent color.
:attr:`transparentColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0]`.
"""
# Ripple.
rippleColor = ColorProperty("#BDBDBD")
"""
Ripple color.
:attr:`rippleColor` is an :class:`~kivy.properties.ColorProperty`
and defaults to `'#BDBDBD'`.
"""

View File

@ -1 +0,0 @@
from .fadingedge import FadingEdgeEffect

View File

@ -1,200 +0,0 @@
"""
Effects/FadingEdgeEffect
========================
.. versionadded:: 1.0.0
The `FadingEdgeEffect` class implements a fade effect for `KivyMD` widgets:
.. code-block:: python
from kivy.lang import Builder
from kivy.uix.scrollview import ScrollView
from kivymd.app import MDApp
from kivymd.effects.fadingedge.fadingedge import FadingEdgeEffect
from kivymd.uix.list import OneLineListItem
KV = '''
MDScreen:
FadeScrollView:
fade_height: self.height / 2
fade_color: root.md_bg_color
MDList:
id: container
'''
class FadeScrollView(FadingEdgeEffect, ScrollView):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(20):
self.root.ids.container.add_widget(
OneLineListItem(text=f"Single-line item {i}")
)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fading-edge-effect-white.gif
:align: center
.. note:: Use the same color value for the fade_color parameter as for the
parent widget.
"""
from typing import Union
from kivy.clock import Clock
from kivy.graphics.context_instructions import Color
from kivy.graphics.vertex_instructions import Rectangle
from kivy.metrics import dp
from kivy.properties import BooleanProperty, ColorProperty, NumericProperty
from kivymd.theming import ThemableBehavior
__all_ = ("FadingEdgeEffect",)
class FadingEdgeEffect(ThemableBehavior):
"""
The class implements the fade effect.
.. versionadded:: 1.0.0
"""
fade_color = ColorProperty(None)
"""
Fade color.
:attr:`fade_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
fade_height = NumericProperty(0)
"""
Fade height.
:attr:`fade_height` is an :class:`~kivy.properties.ColorProperty`
and defaults to `0`.
"""
edge_top = BooleanProperty(True)
"""
Display fade edge top.
:attr:`edge_top` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
edge_bottom = BooleanProperty(True)
"""
Display fade edge bottom.
:attr:`edge_bottom` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
_height_segment = 10
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self.set_fade)
# TODO: Perhaps it would be better if we used a Shader for the fade effect.
# But, I think the canvas instructions shouldn't affect performance
def set_fade(self, interval: Union[int, float]) -> None:
"""Draws a bottom and top fade border on the canvas."""
fade_color = (
self.theme_cls.primary_color
if not self.fade_color
else self.fade_color
)
height_segment = (
self.fade_height if self.fade_height else dp(100)
) // self._height_segment
alpha = 1.1
with self.canvas:
for i in range(self._height_segment):
alpha -= 0.1
Color(rgba=(fade_color[:-1] + [round(alpha, 1)]))
rectangle_top = (
Rectangle(
pos=(self.x, self.height - (i * height_segment)),
size=(self.width, height_segment),
)
if self.edge_top
else None
)
rectangle_bottom = (
Rectangle(
pos=(self.x, i * height_segment),
size=(self.width, height_segment),
)
if self.edge_bottom
else None
)
# How I hate lambda functions because of their length :(
# But I dont want to call the arguments by short,
# incomprehensible names 'a', 'b', 'c'.
self.bind(
pos=lambda instance_fadind_edge_effect, window_size, rectangle_top=rectangle_top, rectangle_bottom=rectangle_bottom, index=i: self.update_canvas(
instance_fadind_edge_effect,
window_size,
rectangle_top,
rectangle_bottom,
index,
),
size=lambda instance_fadind_edge_effect, window_size, rectangle_top=rectangle_top, rectangle_bottom=rectangle_bottom, index=i: self.update_canvas(
instance_fadind_edge_effect,
window_size,
rectangle_top,
rectangle_bottom,
index,
),
)
self.update_canvas(
self, self.size, rectangle_top, rectangle_bottom, i
)
def update_canvas(
self,
instance_fadind_edge_effect,
size: list[int, int],
rectangle_top: Rectangle,
rectangle_bottom: Rectangle,
index: int,
) -> None:
"""
Updates the position and size of the fade border on the canvas.
Called when the application screen is resized.
"""
height_segment = (
self.fade_height if self.fade_height else dp(100)
) // self._height_segment
if rectangle_top:
rectangle_top.pos = (
instance_fadind_edge_effect.x,
size[1]
- (index * height_segment - instance_fadind_edge_effect.y),
)
rectangle_top.size = (size[0], height_segment)
if rectangle_bottom:
rectangle_bottom.pos = (
instance_fadind_edge_effect.x,
index * height_segment + instance_fadind_edge_effect.y,
)
rectangle_bottom.size = (size[0], height_segment)

View File

@ -1 +0,0 @@
from .roulettescroll import RouletteScrollEffect

View File

@ -1,251 +0,0 @@
"""
Effects/RouletteScrollEffect
============================
This is a subclass of :class:`kivy.effects.ScrollEffect` that simulates the
motion of a roulette, or a notched wheel (think Wheel of Fortune). It is
primarily designed for emulating the effect of the iOS and android date pickers.
Usage
-----
Here's an example of using :class:`RouletteScrollEffect` for a
:class:`kivy.uix.scrollview.ScrollView`:
.. code-block:: python
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
# Preparing a `GridLayout` inside a `ScrollView`.
layout = GridLayout(cols=1, padding=10, size_hint=(None, None), width=500)
layout.bind(minimum_height=layout.setter('height'))
for i in range(30):
btn = Button(text=str(i), size=(480, 40), size_hint=(None, None))
layout.add_widget(btn)
root = ScrollView(
size_hint=(None, None),
size=(500, 320),
pos_hint={'center_x': .5, 'center_y': .5},
do_scroll_x=False,
)
root.add_widget(layout)
# Preparation complete. Now add the new scroll effect.
root.effect_y = RouletteScrollEffect(anchor=20, interval=40)
runTouchApp(root)
Here the :class:`ScrollView` scrolls through a series of buttons with height
40. We then attached a :class:`RouletteScrollEffect` with interval 40,
corresponding to the button heights. This allows the scrolling to stop at
the same offset no matter where it stops. The :attr:`RouletteScrollEffect.anchor`
adjusts this offset.
Customizations
--------------
Other settings that can be played with include:
:attr:`RouletteScrollEffect.pull_duration`,
:attr:`RouletteScrollEffect.coasting_alpha`,
:attr:`RouletteScrollEffect.pull_back_velocity`, and
:attr:`RouletteScrollEffect.terminal_velocity`.
See their module documentations for details.
:class:`RouletteScrollEffect` has one event ``on_coasted_to_stop`` that
is fired when the roulette stops, "making a selection". It can be listened to
for handling or cleaning up choice making.
"""
from math import ceil, exp, floor
from kivy.animation import Animation
from kivy.effects.scroll import ScrollEffect
from kivy.properties import AliasProperty, NumericProperty, ObjectProperty
__all_ = ("RouletteScrollEffect",)
class RouletteScrollEffect(ScrollEffect):
"""
This is a subclass of :class:`kivy.effects.ScrollEffect` that simulates the
motion of a roulette, or a notched wheel (think Wheel of Fortune). It is
primarily designed for emulating the effect of the iOS and android date pickers.
.. versionadded:: 0.104.2
"""
__events__ = ("on_coasted_to_stop",)
drag_threshold = NumericProperty(0)
"""
Overrides :attr:`ScrollEffect.drag_threshold` to abolish drag threshold.
.. note::
If using this with a :class:`Roulette` or other :class:`Tickline`
subclasses, what matters is :attr:`Tickline.drag_threshold`, which
is passed to this attribute in the end.
:attr:`drag_threshold` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0`.
"""
min = NumericProperty(-float("inf"))
max = NumericProperty(float("inf"))
interval = NumericProperty(50)
"""
The interval of the values of the "roulette".
:attr:`interval` is an :class:`~kivy.properties.NumericProperty`
and defaults to `50`.
"""
anchor = NumericProperty(0)
"""
One of the valid stopping values.
:attr:`anchor` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0`.
"""
pull_duration = NumericProperty(0.2)
"""
When movement slows around a stopping value, an animation is used
to pull it toward the nearest value. :attr:`pull_duration` is the duration
used for such an animation.
:attr:`pull_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
coasting_alpha = NumericProperty(0.5)
"""
When within :attr:`coasting_alpha` * :attr:`interval` of the
next notch and velocity is below :attr:`terminal_velocity`,
coasting begins and will end on the next notch.
:attr:`coasting_alpha` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.5`.
"""
pull_back_velocity = NumericProperty("50sp")
"""
The velocity below which the scroll value will be drawn to the
*nearest* notch instead of the *next* notch in the direction travelled.
:attr:`pull_back_velocity` is an :class:`~kivy.properties.NumericProperty`
and defaults to `50sp`.
"""
_anim = ObjectProperty(None)
def get_term_vel(self):
return (
exp(self.friction)
* self.interval
* self.coasting_alpha
/ self.pull_duration
)
def set_term_vel(self, val):
self.pull_duration = (
exp(self.friction) * self.interval * self.coasting_alpha / val
)
terminal_velocity = AliasProperty(
get_term_vel,
set_term_vel,
bind=["interval", "coasting_alpha", "pull_duration", "friction"],
cache=True,
)
"""
If velocity falls between :attr:`pull_back_velocity` and
:attr:`terminal velocity` then the movement will start to coast
to the next coming stopping value.
:attr:`terminal_velocity` is computed from a set formula given
:attr:`interval`, :attr:`coasting_alpha`, :attr:`pull_duration`,
and :attr:`friction`. Setting :attr:`terminal_velocity` has the
effect of setting :attr:`pull_duration`.
"""
def start(self, val, t=None):
if self._anim:
self._anim.stop(self)
return ScrollEffect.start(self, val, t=t)
def on_notch(self, *args):
return (self.scroll - self.anchor) % self.interval == 0
def nearest_notch(self, *args):
interval = float(self.interval)
anchor = self.anchor
n = round((self.scroll - anchor) / interval)
return anchor + n * interval
def next_notch(self, *args):
interval = float(self.interval)
anchor = self.anchor
round_ = ceil if self.velocity > 0 else floor
n = round_((self.scroll - anchor) / interval)
return anchor + n * interval
def near_notch(self, d=0.01):
nearest = self.nearest_notch()
if abs((nearest - self.scroll) / self.interval) % 1 < d:
return nearest
else:
return None
def near_next_notch(self, d=None):
d = d or self.coasting_alpha
next_ = self.next_notch()
if abs((next_ - self.scroll) / self.interval) % 1 < d:
return next_
else:
return None
def update_velocity(self, dt):
if self.is_manual:
return
velocity = self.velocity
t_velocity = self.terminal_velocity
next_ = self.near_next_notch()
pull_back_velocity = self.pull_back_velocity
if pull_back_velocity < abs(velocity) < t_velocity and next_:
duration = abs((next_ - self.scroll) / self.velocity)
anim = Animation(
scroll=next_,
duration=duration,
)
self._anim = anim
anim.on_complete = self._coasted_to_stop
anim.start(self)
return
if abs(velocity) < pull_back_velocity and not self.on_notch():
anim = Animation(
scroll=self.nearest_notch(),
duration=self.pull_duration,
t="in_out_circ",
)
self._anim = anim
anim.on_complete = self._coasted_to_stop
anim.start(self)
else:
self.velocity -= self.velocity * self.friction
self.apply_distance(self.velocity * dt)
self.trigger_velocity_update()
def on_coasted_to_stop(self, *args):
"""
This event fires when the roulette has stopped, `making a selection`.
"""
def _coasted_to_stop(self, *args):
self.velocity = 0
self.dispatch("on_coasted_to_stop")

View File

@ -7,11 +7,11 @@ from kivy.factory import Factory
register = Factory.register
register("MDSegmentedButton", module="kivymd.uix.segmentedbutton")
register("MDSegmentedButtonItem", module="kivymd.uix.segmentedbutton")
register("MDSegmentButtonIcon", module="kivymd.uix.segmentedbutton")
register("MDSegmentButtonLabel", module="kivymd.uix.segmentedbutton")
register("MDScrollView", module="kivymd.uix.scrollview")
register("MDRecycleView", module="kivymd.uix.recycleview")
register("MDResponsiveLayout", module="kivymd.uix.responsivelayout")
register("MDSegmentedControl", module="kivymd.uix.segmentedcontrol")
register("MDSegmentedControlItem", module="kivymd.uix.segmentedcontrol")
register("MDSliverAppbar", module="kivymd.uix.sliverappbar")
register("MDSliverAppbarContent", module="kivymd.uix.sliverappbar")
register("MDSliverAppbarHeader", module="kivymd.uix.sliverappbar")
@ -19,8 +19,9 @@ register("MDNavigationRailItem", module="kivymd.uix.navigationrail")
register("MDNavigationRail", module="kivymd.uix.navigationrail")
register("MDNavigationRailFabButton", module="kivymd.uix.navigationrail")
register("MDNavigationRailMenuButton", module="kivymd.uix.navigationrail")
register("MDNavigationRailItemIcon", module="kivymd.uix.navigationrail")
register("MDNavigationRailItemLabel", module="kivymd.uix.navigationrail")
register("MDSwiper", module="kivymd.uix.swiper")
register("MDCarousel", module="kivymd.uix.carousel")
register("MDWidget", module="kivymd.uix.widget")
register("MDFloatLayout", module="kivymd.uix.floatlayout")
register("MDAnchorLayout", module="kivymd.uix.anchorlayout")
@ -32,80 +33,102 @@ register("MDRelativeLayout", module="kivymd.uix.relativelayout")
register("MDGridLayout", module="kivymd.uix.gridlayout")
register("MDStackLayout", module="kivymd.uix.stacklayout")
register("MDExpansionPanel", module="kivymd.uix.expansionpanel")
register("MDExpansionPanelOneLine", module="kivymd.uix.expansionpanel")
register("MDExpansionPanelTwoLine", module="kivymd.uix.expansionpanel")
register("MDExpansionPanelThreeLine", module="kivymd.uix.expansionpanel")
register("MDExpansionPanelHeader", module="kivymd.uix.expansionpanel")
register("MDExpansionPanelContent", module="kivymd.uix.expansionpanel")
register("FitImage", module="kivymd.uix.fitimage")
register("MDBackdrop", module="kivymd.uix.backdrop")
register("MDBanner", module="kivymd.uix.banner")
register("MDTooltip", module="kivymd.uix.tooltip")
register("MDTooltipPlain", module="kivymd.uix.tooltip")
register("MDTooltipRich", module="kivymd.uix.tooltip")
register("MDTooltipRichActionButton", module="kivymd.uix.tooltip")
register("MDTooltipRichSubhead", module="kivymd.uix.tooltip")
register("MDTooltipRichSupportingText", module="kivymd.uix.tooltip")
register("MDBottomSheet", module="kivymd.uix.bottomsheet")
register("MDBottomNavigation", module="kivymd.uix.bottomnavigation")
register("MDBottomNavigationItem", module="kivymd.uix.bottomnavigation")
register("MDBottomSheetDragHandle", module="kivymd.uix.bottomsheet")
register("MDBottomSheetDragHandleButton", module="kivymd.uix.bottomsheet")
register("MDBottomSheetDragHandleTitle", module="kivymd.uix.bottomsheet")
register("MDNavigationBar", module="kivymd.uix.navigationbar")
register("MDNavigationItem", module="kivymd.uix.navigationbar")
register("MDNavigationItemLabel", module="kivymd.uix.navigationbar")
register("MDNavigationItemIcon", module="kivymd.uix.navigationbar")
register("MDToggleButton", module="kivymd.uix.behaviors.toggle_behavior")
register("MDFloatingActionButtonSpeedDial", module="kivymd.uix.button")
register("MDButton", module="kivymd.uix.button")
register("MDButtonText", module="kivymd.uix.button")
register("MDButtonIcon", module="kivymd.uix.button")
register("MDFabButton", module="kivymd.uix.button")
register("MDIconButton", module="kivymd.uix.button")
register("MDRoundImageButton", module="kivymd.uix.button")
register("MDFlatButton", module="kivymd.uix.button")
register("MDRaisedButton", module="kivymd.uix.button")
register("MDFloatingActionButton", module="kivymd.uix.button")
register("MDRectangleFlatButton", module="kivymd.uix.button")
register("MDTextButton", module="kivymd.uix.button")
register("MDCustomRoundIconButton", module="kivymd.uix.button")
register("MDRoundFlatButton", module="kivymd.uix.button")
register("MDFillRoundFlatButton", module="kivymd.uix.button")
register("MDRectangleFlatIconButton", module="kivymd.uix.button")
register("MDRoundFlatIconButton", module="kivymd.uix.button")
register("MDFillRoundFlatIconButton", module="kivymd.uix.button")
register("MDExtendedFabButton", module="kivymd.uix.button")
register("MDExtendedFabButtonIcon", module="kivymd.uix.button")
register("MDExtendedFabButtonText", module="kivymd.uix.button")
register("MDCard", module="kivymd.uix.card")
register("MDSeparator", module="kivymd.uix.card")
register("MDSelectionList", module="kivymd.uix.selection")
register("MDDivider", module="kivymd.uix.divider")
register("MDChip", module="kivymd.uix.chip")
register("MDChipLeadingAvatar", module="kivymd.uix.chip")
register("MDChipLeadingIcon", module="kivymd.uix.chip")
register("MDChipTrailingIcon", module="kivymd.uix.chip")
register("MDChipText", module="kivymd.uix.chip")
register("MDSmartTile", module="kivymd.uix.imagelist")
register("MDSmartTileOverlayContainer", module="kivymd.uix.imagelist")
register("MDSmartTileImage", module="kivymd.uix.imagelist")
register("MDLabel", module="kivymd.uix.label")
register("MDIcon", module="kivymd.uix.label")
register("MDBadge", module="kivymd.uix.badge")
register("MDList", module="kivymd.uix.list")
register("ILeftBody", module="kivymd.uix.list")
register("ILeftBodyTouch", module="kivymd.uix.list")
register("IRightBody", module="kivymd.uix.list")
register("IRightBodyTouch", module="kivymd.uix.list")
register("OneLineListItem", module="kivymd.uix.list")
register("TwoLineListItem", module="kivymd.uix.list")
register("ThreeLineListItem", module="kivymd.uix.list")
register("OneLineAvatarListItem", module="kivymd.uix.list")
register("TwoLineAvatarListItem", module="kivymd.uix.list")
register("ThreeLineAvatarListItem", module="kivymd.uix.list")
register("OneLineIconListItem", module="kivymd.uix.list")
register("TwoLineIconListItem", module="kivymd.uix.list")
register("ThreeLineIconListItem", module="kivymd.uix.list")
register("OneLineRightIconListItem", module="kivymd.uix.list")
register("TwoLineRightIconListItem", module="kivymd.uix.list")
register("ThreeLineRightIconListItem", module="kivymd.uix.list")
register("OneLineAvatarIconListItem", module="kivymd.uix.list")
register("TwoLineAvatarIconListItem", module="kivymd.uix.list")
register("ThreeLineAvatarIconListItem", module="kivymd.uix.list")
register("MDListItem", module="kivymd.uix.list")
register("MDListItemHeadlineText", module="kivymd.uix.list")
register("MDListItemSupportingText", module="kivymd.uix.list")
register("MDListItemTrailingSupportingText", module="kivymd.uix.list")
register("MDListItemLeadingIcon", module="kivymd.uix.list")
register("MDListItemTrailingIcon", module="kivymd.uix.list")
register("MDListItemTrailingCheckbox", module="kivymd.uix.list")
register("MDListItemTertiaryText", module="kivymd.uix.list")
register("HoverBehavior", module="kivymd.uix.behaviors.hover_behavior")
register("FocusBehavior", module="kivymd.uix.behaviors.focus_behavior")
register("MagicBehavior", module="kivymd.uix.behaviors.magic_behavior")
register("MDNavigationDrawer", module="kivymd.uix.navigationdrawer")
register("MDNavigationLayout", module="kivymd.uix.navigationdrawer")
register("MDNavigationDrawerMenu", module="kivymd.uix.navigationdrawer")
register("MDNavigationDrawerHeader", module="kivymd.uix.navigationdrawer")
register("MDNavigationDrawerItem", module="kivymd.uix.navigationdrawer")
register(
"MDNavigationDrawerItemLeadingIcon", module="kivymd.uix.navigationdrawer"
)
register(
"MDNavigationDrawerItemTrailingText", module="kivymd.uix.navigationdrawer"
)
register("MDNavigationDrawerHeader", module="kivymd.uix.navigationdrawer")
register("MDNavigationDrawerItemText", module="kivymd.uix.navigationdrawer")
register("MDNavigationDrawerLabel", module="kivymd.uix.navigationdrawer")
register("MDNavigationDrawerDivider", module="kivymd.uix.navigationdrawer")
register("MDProgressBar", module="kivymd.uix.progressbar")
register("MDScrollViewRefreshLayout", module="kivymd.uix.refreshlayout")
register("MDCheckbox", module="kivymd.uix.selectioncontrol")
register("MDSwitch", module="kivymd.uix.selectioncontrol")
register("MDSlider", module="kivymd.uix.slider")
register("MDSpinner", module="kivymd.uix.spinner")
register("MDTabs", module="kivymd.uix.tab")
register("MDCircularProgressIndicator", module="kivymd.uix.progressindicator")
register("MDLinearProgressIndicator", module="kivymd.uix.progressindicator")
register("MDTabsPrimary", module="kivymd.uix.tab")
register("MDTabsSecondary", module="kivymd.uix.tab")
register("MDTabsItem", module="kivymd.uix.tab")
register("MDTabsItemSecondary", module="kivymd.uix.tab")
register("MDTabsBadge", module="kivymd.uix.tab")
register("MDTabsItemIcon", module="kivymd.uix.tab")
register("MDTabsItemText", module="kivymd.uix.tab")
register("MDTabsCarousel", module="kivymd.uix.tab")
register("MDTextField", module="kivymd.uix.textfield")
register("MDTextFieldRect", module="kivymd.uix.textfield")
register("MDTopAppBar", module="kivymd.uix.toolbar")
register("MDBottomAppBar", module="kivymd.uix.toolbar")
register("MDTextFieldHelperText", module="kivymd.uix.textfield")
register("MDTextFieldMaxLengthText", module="kivymd.uix.textfield")
register("MDTextFieldHintText", module="kivymd.uix.textfield")
register("MDTextFieldLeadingIcon", module="kivymd.uix.textfield")
register("MDTextFieldTrailingIcon", module="kivymd.uix.textfield")
register("MDTopAppBarTrailingButtonContainer", module="kivymd.uix.appbar")
register("MDTopAppBarLeadingButtonContainer", module="kivymd.uix.appbar")
register("MDFabBottomAppBarButton", module="kivymd.uix.appbar")
register("MDActionBottomAppBarButton", module="kivymd.uix.appbar")
register("MDTopAppBarTitle", module="kivymd.uix.appbar")
register("MDTopAppBar", module="kivymd.uix.appbar")
register("MDBottomAppBar", module="kivymd.uix.appbar")
register("MDActionTopAppBarButton", module="kivymd.uix.appbar")
register("MDDropDownItem", module="kivymd.uix.dropdownitem")
register("MDDropDownItemText", module="kivymd.uix.dropdownitem")
register("MDCircularLayout", module="kivymd.uix.circularlayout")
register("MDHeroFrom", module="kivymd.uix.hero")
register("MDHeroTo", module="kivymd.uix.hero")

View File

@ -1,5 +1,5 @@
"""
Themes/Font Definitions
Themes/Font definitions
=======================
.. seealso::
@ -8,6 +8,7 @@ Themes/Font Definitions
"""
from kivy.core.text import LabelBase
from kivy.metrics import sp
from kivymd import fonts_path
@ -48,22 +49,102 @@ fonts = [
for font in fonts:
LabelBase.register(**font)
theme_font_styles = [
"H1",
"H2",
"H3",
"H4",
"H5",
"H6",
"Subtitle1",
"Subtitle2",
"Body1",
"Body2",
"Button",
"Caption",
"Overline",
"Icon",
]
# TODO: Add `weight` properties.
theme_font_styles = {
"Icon": {
"large": {
"line-height": 1,
"font-name": "Icons",
"font-size": sp(24),
},
},
"Display": {
"large": {
"line-height": 1.64,
"font-name": "Roboto",
"font-size": sp(57),
},
"medium": {
"line-height": 1.52,
"font-name": "Roboto",
"font-size": sp(45),
},
"small": {
"line-height": 1.44,
"font-name": "Roboto",
"font-size": sp(36),
},
},
"Headline": {
"large": {
"line-height": 1.40,
"font-name": "Roboto",
"font-size": sp(32),
},
"medium": {
"line-height": 1.36,
"font-name": "Roboto",
"font-size": sp(28),
},
"small": {
"line-height": 1.32,
"font-name": "Roboto",
"font-size": sp(24),
},
},
"Title": {
"large": {
"line-height": 1.28,
"font-name": "Roboto",
"font-size": sp(22),
},
"medium": {
"line-height": 1.24,
"font-name": "Roboto",
"font-size": sp(16),
},
"small": {
"line-height": 1.20,
"font-name": "Roboto",
"font-size": sp(14),
},
},
"Body": {
"large": {
"line-height": 1.24,
"font-name": "Roboto",
"font-size": sp(16),
},
"medium": {
"line-height": 1.20,
"font-name": "Roboto",
"font-size": sp(14),
},
"small": {
"line-height": 1.16,
"font-name": "Roboto",
"font-size": sp(12),
},
},
"Label": {
"large": {
"line-height": 1.20,
"font-name": "Roboto",
"font-size": sp(14),
},
"medium": {
"line-height": 1.16,
"font-name": "Roboto",
"font-size": sp(12),
},
"small": {
"line-height": 1.16,
"font-name": "Roboto",
"font-size": sp(11),
},
},
}
"""
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-styles-2.png
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/label-font-style-preview.png
:align: center
"""

View File

@ -2,17 +2,17 @@
Themes/Icon Definitions
=======================
.. seealso::
.. seealso::Updateeeee
`Material Design Icons <https://materialdesignicons.com/>`_
`Material Design Icons <https://m3.material.io/styles/icons/overview>`_
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/material-icons.png
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/material-m3-icons.png
:align: center
List of icons from materialdesignicons.com. These expanded material design
icons are maintained by Austin Andrews (Templarian on Github).
LAST UPDATED: Version 7.2.96
Version 7.4.47
To preview the icons and their names, you can use the following application:
----------------------------------------------------------------------------
@ -21,25 +21,28 @@ To preview the icons and their names, you can use the following application:
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.screenmanager import Screen
from kivymd.icon_definitions import md_icons
from kivymd.uix.screen import MDScreen
from kivymd.app import MDApp
from kivymd.uix.list import OneLineIconListItem
from kivymd.uix.list import MDListItem
Builder.load_string(
'''
#:import images_path kivymd.images_path
<CustomOneLineIconListItem>
<IconItem>
IconLeftWidget:
MDListItemLeadingIcon:
icon: root.icon
MDListItemSupportingText:
text: root.text
<PreviousMDIcons>
md_bg_color: self.theme_cls.backgroundColor
MDBoxLayout:
orientation: 'vertical'
@ -51,6 +54,7 @@ To preview the icons and their names, you can use the following application:
MDIconButton:
icon: 'magnify'
pos_hint: {'center_y': .5}
MDTextField:
id: search_field
@ -63,7 +67,7 @@ To preview the icons and their names, you can use the following application:
key_size: 'height'
RecycleBoxLayout:
padding: dp(10)
padding: dp(10), dp(10), 0, dp(10)
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
@ -73,19 +77,19 @@ To preview the icons and their names, you can use the following application:
)
class CustomOneLineIconListItem(OneLineIconListItem):
class IconItem(MDListItem):
icon = StringProperty()
text = StringProperty()
class PreviousMDIcons(Screen):
class PreviousMDIcons(MDScreen):
def set_list_md_icons(self, text="", search=False):
'''Builds a list of icons for the screen MDIcons.'''
def add_icon_item(name_icon):
self.ids.rv.data.append(
{
"viewclass": "CustomOneLineIconListItem",
"viewclass": "IconItem",
"icon": name_icon,
"text": name_icon,
"callback": lambda x: x,
@ -115,7 +119,7 @@ To preview the icons and their names, you can use the following application:
MainApp().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icons-previous.gif
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/m3-icons-previous.gif
:align: center
"""
@ -149,9 +153,12 @@ md_icons = {
"account-badge": "\U000F1B0A",
"account-badge-outline": "\U000F1B0B",
"account-box": "\U000F0006",
"account-box-edit-outline": "\U000F1CC8",
"account-box-minus-outline": "\U000F1CC9",
"account-box-multiple": "\U000F0934",
"account-box-multiple-outline": "\U000F100A",
"account-box-outline": "\U000F0007",
"account-box-plus-outline": "\U000F1CCA",
"account-cancel": "\U000F12DF",
"account-cancel-outline": "\U000F12E0",
"account-card": "\U000F1BA4",
@ -181,6 +188,10 @@ md_icons = {
"account-edit-outline": "\U000F0FFB",
"account-eye": "\U000F0420",
"account-eye-outline": "\U000F127B",
"account-file": "\U000F1CA7",
"account-file-outline": "\U000F1CA8",
"account-file-text": "\U000F1CA9",
"account-file-text-outline": "\U000F1CAA",
"account-filter": "\U000F0936",
"account-filter-outline": "\U000F0F9D",
"account-group": "\U000F0849",
@ -669,6 +680,8 @@ md_icons = {
"arrow-left-thin-circle-outline": "\U000F159A",
"arrow-left-top": "\U000F17A7",
"arrow-left-top-bold": "\U000F17A8",
"arrow-oscillating": "\U000F1C91",
"arrow-oscillating-off": "\U000F1C92",
"arrow-projectile": "\U000F1840",
"arrow-projectile-multiple": "\U000F183F",
"arrow-right": "\U000F0054",
@ -840,6 +853,8 @@ md_icons = {
"bag-personal-off": "\U000F0E11",
"bag-personal-off-outline": "\U000F0E12",
"bag-personal-outline": "\U000F0E13",
"bag-personal-plus": "\U000F1CA4",
"bag-personal-plus-outline": "\U000F1CA5",
"bag-personal-tag": "\U000F1B0C",
"bag-personal-tag-outline": "\U000F1B0D",
"bag-suitcase": "\U000F158B",
@ -1145,10 +1160,12 @@ md_icons = {
"book-off-outline": "\U000F1695",
"book-open": "\U000F00BD",
"book-open-blank-variant": "\U000F00BE",
"book-open-blank-variant-outline": "\U000F1CCB",
"book-open-outline": "\U000F0B63",
"book-open-page-variant": "\U000F05DA",
"book-open-page-variant-outline": "\U000F15D6",
"book-open-variant": "\U000F14F7",
"book-open-variant-outline": "\U000F1CCC",
"book-outline": "\U000F0B64",
"book-play": "\U000F0E82",
"book-play-outline": "\U000F0E83",
@ -1339,9 +1356,11 @@ md_icons = {
"bus-multiple": "\U000F0F3F",
"bus-school": "\U000F079F",
"bus-side": "\U000F07A0",
"bus-sign": "\U000F1CC1",
"bus-stop": "\U000F1012",
"bus-stop-covered": "\U000F1013",
"bus-stop-uncovered": "\U000F1014",
"bus-wrench": "\U000F1CC2",
"butterfly": "\U000F1589",
"butterfly-outline": "\U000F158A",
"button-cursor": "\U000F1B4F",
@ -1521,6 +1540,7 @@ md_icons = {
"car-defrost-rear": "\U000F0D62",
"car-door": "\U000F0B6B",
"car-door-lock": "\U000F109D",
"car-door-lock-open": "\U000F1C81",
"car-electric": "\U000F0B6C",
"car-electric-outline": "\U000F15B5",
"car-emergency": "\U000F160F",
@ -1639,6 +1659,7 @@ md_icons = {
"cash-100": "\U000F0115",
"cash-check": "\U000F14EE",
"cash-clock": "\U000F1A91",
"cash-edit": "\U000F1CAB",
"cash-fast": "\U000F185C",
"cash-lock": "\U000F14EA",
"cash-lock-open": "\U000F14EB",
@ -1702,6 +1723,7 @@ md_icons = {
"chair-school": "\U000F0125",
"chandelier": "\U000F1793",
"charity": "\U000F0C4F",
"charity-search": "\U000F1C82",
"chart-arc": "\U000F0126",
"chart-areaspline": "\U000F0127",
"chart-areaspline-variant": "\U000F0E91",
@ -1710,6 +1732,8 @@ md_icons = {
"chart-bell-curve": "\U000F0C50",
"chart-bell-curve-cumulative": "\U000F0FA7",
"chart-box": "\U000F154D",
"chart-box-multiple": "\U000F1CCD",
"chart-box-multiple-outline": "\U000F1CCE",
"chart-box-outline": "\U000F154E",
"chart-box-plus-outline": "\U000F154F",
"chart-bubble": "\U000F05E3",
@ -2026,6 +2050,8 @@ md_icons = {
"cloud-cog-outline": "\U000F1BF1",
"cloud-download": "\U000F0162",
"cloud-download-outline": "\U000F0B7D",
"cloud-key": "\U000F1CA1",
"cloud-key-outline": "\U000F1CA2",
"cloud-lock": "\U000F11F1",
"cloud-lock-open": "\U000F1BF2",
"cloud-lock-open-outline": "\U000F1BF3",
@ -2063,6 +2089,10 @@ md_icons = {
"coach-lamp-variant": "\U000F1A37",
"coat-rack": "\U000F109E",
"code-array": "\U000F0168",
"code-block-braces": "\U000F1C83",
"code-block-brackets": "\U000F1C84",
"code-block-parentheses": "\U000F1C85",
"code-block-tags": "\U000F1C86",
"code-braces": "\U000F0169",
"code-braces-box": "\U000F10D6",
"code-brackets": "\U000F016A",
@ -2501,6 +2531,7 @@ md_icons = {
"diamond": "\U000F0B8A",
"diamond-outline": "\U000F0B8B",
"diamond-stone": "\U000F01C8",
"diaper-outline": "\U000F1CCF",
"dice-1": "\U000F01CA",
"dice-1-outline": "\U000F114A",
"dice-2": "\U000F01CB",
@ -2584,6 +2615,7 @@ md_icons = {
"donkey": "\U000F07C2",
"door": "\U000F081A",
"door-closed": "\U000F081B",
"door-closed-cancel": "\U000F1C93",
"door-closed-lock": "\U000F10AF",
"door-open": "\U000F081C",
"door-sliding": "\U000F181E",
@ -2611,6 +2643,7 @@ md_icons = {
"download-lock": "\U000F1320",
"download-lock-outline": "\U000F1321",
"download-multiple": "\U000F09E9",
"download-multiple-outline": "\U000F1CD0",
"download-network": "\U000F06F4",
"download-network-outline": "\U000F0C66",
"download-off": "\U000F10B0",
@ -2643,7 +2676,10 @@ md_icons = {
"earbuds-off-outline": "\U000F1851",
"earbuds-outline": "\U000F1852",
"earth": "\U000F01E7",
"earth-arrow-down": "\U000F1C87",
"earth-arrow-left": "\U000F1C88",
"earth-arrow-right": "\U000F1311",
"earth-arrow-up": "\U000F1C89",
"earth-box": "\U000F06CD",
"earth-box-minus": "\U000F1407",
"earth-box-off": "\U000F06CE",
@ -2747,11 +2783,17 @@ md_icons = {
"emoticon-kiss-outline": "\U000F0C73",
"emoticon-lol": "\U000F1214",
"emoticon-lol-outline": "\U000F1215",
"emoticon-minus": "\U000F1CB2",
"emoticon-minus-outline": "\U000F1CB3",
"emoticon-neutral": "\U000F0C74",
"emoticon-neutral-outline": "\U000F01F6",
"emoticon-outline": "\U000F01F2",
"emoticon-plus": "\U000F1CB4",
"emoticon-plus-outline": "\U000F1CB5",
"emoticon-poop": "\U000F01F7",
"emoticon-poop-outline": "\U000F0C75",
"emoticon-remove": "\U000F1CB6",
"emoticon-remove-outline": "\U000F1CB7",
"emoticon-sad": "\U000F0C76",
"emoticon-sad-outline": "\U000F01F8",
"emoticon-sick": "\U000F157C",
@ -2781,6 +2823,7 @@ md_icons = {
"ethernet": "\U000F0200",
"ethernet-cable": "\U000F0201",
"ethernet-cable-off": "\U000F0202",
"ethernet-off": "\U000F1CD1",
"ev-plug-ccs1": "\U000F1519",
"ev-plug-ccs2": "\U000F151A",
"ev-plug-chademo": "\U000F151B",
@ -2811,6 +2854,7 @@ md_icons = {
"eye-check-outline": "\U000F0D05",
"eye-circle": "\U000F0B94",
"eye-circle-outline": "\U000F0B95",
"eye-closed": "\U000F1CA3",
"eye-lock": "\U000F1C06",
"eye-lock-open": "\U000F1C07",
"eye-lock-open-outline": "\U000F1C08",
@ -3090,6 +3134,7 @@ md_icons = {
"fire-hydrant-alert": "\U000F1138",
"fire-hydrant-off": "\U000F1139",
"fire-off": "\U000F1722",
"fire-station": "\U000F1CC3",
"fire-truck": "\U000F08AB",
"firebase": "\U000F0967",
"firefox": "\U000F0239",
@ -3531,6 +3576,8 @@ md_icons = {
"gas-burner": "\U000F1A1B",
"gas-cylinder": "\U000F0647",
"gas-station": "\U000F0298",
"gas-station-in-use": "\U000F1CC4",
"gas-station-in-use-outline": "\U000F1CC5",
"gas-station-off": "\U000F1409",
"gas-station-off-outline": "\U000F140A",
"gas-station-outline": "\U000F0EB8",
@ -3559,6 +3606,9 @@ md_icons = {
"gender-male-female-variant": "\U000F113F",
"gender-non-binary": "\U000F1140",
"gender-transgender": "\U000F029F",
"generator-mobile": "\U000F1C8A",
"generator-portable": "\U000F1C8B",
"generator-stationary": "\U000F1C8C",
"gentoo": "\U000F08E8",
"gesture": "\U000F07CB",
"gesture-double-tap": "\U000F073C",
@ -3794,6 +3844,7 @@ md_icons = {
"heart-pulse": "\U000F05F6",
"heart-remove": "\U000F1430",
"heart-remove-outline": "\U000F1433",
"heart-search": "\U000F1C8D",
"heart-settings": "\U000F1665",
"heart-settings-outline": "\U000F1666",
"heat-pump": "\U000F1A43",
@ -3918,7 +3969,10 @@ md_icons = {
"hospital-building": "\U000F02E1",
"hospital-marker": "\U000F02E2",
"hot-tub": "\U000F0828",
"hours-12": "\U000F1C94",
"hours-24": "\U000F1478",
"hub": "\U000F1C95",
"hub-outline": "\U000F1C96",
"hubspot": "\U000F0D17",
"hulu": "\U000F0829",
"human": "\U000F02E6",
@ -3933,6 +3987,7 @@ md_icons = {
"human-female-boy": "\U000F0A59",
"human-female-dance": "\U000F15C9",
"human-female-female": "\U000F0A5A",
"human-female-female-child": "\U000F1C8E",
"human-female-girl": "\U000F0A5B",
"human-greeting": "\U000F17C4",
"human-greeting-proximity": "\U000F159D",
@ -3950,6 +4005,7 @@ md_icons = {
"human-male-height": "\U000F0EFB",
"human-male-height-variant": "\U000F0EFC",
"human-male-male": "\U000F0A5E",
"human-male-male-child": "\U000F1C8F",
"human-non-binary": "\U000F1848",
"human-pregnant": "\U000F05CF",
"human-queue": "\U000F1571",
@ -4063,6 +4119,59 @@ md_icons = {
"integrated-circuit-chip": "\U000F1913",
"invert-colors": "\U000F0301",
"invert-colors-off": "\U000F0E4A",
"invoice": "\U000F1CD2",
"invoice-arrow-left": "\U000F1CD3",
"invoice-arrow-left-outline": "\U000F1CD4",
"invoice-arrow-right": "\U000F1CD5",
"invoice-arrow-right-outline": "\U000F1CD6",
"invoice-check": "\U000F1CD7",
"invoice-check-outline": "\U000F1CD8",
"invoice-clock": "\U000F1CD9",
"invoice-clock-outline": "\U000F1CDA",
"invoice-edit": "\U000F1CDB",
"invoice-edit-outline": "\U000F1CDC",
"invoice-export-outline": "\U000F1CDD",
"invoice-fast": "\U000F1CDE",
"invoice-fast-outline": "\U000F1CDF",
"invoice-import": "\U000F1CE0",
"invoice-import-outline": "\U000F1CE1",
"invoice-list": "\U000F1CE2",
"invoice-list-outline": "\U000F1CE3",
"invoice-minus": "\U000F1CE4",
"invoice-minus-outline": "\U000F1CE5",
"invoice-multiple": "\U000F1CE6",
"invoice-multiple-outline": "\U000F1CE7",
"invoice-outline": "\U000F1CE8",
"invoice-plus": "\U000F1CE9",
"invoice-plus-outline": "\U000F1CEA",
"invoice-remove": "\U000F1CEB",
"invoice-remove-outline": "\U000F1CEC",
"invoice-send": "\U000F1CED",
"invoice-send-outline": "\U000F1CEE",
"invoice-text": "\U000F1CEF",
"invoice-text-arrow-left": "\U000F1CF0",
"invoice-text-arrow-left-outline": "\U000F1CF1",
"invoice-text-arrow-right": "\U000F1CF2",
"invoice-text-arrow-right-outline": "\U000F1CF3",
"invoice-text-check": "\U000F1CF4",
"invoice-text-check-outline": "\U000F1CF5",
"invoice-text-clock": "\U000F1CF6",
"invoice-text-clock-outline": "\U000F1CF7",
"invoice-text-edit": "\U000F1CF8",
"invoice-text-edit-outline": "\U000F1CF9",
"invoice-text-fast": "\U000F1CFA",
"invoice-text-fast-outline": "\U000F1CFB",
"invoice-text-minus": "\U000F1CFC",
"invoice-text-minus-outline": "\U000F1CFD",
"invoice-text-multiple": "\U000F1CFE",
"invoice-text-multiple-outline": "\U000F1CFF",
"invoice-text-outline": "\U000F1D00",
"invoice-text-plus": "\U000F1D01",
"invoice-text-plus-outline": "\U000F1D02",
"invoice-text-remove": "\U000F1D03",
"invoice-text-remove-outline": "\U000F1D04",
"invoice-text-send": "\U000F1D05",
"invoice-text-send-outline": "\U000F1D06",
"iobroker": "\U000F12E8",
"ip": "\U000F0A5F",
"ip-network": "\U000F0A60",
@ -4073,6 +4182,7 @@ md_icons = {
"iron-board": "\U000F1838",
"iron-outline": "\U000F1825",
"island": "\U000F104F",
"island-variant": "\U000F1CC6",
"iv-bag": "\U000F10B9",
"jabber": "\U000F0DD5",
"jeepney": "\U000F0302",
@ -4313,6 +4423,9 @@ md_icons = {
"link-box-outline": "\U000F0D1B",
"link-box-variant": "\U000F0D1C",
"link-box-variant-outline": "\U000F0D1D",
"link-circle": "\U000F1CAC",
"link-circle-outline": "\U000F1CAD",
"link-edit": "\U000F1CAE",
"link-lock": "\U000F10BA",
"link-off": "\U000F0338",
"link-plus": "\U000F0C94",
@ -4487,9 +4600,11 @@ md_icons = {
"medication-outline": "\U000F1B15",
"meditation": "\U000F117B",
"memory": "\U000F035B",
"memory-arrow-down": "\U000F1CA6",
"menorah": "\U000F17D4",
"menorah-fire": "\U000F17D5",
"menu": "\U000F035C",
"menu-close": "\U000F1C90",
"menu-down": "\U000F035D",
"menu-down-outline": "\U000F06B6",
"menu-left": "\U000F035E",
@ -4694,10 +4809,16 @@ md_icons = {
"motorbike-off": "\U000F1B16",
"mouse": "\U000F037D",
"mouse-bluetooth": "\U000F098B",
"mouse-left-click": "\U000F1D07",
"mouse-left-click-outline": "\U000F1D08",
"mouse-move-down": "\U000F1550",
"mouse-move-up": "\U000F1551",
"mouse-move-vertical": "\U000F1552",
"mouse-off": "\U000F037E",
"mouse-outline": "\U000F1D09",
"mouse-right-click": "\U000F1D0A",
"mouse-right-click-outline": "\U000F1D0B",
"mouse-scroll-wheel": "\U000F1D0C",
"mouse-variant": "\U000F037F",
"mouse-variant-off": "\U000F0380",
"move-resize": "\U000F0655",
@ -5139,7 +5260,13 @@ md_icons = {
"parking": "\U000F03E3",
"party-popper": "\U000F1056",
"passport": "\U000F07E3",
"passport-alert": "\U000F1CB8",
"passport-biometric": "\U000F0DE1",
"passport-cancel": "\U000F1CB9",
"passport-check": "\U000F1CBA",
"passport-minus": "\U000F1CBB",
"passport-plus": "\U000F1CBC",
"passport-remove": "\U000F1CBD",
"pasta": "\U000F1160",
"patio-heater": "\U000F0F80",
"patreon": "\U000F0882",
@ -5349,6 +5476,7 @@ md_icons = {
"plus-network-outline": "\U000F0CBA",
"plus-outline": "\U000F0705",
"plus-thick": "\U000F11EC",
"pocket": "\U000F1CBE",
"podcast": "\U000F0994",
"podium": "\U000F0D25",
"podium-bronze": "\U000F0D26",
@ -5478,6 +5606,7 @@ md_icons = {
"progress-question": "\U000F1522",
"progress-star": "\U000F1788",
"progress-star-four-points": "\U000F1C3D",
"progress-tag": "\U000F1D0D",
"progress-upload": "\U000F0998",
"progress-wrench": "\U000F0CBD",
"projector": "\U000F042E",
@ -5531,6 +5660,7 @@ md_icons = {
"quality-high": "\U000F0435",
"quality-low": "\U000F0A0C",
"quality-medium": "\U000F0A0D",
"queue-first-in-last-out": "\U000F1CAF",
"quora": "\U000F0D29",
"rabbit": "\U000F0907",
"rabbit-variant": "\U000F1A61",
@ -5779,6 +5909,7 @@ md_icons = {
"rounded-corner": "\U000F0607",
"router": "\U000F11E2",
"router-network": "\U000F1087",
"router-network-wireless": "\U000F1C97",
"router-wireless": "\U000F0469",
"router-wireless-off": "\U000F15A3",
"router-wireless-settings": "\U000F0A69",
@ -5923,10 +6054,14 @@ md_icons = {
"serial-port": "\U000F065C",
"server": "\U000F048B",
"server-minus": "\U000F048C",
"server-minus-outline": "\U000F1C98",
"server-network": "\U000F048D",
"server-network-off": "\U000F048E",
"server-network-outline": "\U000F1C99",
"server-off": "\U000F048F",
"server-outline": "\U000F1C9A",
"server-plus": "\U000F0490",
"server-plus-outline": "\U000F1C9B",
"server-remove": "\U000F0491",
"server-security": "\U000F0492",
"set-all": "\U000F0778",
@ -6466,6 +6601,7 @@ md_icons = {
"swap-horizontal-bold": "\U000F0BCD",
"swap-horizontal-circle": "\U000F0FE1",
"swap-horizontal-circle-outline": "\U000F0FE2",
"swap-horizontal-hidden": "\U000F1D0E",
"swap-horizontal-variant": "\U000F08C1",
"swap-vertical": "\U000F04E2",
"swap-vertical-bold": "\U000F0BCE",
@ -6563,6 +6699,8 @@ md_icons = {
"tag-arrow-up-outline": "\U000F1732",
"tag-check": "\U000F1A7A",
"tag-check-outline": "\U000F1A7B",
"tag-edit": "\U000F1C9C",
"tag-edit-outline": "\U000F1C9D",
"tag-faces": "\U000F04FA",
"tag-heart": "\U000F068B",
"tag-heart-outline": "\U000F0BCF",
@ -6838,6 +6976,7 @@ md_icons = {
"traffic-light": "\U000F052B",
"traffic-light-outline": "\U000F182A",
"train": "\U000F052C",
"train-bus": "\U000F1CC7",
"train-car": "\U000F0BD8",
"train-car-autorack": "\U000F1B2D",
"train-car-box": "\U000F1B2E",
@ -6931,6 +7070,8 @@ md_icons = {
"truck-flatbed": "\U000F1891",
"truck-minus": "\U000F19AE",
"truck-minus-outline": "\U000F19BD",
"truck-off-road": "\U000F1C9E",
"truck-off-road-off": "\U000F1C9F",
"truck-outline": "\U000F129D",
"truck-plus": "\U000F19AD",
"truck-plus-outline": "\U000F19BC",
@ -6975,6 +7116,7 @@ md_icons = {
"umbrella-closed-outline": "\U000F13E2",
"umbrella-closed-variant": "\U000F13E1",
"umbrella-outline": "\U000F054B",
"underwear-outline": "\U000F1D0F",
"undo": "\U000F054C",
"undo-variant": "\U000F054D",
"unfold-less-horizontal": "\U000F054E",
@ -6990,15 +7132,21 @@ md_icons = {
"unreal": "\U000F09B1",
"update": "\U000F06B0",
"upload": "\U000F0552",
"upload-box": "\U000F1D10",
"upload-box-outline": "\U000F1D11",
"upload-circle": "\U000F1D12",
"upload-circle-outline": "\U000F1D13",
"upload-lock": "\U000F1373",
"upload-lock-outline": "\U000F1374",
"upload-multiple": "\U000F083D",
"upload-multiple-outline": "\U000F1D14",
"upload-network": "\U000F06F6",
"upload-network-outline": "\U000F0CD8",
"upload-off": "\U000F10C6",
"upload-off-outline": "\U000F10C7",
"upload-outline": "\U000F0E07",
"usb": "\U000F0553",
"usb-c-port": "\U000F1CBF",
"usb-flash-drive": "\U000F129E",
"usb-flash-drive-outline": "\U000F129F",
"usb-port": "\U000F11F0",
@ -7083,6 +7231,7 @@ md_icons = {
"video-plus": "\U000F09B3",
"video-plus-outline": "\U000F01D3",
"video-stabilization": "\U000F091B",
"video-standard-definition": "\U000F1CA0",
"video-switch": "\U000F0569",
"video-switch-outline": "\U000F0790",
"video-vintage": "\U000F0A1C",
@ -7233,6 +7382,9 @@ md_icons = {
"watering-can-outline": "\U000F1482",
"watermark": "\U000F0612",
"wave": "\U000F0F2E",
"wave-arrow-down": "\U000F1CB0",
"wave-arrow-up": "\U000F1CB1",
"wave-undercurrent": "\U000F1CC0",
"waveform": "\U000F147D",
"waves": "\U000F078D",
"waves-arrow-left": "\U000F1859",
@ -7251,6 +7403,9 @@ md_icons = {
"weather-hurricane-outline": "\U000F1C78",
"weather-lightning": "\U000F0593",
"weather-lightning-rainy": "\U000F067E",
"weather-moonset": "\U000F1D15",
"weather-moonset-down": "\U000F1D16",
"weather-moonset-up": "\U000F1D17",
"weather-night": "\U000F0594",
"weather-night-partly-cloudy": "\U000F0F31",
"weather-partly-cloudy": "\U000F0595",
@ -7424,23 +7579,27 @@ md_icons = {
if __name__ == "__main__":
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.screenmanager import Screen
from kivymd.uix.screen import MDScreen
from kivymd.app import MDApp
from kivymd.uix.list import OneLineIconListItem
from kivymd.uix.list import MDListItem
Builder.load_string(
"""
#:import images_path kivymd.images_path
<CustomOneLineIconListItem>
<IconItem>
IconLeftWidget:
MDListItemLeadingIcon:
icon: root.icon
MDListItemSupportingText:
text: root.text
<PreviousMDIcons>
md_bg_color: self.theme_cls.backgroundColor
MDBoxLayout:
orientation: 'vertical'
@ -7452,6 +7611,7 @@ if __name__ == "__main__":
MDIconButton:
icon: 'magnify'
pos_hint: {'center_y': .5}
MDTextField:
id: search_field
@ -7464,7 +7624,7 @@ if __name__ == "__main__":
key_size: 'height'
RecycleBoxLayout:
padding: dp(10)
padding: dp(10), dp(10), 0, dp(10)
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
@ -7473,17 +7633,18 @@ if __name__ == "__main__":
"""
)
class CustomOneLineIconListItem(OneLineIconListItem):
class IconItem(MDListItem):
icon = StringProperty()
text = StringProperty()
class PreviousMDIcons(Screen):
class PreviousMDIcons(MDScreen):
def set_list_md_icons(self, text="", search=False):
"""Builds a list of icons for the screen MDIcons."""
def add_icon_item(name_icon):
self.ids.rv.data.append(
{
"viewclass": "CustomOneLineIconListItem",
"viewclass": "IconItem",
"icon": name_icon,
"text": name_icon,
"callback": lambda x: x,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Some files were not shown because too many files have changed in this diff Show More