# HG changeset patch # User Goffi # Date 1616246475 -3600 # Node ID 5f0705a9cd3b463b36615671df7f696289458fb3 # Parent 83c67b0933505e45014b4d6b5e8033c67c69c14e install: set minimum version to Kivy 2.0.0: this version brings async support and bugfixes which were backported, thus backport is not needed anymore and has been removed. diff -r 83c67b093350 -r 5f0705a9cd3b cagou/backport/LICENSE --- a/cagou/backport/LICENSE Sat Mar 20 13:51:27 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -Copyright (c) 2010-2019 Kivy Team and other contributors - -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. diff -r 83c67b093350 -r 5f0705a9cd3b cagou/backport/README --- a/cagou/backport/README Sat Mar 20 13:51:27 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -This directory include files backported from unreleased versions of Kivy until -they are actually released. Note that the LICENSE in this directory apply only -to this directory, other files follow general Cagou license specified in root -directory's COPYING (AGPL v3+). - -The files here (except __init__.py) comes from Kivy repository (https://github.com/kivy/kivy) and are -copyrighted to their respective authors - -"__init__.py" is part of Cagou and licensed under the same license (see root COPYING). diff -r 83c67b093350 -r 5f0705a9cd3b cagou/backport/__init__.py --- a/cagou/backport/__init__.py Sat Mar 20 13:51:27 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -#!/usr/bin/env python3 - -# Cagou: desktop/mobile frontend for Salut à Toi XMPP client -# Copyright (C) 2016-2021 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import kivy -from sat.core import log as logging - - -log = logging.getLogger(__name__) - - -def do_backport(): - version = tuple(kivy.parse_kivy_version(kivy.__version__)[0]) - if version < (2, 0, 0): - log.info("installing backport for Carousel") - import sys - from kivy.uix import carousel # NOQA - from . import carousel as carousel_backport - sys.modules['kivy.uix.carousel'] = carousel_backport - else: - log.info("Kivy >= 2.0.0 is used, Carousel backport is not needed anymore") diff -r 83c67b093350 -r 5f0705a9cd3b cagou/backport/carousel.py --- a/cagou/backport/carousel.py Sat Mar 20 13:51:27 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,690 +0,0 @@ -''' -Carousel -======== - -.. image:: images/carousel.gif - :align: right - -.. versionadded:: 1.4.0 - -The :class:`Carousel` widget provides the classic mobile-friendly carousel view -where you can swipe between slides. -You can add any content to the carousel and have it move horizontally or -vertically. The carousel can display pages in a sequence or a loop. - -Example:: - - from kivy.app import App - from kivy.uix.carousel import Carousel - from kivy.uix.image import AsyncImage - - - class CarouselApp(App): - def build(self): - carousel = Carousel(direction='right') - for i in range(10): - src = "http://placehold.it/480x270.png&text=slide-%d&.png" % i - image = AsyncImage(source=src, allow_stretch=True) - carousel.add_widget(image) - return carousel - - - CarouselApp().run() - - -Kv Example:: - - Carousel: - direction: 'right' - AsyncImage: - source: 'http://placehold.it/480x270.png&text=slide-1.png' - AsyncImage: - source: 'http://placehold.it/480x270.png&text=slide-2.png' - AsyncImage: - source: 'http://placehold.it/480x270.png&text=slide-3.png' - AsyncImage: - source: 'http://placehold.it/480x270.png&text=slide-4.png' - - -.. versionchanged:: 1.5.0 - The carousel now supports active children, like the - :class:`~kivy.uix.scrollview.ScrollView`. It will detect a swipe gesture - according to the :attr:`Carousel.scroll_timeout` and - :attr:`Carousel.scroll_distance` properties. - - In addition, the slide container is no longer exposed by the API. - The impacted properties are - :attr:`Carousel.slides`, :attr:`Carousel.current_slide`, - :attr:`Carousel.previous_slide` and :attr:`Carousel.next_slide`. - -''' - -__all__ = ('Carousel', ) - -from functools import partial -from kivy.clock import Clock -from kivy.factory import Factory -from kivy.animation import Animation -from kivy.uix.stencilview import StencilView -from kivy.uix.relativelayout import RelativeLayout -from kivy.properties import BooleanProperty, OptionProperty, AliasProperty, \ - NumericProperty, ListProperty, ObjectProperty, StringProperty - - -class Carousel(StencilView): - '''Carousel class. See module documentation for more information. - ''' - - slides = ListProperty([]) - '''List of slides inside the Carousel. The slides are the - widgets added to the Carousel using the :attr:`add_widget` method. - - :attr:`slides` is a :class:`~kivy.properties.ListProperty` and is - read-only. - ''' - - def _get_slides_container(self): - return [x.parent for x in self.slides] - - slides_container = AliasProperty(_get_slides_container, bind=('slides',)) - - direction = OptionProperty('right', - options=('right', 'left', 'top', 'bottom')) - '''Specifies the direction in which the slides are ordered. This - corresponds to the direction from which the user swipes to go from one - slide to the next. It - can be `right`, `left`, `top`, or `bottom`. For example, with - the default value of `right`, the second slide is to the right - of the first and the user would swipe from the right towards the - left to get to the second slide. - - :attr:`direction` is an :class:`~kivy.properties.OptionProperty` and - defaults to 'right'. - ''' - - min_move = NumericProperty(0.2) - '''Defines the minimum distance to be covered before the touch is - considered a swipe gesture and the Carousel content changed. - This is a expressed as a fraction of the Carousel's width. - If the movement doesn't reach this minimum value, the movement is - cancelled and the content is restored to its original position. - - :attr:`min_move` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0.2. - ''' - - anim_move_duration = NumericProperty(0.5) - '''Defines the duration of the Carousel animation between pages. - - :attr:`anim_move_duration` is a :class:`~kivy.properties.NumericProperty` - and defaults to 0.5. - ''' - - anim_cancel_duration = NumericProperty(0.3) - '''Defines the duration of the animation when a swipe movement is not - accepted. This is generally when the user does not make a large enough - swipe. See :attr:`min_move`. - - :attr:`anim_cancel_duration` is a :class:`~kivy.properties.NumericProperty` - and defaults to 0.3. - ''' - - loop = BooleanProperty(False) - '''Allow the Carousel to loop infinitely. If True, when the user tries to - swipe beyond last page, it will return to the first. If False, it will - remain on the last page. - - :attr:`loop` is a :class:`~kivy.properties.BooleanProperty` and - defaults to False. - ''' - - def _get_index(self): - if self.slides: - return self._index % len(self.slides) - return None - - def _set_index(self, value): - if self.slides: - self._index = value % len(self.slides) - else: - self._index = None - - index = AliasProperty(_get_index, _set_index, - bind=('_index', 'slides'), - cache=True) - '''Get/Set the current slide based on the index. - - :attr:`index` is an :class:`~kivy.properties.AliasProperty` and defaults - to 0 (the first item). - ''' - - def _prev_slide(self): - slides = self.slides - len_slides = len(slides) - index = self.index - if len_slides < 2: # None, or 1 slide - return None - if self.loop and index == 0: - return slides[-1] - if index > 0: - return slides[index - 1] - - previous_slide = AliasProperty(_prev_slide, - bind=('slides', 'index', 'loop'), - cache=True) - '''The previous slide in the Carousel. It is None if the current slide is - the first slide in the Carousel. This ordering reflects the order in which - the slides are added: their presentation varies according to the - :attr:`direction` property. - - :attr:`previous_slide` is an :class:`~kivy.properties.AliasProperty`. - - .. versionchanged:: 1.5.0 - This property no longer exposes the slides container. It returns - the widget you have added. - ''' - - def _curr_slide(self): - if len(self.slides): - return self.slides[self.index or 0] - - current_slide = AliasProperty(_curr_slide, - bind=('slides', 'index'), - cache=True) - '''The currently shown slide. - - :attr:`current_slide` is an :class:`~kivy.properties.AliasProperty`. - - .. versionchanged:: 1.5.0 - The property no longer exposes the slides container. It returns - the widget you have added. - ''' - - def _next_slide(self): - if len(self.slides) < 2: # None, or 1 slide - return None - if self.loop and self.index == len(self.slides) - 1: - return self.slides[0] - if self.index < len(self.slides) - 1: - return self.slides[self.index + 1] - - next_slide = AliasProperty(_next_slide, - bind=('slides', 'index', 'loop'), - cache=True) - '''The next slide in the Carousel. It is None if the current slide is - the last slide in the Carousel. This ordering reflects the order in which - the slides are added: their presentation varies according to the - :attr:`direction` property. - - :attr:`next_slide` is an :class:`~kivy.properties.AliasProperty`. - - .. versionchanged:: 1.5.0 - The property no longer exposes the slides container. - It returns the widget you have added. - ''' - - scroll_timeout = NumericProperty(200) - '''Timeout allowed to trigger the :attr:`scroll_distance`, in milliseconds. - If the user has not moved :attr:`scroll_distance` within the timeout, - no scrolling will occur and the touch event will go to the children. - - :attr:`scroll_timeout` is a :class:`~kivy.properties.NumericProperty` and - defaults to 200 (milliseconds) - - .. versionadded:: 1.5.0 - ''' - - scroll_distance = NumericProperty('20dp') - '''Distance to move before scrolling the :class:`Carousel` in pixels. As - soon as the distance has been traveled, the :class:`Carousel` will start - to scroll, and no touch event will go to children. - It is advisable that you base this value on the dpi of your target device's - screen. - - :attr:`scroll_distance` is a :class:`~kivy.properties.NumericProperty` and - defaults to 20dp. - - .. versionadded:: 1.5.0 - ''' - - anim_type = StringProperty('out_quad') - '''Type of animation to use while animating to the next/previous slide. - This should be the name of an - :class:`~kivy.animation.AnimationTransition` function. - - :attr:`anim_type` is a :class:`~kivy.properties.StringProperty` and - defaults to 'out_quad'. - - .. versionadded:: 1.8.0 - ''' - - ignore_perpendicular_swipes = BooleanProperty(False) - '''Ignore swipes on axis perpendicular to direction. - - :attr:`ignore_perpendicular_swipes` is a - :class:`~kivy.properties.BooleanProperty` and defaults to False. - - .. versionadded:: 1.10.0 - ''' - - # private properties, for internal use only ### - _index = NumericProperty(0, allownone=True) - _prev = ObjectProperty(None, allownone=True) - _current = ObjectProperty(None, allownone=True) - _next = ObjectProperty(None, allownone=True) - _offset = NumericProperty(0) - _touch = ObjectProperty(None, allownone=True) - - _change_touch_mode_ev = None - - def __init__(self, **kwargs): - self._trigger_position_visible_slides = Clock.create_trigger( - self._position_visible_slides, -1) - super(Carousel, self).__init__(**kwargs) - self._skip_slide = None - self.touch_mode_change = False - self._prioritize_next = False - self.fbind('loop', lambda *args: self._insert_visible_slides()) - - def load_slide(self, slide): - '''Animate to the slide that is passed as the argument. - - .. versionchanged:: 1.8.0 - ''' - slides = self.slides - start, stop = slides.index(self.current_slide), slides.index(slide) - if start == stop: - return - - self._skip_slide = stop - if stop > start: - self._prioritize_next = True - self._insert_visible_slides(_next_slide=slide) - self.load_next() - else: - self._prioritize_next = False - self._insert_visible_slides(_prev_slide=slide) - self.load_previous() - - def load_previous(self): - '''Animate to the previous slide. - - .. versionadded:: 1.7.0 - ''' - self.load_next(mode='prev') - - def load_next(self, mode='next'): - '''Animate to the next slide. - - .. versionadded:: 1.7.0 - ''' - if self.index is not None: - w, h = self.size - _direction = { - 'top': -h / 2, - 'bottom': h / 2, - 'left': w / 2, - 'right': -w / 2} - _offset = _direction[self.direction] - if mode == 'prev': - _offset = -_offset - - self._start_animation(min_move=0, offset=_offset) - - def get_slide_container(self, slide): - return slide.parent - - @property - def _prev_equals_next(self): - return self.loop and len(self.slides) == 2 - - def _insert_visible_slides(self, _next_slide=None, _prev_slide=None): - get_slide_container = self.get_slide_container - - previous_slide = _prev_slide if _prev_slide else self.previous_slide - if previous_slide: - self._prev = get_slide_container(previous_slide) - else: - self._prev = None - - current_slide = self.current_slide - if current_slide: - self._current = get_slide_container(current_slide) - else: - self._current = None - - next_slide = _next_slide if _next_slide else self.next_slide - if next_slide: - self._next = get_slide_container(next_slide) - else: - self._next = None - - if self._prev_equals_next: - setattr(self, '_prev' if self._prioritize_next else '_next', None) - - super_remove = super(Carousel, self).remove_widget - for container in self.slides_container: - super_remove(container) - - if self._prev and self._prev.parent is not self: - super(Carousel, self).add_widget(self._prev) - if self._next and self._next.parent is not self: - super(Carousel, self).add_widget(self._next) - if self._current: - super(Carousel, self).add_widget(self._current) - - def _position_visible_slides(self, *args): - slides, index = self.slides, self.index - no_of_slides = len(slides) - 1 - if not slides: - return - x, y, width, height = self.x, self.y, self.width, self.height - _offset, direction = self._offset, self.direction[0] - _prev, _next, _current = self._prev, self._next, self._current - get_slide_container = self.get_slide_container - last_slide = get_slide_container(slides[-1]) - first_slide = get_slide_container(slides[0]) - skip_next = False - _loop = self.loop - - if direction in 'rl': - xoff = x + _offset - x_prev = {'l': xoff + width, 'r': xoff - width} - x_next = {'l': xoff - width, 'r': xoff + width} - if _prev: - _prev.pos = (x_prev[direction], y) - elif _loop and _next and index == 0: - # if first slide is moving to right with direction set to right - # or toward left with direction set to left - if ((_offset > 0 and direction == 'r') or - (_offset < 0 and direction == 'l')): - # put last_slide before first slide - last_slide.pos = (x_prev[direction], y) - skip_next = True - if _current: - _current.pos = (xoff, y) - if skip_next: - return - if _next: - _next.pos = (x_next[direction], y) - elif _loop and _prev and index == no_of_slides: - if ((_offset < 0 and direction == 'r') or - (_offset > 0 and direction == 'l')): - first_slide.pos = (x_next[direction], y) - if direction in 'tb': - yoff = y + _offset - y_prev = {'t': yoff - height, 'b': yoff + height} - y_next = {'t': yoff + height, 'b': yoff - height} - if _prev: - _prev.pos = (x, y_prev[direction]) - elif _loop and _next and index == 0: - if ((_offset > 0 and direction == 't') or - (_offset < 0 and direction == 'b')): - last_slide.pos = (x, y_prev[direction]) - skip_next = True - if _current: - _current.pos = (x, yoff) - if skip_next: - return - if _next: - _next.pos = (x, y_next[direction]) - elif _loop and _prev and index == no_of_slides: - if ((_offset < 0 and direction == 't') or - (_offset > 0 and direction == 'b')): - first_slide.pos = (x, y_next[direction]) - - def on_size(self, *args): - size = self.size - for slide in self.slides_container: - slide.size = size - self._trigger_position_visible_slides() - - def on_pos(self, *args): - self._trigger_position_visible_slides() - - def on_index(self, *args): - self._insert_visible_slides() - self._trigger_position_visible_slides() - self._offset = 0 - - def on_slides(self, *args): - if self.slides: - self.index = self.index % len(self.slides) - self._insert_visible_slides() - self._trigger_position_visible_slides() - - def on__offset(self, *args): - self._trigger_position_visible_slides() - # if reached full offset, switch index to next or prev - direction = self.direction[0] - _offset = self._offset - width = self.width - height = self.height - index = self.index - if self._skip_slide is not None or index is None: - return - - # Move to next slide? - if (direction == 'r' and _offset <= -width) or \ - (direction == 'l' and _offset >= width) or \ - (direction == 't' and _offset <= - height) or \ - (direction == 'b' and _offset >= height): - if self.next_slide: - self.index += 1 - - # Move to previous slide? - elif (direction == 'r' and _offset >= width) or \ - (direction == 'l' and _offset <= -width) or \ - (direction == 't' and _offset >= height) or \ - (direction == 'b' and _offset <= -height): - if self.previous_slide: - self.index -= 1 - - elif self._prev_equals_next: - new_value = (_offset < 0) is (direction in 'rt') - if self._prioritize_next is not new_value: - self._prioritize_next = new_value - if new_value is (self._next is None): - self._prev, self._next = self._next, self._prev - - def _start_animation(self, *args, **kwargs): - # compute target offset for ease back, next or prev - new_offset = 0 - direction = kwargs.get('direction', self.direction)[0] - is_horizontal = direction in 'rl' - extent = self.width if is_horizontal else self.height - min_move = kwargs.get('min_move', self.min_move) - _offset = kwargs.get('offset', self._offset) - - if _offset < min_move * -extent: - new_offset = -extent - elif _offset > min_move * extent: - new_offset = extent - - # if new_offset is 0, it wasnt enough to go next/prev - dur = self.anim_move_duration - if new_offset == 0: - dur = self.anim_cancel_duration - - # detect edge cases if not looping - len_slides = len(self.slides) - index = self.index - if not self.loop or len_slides == 1: - is_first = (index == 0) - is_last = (index == len_slides - 1) - if direction in 'rt': - towards_prev = (new_offset > 0) - towards_next = (new_offset < 0) - else: - towards_prev = (new_offset < 0) - towards_next = (new_offset > 0) - if (is_first and towards_prev) or (is_last and towards_next): - new_offset = 0 - - anim = Animation(_offset=new_offset, d=dur, t=self.anim_type) - anim.cancel_all(self) - - def _cmp(*l): - if self._skip_slide is not None: - self.index = self._skip_slide - self._skip_slide = None - - anim.bind(on_complete=_cmp) - anim.start(self) - - def _get_uid(self, prefix='sv'): - return '{0}.{1}'.format(prefix, self.uid) - - def on_touch_down(self, touch): - if not self.collide_point(*touch.pos): - touch.ud[self._get_uid('cavoid')] = True - return - if self.disabled: - return True - if self._touch: - return super(Carousel, self).on_touch_down(touch) - Animation.cancel_all(self) - self._touch = touch - uid = self._get_uid() - touch.grab(self) - touch.ud[uid] = { - 'mode': 'unknown', - 'time': touch.time_start} - self._change_touch_mode_ev = Clock.schedule_once( - self._change_touch_mode, self.scroll_timeout / 1000.) - self.touch_mode_change = False - return True - - def on_touch_move(self, touch): - if not self.touch_mode_change: - if self.ignore_perpendicular_swipes and \ - self.direction in ('top', 'bottom'): - if abs(touch.oy - touch.y) < self.scroll_distance: - if abs(touch.ox - touch.x) > self.scroll_distance: - self._change_touch_mode() - self.touch_mode_change = True - elif self.ignore_perpendicular_swipes and \ - self.direction in ('right', 'left'): - if abs(touch.ox - touch.x) < self.scroll_distance: - if abs(touch.oy - touch.y) > self.scroll_distance: - self._change_touch_mode() - self.touch_mode_change = True - - if self._get_uid('cavoid') in touch.ud: - return - if self._touch is not touch: - super(Carousel, self).on_touch_move(touch) - return self._get_uid() in touch.ud - if touch.grab_current is not self: - return True - ud = touch.ud[self._get_uid()] - direction = self.direction[0] - if ud['mode'] == 'unknown': - if direction in 'rl': - distance = abs(touch.ox - touch.x) - else: - distance = abs(touch.oy - touch.y) - if distance > self.scroll_distance: - ev = self._change_touch_mode_ev - if ev is not None: - ev.cancel() - ud['mode'] = 'scroll' - else: - if direction in 'rl': - self._offset += touch.dx - if direction in 'tb': - self._offset += touch.dy - return True - - def on_touch_up(self, touch): - if self._get_uid('cavoid') in touch.ud: - return - if self in [x() for x in touch.grab_list]: - touch.ungrab(self) - self._touch = None - ud = touch.ud[self._get_uid()] - if ud['mode'] == 'unknown': - ev = self._change_touch_mode_ev - if ev is not None: - ev.cancel() - super(Carousel, self).on_touch_down(touch) - Clock.schedule_once(partial(self._do_touch_up, touch), .1) - else: - self._start_animation() - - else: - if self._touch is not touch and self.uid not in touch.ud: - super(Carousel, self).on_touch_up(touch) - return self._get_uid() in touch.ud - - def _do_touch_up(self, touch, *largs): - super(Carousel, self).on_touch_up(touch) - # don't forget about grab event! - for x in touch.grab_list[:]: - touch.grab_list.remove(x) - x = x() - if not x: - continue - touch.grab_current = x - super(Carousel, self).on_touch_up(touch) - touch.grab_current = None - - def _change_touch_mode(self, *largs): - if not self._touch: - return - self._start_animation() - uid = self._get_uid() - touch = self._touch - ud = touch.ud[uid] - if ud['mode'] == 'unknown': - touch.ungrab(self) - self._touch = None - super(Carousel, self).on_touch_down(touch) - return - - def add_widget(self, widget, index=0, canvas=None): - container = RelativeLayout( - size=self.size, x=self.x - self.width, y=self.y) - container.add_widget(widget) - super(Carousel, self).add_widget(container, index, canvas) - if index != 0: - self.slides.insert(index - len(self.slides), widget) - else: - self.slides.append(widget) - - def remove_widget(self, widget, *args, **kwargs): - # XXX be careful, the widget.parent refer to the RelativeLayout - # added in add_widget(). But it will break if RelativeLayout - # implementation change. - # if we passed the real widget - slides = self.slides - if widget in slides: - if self.index >= slides.index(widget): - self.index = max(0, self.index - 1) - container = widget.parent - slides.remove(widget) - super(Carousel, self).remove_widget(container) - return container.remove_widget(widget, *args, **kwargs) - return super(Carousel, self).remove_widget(widget, *args, **kwargs) - - def clear_widgets(self): - for slide in self.slides[:]: - self.remove_widget(slide) - super(Carousel, self).clear_widgets() - - -if __name__ == '__main__': - from kivy.app import App - - class Example1(App): - - def build(self): - carousel = Carousel(direction='left', - loop=True) - for i in range(4): - src = "http://placehold.it/480x270.png&text=slide-%d&.png" % i - image = Factory.AsyncImage(source=src, allow_stretch=True) - carousel.add_widget(image) - return carousel - - Example1().run() diff -r 83c67b093350 -r 5f0705a9cd3b cagou/core/cagou_main.py --- a/cagou/core/cagou_main.py Sat Mar 20 13:51:27 2021 +0100 +++ b/cagou/core/cagou_main.py Sat Mar 20 14:21:15 2021 +0100 @@ -26,8 +26,6 @@ from sat.core.i18n import _ from . import kivy_hack kivy_hack.do_hack() -from cagou.backport import do_backport -do_backport() from .constants import Const as C from sat.core import log as logging from sat.core import exceptions diff -r 83c67b093350 -r 5f0705a9cd3b setup.py --- a/setup.py Sat Mar 20 13:51:27 2021 +0100 +++ b/setup.py Sat Mar 20 14:21:15 2021 +0100 @@ -24,7 +24,7 @@ NAME = 'cagou' install_requires = [ - 'kivy>=1.10.0', + 'kivy>=2.0.0', 'kivy_garden.modernmenu', 'pillow', 'plyer',